3 namespace Sabre\VObject\Component;
8 * The VCalendar component
10 * This component adds functionality to a component, specific for a VCALENDAR.
12 * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
13 * @author Evert Pot (http://www.rooftopsolutions.nl/)
14 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
16 class VCalendar extends VObject\Component {
19 * Returns a list of all 'base components'. For instance, if an Event has
20 * a recurrence rule, and one instance is overridden, the overridden event
21 * will have the same UID, but will be excluded from this list.
23 * VTIMEZONE components will always be excluded.
25 * @param string $componentName filter by component name
28 public function getBaseComponents($componentName = null) {
30 $components = array();
31 foreach($this->children as $component) {
33 if (!$component instanceof VObject\Component)
36 if (isset($component->{'RECURRENCE-ID'}))
39 if ($componentName && $component->name !== strtoupper($componentName))
42 if ($component->name === 'VTIMEZONE')
45 $components[] = $component;
54 * If this calendar object, has events with recurrence rules, this method
55 * can be used to expand the event into multiple sub-events.
57 * Each event will be stripped from it's recurrence information, and only
58 * the instances of the event in the specified timerange will be left
61 * In addition, this method will cause timezone information to be stripped,
62 * and normalized to UTC.
64 * This method will alter the VCalendar. This cannot be reversed.
66 * This functionality is specifically used by the CalDAV standard. It is
67 * possible for clients to request expand events, if they are rather simple
68 * clients and do not have the possibility to calculate recurrences.
70 * @param DateTime $start
71 * @param DateTime $end
74 public function expand(\DateTime $start, \DateTime $end) {
78 foreach($this->select('VEVENT') as $key=>$vevent) {
80 if (isset($vevent->{'RECURRENCE-ID'})) {
81 unset($this->children[$key]);
86 if (!$vevent->rrule) {
87 unset($this->children[$key]);
88 if ($vevent->isInTimeRange($start, $end)) {
89 $newEvents[] = $vevent;
94 $uid = (string)$vevent->uid;
96 throw new \LogicException('Event did not have a UID!');
99 $it = new VObject\RecurrenceIterator($this, $vevent->uid);
100 $it->fastForward($start);
102 while($it->valid() && $it->getDTStart() < $end) {
104 if ($it->getDTEnd() > $start) {
106 $newEvents[] = $it->getEventObject();
112 unset($this->children[$key]);
116 foreach($newEvents as $newEvent) {
118 foreach($newEvent->children as $child) {
119 if ($child instanceof VObject\Property\DateTime &&
120 $child->getDateType() == VObject\Property\DateTime::LOCALTZ) {
121 $child->setDateTime($child->getDateTime(),VObject\Property\DateTime::UTC);
125 $this->add($newEvent);
129 // Removing all VTIMEZONE components
130 unset($this->VTIMEZONE);
135 * Validates the node for correctness.
136 * An array is returned with warnings.
138 * Every item in the array has the following properties:
139 * * level - (number between 1 and 3 with severity information)
140 * * message - (human readable message)
141 * * node - (reference to the offending node)
146 public function validate() {
150 $version = $this->select('VERSION');
151 if (count($version)!==1) {
154 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
158 if ((string)$this->VERSION !== '2.0') {
161 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
166 $version = $this->select('PRODID');
167 if (count($version)!==1) {
170 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
174 if (count($this->CALSCALE) > 1) {
177 'message' => 'The CALSCALE property must not be specified more than once.',
181 if (count($this->METHOD) > 1) {
184 'message' => 'The METHOD property must not be specified more than once.',
189 $allowedComponents = array(
196 $allowedProperties = array(
202 $componentsFound = 0;
203 foreach($this->children as $child) {
204 if($child instanceof Component) {
206 if (!in_array($child->name, $allowedComponents)) {
209 'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
214 if ($child instanceof Property) {
215 if (!in_array($child->name, $allowedProperties)) {
218 'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
225 if ($componentsFound===0) {
228 'message' => 'An iCalendar object must have at least 1 component.',