Skip to the content.

← Back to Gatherings System

Gathering Calendar Download Feature

Last Updated: November 4, 2025
Status: Active
Service: ICalendarService
Controller: GatheringsController::downloadCalendar()

Overview

The calendar download feature generates RFC 5545 compliant iCalendar (.ics) files that users can import into any calendar application. This allows attendees to easily add events to their personal calendars (Google Calendar, Outlook, Apple Calendar, Android, etc.).

Features

Universal Compatibility

Event Information Included

Each generated .ics file contains:

Access Control

Security:

Implementation Details

ICalendarService

Location: src/Services/ICalendarService.php

Main Method:

public function generateICalendar(Gathering $gathering, string $eventUrl): string

Features:

Event Formats:

Single-Day Events:

DTSTART:20251215T090000Z
DTEND:20251215T170000Z

Multi-Day Events:

DTSTART;VALUE=DATE:20251215
DTEND;VALUE=DATE:20251218

(Note: End date is exclusive in iCalendar, so day after last event day)

Filename Generation

Format: event-name-YYYY-MM-DD.ics

Example: winter-festival-2025-12-15.ics

Method:

public function getFilename(Gathering $gathering): string

Sanitizes event name by:

Controller Integration

GatheringsController::downloadCalendar() Action:

  1. Parse route parameters (id or publicId)
  2. Load gathering with associations (Branch, GatheringType, Activities, Staff)
  3. Check authorization:
    • For authenticated: User has view permission
    • For public: public_page_enabled = true
  4. Generate event URL for calendar link
  5. Call ICalendarService::generateICalendar()
  6. Return response with:
    • Content-Type: text/calendar; charset=UTF-8
    • Content-Disposition: attachment; filename="..."
    • Body: iCalendar content

Routes Configuration

File: config/routes.php

// Authenticated route
$routes->connect(
    '/gatherings/:id/download-calendar',
    ['controller' => 'Gatherings', 'action' => 'downloadCalendar'],
    ['pass' => ['id'], 'id' => '\d+']
);

// Public route
$routes->connect(
    '/gatherings/download-calendar/:publicId',
    ['controller' => 'Gatherings', 'action' => 'downloadCalendar'],
    ['pass' => ['publicId']]
);

UI Integration

1. Gathering View Page

Location: templates/Gatherings/view.php

Button:

<?= $this->Html->link(
    '<i class="bi bi-calendar-plus"></i> ' . __('Add to Calendar'),
    ['action' => 'downloadCalendar', $gathering->id],
    [
        'class' => 'btn btn-outline-success btn-sm',
        'escape' => false,
        'title' => __('Download calendar file (.ics) for Outlook, Google Calendar, iOS, etc.')
    ]
) ?>

Position: First action button, before “Share Event”

2. Calendar Quick View Modal

Location: templates/Gatherings/quick_view.php

Button: Similar to view page, but opens in new tab/window via Turbo frame

Position: Before “Full Details” button in modal footer

3. Public Landing Page

Location: templates/element/gatherings/public_content.php

Button:

<?= $this->Html->link(
    '<i class="bi bi-calendar-plus"></i> ' . __('Add to Calendar'),
    [
        'controller' => 'Gatherings',
        'action' => 'downloadCalendar',
        $gathering->public_id
    ],
    [
        'class' => 'btn btn-outline-light btn-lg mb-4',
        'escape' => false
    ]
) ?>

Position: Hero section, prominently displayed below event metadata

Styling: Large button with light outline to match public page aesthetic

Browser Behavior

Desktop Browsers:

iOS Safari:

Android:

All Platforms:

Testing

Unit Tests

Location: tests/TestCase/Services/ICalendarServiceTest.php

Test Coverage:

Run Tests:

cd app
vendor/bin/phpunit tests/TestCase/Services/ICalendarServiceTest.php

Expected Output: OK (4 tests, 14 assertions)

Manual Testing

Test Single-Day Event:

  1. Navigate to a single-day gathering view page
  2. Click “Add to Calendar”
  3. Verify .ics file downloads
  4. Open file in text editor - check DTSTART/DTEND have times
  5. Import into calendar app - verify shows as 9 AM - 5 PM event

Test Multi-Day Event:

  1. Navigate to a multi-day gathering (3+ days)
  2. Click “Add to Calendar”
  3. Open file in text editor - check VALUE=DATE format
  4. Import into calendar - verify shows as all-day, multi-day event

Test Public Access:

  1. Enable public page for a gathering
  2. Visit /gatherings/public-landing/{publicId} (not logged in)
  3. Click “Add to Calendar”
  4. Verify download works without authentication

Test Security:

  1. Try accessing /gatherings/download-calendar/{publicId} for gathering with public_page_enabled = false
  2. Should redirect or show error (not found)

Example iCalendar Output

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//KMP//Gathering Calendar//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:gathering-123@kmp.example.com
DTSTAMP:20251104T120000Z
DTSTART;VALUE=DATE:20251215
DTEND;VALUE=DATE:20251218
SUMMARY:Winter Festival 2025
DESCRIPTION:Event Type: Festival\nHosted by: Kingdom Branch\n\nJoin us for
  our annual winter celebration...\n\nActivities:\n- Heavy Combat\n- Archer
 y\n- Arts & Sciences\n\nEvent Steward(s):\n- Lord John Smith (john@examp
 le.com)\n\nMore information: https://kmp.example.com/gatherings/view/123
LOCATION:Event Center\, 123 Main St\, City\, State 12345
GEO:40.7128;-74.0060
URL:https://kmp.example.com/gatherings/view/123
STATUS:CONFIRMED
ORGANIZER;CN=Kingdom Branch:noreply@kmp.example.com
CATEGORIES:Festival
END:VEVENT
END:VCALENDAR

Troubleshooting

Button Not Appearing

Check:

Download Not Working

Check:

Calendar App Won’t Import

Check:

Missing Event Details

Check:

Public Download Not Working

Check:

Future Enhancements

Potential Improvements:

  1. Custom Event Times: Allow organizers to specify exact start/end times instead of defaults
  2. Calendar Subscriptions: Generate subscription feeds (.ics URLs) for automatic updates
  3. Reminder/Alarm Settings: Include pre-event reminders in calendar file
  4. Recurring Events: Support for recurring event patterns
  5. Bulk Download: Download multiple gatherings as single calendar file
  6. Time Zone Support: Include time zone information for multi-region kingdoms
  7. Attendee List: Include other confirmed attendees (with privacy controls)

Quick Reference

For End Users:

For Developers:

Supported Apps: ✅ Google Calendar
✅ Microsoft Outlook
✅ Apple Calendar
✅ Android Calendar
✅ Mozilla Thunderbird
✅ Any RFC 5545 compliant app