1<?php
2
3namespace Sabre\VObject\Component;
4
5use DateTimeInterface;
6use Sabre\VObject;
7use Sabre\VObject\Recur\EventIterator;
8use Sabre\VObject\Recur\NoInstancesException;
9
10/**
11 * VEvent component.
12 *
13 * This component contains some additional functionality specific for VEVENT's.
14 *
15 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
16 * @author Evert Pot (http://evertpot.com/)
17 * @license http://sabre.io/license/ Modified BSD License
18 */
19class VEvent extends VObject\Component
20{
21    /**
22     * Returns true or false depending on if the event falls in the specified
23     * time-range. This is used for filtering purposes.
24     *
25     * The rules used to determine if an event falls within the specified
26     * time-range is based on the CalDAV specification.
27     *
28     * @param DateTimeInterface $start
29     * @param DateTimeInterface $end
30     *
31     * @return bool
32     */
33    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
34    {
35        if ($this->RRULE) {
36            try {
37                $it = new EventIterator($this, null, $start->getTimezone());
38            } catch (NoInstancesException $e) {
39                // If we've caught this exception, there are no instances
40                // for the event that fall into the specified time-range.
41                return false;
42            }
43
44            $it->fastForward($start);
45
46            // We fast-forwarded to a spot where the end-time of the
47            // recurrence instance exceeded the start of the requested
48            // time-range.
49            //
50            // If the starttime of the recurrence did not exceed the
51            // end of the time range as well, we have a match.
52            return $it->getDTStart() < $end && $it->getDTEnd() > $start;
53        }
54
55        $effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
56        if (isset($this->DTEND)) {
57            // The DTEND property is considered non inclusive. So for a 3 day
58            // event in july, dtstart and dtend would have to be July 1st and
59            // July 4th respectively.
60            //
61            // See:
62            // http://tools.ietf.org/html/rfc5545#page-54
63            $effectiveEnd = $this->DTEND->getDateTime($end->getTimezone());
64        } elseif (isset($this->DURATION)) {
65            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
66        } elseif (!$this->DTSTART->hasTime()) {
67            $effectiveEnd = $effectiveStart->modify('+1 day');
68        } else {
69            $effectiveEnd = $effectiveStart;
70        }
71
72        return
73            ($start < $effectiveEnd) && ($end > $effectiveStart)
74        ;
75    }
76
77    /**
78     * This method should return a list of default property values.
79     *
80     * @return array
81     */
82    protected function getDefaults()
83    {
84        return [
85            'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
86            'DTSTAMP' => gmdate('Ymd\\THis\\Z'),
87        ];
88    }
89
90    /**
91     * A simple list of validation rules.
92     *
93     * This is simply a list of properties, and how many times they either
94     * must or must not appear.
95     *
96     * Possible values per property:
97     *   * 0 - Must not appear.
98     *   * 1 - Must appear exactly once.
99     *   * + - Must appear at least once.
100     *   * * - Can appear any number of times.
101     *   * ? - May appear, but not more than once.
102     *
103     * @var array
104     */
105    public function getValidationRules()
106    {
107        $hasMethod = isset($this->parent->METHOD);
108
109        return [
110            'UID' => 1,
111            'DTSTAMP' => 1,
112            'DTSTART' => $hasMethod ? '?' : '1',
113            'CLASS' => '?',
114            'CREATED' => '?',
115            'DESCRIPTION' => '?',
116            'GEO' => '?',
117            'LAST-MODIFIED' => '?',
118            'LOCATION' => '?',
119            'ORGANIZER' => '?',
120            'PRIORITY' => '?',
121            'SEQUENCE' => '?',
122            'STATUS' => '?',
123            'SUMMARY' => '?',
124            'TRANSP' => '?',
125            'URL' => '?',
126            'RECURRENCE-ID' => '?',
127            'RRULE' => '?',
128            'DTEND' => '?',
129            'DURATION' => '?',
130
131            'ATTACH' => '*',
132            'ATTENDEE' => '*',
133            'CATEGORIES' => '*',
134            'COMMENT' => '*',
135            'CONTACT' => '*',
136            'EXDATE' => '*',
137            'REQUEST-STATUS' => '*',
138            'RELATED-TO' => '*',
139            'RESOURCES' => '*',
140            'RDATE' => '*',
141        ];
142    }
143}
144