Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Calendr Bundle Laravel Package

frequence-web/calendr-bundle

A Symfony bundle that integrates the Calendr calendar library into your application, offering ready-made services, configuration, and Twig helpers so you can build, render, and manage calendars and events with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: frequence-web/calendr-bundle is a Symfony bundle, not a Laravel package. As a Laravel developer, the bundle itself is mostly reference material — the real dependency you want is the underlying library, yohang/calendr. The bundle's job is wiring CalendR's Calendar factory and event providers into Symfony's container plus a Twig helper; there is no Laravel service provider, no facade, and no Blade directives.

Minimal path for a Laravel app:

composer require yohang/calendr

Then bind the factory once in a service provider:

// app/Providers/CalendarServiceProvider.php
public function register(): void
{
    $this->app->singleton(\CalendR\Calendar::class, fn () => new \CalendR\Calendar());
}

Minimal path for a Symfony app (the bundle's intended home):

composer require frequence-web/calendr-bundle

Register FrequenceWeb\Bundle\CalendRBundle\FrequenceWebCalendRBundle in AppKernel::$bundles (Symfony 2/3) or config/bundles.php (Symfony 4), then check vendor/frequence-web/calendr-bundle/Resources/config/ for the service IDs it exposes and debug:container calendr to confirm.

Where to look first:

  1. vendor/yohang/calendr/src/CalendR/Period/ — Month, Week, Day, Year, PeriodInterface. This is where 90% of your day-to-day API lives.
  2. vendor/yohang/calendr/src/CalendR/Event/ — EventInterface, Event\Collection, and the provider contract.
  3. The bundle's DependencyInjection/ extension and Twig extension class — useful only if you're copying the event-provider wiring pattern into a Laravel provider.

First use case: render a month grid with events.

$calendar = app(\CalendR\Calendar::class);
$month = $calendar->getMonth(2024, 6); // June 2024
$events = $this->events->forPeriod($month); // your own repository

return view('calendar.month', compact('month', 'events'));

Implementation Patterns

1. Treat Calendar as a period factory, not a service. It builds Year, Month, Week, Day objects. Keep it injected or resolved from the container; never new periods directly — you lose the bundle's configuration (first day of week, etc.) and make testing harder.

2. Load events by period, not globally. The pattern the bundle encourages (and the only one that scales) is an event provider that receives a period and returns the events intersecting it. In Laravel this is a repository or query scope:

public function forPeriod(\CalendR\Period\PeriodInterface $period): iterable
{
    return Event::query()
        ->where('starts_at', '<', $period->getEnd())
        ->where('ends_at', '>', $period->getStart())
        ->get()
        ->map(fn ($e) => new CalendarEvent($e));
}

3. Implement CalendR\Event\EventInterface on a thin DTO. Don't make Eloquent models implement it directly — you'll fight with getUid(), getStart(), and getEnd() semantics and leak persistence into your view layer.

final class CalendarEvent implements \CalendR\Event\EventInterface
{
    public function __construct(
        private string $uid,
        private \DateTimeInterface $start,
        private \DateTimeInterface $end,
        private string $title,
    ) {}

    public function getUid(): string { return $this->uid; }
    public function getStart(): \DateTimeInterface { return $this->start; }
    public function getEnd(): \DateTimeInterface { return $this->end; }
    public function getTitle(): string { return $this->title; }
}

4. Render by iterating the period and asking which events it contains. This avoids pre-bucketing events into days and handles multi-day events naturally:

@foreach ($month as $day)
    <div class="day">
        <span>{{ $day->getStart()->format('j') }}</span>
        @foreach ($events as $event)
            @if ($day->contains($event->getStart()))
                <span class="pill">{{ $event->getTitle() }}</span>
            @endif
        @endforeach
    </div>
@endforeach

5. Navigation is free. $month->getNext() / $month->getPrevious() return new period objects; wire them to ?month=2024-07 query params. Parse the input once at the controller boundary and pass periods, never raw year/month pairs, into views.

6. In Symfony, register providers via the tag/compiler pass the bundle exposes. This is the one thing worth copying if you later move the app: a calendr.event_provider tag (or its equivalent in the bundle's CompilerPass) collects providers into a registry. In Laravel, mirror it with a tagged binding:

$this->app->tag([DatabaseEventProvider::class], 'calendar.providers');
$this->app->singleton(EventProviderRegistry::class, fn ($app) =>
    new EventProviderRegistry($app->tagged('calendar.providers'))
);

7. Prefer DateTimeImmutable if the library version allows it. Older CalendR releases mutate DateTime internally in places; mixing mutable and immutable instances is a common source of "my event moved by a day" bugs.

Gotchas and Tips

  • Maintenance risk is the headline. 23 stars and 0 dependents means the bundle is effectively unmaintained. Its composer constraints target the Symfony 2/3 era and older PHP; you will hit conflicts on Laravel 10/11 and PHP 8.2+. The underlying yohang/calendr is also quiet. Budget for vendoring or forking, and pin versions.
  • CalendR is a period/event model, not a calendar UI. No grid rendering, no ICS import/export, no RRULE recurrence expansion. If you need recurrence, expand rules into concrete event instances before handing them to CalendR — do not expect the library to do it.
  • contains() boundary semantics. Period containment checks are typically inclusive at start and exclusive at end. Events ending exactly at midnight will appear on the following day in naive loops. Test midnight and DST boundaries explicitly.
  • Weeks are configured, not assumed. First day of week and week numbering come from configuration; if you skip it, ISO weeks and Sunday-start weeks will disagree with your UI. Set it once, explicitly, in your service provider.
  • getUid() must be globally unique per event instance. Duplicate UIDs in a collection will silently deduplicate or overwrite depending on the code path. For recurring events, suffix the occurrence date.
  • Iterating a Month yields Day objects, not DateTime. Calling ->format() directly on the loop variable fails; always go through ->getStart(). This trips up almost everyone on first use.
  • Timezone discipline. Store UTC, convert at the display boundary. CalendR compares DateTime objects directly; mixing timezones produces off-by-one-day layouts that are painful to debug in a Blade template.
  • Don't dump the whole period. A Year iterator over days is fine; dumping it recursively will blow up your request. Log getStart()/getEnd() of the period and the count of events instead.
  • Debugging in Symfony: bin/console debug:container calendr and debug:twig to confirm the bundle's services and filters are registered. In Laravel there is nothing to debug — if Calendar resolves, you're done.
  • Extension points are shallow. Custom periods (quarter, semester) require extending CalendR\Period\Period and overriding getDatePeriod() plus iteration; the bundle won't help. Event providers are the only genuinely pluggable seam, and that pattern is worth lifting into Laravel even if you never install the bundle.
  • Bottom line for a Laravel shop: take the provider-registry pattern and the period-containment idiom, depend on yohang/calendr directly, and skip the bundle. Treat frequence-web/calendr-bundle as a design reference, not a dependency.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource