Install & Publish Run the installation commands in order:
composer require ticket/ticketit:dev-main
php artisan vendor:publish --provider="Ticket\Ticketit\TicketitServiceProvider" --tag=ticketit-config
php artisan vendor:publish --provider="Ticket\Ticketit\TicketitServiceProvider" --tag=ticketit-migrations
php artisan migrate
Verify config/ticketit.php exists and adjust defaults if needed.
User Model Integration
Add HasTickets trait to your User model (both Customer and Staff models if separate):
use Ticket\Ticketit\Traits\HasTickets;
class User extends Authenticatable { use HasTickets; }
First Ticket Creation Use the facade or service directly:
use Ticket\Ticketit\Facades\Ticketit;
// Create a ticket for the current customer
$ticket = Ticketit::createTicket([
'subject' => 'Account Issue',
'description' => 'Login not working',
'priority' => 'high',
]);
Customer Flow:
ticketit::customer views to resources/views/vendor/ticketit/.--tag=ticketit-routes) or extend them in routes/web.php.ticketit::customer.tickets.index view to match your theme.Staff Flow:
Ticketit::tickets() to fetch assigned tickets:
$assignedTickets = Ticketit::tickets()->where('assigned_to', auth()->id())->get();
// Customer creates a ticket
$ticket = auth()->user()->createTicket([
'subject' => 'Payment Failed',
'priority' => 'medium',
'attachments' => ['/path/to/receipt.pdf'],
]);
// Staff assigns ticket to another agent
$ticket->assignTo(2); // User ID
$ticket->updateStatus('resolved');
$ticket->reopen(); // Built-in method
// Bulk update status
Ticketit::tickets()->whereIn('id', [1, 2, 3])->update(['status' => 'closed']);
// Add a comment (visible to customer)
$ticket->addComment('Please check your email for updates.', ['is_private' => false]);
// Customer replies to a ticket
$ticket->addComment('Here’s the error screenshot.', ['attachments' => ['screenshot.png']]);
// Staff: Get high-priority unassigned tickets
$tickets = Ticketit::tickets()
->where('priority', 'high')
->whereNull('assigned_to')
->with('comments')
->get();
// Customer: Get their open tickets
$tickets = auth()->user()->tickets()->where('status', '!=', 'closed')->get();
// Trigger when ticket status changes
event(new TicketStatusUpdated($ticket, 'resolved'));
// Listen for ticket creation
Ticketit::onTicketCreated(function ($ticket) {
// Send Slack notification
});
Override published views in resources/views/vendor/ticketit/:
php artisan vendor:publish --provider="Ticket\Ticketit\TicketitServiceProvider" --tag=ticketit-views --force
ticketit::customer.tickets.show to add custom fields:
@extends('ticketit::customer.tickets.show')
@section('ticket-meta')
<div class="custom-field">
{{ $ticket->custom_field }}
</div>
@endsection
Add custom attributes to tickets via model events:
// app/Providers/TicketitServiceProvider.php
public function boot()
{
\Ticket\Ticketit\Models\Ticket::created(function ($ticket) {
$ticket->update(['custom_data' => json_encode(['source' => 'web'])]);
});
}
Use Laravel’s API resources to expose tickets:
// routes/api.php
Route::middleware('auth:api')->get('/tickets', function () {
return Ticketit::tickets()->where('user_id', auth()->id())->paginate();
});
Migration Conflicts
php artisan vendor:publish --tag=ticketit-migrations --force
before altering them. Merge changes manually to avoid overwrites.Role-Based Route Access
routes/web.php:
Route::middleware(['auth', 'role:admin'])->group(function () {
Route::get('/admin/tickets', 'TicketController@index');
});
Attachment Handling
storage/app/public/ticket_attachments. Ensure the symlink exists:
php artisan storage:link
config/ticketit.php:
'attachments' => [
'disk' => 's3',
'path' => 'ticket-attachments',
],
Priority/Status Validation
priority (low, medium, high) and status (open, pending, resolved, closed). Extend validation in app/Providers/TicketitServiceProvider.php:
use Ticket\Ticketit\Rules\ValidPriority;
$request->validate([
'priority' => ['required', new ValidPriority],
]);
Query Logging Enable Laravel’s query logging to debug ticket queries:
DB::enableQueryLog();
$tickets = Ticketit::tickets()->get();
dd(DB::getQueryLog());
Event Debugging
Listen for events in AppServiceProvider:
public function boot()
{
Ticket\Ticketit\Events\TicketCreated::class => function ($event) {
\Log::info('Ticket created', ['ticket' => $event->ticket]);
},
}
Middleware Issues If routes fail silently, check:
TicketitServiceProvider is registered in config/app.php.auth middleware is properly configured for your guards (e.g., auth:customer or auth:staff).Custom Ticket Fields Add fields via model events or database migrations:
// Add a 'department' field
Schema::table('tickets', function (Blueprint $table) {
$table->string('department')->nullable()->after('subject');
});
Update the Ticket model to cast the field:
protected $casts = [
'department' => 'string',
];
Custom Statuses/Priorities
Extend the Ticket model’s getStatusOptions() and getPriorityOptions() methods:
public function getStatusOptions()
{
return array_merge(parent::getStatusOptions(), ['escalated']);
}
Custom Notifications
Override the notification logic in AppServiceProvider:
Ticket\Ticketit\Events\TicketCreated::class => [
'TicketCreatedNotification',
],
Create a custom notification:
use Ticket\Ticketit\Events\TicketCreated;
class TicketCreatedNotification implements ShouldQueue
{
public function handle(TicketCreated $event)
{
Notification::route('mail', $event->ticket->customer->email)
->notify(new TicketCreatedNotification($event->ticket));
}
}
API Rate Limiting Apply rate limits to ticket endpoints:
Route::middleware(['auth:api', 'throttle:10,1'])->group(function () {
Route::apiResource('tickets', 'TicketController');
});
Search Functionality Use Laravel Scout for full-text search:
// Add to Ticket model
use Laravel\Scout\Searchable
How can I help you explore Laravel packages today?