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    function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
34
35        if ($this->RRULE) {
36
37            try {
38
39                $it = new EventIterator($this, null, $start->getTimezone());
40
41            } catch (NoInstancesException $e) {
42
43                // If we've catched this exception, there are no instances
44                // for the event that fall into the specified time-range.
45                return false;
46
47            }
48
49            $it->fastForward($start);
50
51            // We fast-forwarded to a spot where the end-time of the
52            // recurrence instance exceeded the start of the requested
53            // time-range.
54            //
55            // If the starttime of the recurrence did not exceed the
56            // end of the time range as well, we have a match.
57            return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
58
59        }
60
61        $effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
62        if (isset($this->DTEND)) {
63
64            // The DTEND property is considered non inclusive. So for a 3 day
65            // event in july, dtstart and dtend would have to be July 1st and
66            // July 4th respectively.
67            //
68            // See:
69            // http://tools.ietf.org/html/rfc5545#page-54
70            $effectiveEnd = $this->DTEND->getDateTime($end->getTimezone());
71
72        } elseif (isset($this->DURATION)) {
73            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
74        } elseif (!$this->DTSTART->hasTime()) {
75            $effectiveEnd = $effectiveStart->modify('+1 day');
76        } else {
77            $effectiveEnd = $effectiveStart;
78        }
79        return (
80            ($start < $effectiveEnd) && ($end > $effectiveStart)
81        );
82
83    }
84
85    /**
86     * This method should return a list of default property values.
87     *
88     * @return array
89     */
90    protected function getDefaults() {
91
92        return [
93            'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
94            'DTSTAMP' => date('Ymd\\THis\\Z'),
95        ];
96
97    }
98
99    /**
100     * A simple list of validation rules.
101     *
102     * This is simply a list of properties, and how many times they either
103     * must or must not appear.
104     *
105     * Possible values per property:
106     *   * 0 - Must not appear.
107     *   * 1 - Must appear exactly once.
108     *   * + - Must appear at least once.
109     *   * * - Can appear any number of times.
110     *   * ? - May appear, but not more than once.
111     *
112     * @var array
113     */
114    function getValidationRules() {
115
116        $hasMethod = isset($this->parent->METHOD);
117        return [
118            'UID'           => 1,
119            'DTSTAMP'       => 1,
120            'DTSTART'       => $hasMethod ? '?' : '1',
121            'CLASS'         => '?',
122            'CREATED'       => '?',
123            'DESCRIPTION'   => '?',
124            'GEO'           => '?',
125            'LAST-MODIFIED' => '?',
126            'LOCATION'      => '?',
127            'ORGANIZER'     => '?',
128            'PRIORITY'      => '?',
129            'SEQUENCE'      => '?',
130            'STATUS'        => '?',
131            'SUMMARY'       => '?',
132            'TRANSP'        => '?',
133            'URL'           => '?',
134            'RECURRENCE-ID' => '?',
135            'RRULE'         => '?',
136            'DTEND'         => '?',
137            'DURATION'      => '?',
138
139            'ATTACH'         => '*',
140            'ATTENDEE'       => '*',
141            'CATEGORIES'     => '*',
142            'COMMENT'        => '*',
143            'CONTACT'        => '*',
144            'EXDATE'         => '*',
145            'REQUEST-STATUS' => '*',
146            'RELATED-TO'     => '*',
147            'RESOURCES'      => '*',
148            'RDATE'          => '*',
149        ];
150
151    }
152
153}
154