We've recently enhanced Fakoli's calendar component to send event invitations in iCalendar format for posting on Apple Calendar, Google Calendar, Microsoft Outlook, and other calendar clients using Fakoli's iCalendarEventManager class.
Before getting into the details of how this iCalendar enhancement works, let's review Fakoli's calendar component.
Calendar - defines a container for events with a set of read/write permissions. Web sites may a separate calendar for staff, visitors, or other defined groups.
Event - belongs to one and only one calendar. Contains details about a calendar event such as the event title, location, and start and end time.
Calendar events can be displayed on a full page calendar, a minicalendar such as in a sidebar module, and in a list view. Though Fakoli's calendar typically displays events of class
Event, it can include other types of date-based objects. Any object that wants to be displayed in the calendar, must implement the EventHandler class, formatting its event details for each type of calendar display. The Event DataItem is displayed with the StandardEventHandler.
We integrated the iCalendar functionality into Fakoli's calendar component by adding the method formatiCalendar to the EventHandler abstract class. The method requires an instance of the event class and the sequence_id of the calendar invitation. This sequence id starts at 0 and must be incremented any time the event is modified and updates are sent to the recipients. The sequence id is what makes updated events appears in your calendar client as modified, rather than as a duplicate event.
function formatiCalendar($event, $sequence_id = 0)
{
return new iCalendarEventManager($event->event_id, $event->start_date, $event->end_date, $event->title, $event->description, $event->location, $sequence_id, $event->TimeZone());
}
The formatiCalendar function creates an instance if iCalendarEventManager by sending the event details from its fields, and returns it to the calling code that will email the calendar invitation to one or more recipients. iCalendarEventManager takes this event information and formats it into the structure that calendar clients like Google Calendar can understand.
A simple iCalendar example follows:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Microsoft Corporation//Outlook 11.0 MIMEDIR//EN
BEGIN:VEVENT
UID:event_id_1@mywebsite.org
DTSTAMP:19970714T170000Z
ORGANIZER;CN=Mary Brown:MAILTO:marybrown@google.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Team Kick Off
END:VEVENT
END:VCALENDAR
The words in all capitals are properties that iCalendar recognizes in reading the event details.
BEGIN:VCALENDAR - property that signifies the start of a calendar event
VERSION - Specifies the version number that is required to parse the event. We recommend using 2.0.
PRODID - Although the id specifies Outlook, the format is recognized by other calendar clients.
BEGIN:VEVENT - groups the properties that describe an event.
UID - a globally unique identifier for the event
DTSTAMP - the datetime stamp for the moment when the event is sent in format 'Ymd\THis'
ORGANIZER - the event organizer, usually also the person to whom replies should be sent
DTSTART - the event starting date and time in format 'Ymd\THis'
DTEND - the event ending date and time in format 'Ymd\THis'
SUMMARY - this property is what a Fakoli event calls the "title"
END:VEVENT - the event detail end tag
END:VCALENDAR - the calendar end tag
Now let's look at an example of code that uses the iCalendarEventManager object instance to send a calendar event.
$event = new Event($event_id);
$invitation = $event->Invitation();
$eventHandler = new StandardEventHandler($event);
$iCalMgr = $eventHandler->formatiCalendar($event, $invitation->sequence_id);
$iCalMgr->setAttendeeName("Sally Smith");
$mail = new EmailHandler("sally@yahoo.com", $invitation->subject, $invitation->message, $invitation->sender_email, $invitation->sender_name, null, $iCalMgr);
$rtn = $mail->send();
In this example, we instantiate the event and retrieve its related Invitation object that contains the event organizer's name, email address, email subject, and message. We use the StandardEventHandler to format the iCalendarEventManager instance and, optionally, use that instance to set the attendee name to appear in the invitation rather than just the email address. Finally, we ask the EmailHandler to send the email for us, inviting Sally Smith to our event.
The EmailHandler's job is to format email headers, content types, attachments, and any other mail properties before sending it off to its destination. When the EmailHandler is provided an iCalendarEventManager object, it sets the event organizer property to the same person who is sending the email and sets the attendee property's email address. We could sets these properties to the iCalendarEventManager object in the calling code but why bother since we have to provide them to the EmailHandler anyway to send the email.
The EmailHandler formats the final version of the iCalendar code into the email message with segment header and start and end delimiters that allow clients to recognize the iCalendar section of the message. The function in EmailHandler that formats the iCalendar event follows:
function formatiCalendar($iCalMgr, $random_hash)
{
$method = $iCalMgr->data->get("method");
$cal_message = "----PHP-alt-{$random_hash}\n";
$cal_message .= "Content-Type: text/calendar; charset=utf-8;method={$method}\n";
$cal_message .= "Content-Disposition: inline; filename=meeting.ics\n";
$cal_message .= "Content-Transfer-Encoding: 8bit\n";
$cal_message .= $iCalMgr->format();
return $cal_message;
}
The format function in iCalendarEventManager puts all the iCalendar properties into the required format with the begin and end tags similar to the example shown above.
If a website supports users in multiple time zones, you may optionally send to the iCalendarEventManager the time zone of the organizer and the class will format the event so that receiving clients can translate the event start and end times to its own time zone setting.
Stay tuned for recurring events.
Improve download performance with mod_xsendfile »
« Managing long-running processes