eluceo — iCal 2

repository·2.x·Indexed 22 days ago

https://github.com/markuspoerschke/ical

A PHP abstraction layer for creating iCalendar (*.ics) files following the RFC 5545 standard. It separates data from representation using the Eluceo\iCal\Domain namespace for event and calendar entities and the Eluceo\iCal\Presentation namespace for transforming those domain objects into the iCalendar file format.

Tokens
14.5K
Snippets
45
Records
54
Agent score
78%

What's inside eluceo/ical

  1. Generate .ics files with eluceo/ical

    2.x

    The eluceo/ical package allows you to generate iCalendar (.ics) files following the RFC 5545 specification. It uses a two-layer architecture to decouple event data from the file format:

    1. Domain Layer (Eluceo\iCal\Domain): Use these classes to store calendar information (events, calendars, dates) in simple PHP objects. This layer requires no deep knowledge of the iCalendar specification.
    2. Presentation Layer (Eluceo\iCal\Presentation): Use these classes to transform your domain objects into the actual iCalendar string representation.

    To generate a file, you define your events and calendars using domain entities, then use a CalendarFactory to convert the calendar into a string component.

    <?php
    
    use Eluceo\iCal\Domain\Entity\Calendar;
    use Eluceo\iCal\Domain\Entity\Event;
    use Eluceo\iCal\Domain\ValueObject\Date;
    use Eluceo\iCal\Domain\ValueObject\SingleDay;
    use Eluceo\iCal\Presentation\Factory\CalendarFactory;
    
    // 1. Create Event domain entity
    $event = new Event();
    $event
        ->setSummary('Christmas Eve')
        ->setOccurrence(
            new SingleDay(
                new Date(DateTimeImmutable::createFromFormat('Y-m-d', '2030-12-24'))
            )
        );
    
    // 2. Create Calendar domain entity
    $calendar = new Calendar([$event]);
    
    // 3. Transform domain entity into an iCalendar component
    $componentFactory = new CalendarFactory();
    $calendarComponent = $componentFactory->createCalendar($calendar);
    
    // 4. Set HTTP headers
    header('Content-Type: text/calendar; charset=utf-8');
    header('Content-Disposition: attachment; filename="cal.ics"');
    
    // 5. Output
    echo $calendarComponent;
  2. How the Domain and Presentation layers work together

    2.x

    The library separates the what (data) from the how (format).

    • Domain Entities: You interact with Eluceo\iCal\Domain\Entity\Event and Eluceo\iCal\Domain\Entity\Calendar to build your schedule. You use ValueObject classes like Date and SingleDay to define when things happen.
    • Presentation Factories: Once your domain model is complete, you pass the Calendar entity to a factory (e.g., Eluceo\iCal\Presentation\Factory\CalendarFactory) which produces the formatted string required for an .ics file.

    This separation ensures that if the iCalendar specification changes, your domain logic remains untouched; only the presentation layer needs updating.

  3. Set Event Occurrence (Single Day, Multi Day, or Timespan)

    2.x

    The setOccurrence() method defines when an event takes place. There are three supported types of occurrences:

    1. SingleDay: The event takes place all day on a specific date.
    2. MultiDay: The event spans multiple consecutive days (inclusive of start and end dates).
    3. TimeSpan: The event has a specific start and end time.

    Use the appropriate ValueObject from \Eluceo\iCal\Domain\ValueObject to define the timing.

    use Eluceo\iCal\Domain\Entity\Event;
    
    // 1. Single Day
    use Eluceo\iCal\Domain\ValueObject\SingleDay;
    use Eluceo\iCal\Domain\ValueObject\Date;
    $date = new Date(DateTimeImmutable::createFromFormat('Y-m-d', '2019-12-24'));
    $event->setOccurrence(new SingleDay($date));
    
    // 2. Multi Day
    use Eluceo\iCal\Domain\ValueObject\MultiDay;
    $firstDay = new Date(DateTimeImmutable::createFromFormat('Y-m-d', '2019-12-24'));
    $lastDay = new Date(DateTimeImmutable::createFromFormat('Y-m-d', '2019-12-26'));
    $event->setOccurrence(new MultiDay($firstDay, $lastDay));
    
    // 3. TimeSpan
    use Eluceo\iCal\Domain\ValueObject\TimeSpan;
    use Eluceo\iCal\Domain\ValueObject\DateTime;
    $start = new DateTime(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2020-01-03 13:00:00'), false);
    $end = new DateTime(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2020-01-03 14:00:00'), false);
    $event->setOccurrence(new TimeSpan($start, $end));
  4. Understand the Domain and Presentation namespaces

    2.x

    The package is organized into two primary namespaces that separate data from its representation:

    1. Eluceo\iCal\Domain: Contains domain objects (entities and value objects) that represent the information about events and calendars.
    2. Eluceo\iCal\Presentation: Contains the logic to transform Domain objects into a *.ics file format (iCalendar representation).

    To generate a calendar, you first build your domain objects, then use a factory from the Presentation namespace to transform them into a component that can be cast to a string.

  5. Migrate from version 0.16.* to 2.0

    2.x

    The transition from version 0.16.* to 2.0 involves a fundamental architectural shift: the separation of the domain layer from the presentation layer.

    In version 0.16.*, components like Event could be rendered directly to output. In version 2.0, you must first construct domain entities (using Eluceo\iCal\Domain\Entity\...) and then pass these entities to a factory (such as Eluceo\iCal\Presentation\Factory\CalendarFactory) to create the iCalendar presentation components used for output.

    /* Version 0.16.* approach (Direct rendering) */
    $vCalendar->render();
    
    /* Version 2.0 approach (Domain -> Factory -> Presentation) */
    $calendar = new Eluceo\iCal\Domain\Entity\Calendar([$event]);
    $componentFactory = new Eluceo\iCal\Presentation\Factory\CalendarFactory();
    $calendarComponent = $componentFactory->createCalendar($calendar);
    echo $calendarComponent;
  6. Deploy the website to GitHub Pages

    2.x

    Use the following command to build the website and push the static content to the gh-pages branch. You must provide your GitHub username via the GIT_USER environment variable and set USE_SSH=true.

    GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
  7. Create a basic empty iCalendar event

    2.x

    This workflow demonstrates the minimum steps required to generate an iCalendar file containing a single empty event.

    1. Create an event domain entity: Instantiate \Eluceo\iCal\Domain\Entity\Event.
    2. Create a calendar domain entity: Instantiate \Eluceo\iCal\Domain\Entity\Calendar and pass the event(s) in the constructor.
    3. Transform to presentation: Use \Eluceo\iCal\Presentation\Factory\CalendarFactory to create a calendar component.
    4. Output: Cast the component to a string to save to a file or echo via HTTP.
    // 1. Create an event domain entity
    $event = new \Eluceo\iCal\Domain\Entity\Event();
    
    // 2. Create a calendar domain entity
    $calendar = new \Eluceo\iCal\Domain\Entity\Calendar([$event]);
    
    // 3. Transform calendar domain object into a presentation object
    $iCalendarComponent = (new \Eluceo\iCal\Presentation\Factory\CalendarFactory())->createCalendar($calendar);
    
    // 4. a) Save to file
    file_put_contents('calendar.ics', (string) $iCalendarComponent);
    
    // 4. b) Send via HTTP
    header('Content-Type: text/calendar; charset=utf-8');
    header('Content-Disposition: attachment; filename="cal.ics"');
    echo $iCalendarComponent;
  8. Add custom properties to iCal files

    2.x

    To add non-standard properties (e.g., X-CUSTOM: value) to an iCal file, you must extend the domain entity to store the data and extend the factory to include the property in the presentation component. This process involves three main steps: extending \Eluceo\iCal\Domain\Entity\Event, extending \Eluceo\iCal\Presentation\Factory\EventFactory, and passing your custom factory to the CalendarFactory.

    <?php
    // 1. Create custom entity
    class CustomEvent extends \Eluceo\iCal\Domain\Entity\Event {
        private string $myCustomProperty = 'foo bar baz!';
        public function getMyCustomProperty(): string { return $this->myCustomProperty; }
    }
    
    // 2. Create custom factory
    class CustomEventFactory extends \Eluceo\iCal\Presentation\Factory\EventFactory {
        public function createComponent(\Eluceo\iCal\Domain\Entity\Event $event): \Eluceo\iCal\Presentation\Component {
            $component = parent::createComponent($event);
            if ($event instanceof CustomEvent) {
                $component = $component->withProperty(
                    new \Eluceo\iCal\Presentation\Component\Property(
                        'X-CUSTOM',
                        new \Eluceo\iCal\Presentation\Component\Property\Value\TextValue($event->getMyCustomProperty())
                    )
                );
            }
            return $component;
        }
    }
    
    // 3. Plug it together
    $event = new CustomEvent();
    $event->setSummary('This is a test event');
    $calendar = new \Eluceo\iCal\Domain\Entity\Calendar([$event]);
    
    $calendarComponentFactory = new \Eluceo\iCal\Presentation\Factory\CalendarFactory(new CustomEventFactory());
    $calendarComponent = $calendarComponentFactory->createCalendar($calendar);
    
    echo $calendarComponent;
  9. Create a Calendar and add events

    2.x

    A Calendar is a collection of Event entities that can be represented as an .ical file. You can instantiate a calendar and populate it with events using three different methods:

    1. Via Constructor: Pass an array of Event objects directly to the Calendar constructor.
    2. Via addEvent() method: Create an empty Calendar and chain calls to addEvent() for each new Event.
    3. Via Generator: Pass a PHP Generator that yields Event objects to the Calendar constructor, which is useful for memory-efficient processing of large numbers of events.
    use Eluceo\ iCal\u0020Domain\u0020Entity\u0020Calendar;
    use Eluceo\u0020iCal\u0020Domain\u0020Entity\u0020Event;
    
    // Method 1: Constructor with array
    $events = [
        new Event(),
        new Event(),
    ];
    $calendar = new Calendar($events);
    
    // Method 2: addEvent method
    $calendar = new Calendar();
    $calendar
        ->addEvent(new Event())
        ->addEvent(new Event());
    
    // Method 3: Using a Generator
    $eventGenerator = function(): Generator {
        yield new Event();
        yield new Event();
    };
    $calendar = new Calendar($eventGenerator());