Installation
composer require saadzer/ticketit
php artisan vendor:publish --provider="Saadzer\Ticketit\TicketitServiceProvider"
php artisan migrate
php artisan ticketit:install to seed default roles (users, agents, admins) and departments.Configure Routes
Add to routes/web.php:
Route::middleware(['auth'])->group(function () {
Route::prefix('ticketit')->group(function () {
require __DIR__.'/ticketit.php';
});
});
First Ticket Creation
/ticketit/tickets/create.Key Files to Review
config/ticketit.php (core settings like roles, permissions, and auto-assignment logic).resources/views/vendor/ticketit/ (customize blades if needed).app/Providers/TicketitServiceProvider.php (service binding overrides).Ticket Lifecycle
TicketController@create (form + Ticket model).TicketObserver (lowest queue logic in TicketitService::assignTicket()).CommentController (rich text + attachments via TicketitService::uploadImage()).TicketController@close (triggers TicketClosed event).Role-Based Permissions
can() gates (e.g., auth()->user()->can('close_ticket')) to restrict actions.TicketitServiceProvider::boot():
Gate::define('close_ticket', function ($user) {
return $user->isAdmin() || $user->isAgent();
});
Auto-Assignment Logic
config/ticketit.php:
'departments' => [
'technical' => ['agents' => [1, 3]], // Agent IDs
],
Saadzer\Ticketit\Services\TicketitService.Localization
config/app.php:
'locale' => 'fr', // e.g., for French
resources/lang/{locale}/ticketit.php.Dashboard Integration
TicketitService::getDashboardStats():
$stats = app(Saadzer\Ticketit\Services\TicketitService::class)->getDashboardStats();
@foreach($stats['ticketCounts'] as $status => $count)
<div>{{ $status }}: {{ $count }}</div>
@endforeach
Rich Text Editor
config/ticketit.php):
'editor' => [
'enabled' => true,
'config' => [
'filebrowserUploadUrl' => route('ticketit.upload'),
],
],
UploadController@upload.Migration Conflicts
php artisan vendor:publish --tag=ticketit-migrations to update migrations.updated_at timestamps) in database/migrations/.Auto-Assignment Failures
config/ticketit.php for valid departments and agents.is_active = 1 in users table).TicketitService::assignTicket() to log unassigned tickets.Permission Denied Errors
isAdmin(), isAgent()) in User model.routes/web.php (e.g., auth + role:admin).php artisan ticketit:permissions to regenerate gates.Editor Uploads Not Working
storage/app/public is writable and symlinked:
php artisan storage:link
filebrowserUploadUrl in config/ticketit.php matches your UploadController route.Localization Issues
vendor/saadzer/ticketit/resources/lang/{locale}.config/app.php has the correct locale.php artisan vendor:publish --tag=ticketit-lang
Log Auto-Assignment
Add to TicketitService.php:
Log::debug('Available agents for dept X:', [$agents]);
Check Queue Logic
Override getAgentWithLowestQueue() to log queue counts:
public function getAgentWithLowestQueue($department) {
$queues = $this->getAgentQueues($department);
Log::debug('Agent queues:', $queues);
return array_reduce($queues, fn($carry, $item) => $item['count'] < $carry['count'] ? $item : $carry);
}
Test Permissions Use Tinker to verify gates:
php artisan tinker
>>> auth()->user()->can('close_ticket')
Custom Ticket Fields
Ticket model:
class Ticket extends \Saadzer\Ticketit\Models\Ticket {
protected $casts = [
'priority' => 'integer',
];
}
resources/views/vendor/ticketit/tickets/form.blade.php).Custom Assignment Logic
TicketitService:
class CustomTicketitService extends \Saadzer\Ticketit\Services\TicketitService {
public function assignTicket($ticket) {
// Custom logic (e.g., round-robin)
$agent = $this->getNextAgentInRoundRobin($ticket->department);
$ticket->agent_id = $agent->id;
$ticket->save();
}
}
TicketitServiceProvider:
$this->app->bind(
\Saadzer\Ticketit\Services\TicketitService::class,
CustomTicketitService::class
);
Webhooks for External Systems
TicketClosed events in EventServiceProvider:
protected $listen = [
\Saadzer\Ticketit\Events\TicketClosed::class => [
\App\Listeners\SendSlackNotification::class,
],
];
API Endpoints
TicketController:
Route::middleware('auth:api')->get('/ticketit/tickets', [TicketController::class, 'apiIndex']);
public function apiIndex() {
return Ticket::with('comments', 'agent')->get();
}
How can I help you explore Laravel packages today?