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(); }
/** * create VObject * @param string VObject as string * @return Sabre_VObject or null */ private function createVObject($vobject_or_name) { if (is_object($vobject_or_name)) { return $vobject_or_name; } else { $vcomponent = null; switch ($vobject_or_name) { case 'VCALENDAR': case 'VTODO': case 'VEVENT': case 'VALARM': case 'VFREEBUSY': case 'VJOURNAL': case 'VTIMEZONE': $vcomponent = new VCalendar(); break; case 'VCARD': $vcomponent = new VCard(); break; default: $vcomponent = new VCalendar(); break; } if ($vcomponent !== null) { $vobject = $vcomponent->createComponent($vobject_or_name); return $vobject; } else { return null; } } }
/** * @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); }
public function timeRangeTestData() { $tests = array(); $calendar = new VCalendar(); $vevent = $calendar->createComponent('VEVENT'); $vevent->DTSTART = '20111223T120000Z'; $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent2 = clone $vevent; $vevent2->DTEND = '20111225T120000Z'; $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent3 = clone $vevent; $vevent3->DURATION = 'P1D'; $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent4 = clone $vevent; $vevent4->DTSTART = '20111225'; $vevent4->DTSTART['VALUE'] = 'DATE'; $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); // Event with no end date should be treated as lasting the entire day. $tests[] = array($vevent4, new \DateTime('2011-12-25 16:00:00'), new \DateTime('2011-12-25 17:00:00'), true); // DTEND is non inclusive so all day events should not be returned on the next day. $tests[] = array($vevent4, new \DateTime('2011-12-26 00:00:00'), new \DateTime('2011-12-26 17:00:00'), false); // The timezone of timerange in question also needs to be considered. $tests[] = array($vevent4, new \DateTime('2011-12-26 00:00:00', new \DateTimeZone('Europe/Berlin')), new \DateTime('2011-12-26 17:00:00', new \DateTimeZone('Europe/Berlin')), false); $vevent5 = clone $vevent; $vevent5->DURATION = 'P1D'; $vevent5->RRULE = 'FREQ=YEARLY'; $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $tests[] = array($vevent5, new \DateTime('2013-12-01'), new \DateTime('2013-12-31'), true); $vevent6 = clone $vevent; $vevent6->DTSTART = '20111225'; $vevent6->DTSTART['VALUE'] = 'DATE'; $vevent6->DTEND = '20111225'; $vevent6->DTEND['VALUE'] = 'DATE'; $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); // Added this test to ensure that recurrence rules with no DTEND also // get checked for the entire day. $vevent7 = clone $vevent; $vevent7->DTSTART = '20120101'; $vevent7->DTSTART['VALUE'] = 'DATE'; $vevent7->RRULE = 'FREQ=MONTHLY'; $tests[] = array($vevent7, new \DateTime('2012-02-01 15:00:00'), new \DateTime('2012-02-02'), true); // The timezone of timerange in question should also be considered. // Added this test to check recurring events that have no instances. $vevent8 = clone $vevent; $vevent8->DTSTART = '20130329T140000'; $vevent8->DTEND = '20130329T153000'; $vevent8->RRULE = array('FREQ' => 'WEEKLY', 'BYDAY' => array('FR'), 'UNTIL' => '20130412T115959Z'); $vevent8->add('EXDATE', '20130405T140000'); $vevent8->add('EXDATE', '20130329T140000'); $tests[] = array($vevent8, new \DateTime('2013-03-01'), new \DateTime('2013-04-01'), false); return $tests; }
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)); }
/** * @Route("/schedule/export", name="user_schedule_export") * @Template() */ public function exportAction() { if (!$this->getUserLayer()->isStudent()) { return $this->createAccessDeniedResponse(); } /** @var $em EntityManager */ $em = $this->getDoctrine()->getManager(); /** @var $courses Course[] */ $courses = $em->getRepository('EtuUserBundle:Course')->findByUser($this->getUser()); $vcalendar = new VCalendar(); $semesterEnd = SemesterManager::current()->getEnd()->format('Ymd\\THis'); foreach ($courses as $course) { if ($course->getUv() == 'SPJE') { continue; } if ($course->getDay() == Course::DAY_SATHURDAY) { $day = 'saturday'; } else { $day = $course->getDay(); } $day = new \DateTime('last ' . $day); $start = clone $day; $time = explode(':', $course->getStart()); $start->setTime($time[0], $time[1]); $end = clone $day; $time = explode(':', $course->getEnd()); $end->setTime($time[0], $time[1]); $summary = $course->getWeek() != 'T' ? $course->getUv() . ' (' . $course->getWeek() . ')' : $course->getUv(); $vcalendar->add('VEVENT', ['SUMMARY' => $summary . ' - ' . $course->getType(), 'DTSTART' => $start, 'DTEND' => $end, 'RRULE' => 'FREQ=WEEKLY;INTERVAL=1;UNTIL=' . $semesterEnd, 'LOCATION' => $course->getRoom(), 'CATEGORIES' => $course->getType()]); } $response = new Response($vcalendar->serialize()); $response->headers->set('Content-Type', 'text/calendar; charset=utf-8'); $response->headers->set('Content-Disposition', 'attachment; filename="etuutt_schedule.ics"'); return $response; }
public function timeRangeTestData() { $tests = array(); $calendar = new VCalendar(); $vevent = $calendar->createComponent('VEVENT'); $vevent->DTSTART = '20111223T120000Z'; $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent2 = clone $vevent; $vevent2->DTEND = '20111225T120000Z'; $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent3 = clone $vevent; $vevent3->DURATION = 'P1D'; $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vevent4 = clone $vevent; $vevent4->DTSTART = '20111225'; $vevent4->DTSTART['VALUE'] = 'DATE'; $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); // Event with no end date should be treated as lasting the entire day. $tests[] = array($vevent4, new \DateTime('2011-12-25 16:00:00'), new \DateTime('2011-12-25 17:00:00'), true); $vevent5 = clone $vevent; $vevent5->DURATION = 'P1D'; $vevent5->RRULE = 'FREQ=YEARLY'; $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $tests[] = array($vevent5, new \DateTime('2013-12-01'), new \DateTime('2013-12-31'), true); $vevent6 = clone $vevent; $vevent6->DTSTART = '20111225'; $vevent6->DTSTART['VALUE'] = 'DATE'; $vevent6->DTEND = '20111225'; $vevent6->DTEND['VALUE'] = 'DATE'; $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); // Added this test to ensure that recurrence rules with no DTEND also // get checked for the entire day. $vevent7 = clone $vevent; $vevent7->DTSTART = '20120101'; $vevent7->DTSTART['VALUE'] = 'DATE'; $vevent7->RRULE = 'FREQ=MONTHLY'; $tests[] = array($vevent7, new \DateTime('2012-02-01 15:00:00'), new \DateTime('2012-02-02'), true); return $tests; }
public function timeRangeTestData() { $calendar = new VCalendar(); $tests = array(); $vjournal = $calendar->createComponent('VJOURNAL'); $vjournal->DTSTART = '20111223T120000Z'; $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vjournal2 = $calendar->createComponent('VJOURNAL'); $vjournal2->DTSTART = '20111223'; $vjournal2->DTSTART['VALUE'] = 'DATE'; $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vjournal3 = $calendar->createComponent('VJOURNAL'); $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), false); $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); return $tests; }
/** * * @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); }
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)); }
/** * 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']; } } }
private function importEvents(Calendar $calendar, VCalendar $document) { // Prepare by deleting all existing events foreach ($calendar->getEvents() as $event) { $this->getEntityManager()->remove($event); } $calendar->getEvents()->clear(); // Abort if there is no events at all if (!$document->VEVENT) { return; } // First, import only originals, because we want to save RRULE before it is destroyed when expanding $originals = []; foreach ($document->VEVENT as $vevent) { if (!$vevent->__get('RECURRENCE-ID')) { $event = $this->importEvent($calendar, $vevent); $originals[$event->getUid()] = $event; } } // Expand repetitions 2 month in the past and 1 year in the future $now = Utility::getNow(); $start = $now->sub(new \DateInterval('P2M')); $end = $now->add(new \DateInterval('P1Y')); // Then we expand recurent rules $expandedDocument = $document->expand($start, $end); // Abort if there is no repetitions at all if (!$expandedDocument->VEVENT) { return; } // Finally re-import, but this time only the recurrent things foreach ($expandedDocument->VEVENT as $vevent) { $original = $this->findOriginal($originals, $vevent); if ($original) { $repetition = $this->importEvent($calendar, $vevent); $repetition->setOriginal($original); } } }
/** * check if object is valid * @return bool */ public function isValid() { $typeChecker = parent::isValid(); if (!$typeChecker) { return false; } $validate = $this->vObject->validate(); foreach ($validate as $item) { if (isset($item['level']) && intval($item['level']) === 3) { return false; } } return true; }
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(); }
/** * 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(); }
public function timeRangeTestData() { $tests = array(); $calendar = new VCalendar(); $vtodo = $calendar->createComponent('VTODO'); $vtodo->DTSTART = '20111223T120000Z'; $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo2 = clone $vtodo; $vtodo2->DURATION = 'P1D'; $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo3 = clone $vtodo; $vtodo3->DUE = '20111225'; $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo4 = $calendar->createComponent('VTODO'); $vtodo4->DUE = '20111225'; $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo5 = $calendar->createComponent('VTODO'); $vtodo5->COMPLETED = '20111225'; $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo6 = $calendar->createComponent('VTODO'); $vtodo6->CREATED = '20111225'; $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo7 = $calendar->createComponent('VTODO'); $vtodo7->CREATED = '20111225'; $vtodo7->COMPLETED = '20111226'; $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); $vtodo7 = $calendar->createComponent('VTODO'); $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), true); return $tests; }
/** * 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()); }
/** * 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; }
/** * @expectedException LogicException */ public function testInTimeRangeInvalidComponent() { $calendar = new VCalendar(); $valarm = $calendar->createComponent('VALARM'); $valarm->TRIGGER = '-P1D'; $valarm->TRIGGER['RELATED'] = 'END'; $vjournal = $calendar->createComponent('VJOURNAL'); $vjournal->add($valarm); $valarm->isInTimeRange(new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00')); }
/** * 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; }
/** * @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; }
/** * 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]); }
$copygame = true; } 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];
function testGetDocumentType() { $vcard = new VCalendar(); $vcard->VERSION = '2.0'; $this->assertEquals(VCalendar::ICALENDAR20, $vcard->getDocumentType()); }
{$cmd} [events] 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');
/** * Creates a new component. * * By default this object will iterate over its own children, but this can * be overridden with the iterator argument * * @param string $name * @param Sabre_VObject_ElementList $iterator */ public function __construct() { parent::__construct(); $this->version = '2.0'; $this->prodid = '-//Intermesh//NONSGML Group-Office ' . \GO::config()->version . '//EN'; }
/** * 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(); }
/** * 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(); } }
/** * 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; }