Installation
composer require xlabs/pollbundle
Add to config/app.php under providers:
Xlabs\PollBundle\PollBundle::class,
Publish the migration and config:
php artisan vendor:publish --provider="Xlabs\PollBundle\PollBundle" --tag="migrations"
php artisan vendor:publish --provider="Xlabs\PollBundle\PollBundle" --tag="config"
Run migrations:
php artisan migrate
First Use Case: Create a Poll
Register the bundle’s service provider and use the Poll facade:
use Xlabs\PollBundle\Facades\Poll;
$poll = Poll::create([
'title' => 'Favorite Framework?',
'description' => 'Help us improve!',
'expires_at' => now()->addDays(7),
]);
$poll->addOption('Laravel');
$poll->addOption('Symfony');
$poll->addOption('Other');
$poll->save();
Where to Look First
config/poll.php (poll settings, default options, etc.).database/migrations/[timestamp]_create_polls_table.php (schema details).Xlabs\PollBundle\Facades\Poll (core methods).resources/views/vendor/poll/ (if the bundle includes Blade templates).Poll Creation & Management
Use the Poll facade to create, update, and delete polls programmatically:
// Create with options
$poll = Poll::create(['title' => 'Test Poll'])->addOptions(['Yes', 'No'])->save();
// Fetch all active polls
$activePolls = Poll::where('expires_at', '>', now())->get();
// Update poll metadata
$poll->update(['description' => 'Updated description']);
Voting System
Handle votes via the Vote model or facade methods:
// Cast a vote
$poll->vote($userId, 'option_id');
// Check if a user voted
$hasVoted = $poll->hasVoted($userId);
// Get results
$results = $poll->getResults();
Integration with Blade
Render polls in views using the poll directive or helper:
@poll('favorite-framework')
@foreach($poll->options as $option)
<label>{{ $option->text }}</label>
<input type="radio" name="vote" value="{{ $option->id }}">
@endforeach
@endpoll
API Endpoints Expose poll functionality via Laravel routes:
Route::get('/polls/{poll}', [PollController::class, 'show']);
Route::post('/polls/{poll}/vote', [VoteController::class, 'store']);
PollCreated, VoteCast.
// In EventServiceProvider
protected $listen = [
'Xlabs\PollBundle\Events\PollCreated' => [
'App\Listeners\LogPollCreation',
],
];
AppServiceProvider:
Poll::extend(function ($poll) {
$poll->validate(function ($attributes) {
return Validator::make($attributes, [
'title' => 'required|max:255|unique:polls',
]);
});
});
$results = Cache::remember("poll:{$poll->id}:results", now()->addHours(1), function () use ($poll) {
return $poll->getResults();
});
Migration Conflicts
polls or poll_options table, drop and re-run migrations to avoid schema conflicts.php artisan migrate:fresh in development to reset the database.Vote Duplication
votes table:
Schema::table('votes', function (Blueprint $table) {
$table->unique(['poll_id', 'user_id']);
});
SELECT * FROM votes WHERE poll_id = ? AND user_id = ? GROUP BY user_id HAVING COUNT(*) > 1;
Expired Polls
expires_at in the past may still be queryable. Use scopes to filter:
$activePolls = Poll::active()->get(); // Assumes `active()` scope exists
PollBundle or override it:
public function scopeActive($query) {
return $query->where('expires_at', '>', now());
}
Option Management
poll_options table directly to archive them.deleted_at column to poll_options and use Laravel’s soft deletes:
$option->delete(); // Soft delete
$option->forceDelete(); // Permanent delete
Log Poll Events
Enable debug logging for poll events in config/poll.php:
'debug' => env('APP_DEBUG', false),
Check logs for PollBundle events in storage/logs/laravel.log.
Query Debugging Use Laravel’s query logging to inspect poll-related queries:
DB::enableQueryLog();
$poll->getResults();
dd(DB::getQueryLog());
Facade vs. Model Direct Usage
Poll facade for simplicity, but use the Poll model directly for complex queries:
// Facade
$poll = Poll::find(1);
// Model (for custom queries)
$poll = \Xlabs\PollBundle\Models\Poll::with('options.votes')->find(1);
Custom Poll Types
Extend the Poll model to support multi-choice, ranking, or conditional polls:
class CustomPoll extends \Xlabs\PollBundle\Models\Poll {
protected $casts = [
'is_ranked' => 'boolean',
];
}
Third-Party Integrations
Poll::created(function ($poll) {
Http::post('https://your-service.com/webhook', [
'poll_id' => $poll->id,
]);
});
Poll::voted(function ($poll, $user) {
Analytics::track('poll_voted', ['poll_id' => $poll->id]);
});
Localization
// resources/lang/en/poll.php
return [
'vote' => 'Cast your vote',
'results' => 'Results',
];
trans helper in Blade:
<button>{{ trans('poll.vote') }}</button>
Testing
$response = $this->post('/polls/1/vote', ['option_id' => 1]);
$response->assertRedirect('/polls/1');
$this->assertDatabaseHas('votes', ['poll_id' => 1, 'user_id' => auth()->id()]);
How can I help you explore Laravel packages today?