
The missing schedule management for Laravel
A flexible, performant, and developer-friendly schedule management system with deep Laravel integration.
Installation β’ Quick Start β’ Schedule Types β’ Features β’ Documentation β’ Contributing
Requirements: PHP 8.2+ β’ Laravel 11.0+ β’ Carbon 2.0/3.0+
composer require laraveljutsu/zap
# Publish and run migrations
php artisan vendor:publish --tag=zap-migrations
php artisan migrate
# Publish configuration (optional)
php artisan vendor:publish --tag=zap-config
use Zap\Models\Concerns\HasSchedules;
class User extends Authenticatable
{
use HasSchedules;
// ...
}
use Zap\Facades\Zap;
$schedule = Zap::for($user)
->named('Doctor Appointment')
->description('Annual checkup')
->on('2025-03-15') // on() is an alias of from()
->addPeriod('09:00', '10:00')
->save();
// Weekly team meeting
$meeting = Zap::for($user)
->named('Team Standup')
->from('2025-01-01')
->to('2025-12-31')
->addPeriod('09:00', '09:30')
->weekly(['monday', 'wednesday', 'friday'])
->save();
Important
The workingHoursOnly()
and maxDuration()
methods require enabling working_hours
and max_duration
validation rules in your config file. These are disabled by default.
$schedule = Zap::for($user)
->named('Client Meeting')
->from('2025-03-15')
->addPeriod('14:00', '16:00')
->noOverlap() // Prevent conflicts
->workingHoursOnly('09:00', '18:00') // Business hours only
->maxDuration(240) // Max 4 hours
->withMetadata([
'location' => 'Conference Room A',
'priority' => 'high'
])
->save();
Laravel Zap supports four distinct schedule types for complex scheduling scenarios:
Define when someone/something is available. Allows overlaps.
$availability = Zap::for($doctor)
->named('Office Hours')
->availability()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('09:00', '12:00') // Morning session
->addPeriod('14:00', '17:00') // Afternoon session
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
Concrete appointments within availability windows. Prevents overlaps.
$appointment = Zap::for($doctor)
->named('Patient A - Checkup')
->appointment()
->from('2025-01-15')
->addPeriod('10:00', '11:00')
->withMetadata(['patient_id' => 1, 'type' => 'checkup'])
->save();
Time periods that block scheduling (lunch, holidays). Prevents overlaps.
$lunchBreak = Zap::for($doctor)
->named('Lunch Break')
->blocked()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('12:00', '13:00')
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
Default type with explicit rule control.
$custom = Zap::for($user)
->named('Custom Event')
->custom()
->from('2025-01-15')
->addPeriod('15:00', '16:00')
->noOverlap() // Explicitly prevent overlaps
->save();
// Query schedules by type
$availability = Schedule::availability()->get();
$appointments = Schedule::appointments()->get();
$blocked = Schedule::blocked()->get();
// Using relationship methods
$userAppointments = $user->appointmentSchedules()->get();
$userAvailability = $user->availabilitySchedules()->get();
// Check schedule type
$schedule->isAvailability(); // true/false
$schedule->isAppointment(); // true/false
$schedule->isBlocked(); // true/false
- ποΈ Eloquent Integration - Native Laravel models and relationships
- ποΈ Business Rules Engine - Configurable validation with granular control
- β° Temporal Operations - Carbon-based date/time with timezone support
- π Smart Conflict Detection - Automatic overlap checking with buffers
- π Recurring Schedules - Daily, weekly, monthly, and custom patterns
- π Availability Management - Intelligent time slot generation
- π― Schedule Types - Availability, appointment, blocked, and custom
- π§© Laravel Native - Facades, service providers, events, configuration
- π©βπ» Developer Experience - Fluent API, comprehensive testing, documentation
// Check availability
$available = $user->isAvailableAt('2025-03-15', '14:00', '16:00');
// Get available slots
$slots = $user->getAvailableSlots(
date: '2025-03-15',
dayStart: '09:00',
dayEnd: '17:00',
slotDuration: 60
);
// Find next available slot
$nextSlot = $user->getNextAvailableSlot(
afterDate: '2025-03-15',
duration: 120,
dayStart: '09:00',
dayEnd: '17:00'
);
// Check for conflicts
$conflicts = Zap::findConflicts($schedule);
// Automatic conflict prevention
try {
$schedule = Zap::for($user)
->from('2025-03-15')
->addPeriod('14:00', '16:00')
->noOverlap()
->save();
} catch (ScheduleConflictException $e) {
$conflicts = $e->getConflictingSchedules();
}
// Disable overlap checking for availability schedules only
config(['zap.default_rules.no_overlap.applies_to' => ['appointment', 'blocked']]);
// Create availability that can overlap
$availability = Zap::for($user)
->named('General Availability')
->availability()
->from('2025-03-15')
->addPeriod('09:00', '17:00')
->save(); // No overlap validation applied
// Emergency override for specific case
$emergency = Zap::for($user)
->named('Emergency Surgery')
->from('2025-03-15')
->addPeriod('10:30', '12:00')
->withRule('no_overlap', ['enabled' => false])
->save(); // Bypasses overlap validation
// Get schedules for date
$todaySchedules = $user->schedulesForDate(today());
// Get schedules for range
$weekSchedules = $user->schedulesForDateRange('2025-03-11', '2025-03-17');
// Advanced queries
$schedules = Schedule::active()
->forDate('2025-03-15')
->whereHas('periods', function ($query) {
$query->whereBetween('start_time', ['09:00', '17:00']);
})
->get();
π₯ Hospital Scheduling System
// Doctor's working hours (availability)
$availability = Zap::for($doctor)
->named('Dr. Smith - Office Hours')
->availability()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('09:00', '12:00')
->addPeriod('14:00', '17:00')
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
// Lunch break (blocked)
$lunchBreak = Zap::for($doctor)
->named('Lunch Break')
->blocked()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('12:00', '13:00')
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
// Patient appointments
$appointment = Zap::for($doctor)
->named('Patient A - Consultation')
->appointment()
->from('2025-01-15')
->addPeriod('10:00', '11:00')
->withMetadata(['patient_id' => 1, 'type' => 'consultation'])
->save();
π’ Meeting Room Management
// Room availability
$roomAvailability = Zap::for($room)
->named('Conference Room A')
->availability()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('08:00', '18:00')
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
// Meeting bookings
$meeting = Zap::for($room)
->named('Board Meeting')
->appointment()
->from('2025-03-15')
->addPeriod('09:00', '11:00')
->withMetadata([
'organizer' => 'john@company.com',
'equipment' => ['projector', 'whiteboard']
])
->save();
π¨βπΌ Employee Shift Management
// Regular shifts (availability)
$workSchedule = Zap::for($employee)
->named('Regular Shift')
->availability()
->from('2025-01-01')->to('2025-12-31')
->addPeriod('09:00', '17:00')
->weekly(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
->save();
// Time off (blocked)
$vacation = Zap::for($employee)
->named('Vacation Leave')
->blocked()
->from('2025-06-01')->to('2025-06-15')
->addPeriod('00:00', '23:59')
->save();
We welcome contributions! Here's how to get started:
git clone https://github.com/laraveljutsu/zap.git
cd zap
composer install
vendor/bin/pest
- Follow PSR-12 coding standards
- Write tests for new features
- Update documentation as needed
Laravel Zap is open-source software licensed under the MIT License.
If you discover security vulnerabilities, please email ludo@epekta.com instead of using the issue tracker.
β‘ Made with β€οΈ by Laravel Jutsu for the Laravel community β‘
Website β’ Documentation β’ Support