tito10047 / php-calendar
There is no license information available for the latest version (v2.0.0-beta.1) of this package.
Framework-agnostic PHP calendar data library — monthly, weekly and work-week grids, RFC 5545 recurrence rules, iCal import/export, and resource scheduling.
v2.0.0-beta.1
2026-06-30 17:27 UTC
Requires
- php: >=8.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0 || ^12.0 || ^13.0
This package is auto-updated.
Last update: 2026-07-01 07:36:03 UTC
README
Pure PHP calendar library. Zero dependencies. Built for server-side rendering.
Feed it a date. Get back a typed Day[][] table. Build your own template.
Why server-side?
- Works with Symfony UX Turbo / Livewire — no hydration, no client state sync
- Zero frontend dependencies — just your own HTML and CSS
- Every cell carries arbitrary data attached via a simple interface
- Fully immutable — every mutation returns a new instance
Installation
composer require tito10047/php-calendar
Requires PHP 8.2+. No other dependencies.
Quick start
use Tito10047\Calendar\Calendar; use Tito10047\Calendar\Enum\CalendarType; use Tito10047\Calendar\Enum\DayName; $calendar = Calendar::forMonth(2024, 11) ->disableDaysByName(DayName::Saturday, DayName::Sunday) ->setDataLoader(new MyEventLoader()); $table = $calendar->getDaysTable(); // array<int weekNumber, array<int isoDay 1–7, Day>>
<table class="calendar"> <tbody> {% for week in table %} <tr> {% for day in week %} <td class="{{ day.ghost ? 'ghost' : '' }} {{ day.today ? 'today' : '' }} {{ day.enabled ? '' : 'disabled' }}"> {% if not day.ghost %} <span>{{ day.date|date('j') }}</span> {% for event in day.data ?? [] %} <div class="event">{{ event.title }}</div> {% endfor %} {% endif %} </td> {% endfor %} </tr> {% endfor %} </tbody> </table>
The Day object
Every cell is a readonly value object:
$day->date // DateTimeImmutable $day->ghost // belongs to adjacent month (grid padding, Monthly only) $day->today // matches today's date $day->enabled // not disabled by any rule $day->data // ?array — whatever your DayDataLoaderInterface returned
Calendar types
Calendar::forMonth(2024, 11) // full month, aligned to complete weeks Calendar::forWeek(new DateTimeImmutable('2024-11-04')) // one week, Mon–Sun Calendar::forToday(CalendarType::WorkWeek) // this week, Mon–Fri
Or with navigation:
$next = $calendar->nextPeriod(); // next month / next week — depends on type $prev = $calendar->prevPeriod();
Disable and enable days
Three independent layers — see docs/disable-model.md for the full model.
$calendar = Calendar::forMonth(2024, 11) ->disableDaysByName(DayName::Saturday, DayName::Sunday) // structural — survives navigation ->disableDays(new DateTimeImmutable('2024-11-11')) // date-specific — resets on navigation ->enableDays(new DateTimeImmutable('2024-11-30')); // exception — override for one date
Further reading
| Topic | File |
|---|---|
| Disable / enable model (three layers) | docs/disable-model.md |
| Attaching custom data to days | docs/data-loading.md |
| Navigation, caching, CalendarConfig | docs/navigation.md |
| Recurring events (RFC 5545 RRULE) | docs/recurrence.md |
| iCal import and export | docs/ical.md |
| Resource calendar (rooms, people, vehicles) | docs/resource-calendar.md |
| Booking system pattern | docs/booking-mode.md |
Running tests
composer install vendor/bin/phpunit
CI runs across PHP 8.2–8.5 on every push.
License
MIT