public function render(Diary $diary) { $vcalendar = new VCalendar(); $vcalendar->remove('PRODID'); $vcalendar->add('PRODID', '-//Camdram//NONSGML Show Diary//EN'); foreach ($diary->getEvents() as $event) { $start_time = null; $rrule = array(); if ($event instanceof MultiDayEventInterface) { $start_time = new \DateTime($event->getStartDate()->format('Y-m-d') . ' ' . $event->getStartTime()->format('H:i:s')); $last_start_time = new \DateTime($event->getEndDate()->format('Y-m-d') . ' ' . $event->getStartTime()->format('H:i:s')); $rrule = 'FREQ=DAILY;UNTIL=' . $last_start_time->format('Ymd\\THis\\Z'); } elseif ($event instanceof SingleDayEventInterface) { $start_time = new \DateTime($event->getDate() . ' ' . $event->getStartTime()->format('H:i:s')); } if ($start_time) { $utc = new \DateTimeZone('UTC'); $start_time->setTimezone($utc); $end_time = clone $start_time; $end_time->modify('+2 hours'); $dtstamp = clone $event->getUpdatedAt(); $dtstamp->setTimezone($utc); $params = array('SUMMARY' => $event->getName(), 'LOCATION' => $event->getVenue(), 'UID' => $event->getUid(), 'DTSTAMP' => $dtstamp, 'DTSTART' => $start_time, 'DURATION' => 'PT2H00M00S', 'DESCRIPTION' => $event->getDescription()); if ($rrule) { $params['RRULE'] = $rrule; } $vcalendar->add('VEVENT', $params); } } return $vcalendar->serialize(); }
/** * @Route("/{id}.ics") * @Method({"GET"}) */ public function menuIdAction($id) { $api = new ApiController(); $api->setContainer($this->container); $menu = $api->menuIdAction($id); if ($menu->getStatusCode() !== 200) { return new Response('Calendar not found', 404); } $json = json_decode($menu->getContent(), true); $headers = array('Content-Type' => 'text/calendar; charset=utf-8', 'Content-Disposition' => 'attachment; filename="' . $id . '.ics'); $vCalendar = new VCalendar(); foreach ($json['data'] as $event) { $vEvent = $vCalendar->add('VEVENT'); # Timezone $timezone = new DateTimeZone('Europe/Paris'); # Start and end $start = new DateTime(); $start->setTimestamp($event['start']); $start->setTimezone($timezone); $end = new DateTime(); $end->setTimestamp($event['end']); $end->setTimezone($timezone); $name = implode(', ', $event['meals']); $description = implode(', ', $event['meals']); $vEvent->add('UID', uniqid('menu_')); $vEvent->add('DTSTART', $start); $vEvent->add('DTEND', $end); $vEvent->add('SUMMARY', $name); $vEvent->add('DESCRIPTION', $description); } $calendar = $vCalendar->serialize(); return new Response($calendar, 200, $headers); }
function testAlarmWayBefore() { $vcalendar = new VObject\Component\VCalendar(); $vevent = $vcalendar->createComponent('VEVENT'); $vevent->DTSTART = '20120101T120000Z'; $vevent->UID = 'bla'; $valarm = $vcalendar->createComponent('VALARM'); $valarm->TRIGGER = '-P2W1D'; $vevent->add($valarm); $vcalendar->add($vevent); $filter = array('name' => 'VCALENDAR', 'is-not-defined' => false, 'time-range' => null, 'prop-filters' => array(), 'comp-filters' => array(array('name' => 'VEVENT', 'is-not-defined' => false, 'time-range' => null, 'prop-filters' => array(), 'comp-filters' => array(array('name' => 'VALARM', 'is-not-defined' => false, 'prop-filters' => array(), 'comp-filters' => array(), 'time-range' => array('start' => new \DateTime('2011-12-10'), 'end' => new \DateTime('2011-12-20'))))))); $validator = new CalendarQueryValidator(); $this->assertTrue($validator->validate($vcalendar, $filter)); }
/** * * @param Response $response * @param array $data * @param int $status * * @return ResponseInterface */ public function render(ResponseInterface $response, array $data = [], $status = 200) { $icalendar = new VCalendar(); foreach ($data['cfps'] as $cfp) { $cfpStart = new \DateTime($cfp['dateCfpStart']); $cfpEnd = new \DateTime($cfp['dateCfpEnd']); $lastChange = new \DateTime($cfp['lastChange']); $lastChange->setTimezone(new \DateTimeZone('UTC')); if ($cfp['timezone']) { $cfpStart->setTimezone(new \DateTimeZone($cfp['timezone'])); $cfpEnd->setTimezone(new \DateTimeZone($cfp['timezone'])); } $icalendar->add('VEVENT', ['SUMMARY' => $cfp['name'], 'DTSTART' => $cfpStart, 'DTEND' => $cfpEnd, 'URL' => $cfp['uri'], 'DTSTAMP' => $lastChange, 'UID' => $cfp['_rel']['cfp_uri'], 'DESCRIPTION' => $cfp['description'], 'GEO' => round($cfp['latitude'], 6) . ';' . round($cfp['longitude'], 6), 'LOCATION' => $cfp['location']]); } $response = $response->withHeader('Content-Type', 'text/calendar'); $stream = $response->getBody(); $stream->write($icalendar->serialize()); return $response->withBody($stream); }
/** * Render an event as vevent * @param VCalendar $vcalendar * @param Event $event * @param Place $place */ private function renderEvent(VCalendar $vcalendar, Event $event, Place $place = null) { $vevent = $vcalendar->add('VEVENT', [], false); $this->addDate($event, $vevent, 'DTSTART', $event->getStart()); $this->addDate($event, $vevent, 'DTEND', $event->getEnd()); $properties = []; $properties['DTSTAMP'] = ['type' => 'DATE-TIME', 'value' => Utility::getNow()]; $properties['UID'] = ['type' => 'UNKNOWN', 'value' => $event->getUid()]; $properties['DESCRIPTION'] = ['type' => 'UNKNOWN', 'value' => $event->getDescription()]; $properties['SUMMARY'] = ['type' => 'UNKNOWN', 'value' => $event->getName()]; if ($place) { $properties['LOCATION'] = ['type' => 'UNKNOWN', 'value' => $place->getName()]; $properties['GEO'] = ['type' => 'UNKNOWN', 'value' => $place->getLocation()->getLatitude() . ';' . $place->getLocation()->getLongitude()]; } $allProperties = array_merge($properties, $event->getExtra()); foreach ($allProperties as $key => $val) { $prop = $vevent->add($key, $val['value']); if ($val['type'] === 'DATE') { $prop['VALUE'] = $val['type']; } } }
public function listAction() { $em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default'); $result = $em->getRepository('Phpug\\Entity\\Cache')->findBy(array('type' => 'event')); $calendar = new VObject\Component\VCalendar(); $affectedUGs = $this->findGroupsWithinRangeAndDistance(); foreach ($result as $cal) { if (!$cal->getGRoup()) { continue; } if ($affectedUGs && !in_array($cal->getGroup()->getShortname(), $affectedUGs)) { continue; } try { $ical = VObject\Reader::read($cal->getCache()); foreach ($ical->children as $event) { if (!$event instanceof VObject\Component\VEvent) { continue; } $result = $event->validate(VObject\Node::REPAIR); if ($result) { error_log(print_r($result, true)); continue; } $event->SUMMARY = '[' . $cal->getGroup()->getName() . '] ' . $event->SUMMARY; $calendar->add($event); } } catch (\Exception $e) { } } $viewModel = $this->getViewModel(); if ($viewModel instanceof ViewModel) { $viewModel->setVariable('location', $this->params()->fromQuery('latitude', 0) . ' ' . $this->params()->fromQuery('longitude', 0)); $viewModel->setVariable('latitude', $this->params()->fromQuery('latitude', 0)); $viewModel->setVariable('longitude', $this->params()->fromQuery('longitude', 0)); $viewModel->setVariable('distance', $this->params()->fromQuery('distance', 100)); } return $viewModel->setVariable('calendar', new \Phpug\Wrapper\SabreVCalendarWrapper($calendar)); }
public function fire($job, $data) { // Get the staff member $staff = StaffModel::find($data['staff']); // Set the calendar we're using $calendarName = str_replace(' ', '', $staff->user->name) . '.ics'; // Get the calendar $calendar = new VCalendar(); // Get a subset of the staff member's appointments $series = $staff->appointments->filter(function ($a) { // Get 14 days prior $targetDate = Date::now()->subDays(14)->startOfDay(); return $a->start >= $targetDate; }); foreach ($series as $a) { // Create a new event $event = []; // Set the summary $event['SUMMARY'] = $a->service->isLesson() ? "{$a->userAppointments->first()->user->name} ({$a->service->name})" : $a->service->name; // Set the start time and end time $event['DTSTART'] = $a->start; $event['DTEND'] = $a->end; if ($a->location) { $event['LOCATION'] = $a->location->present()->name; } if (!empty($a->notes)) { $event['DESCRIPTION'] = $a->notes; } // Add the event to the calendar $calendar->add('VEVENT', $event); } // Write the new output to the file File::put(App::make('path.public') . "/calendars/{$calendarName}", $calendar->serialize()); // Delete the job from the queue $job->delete(); }
/** * This issue was discovered on the sabredav mailing list. */ function testCreateDatePropertyThroughAdd() { $vcal = new VCalendar(); $vevent = $vcal->add('VEVENT'); $dtstart = $vevent->add('DTSTART', new \DateTime('2014-03-07'), ['VALUE' => 'DATE']); $this->assertEquals("DTSTART;VALUE=DATE:20140307\r\n", $dtstart->serialize()); }
/** * Export events to iCalendar format * * @param array Events as array * @param string VCalendar method to advertise * @param boolean Directly send data to stdout instead of returning * @param callable Callback function to fetch attachment contents, false if no attachment export * @param boolean Add VTIMEZONE block with timezone definitions for the included events * @return string Events in iCalendar format (http://tools.ietf.org/html/rfc5545) */ public function export($objects, $method = null, $write = false, $get_attachment = false, $with_timezones = true) { $this->method = $method; // encapsulate in VCALENDAR container $vcal = new VObject\Component\VCalendar(); $vcal->VERSION = '2.0'; $vcal->PRODID = $this->prodid; $vcal->CALSCALE = 'GREGORIAN'; if (!empty($method)) { $vcal->METHOD = $method; } // write vcalendar header if ($write) { echo preg_replace('/END:VCALENDAR[\\r\\n]*$/m', '', $vcal->serialize()); } foreach ($objects as $object) { $this->_to_ical($object, !$write ? $vcal : false, $get_attachment); } // include timezone information if ($with_timezones || !empty($method)) { foreach ($this->vtimezones as $tzid => $range) { $vt = self::get_vtimezone($tzid, $range[0], $range[1]); if (empty($vt)) { continue; // no timezone information found } if ($write) { echo $vt->serialize(); } else { $vcal->add($vt); } } } if ($write) { echo "END:VCALENDAR\r\n"; return true; } else { return $vcal->serialize(); } }
function testGetDateInterval() { $vcal = new VCalendar(); $event = $vcal->add('VEVENT', array('DURATION' => array('PT1H'))); $this->assertEquals(new \DateInterval('PT1H'), $event->{'DURATION'}->getDateInterval()); }
function testRemoveByObj() { $comp = new VCalendar(array(), false); $comp->add('prop1', 'val1'); $prop = $comp->add('prop2', 'val2'); $comp->remove($prop); $this->assertFalse(isset($comp->prop2)); $this->assertTrue(isset($comp->prop1)); }
function testSetSubParts() { $vcal = new VCalendar(); $recur = $vcal->add('RRULE', array('FREQ' => 'DAILY', 'BYDAY' => 'mo,tu', 'BYMONTH' => array(0, 1))); $this->assertEquals(array('FREQ' => 'DAILY', 'BYDAY' => array('MO', 'TU'), 'BYMONTH' => array(0, 1)), $recur->getParts()); }
/** * ElementList should reject this. * * @expectedException \LogicException */ public function testArrayAccessUnsetInt() { $calendar = new VCalendar(); $property = $calendar->createProperty("X-PROP", null); $calendar->add($property); unset($calendar->{'X-PROP'}[0]); }
} elseif ($game[3] == 'Quarter-Finals' && $param == 'ALLQ') { $copygame = true; } elseif ($game[3] == 'Half-Finals' && $param == 'ALLH') { $copygame = true; } /* elseif ($game[3] == 'Quarter-Finals' || $game[3] == 'Half-Finals' || $game[3] == 'Final') { // for now everyone gets the quarter/half/Final $copygame = true; }*/ } if ($copygame) { array_push($outgames, $game); } } // format the calendar $vcalendar = new VObject\Component\VCalendar(); $vcalendar->add('X-WR-CALNAME', 'EURO 2016 Schedule ' . $param_in); $vcalendar->add('X-WR-CALDESC', 'EURO 2016 Schedule ' . $param_in . "\nbrought to you by http://kralo.github.io/euro2016-calendar-ics-exporter/"); foreach ($outgames as $game) { $vev = $vcalendar->add('VEVENT', ['UID' => 'euro2016_game' . $game[0]]); // Summary and description; also resources if ($game[6] != 'Z' && sizeof($game[6]) == 1) { $involved = $game[6][0]; } else { $involved = $game[4]; } $involved .= ' - '; if ($game[7] != 'Z' && sizeof($game[7]) == 1) { $involved .= $game[7][0]; } else { $involved .= $game[5]; }
/** * Generate ical file content * * @param $who user ID * @param $who_group group ID * @param $limititemtype itemtype only display this itemtype (default '') * * @return icalendar string **/ static function generateIcal($who, $who_group, $limititemtype = '') { global $CFG_GLPI; if ($who === 0 && $who_group === 0) { return false; } if (!empty($CFG_GLPI["version"])) { $unique_id = "GLPI-Planning-" . trim($CFG_GLPI["version"]); } else { $unique_id = "GLPI-Planning-UnknownVersion"; } // create vcalendar $vcalendar = new VObject\Component\VCalendar(); // $xprops = array( "X-LIC-LOCATION" => $tz ); // iCalUtilityFunctions::createTimezone( $v, $tz, $xprops ); $interv = array(); $begin = time() - MONTH_TIMESTAMP * 12; $end = time() + MONTH_TIMESTAMP * 12; $begin = date("Y-m-d H:i:s", $begin); $end = date("Y-m-d H:i:s", $end); $params = array('genical' => true, 'who' => $who, 'who_group' => $who_group, 'whogroup' => $who_group, 'begin' => $begin, 'end' => $end); $interv = array(); if (empty($limititemtype)) { foreach ($CFG_GLPI['planning_types'] as $itemtype) { $interv = array_merge($interv, $itemtype::populatePlanning($params)); } } else { $interv = $limititemtype::populatePlanning($params); } if (count($interv) > 0) { foreach ($interv as $key => $val) { if (isset($val['itemtype'])) { if (isset($val[getForeignKeyFieldForItemType($val['itemtype'])])) { $uid = $val['itemtype'] . "#" . $val[getForeignKeyFieldForItemType($val['itemtype'])]; } else { $uid = "Other#" . $key; } } else { $uid = "Other#" . $key; } $vevent['UID'] = $uid; $vevent['DTSTART'] = new \DateTime($val["begin"]); $vevent['DTEND'] = new \DateTime($val["end"]); if (isset($val["tickets_id"])) { $summary = sprintf(__('Ticket #%1$s %2$s'), $val["tickets_id"], $val["name"]); } else { if (isset($val["name"])) { $summary = $val["name"]; } } $vevent['SUMMARY'] = $summary; if (isset($val["content"])) { $description = $val["content"]; // be sure to replace nl by \r\n $description = preg_replace("/<br( [^>]*)?" . ">/i", "\r\n", $description); $description = Html::clean($description); } else { if (isset($val["name"])) { $description = $val["name"]; // be sure to replace nl by \r\n $description = preg_replace("/<br( [^>]*)?" . ">/i", "\r\n", $description); $description = Html::clean($description); } } $vevent['DESCRIPTION'] = $description; if (isset($val["url"])) { $vevent['URL'] = $val["url"]; } $vcalendar->add('VEVENT', $vevent); } } $output = $vcalendar->serialize(); $filename = date('YmdHis') . '.ics'; @Header("Content-Disposition: attachment; filename=\"{$filename}\""); @Header("Content-Length: " . Toolbox::strlen($output)); @Header("Connection: close"); @Header("content-type: text/calendar; charset=utf-8"); echo $output; }
/** * @depends testValues */ function testOverridenEventNoValuesExpected() { $vcal = new VCalendar(); $ev1 = $vcal->createComponent('VEVENT'); $ev1->UID = 'overridden'; $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; $ev1->DTSTART = '20120124T120000Z'; $ev1->SUMMARY = 'baseEvent'; $vcal->add($ev1); // ev2 overrides an event, and puts it 6 days earlier instead. $ev2 = $vcal->createComponent('VEVENT'); $ev2->UID = 'overridden'; $ev2->{'RECURRENCE-ID'} = '20120131T120000Z'; $ev2->DTSTART = '20120125T120000Z'; $ev2->SUMMARY = 'Override!'; $vcal->add($ev2); $it = new RecurrenceIterator($vcal, 'overridden'); $dates = array(); $summaries = array(); // The reported problem was specifically related to the VCALENDAR // expansion. In this parcitular case, we had to forward to the 28th of // january. $it->fastForward(new DateTime('2012-01-28 23:00:00')); // We stop the loop when it hits the 6th of februari. Normally this // iterator would hit 24, 25 (overriden from 31) and 7 feb but because // we 'filter' from the 28th till the 6th, we should get 0 results. while ($it->valid() && $it->getDTSTart() < new DateTime('2012-02-06 23:00:00')) { $dates[] = $it->getDTStart(); $summaries[] = (string) $it->getEventObject()->SUMMARY; $it->next(); } $this->assertEquals(array(), $dates); $this->assertEquals(array(), $summaries); }
/** * Merges all calendar objects, and builds one big ics export * * @param array $nodes * @return string */ public function generateICS(array $nodes) { $calendar = new VObject\Component\VCalendar(); $calendar->version = '2.0'; if (DAV\Server::$exposeVersion) { $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN'; } else { $calendar->prodid = '-//SabreDAV//SabreDAV//EN'; } $calendar->calscale = 'GREGORIAN'; $collectedTimezones = array(); $timezones = array(); $objects = array(); foreach ($nodes as $node) { if (!isset($node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'])) { continue; } $nodeData = $node[200]['{' . Plugin::NS_CALDAV . '}calendar-data']; $nodeComp = VObject\Reader::read($nodeData); foreach ($nodeComp->children() as $child) { switch ($child->name) { case 'VEVENT': case 'VTODO': case 'VJOURNAL': $objects[] = $child; break; // VTIMEZONE is special, because we need to filter out the duplicates // VTIMEZONE is special, because we need to filter out the duplicates case 'VTIMEZONE': // Naively just checking tzid. if (in_array((string) $child->TZID, $collectedTimezones)) { continue; } $timezones[] = $child; $collectedTimezones[] = $child->TZID; break; } } } foreach ($timezones as $tz) { $calendar->add($tz); } foreach ($objects as $obj) { $calendar->add($obj); } return $calendar->serialize(); }
function testSetSubParts() { $vcal = new VCalendar(); $recur = $vcal->add('RRULE', ['FREQ' => 'DAILY', 'BYDAY' => 'mo,tu', 'BYMONTH' => [0, 1]]); $this->assertEquals(['FREQ' => 'DAILY', 'BYDAY' => ['MO', 'TU'], 'BYMONTH' => [0, 1]], $recur->getParts()); }
/** * @return VCalendar */ public function getVObject() { $vCal = new VCalendar(); $vCal->add(new VEvent($vCal, 'VEVENT')); $uid = strtoupper(substr($vCal->VEVENT->UID->getValue(), 14)); // To remove the "sabre-vobject-" at the beginning $vCal->VEVENT->__set('UID', $uid); foreach ($this->properties as $key => $value) { if ($value != null) { $name = self::$convertTable[$key]; if (!$vCal->VEVENT->__isset($name)) { $vCal->VEVENT->add($name); } $vCal->VEVENT->__set($name, $value); } } return $vCal; }
/** * This method takes a FreeBusyData object and generates the VCALENDAR * object associated with it. * * @return VCalendar */ protected function generateFreeBusyCalendar(FreeBusyData $fbData) { if ($this->baseObject) { $calendar = $this->baseObject; } else { $calendar = new VCalendar(); } $vfreebusy = $calendar->createComponent('VFREEBUSY'); $calendar->add($vfreebusy); if ($this->start) { $dtstart = $calendar->createProperty('DTSTART'); $dtstart->setDateTime($this->start); $vfreebusy->add($dtstart); } if ($this->end) { $dtend = $calendar->createProperty('DTEND'); $dtend->setDateTime($this->end); $vfreebusy->add($dtend); } $tz = new \DateTimeZone('UTC'); $dtstamp = $calendar->createProperty('DTSTAMP'); $dtstamp->setDateTime(new DateTimeImmutable('now', $tz)); $vfreebusy->add($dtstamp); foreach ($fbData->getData() as $busyTime) { $busyType = strtoupper($busyTime['type']); // Ignoring all the FREE parts, because those are already assumed. if ($busyType === 'FREE') { continue; } $busyTime[0] = new \DateTimeImmutable('@' . $busyTime['start'], $tz); $busyTime[1] = new \DateTimeImmutable('@' . $busyTime['end'], $tz); $prop = $calendar->createProperty('FREEBUSY', $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')); // Only setting FBTYPE if it's not BUSY, because BUSY is the // default anyway. if ($busyType !== 'BUSY') { $prop['FBTYPE'] = $busyType; } $vfreebusy->add($prop); } return $calendar; }
HI ); die; } $events = 100; if (isset($argv[1])) { $events = (int) $argv[1]; } include __DIR__ . '/../vendor/autoload.php'; fwrite(STDERR, "Generating " . $events . " events\n"); $currentDate = new DateTime('-' . round($events / 2) . ' days'); $calendar = new VObject\Component\VCalendar(); $ii = 0; while ($ii < $events) { $ii++; $event = $calendar->add('VEVENT'); $event->DTSTART = 'bla'; $event->SUMMARY = 'Event #' . $ii; $event->UID = md5(microtime(true)); $doctorRandom = mt_rand(1, 1000); switch ($doctorRandom) { // All-day event case 1: $event->DTEND = 'bla'; $dtStart = clone $currentDate; $dtEnd = clone $currentDate; $dtEnd->modify('+' . mt_rand(1, 3) . ' days'); $event->DTSTART->setDateTime($dtStart); $event->DTSTART['VALUE'] = 'DATE'; $event->DTEND->setDateTime($dtEnd); break;
/** * @depends testValues * @expectedException \InvalidArgumentException */ function testNoMasterBadUID() { $vcal = new VCalendar(); // ev2 overrides an event, and puts it on 2pm instead. $ev2 = $vcal->createComponent('VEVENT'); $ev2->UID = 'overridden'; $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; $ev2->DTSTART = '20120110T140000Z'; $ev2->SUMMARY = 'Event 2'; $vcal->add($ev2); // ev3 overrides an event, and puts it 2 days and 2 hours later $ev3 = $vcal->createComponent('VEVENT'); $ev3->UID = 'overridden'; $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; $ev3->DTSTART = '20120115T140000Z'; $ev3->SUMMARY = 'Event 3'; $vcal->add($ev3); $it = new EventIterator($vcal, 'broken'); }
/** * Parses the input data and returns a VCALENDAR. * * @return Component/VCalendar */ function getResult() { $calendar = new VCalendar(); foreach ($this->objects as $object) { // Skip if there is no BDAY property. if (!$object->select('BDAY')) { continue; } // We've seen clients (ez-vcard) putting "BDAY:" properties // without a value into vCards. If we come across those, we'll // skip them. if (empty($object->BDAY->getValue())) { continue; } // We're always converting to vCard 4.0 so we can rely on the // VCardConverter handling the X-APPLE-OMIT-YEAR property for us. $object = $object->convert(Document::VCARD40); // Skip if the card has no FN property. if (!isset($object->FN)) { continue; } // Skip if the BDAY property is not of the right type. if (!$object->BDAY instanceof Property\VCard\DateAndOrTime) { continue; } // Skip if we can't parse the BDAY value. try { $dateParts = DateTimeParser::parseVCardDateTime($object->BDAY->getValue()); } catch (\InvalidArgumentException $e) { continue; } // Set a year if it's not set. $unknownYear = false; if (!$dateParts['year']) { $object->BDAY = self::DEFAULT_YEAR . '-' . $dateParts['month'] . '-' . $dateParts['date']; $unknownYear = true; } // Create event. $event = $calendar->add('VEVENT', ['SUMMARY' => sprintf($this->format, $object->FN->getValue()), 'DTSTART' => new \DateTime($object->BDAY->getValue()), 'RRULE' => 'FREQ=YEARLY', 'TRANSP' => 'TRANSPARENT']); // add VALUE=date $event->DTSTART['VALUE'] = 'DATE'; // Add X-SABRE-BDAY property. if ($unknownYear) { $event->add('X-SABRE-BDAY', 'BDAY', ['X-SABRE-VCARD-UID' => $object->UID->getValue(), 'X-SABRE-VCARD-FN' => $object->FN->getValue(), 'X-SABRE-OMIT-YEAR' => self::DEFAULT_YEAR]); } else { $event->add('X-SABRE-BDAY', 'BDAY', ['X-SABRE-VCARD-UID' => $object->UID->getValue(), 'X-SABRE-VCARD-FN' => $object->FN->getValue()]); } } return $calendar; }
/** * Action : download an iCal event corresponding to a leave request * @param int leave request id * @author Benjamin BALET <*****@*****.**> */ public function ical($id) { header('Content-type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename=leave.ics'); $this->load->model('leaves_model'); $leave = $this->leaves_model->getLeaves($id); //Get timezone and language of the user $this->load->model('users_model'); $employee = $this->users_model->getUsers($leave['employee']); if (!is_null($employee['timezone'])) { $tzdef = $employee['timezone']; } else { $tzdef = $this->config->item('default_timezone'); if ($tzdef == FALSE) { $tzdef = 'Europe/Paris'; } } $this->lang->load('global', $this->polyglot->code2language($employee['language'])); $vcalendar = new VObject\Component\VCalendar(); $vcalendar->add('VEVENT', array('SUMMARY' => lang('leave'), 'CATEGORIES' => lang('leave'), 'DESCRIPTION' => $leave['cause'], 'DTSTART' => new \DateTime($leave['startdate'], new \DateTimeZone($tzdef)), 'DTEND' => new \DateTime($leave['enddate'], new \DateTimeZone($tzdef)), 'URL' => base_url() . "leaves/" . $id)); echo $vcalendar->serialize(); }
/** * Parses the input data and returns a correct VFREEBUSY object, wrapped in * a VCALENDAR. * * @return Component */ function getResult() { $busyTimes = []; foreach ($this->objects as $key => $object) { foreach ($object->getBaseComponents() as $component) { switch ($component->name) { case 'VEVENT': $FBTYPE = 'BUSY'; if (isset($component->TRANSP) && strtoupper($component->TRANSP) === 'TRANSPARENT') { break; } if (isset($component->STATUS)) { $status = strtoupper($component->STATUS); if ($status === 'CANCELLED') { break; } if ($status === 'TENTATIVE') { $FBTYPE = 'BUSY-TENTATIVE'; } } $times = []; if ($component->RRULE) { try { $iterator = new EventIterator($object, (string) $component->uid, $this->timeZone); } catch (NoInstancesException $e) { // This event is recurring, but it doesn't have a single // instance. We are skipping this event from the output // entirely. unset($this->objects[$key]); continue; } if ($this->start) { $iterator->fastForward($this->start); } $maxRecurrences = 200; while ($iterator->valid() && --$maxRecurrences) { $startTime = $iterator->getDTStart(); if ($this->end && $startTime > $this->end) { break; } $times[] = [$iterator->getDTStart(), $iterator->getDTEnd()]; $iterator->next(); } } else { $startTime = $component->DTSTART->getDateTime($this->timeZone); if ($this->end && $startTime > $this->end) { break; } $endTime = null; if (isset($component->DTEND)) { $endTime = $component->DTEND->getDateTime($this->timeZone); } elseif (isset($component->DURATION)) { $duration = DateTimeParser::parseDuration((string) $component->DURATION); $endTime = clone $startTime; $endTime = $endTime->add($duration); } elseif (!$component->DTSTART->hasTime()) { $endTime = clone $startTime; $endTime = $endTime->modify('+1 day'); } else { // The event had no duration (0 seconds) break; } $times[] = [$startTime, $endTime]; } foreach ($times as $time) { if ($this->end && $time[0] > $this->end) { break; } if ($this->start && $time[1] < $this->start) { break; } $busyTimes[] = [$time[0], $time[1], $FBTYPE]; } break; case 'VFREEBUSY': foreach ($component->FREEBUSY as $freebusy) { $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY'; // Skipping intervals marked as 'free' if ($fbType === 'FREE') { continue; } $values = explode(',', $freebusy); foreach ($values as $value) { list($startTime, $endTime) = explode('/', $value); $startTime = DateTimeParser::parseDateTime($startTime); if (substr($endTime, 0, 1) === 'P' || substr($endTime, 0, 2) === '-P') { $duration = DateTimeParser::parseDuration($endTime); $endTime = clone $startTime; $endTime = $endTime->add($duration); } else { $endTime = DateTimeParser::parseDateTime($endTime); } if ($this->start && $this->start > $endTime) { continue; } if ($this->end && $this->end < $startTime) { continue; } $busyTimes[] = [$startTime, $endTime, $fbType]; } } break; } } } if ($this->baseObject) { $calendar = $this->baseObject; } else { $calendar = new VCalendar(); } $vfreebusy = $calendar->createComponent('VFREEBUSY'); $calendar->add($vfreebusy); if ($this->start) { $dtstart = $calendar->createProperty('DTSTART'); $dtstart->setDateTime($this->start); $vfreebusy->add($dtstart); } if ($this->end) { $dtend = $calendar->createProperty('DTEND'); $dtend->setDateTime($this->end); $vfreebusy->add($dtend); } $dtstamp = $calendar->createProperty('DTSTAMP'); $dtstamp->setDateTime(new DateTimeImmutable('now', new \DateTimeZone('UTC'))); $vfreebusy->add($dtstamp); foreach ($busyTimes as $busyTime) { $busyTime[0] = $busyTime[0]->setTimeZone(new \DateTimeZone('UTC')); $busyTime[1] = $busyTime[1]->setTimeZone(new \DateTimeZone('UTC')); $prop = $calendar->createProperty('FREEBUSY', $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')); $prop['FBTYPE'] = $busyTime[2]; $vfreebusy->add($prop); } return $calendar; }
/** * Parse an event update for an attendee. * * This function figures out if we need to send a reply to an organizer. * * @param VCalendar $calendar * @param array $eventInfo * @param array $oldEventInfo * @param string $attendee * @return Message[] */ protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, $attendee) { $instances = array(); foreach ($oldEventInfo['attendees'][$attendee]['instances'] as $instance) { $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => $instance['partstat'], 'newstatus' => null); } foreach ($eventInfo['attendees'][$attendee]['instances'] as $instance) { if (isset($instances[$instance['id']])) { $instances[$instance['id']]['newstatus'] = $instance['partstat']; } else { $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => null, 'newstatus' => $instance['partstat']); } } // We need to also look for differences in EXDATE. If there are new // items in EXDATE, it means that an attendee deleted instances of an // event, which means we need to send DECLINED specifically for those // instances. // We only need to do that though, if the master event is not declined. if ($instances['master']['newstatus'] !== 'DECLINED') { foreach ($eventInfo['exdate'] as $exDate) { if (!in_array($exDate, $oldEventInfo['exdate'])) { $instances[$exDate] = array('id' => $exDate, 'oldstatus' => $instances['master']['oldstatus'], 'newstatus' => 'DECLINED'); } } } $message = new Message(); $message->uid = $eventInfo['uid']; $message->method = 'REPLY'; $message->component = 'VEVENT'; $message->sequence = $eventInfo['sequence']; $message->sender = $attendee; $message->senderName = $eventInfo['attendees'][$attendee]['name']; $message->recipient = $eventInfo['organizer']; $message->recipientName = $eventInfo['organizerName']; $icalMsg = new VCalendar(); $icalMsg->METHOD = 'REPLY'; $hasReply = false; foreach ($instances as $instance) { if ($instance['oldstatus'] == $instance['newstatus']) { // Skip continue; } $event = $icalMsg->add('VEVENT', array('UID' => $message->uid, 'SEQUENCE' => $message->sequence)); if ($instance['id'] !== 'master') { $event->{'RECURRENCE-ID'} = DateTimeParser::parseDateTime($instance['id'], $eventInfo['timezone']); } $organizer = $event->add('ORGANIZER', $message->recipient); if ($message->recipientName) { $organizer['CN'] = $message->recipientName; } $attendee = $event->add('ATTENDEE', $message->sender, array('PARTSTAT' => $instance['newstatus'])); if ($message->senderName) { $attendee['CN'] = $message->senderName; } $hasReply = true; } if ($hasReply) { $message->message = $icalMsg; return array($message); } else { return array(); } }
/** * Merges all calendar objects, and builds one big iCalendar blob. * * @param array $properties Some CalDAV properties * @param array $inputObjects * @return VObject\Component\VCalendar */ function mergeObjects(array $properties, array $inputObjects) { $calendar = new VObject\Component\VCalendar(); $calendar->version = '2.0'; if (DAV\Server::$exposeVersion) { $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN'; } else { $calendar->prodid = '-//SabreDAV//SabreDAV//EN'; } if (isset($properties['{DAV:}displayname'])) { $calendar->{'X-WR-CALNAME'} = $properties['{DAV:}displayname']; } if (isset($properties['{http://apple.com/ns/ical/}calendar-color'])) { $calendar->{'X-APPLE-CALENDAR-COLOR'} = $properties['{http://apple.com/ns/ical/}calendar-color']; } $collectedTimezones = []; $timezones = []; $objects = []; foreach ($inputObjects as $href => $inputObject) { $nodeComp = VObject\Reader::read($inputObject); foreach ($nodeComp->children() as $child) { switch ($child->name) { case 'VEVENT': case 'VTODO': case 'VJOURNAL': $objects[] = clone $child; break; // VTIMEZONE is special, because we need to filter out the duplicates // VTIMEZONE is special, because we need to filter out the duplicates case 'VTIMEZONE': // Naively just checking tzid. if (in_array((string) $child->TZID, $collectedTimezones)) { continue; } $timezones[] = clone $child; $collectedTimezones[] = $child->TZID; break; } } // Destroy circular references to PHP will GC the object. $nodeComp->destroy(); unset($nodeComp); } foreach ($timezones as $tz) { $calendar->add($tz); } foreach ($objects as $obj) { $calendar->add($obj); } return $calendar; }
function testValidateBadEncoding() { $document = new VCalendar(); $property = $document->add('X-FOO', 'value'); $property['ENCODING'] = 'invalid'; $result = $property->validate(); $this->assertEquals('ENCODING=INVALID is not valid for this document type.', $result[0]['message']); $this->assertEquals(1, $result[0]['level']); }
/** * Parse an event update for an attendee. * * This function figures out if we need to send a reply to an organizer. * * @param VCalendar $calendar * @param array $eventInfo * @param array $oldEventInfo * @param string $attendee * @return Message[] */ protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, $attendee) { if ($this->scheduleAgentServerRules && $eventInfo['organizerScheduleAgent'] === 'CLIENT') { return array(); } // Don't bother generating messages for events that have already been // cancelled. if ($eventInfo['status'] === 'CANCELLED') { return array(); } $instances = array(); foreach ($oldEventInfo['attendees'][$attendee]['instances'] as $instance) { $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => $instance['partstat'], 'newstatus' => null); } foreach ($eventInfo['attendees'][$attendee]['instances'] as $instance) { if (isset($instances[$instance['id']])) { $instances[$instance['id']]['newstatus'] = $instance['partstat']; } else { $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => null, 'newstatus' => $instance['partstat']); } } // We need to also look for differences in EXDATE. If there are new // items in EXDATE, it means that an attendee deleted instances of an // event, which means we need to send DECLINED specifically for those // instances. // We only need to do that though, if the master event is not declined. if ($instances['master']['newstatus'] !== 'DECLINED') { foreach ($eventInfo['exdate'] as $exDate) { if (!in_array($exDate, $oldEventInfo['exdate'])) { if (isset($instances[$exDate])) { $instances[$exDate]['newstatus'] = 'DECLINED'; } else { $instances[$exDate] = array('id' => $exDate, 'oldstatus' => null, 'newstatus' => 'DECLINED'); } } } } // Gathering a few extra properties for each instance. foreach ($instances as $recurId => $instanceInfo) { if (isset($eventInfo['instances'][$recurId])) { $instances[$recurId]['dtstart'] = clone $eventInfo['instances'][$recurId]->DTSTART; } else { $instances[$recurId]['dtstart'] = $recurId; } } $message = new Message(); $message->uid = $eventInfo['uid']; $message->method = 'REPLY'; $message->component = 'VEVENT'; $message->sequence = $eventInfo['sequence']; $message->sender = $attendee; $message->senderName = $eventInfo['attendees'][$attendee]['name']; $message->recipient = $eventInfo['organizer']; $message->recipientName = $eventInfo['organizerName']; $icalMsg = new VCalendar(); $icalMsg->METHOD = 'REPLY'; $hasReply = false; foreach ($instances as $instance) { if ($instance['oldstatus'] == $instance['newstatus'] && $eventInfo['organizerForceSend'] !== 'REPLY') { // Skip continue; } $event = $icalMsg->add('VEVENT', array('UID' => $message->uid, 'SEQUENCE' => $message->sequence)); $summary = isset($calendar->VEVENT->SUMMARY) ? $calendar->VEVENT->SUMMARY->getValue() : ''; // Adding properties from the correct source instance if (isset($eventInfo['instances'][$instance['id']])) { $instanceObj = $eventInfo['instances'][$instance['id']]; $event->add(clone $instanceObj->DTSTART); if (isset($instanceObj->SUMMARY)) { $event->add('SUMMARY', $instanceObj->SUMMARY->getValue()); } elseif ($summary) { $event->add('SUMMARY', $summary); } } else { // This branch of the code is reached, when a reply is // generated for an instance of a recurring event, through the // fact that the instance has disappeared by showing up in // EXDATE $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']); // Treat is as a DATE field if (strlen($instance['id']) <= 8) { $recur = $event->add('DTSTART', $dt, array('VALUE' => 'DATE')); } else { $recur = $event->add('DTSTART', $dt); } if ($summary) { $event->add('SUMMARY', $summary); } } if ($instance['id'] !== 'master') { $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']); // Treat is as a DATE field if (strlen($instance['id']) <= 8) { $recur = $event->add('RECURRENCE-ID', $dt, array('VALUE' => 'DATE')); } else { $recur = $event->add('RECURRENCE-ID', $dt); } } $organizer = $event->add('ORGANIZER', $message->recipient); if ($message->recipientName) { $organizer['CN'] = $message->recipientName; } $attendee = $event->add('ATTENDEE', $message->sender, array('PARTSTAT' => $instance['newstatus'])); if ($message->senderName) { $attendee['CN'] = $message->senderName; } $hasReply = true; } if ($hasReply) { $message->message = $icalMsg; return array($message); } else { return array(); } }
/** * @param string $cardData * @return null|VCalendar */ public function buildBirthdayFromContact($cardData) { if (empty($cardData)) { return null; } try { $doc = Reader::read($cardData); } catch (Exception $e) { return null; } if (!isset($doc->BDAY)) { return null; } $birthday = $doc->BDAY; if (!(string) $birthday) { return null; } $title = str_replace('{name}', strtr((string) $doc->FN, array('\\,' => ',', '\\;' => ';')), '{name}'); try { $date = new \DateTime($birthday); } catch (Exception $e) { return null; } $vCal = new VCalendar(); $vCal->VERSION = '2.0'; $vEvent = $vCal->createComponent('VEVENT'); $vEvent->add('DTSTART'); $vEvent->DTSTART->setDateTime($date); $vEvent->DTSTART['VALUE'] = 'DATE'; $vEvent->add('DTEND'); $date->add(new \DateInterval('P1D')); $vEvent->DTEND->setDateTime($date); $vEvent->DTEND['VALUE'] = 'DATE'; $vEvent->{'UID'} = $doc->UID; $vEvent->{'RRULE'} = 'FREQ=YEARLY'; $vEvent->{'SUMMARY'} = $title . ' (*' . $date->format('Y') . ')'; $vEvent->{'TRANSP'} = 'TRANSPARENT'; $alarm = $vCal->createComponent('VALARM'); $alarm->add($vCal->createProperty('TRIGGER', '-PT0M', ['VALUE' => 'DURATION'])); $alarm->add($vCal->createProperty('ACTION', 'DISPLAY')); $alarm->add($vCal->createProperty('DESCRIPTION', $vEvent->{'SUMMARY'})); $vEvent->add($alarm); $vCal->add($vEvent); return $vCal; }