Installation Add the package via Composer:
composer require atm/pollbundle
Register the bundle in config/app.php under providers:
Atm\PollBundle\PollBundle::class,
Publish Assets Run the following to publish migrations, config, and views:
php artisan vendor:publish --provider="Atm\PollBundle\PollBundle" --tag="config"
php artisan vendor:publish --provider="Atm\PollBundle\PollBundle" --tag="migrations"
php artisan vendor:publish --provider="Atm\PollBundle\PollBundle" --tag="public"
Migrate the database:
php artisan migrate
First Use Case Create a poll via Tinker or a controller:
use Atm\PollBundle\Entity\Poll;
use Atm\PollBundle\Entity\PollOption;
$poll = new Poll();
$poll->setTitle('Favorite Laravel Feature?');
$poll->setDescription('Help us improve!');
$poll->setExpiresAt(now()->addDays(7));
$option1 = new PollOption();
$option1->setText('Eloquent ORM');
$poll->addOption($option1);
$option2 = new PollOption();
$option2->setText('Blade Templating');
$poll->addOption($option2);
$pollRepository = app()->make('atm_poll.poll.repository');
$pollRepository->save($poll);
Displaying Polls Use the provided Blade directives in your views:
@poll('1') <!-- Renders poll with ID 1 -->
@pollOptions('1') <!-- Renders options for poll with ID 1 -->
Via Controller:
public function createPoll(Request $request)
{
$poll = new Poll();
$poll->setTitle($request->title);
$poll->setDescription($request->description);
$poll->setExpiresAt($request->expires_at);
foreach ($request->options as $optionText) {
$option = new PollOption();
$option->setText($optionText);
$poll->addOption($option);
}
$pollRepository->save($poll);
return redirect()->route('polls.show', $poll->getId());
}
Via API (if extended): Use Laravel's API resources to expose polls and options:
return PollResource::collection(Poll::with('options')->get());
public function vote(Request $request, $pollId, $optionId)
{
$poll = $pollRepository->find($pollId);
$option = $poll->getOption($optionId);
if (!$poll->isActive()) {
abort(403, 'Poll is not active.');
}
$option->incrementVotes();
$pollRepository->save($poll);
return response()->json(['success' => true]);
}
Blade Integration:
@pollResults('1')
Customize results display by extending the bundle's views or overriding templates.
Programmatic Access:
$poll = $pollRepository->find(1);
$results = $poll->getOptions()->mapWithKeys(function ($option) {
return [$option->getId() => $option->getVotes()];
});
Track Votes Over Time:
Extend the PollOption entity to log votes with timestamps:
$option->votes()->create([
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'created_at' => now(),
]);
Use Laravel Events:
Dispatch events for vote actions (e.g., PollVoted):
event(new PollVoted($poll, $option, $request->ip()));
Seed initial polls in DatabaseSeeder.php:
$poll = Poll::create([
'title' => 'Seed Poll',
'description' => 'Test poll for seeding.',
'expires_at' => now()->addDays(30),
]);
PollOption::create([
'poll_id' => $poll->id,
'text' => 'Option 1',
'votes' => 0,
]);
PollOption::create([
'poll_id' => $poll->id,
'text' => 'Option 2',
'votes' => 0,
]);
Extend the bundle's validation logic by overriding the PollType or PollOptionType in your config/packages/atm_poll.yaml:
atm_poll:
validation:
poll:
title: "required|string|max:255"
description: "nullable|string|max:1000"
option:
text: "required|string|max:255"
Support multiple languages by publishing and translating the bundle's views:
php artisan vendor:publish --provider="Atm\PollBundle\PollBundle" --tag="translations"
Update resources/lang/{locale}/poll.php:
return [
'title' => 'Encuesta',
'vote' => 'Votar',
];
Use JavaScript to handle AJAX voting:
$.post(`/polls/${pollId}/options/${optionId}/vote`, function(data) {
if (data.success) {
location.reload(); // Refresh to show updated results
}
});
php artisan vendor:publish --provider="Atm\PollBundle\PollBundle" --tag="migrations" --force
Then run:
php artisan migrate:fresh
Cache::forget("poll_{$poll->getId()}_results");
Cache::forget("poll_{$poll->getId()}_active");
Or disable caching for dynamic poll data in config/cache.php.expires_at is reached.// app/Console/Commands/CheckExpiredPolls.php
public function handle()
{
Poll::where('expires_at', '<', now())
->update(['is_active' => false]);
}
Schedule it in app/Console/Kernel.php:
$schedule->command('poll:check-expired')->daily();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Add logging to track poll interactions:
use Psr\Log\LoggerInterface;
public function vote(Request $request, $pollId, $optionId, LoggerInterface $logger)
{
$logger->info("Vote registered for poll {$pollId}, option {$optionId} by IP: {$request->ip()}");
// Rest of the vote logic...
}
Enable Laravel's query logging in .env:
DB_ENABLE_QUERY_LOG=true
Check logged queries in storage/logs/laravel.log.
Override bundle settings in config/packages/atm_poll.yaml:
atm_poll:
default_vote_limit: 1 # Allow only one vote per IP
enable_anonymous_voting: true
Extend the Poll entity to support custom fields:
class CustomPoll extends Poll
{
protected $customField;
public function setCustomField($value)
{
$this->customField = $value;
}
}
Update the repository to handle the new entity type.
Listen for poll events to trigger actions (e.g., notifications):
// app/Providers/EventServiceProvider.php
protected $listen
How can I help you explore Laravel packages today?