crumbls/timeline

A scheduling and occurrence engine for Laravel

Maintainers

Package info

github.com/Crumbls/timeline

pkg:composer/crumbls/timeline

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.0.1 2026-05-31 19:02 UTC

This package is auto-updated.

Last update: 2026-05-31 20:13:13 UTC


README

A scheduling and occurrence engine for Laravel.

This package is not a calendar UI. It handles the domain model behind recurring events: defining schedules as RRULE strings, pre-generating concrete occurrence records, and giving you a clean query interface to drive any calendar or scheduling feature you build.

Requirements

  • PHP 8.2+
  • Laravel 10, 11, or 12

Installation

composer require crumbls/timeline
php artisan vendor:publish --tag=timeline-migrations
php artisan migrate

Core Concepts

Event — the conceptual thing. "Laravel Meetup" or "Board Meeting". Not a specific date.

Rule — defines when an Event occurs. Stores an RFC 5545 RRULE string. One Event can have multiple Rules.

Occurrence — a concrete scheduled instance. "Laravel Meetup on June 5th." This is the primary query model.

OccurrenceException — a one-off modification to a single Occurrence (cancel, reschedule, modify). Never modifies the parent Rule.

Location — a reusable venue attached to Occurrences.

RRuleBuilder

Writing RRULE strings by hand is error-prone. Use the fluent builder:

use Crumbls\Timeline\Support\RRuleBuilder;

// Every Tuesday
RRuleBuilder::make()->weekly()->onDays('TU')->toString();

// First Friday of the month
RRuleBuilder::make()->monthly()->onNthWeekday(1, 'FR')->toString();

// Every other Monday, 20 times
RRuleBuilder::make()->weekly()->every(2)->onDays('MO')->count(20)->toString();

// Human-readable description of any RRULE
RRuleBuilder::describe('FREQ=WEEKLY;BYDAY=MO,WE,FR');
// "weekly on Monday, Wednesday and Friday"

See IMPLEMENTATION.md for the full builder reference.

Quick Start

use Crumbls\Timeline\Models\Event;
use Crumbls\Timeline\Models\Rule;
use Crumbls\Timeline\Enums\EventStatus;

// Create an event
$event = Event::create([
    'name'     => 'Laravel Meetup',
    'timezone' => 'America/Denver',
    'status'   => EventStatus::Published,
]);

// Add a weekly rule — occurrences generate automatically
Rule::create([
    'event_id'  => $event->id,
    'starts_at' => '2025-06-03 18:00:00',
    'ends_at'   => '2025-06-03 20:00:00',
    'rrule'     => 'FREQ=WEEKLY;BYDAY=TU',
]);

// Query occurrences
use Crumbls\Timeline\Models\Occurrence;
use Carbon\Carbon;

$feed = Occurrence::between(Carbon::parse('2025-06-01'), Carbon::parse('2025-06-30'))
    ->scheduled()
    ->with(['event', 'location'])
    ->orderBy('starts_at')
    ->get();

Occurrence Scopes

Occurrence::upcoming()->get();
Occurrence::today()->get();
Occurrence::between($start, $end)->get();
Occurrence::scheduled()->get();
Occurrence::forEvent($event->id)->get();
Occurrence::atLocation($location->id)->get();

Scopes chain freely:

Occurrence::scheduled()->upcoming()->forEvent($event->id)->paginate(20);

Configuration

// config/timeline.php
return [
    'table_prefix'                 => 'timeline_',
    'occurrence_generation_months' => 12,
    'default_timezone'             => 'UTC',
];

All table names are resolved through table_prefix. Change it before running migrations.

How Occurrence Generation Works

When a Rule is saved, GenerateOccurrencesJob is dispatched. The OccurrenceGenerator service expands the RRULE into concrete dates for the configured window (default: 12 months), then:

  • Creates new Occurrence records for dates not already present
  • Updates ends_at on existing records if the duration changed
  • Deletes future Scheduled occurrences no longer in the expansion
  • Leaves Cancelled and Completed occurrences untouched

You can also trigger generation manually:

use Crumbls\Timeline\Services\OccurrenceGenerator;

app(OccurrenceGenerator::class)->generate($rule);

Testing

composer test

56 Pest tests covering events, rules, occurrences, generator logic, and exceptions.

Further Reading

See IMPLEMENTATION.md for a full implementation guide including calendar feed construction, location usage, exception handling, queue setup, and an RRULE reference table.

License

MIT