4 * The VCalendar component
6 * This component adds functionality to a component, specific for a VCALENDAR.
10 * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
11 * @author Evert Pot (http://www.rooftopsolutions.nl/)
12 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
14 class Sabre_VObject_Component_VCalendar extends Sabre_VObject_Component {
17 * Returns a list of all 'base components'. For instance, if an Event has
18 * a recurrence rule, and one instance is overridden, the overridden event
19 * will have the same UID, but will be excluded from this list.
21 * VTIMEZONE components will always be excluded.
23 * @param string $componentName filter by component name
26 public function getBaseComponents($componentName = null) {
28 $components = array();
29 foreach($this->children as $component) {
31 if (!$component instanceof Sabre_VObject_Component)
34 if (isset($component->{'RECURRENCE-ID'}))
37 if ($componentName && $component->name !== strtoupper($componentName))
40 if ($component->name === 'VTIMEZONE')
43 $components[] = $component;
52 * If this calendar object, has events with recurrence rules, this method
53 * can be used to expand the event into multiple sub-events.
55 * Each event will be stripped from it's recurrence information, and only
56 * the instances of the event in the specified timerange will be left
59 * In addition, this method will cause timezone information to be stripped,
60 * and normalized to UTC.
62 * This method will alter the VCalendar. This cannot be reversed.
64 * This functionality is specifically used by the CalDAV standard. It is
65 * possible for clients to request expand events, if they are rather simple
66 * clients and do not have the possibility to calculate recurrences.
68 * @param DateTime $start
69 * @param DateTime $end
72 public function expand(DateTime $start, DateTime $end) {
76 foreach($this->select('VEVENT') as $key=>$vevent) {
78 if (isset($vevent->{'RECURRENCE-ID'})) {
79 unset($this->children[$key]);
84 if (!$vevent->rrule) {
85 unset($this->children[$key]);
86 if ($vevent->isInTimeRange($start, $end)) {
87 $newEvents[] = $vevent;
92 $uid = (string)$vevent->uid;
94 throw new LogicException('Event did not have a UID!');
97 $it = new Sabre_VObject_RecurrenceIterator($this, $vevent->uid);
98 $it->fastForward($start);
100 while($it->valid() && $it->getDTStart() < $end) {
102 if ($it->getDTEnd() > $start) {
104 $newEvents[] = $it->getEventObject();
110 unset($this->children[$key]);
114 foreach($newEvents as $newEvent) {
116 foreach($newEvent->children as $child) {
117 if ($child instanceof Sabre_VObject_Property_DateTime &&
118 $child->getDateType() == Sabre_VObject_Property_DateTime::LOCALTZ) {
119 $child->setDateTime($child->getDateTime(),Sabre_VObject_Property_DateTime::UTC);
123 $this->add($newEvent);
127 // Removing all VTIMEZONE components
128 unset($this->VTIMEZONE);
133 * Validates the node for correctness.
134 * An array is returned with warnings.
136 * Every item in the array has the following properties:
137 * * level - (number between 1 and 3 with severity information)
138 * * message - (human readable message)
139 * * node - (reference to the offending node)
143 public function validate() {
147 $version = $this->select('VERSION');
148 if (count($version)!==1) {
151 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
155 if ((string)$this->VERSION !== '2.0') {
158 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
163 $version = $this->select('PRODID');
164 if (count($version)!==1) {
167 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
171 if (count($this->CALSCALE) > 1) {
174 'message' => 'The CALSCALE property must not be specified more than once.',
178 if (count($this->METHOD) > 1) {
181 'message' => 'The METHOD property must not be specified more than once.',
186 $allowedComponents = array(
193 $allowedProperties = array(
199 $componentsFound = 0;
200 foreach($this->children as $child) {
201 if($child instanceof Sabre_VObject_Component) {
203 if (!in_array($child->name, $allowedComponents)) {
206 'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
211 if ($child instanceof Sabre_VObject_Property) {
212 if (!in_array($child->name, $allowedProperties)) {
215 'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
222 if ($componentsFound===0) {
225 'message' => 'An iCalendar object must have at least 1 component.',