1<?php
2
3namespace Sabre\VObject\Component;
4
5use DateTimeInterface;
6use Sabre\VObject;
7
8/**
9 * VTodo component.
10 *
11 * This component contains some additional functionality specific for VTODOs.
12 *
13 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
14 * @author Evert Pot (http://evertpot.com/)
15 * @license http://sabre.io/license/ Modified BSD License
16 */
17class VTodo extends VObject\Component
18{
19    /**
20     * Returns true or false depending on if the event falls in the specified
21     * time-range. This is used for filtering purposes.
22     *
23     * The rules used to determine if an event falls within the specified
24     * time-range is based on the CalDAV specification.
25     *
26     * @param DateTimeInterface $start
27     * @param DateTimeInterface $end
28     *
29     * @return bool
30     */
31    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
32    {
33        $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
34        $duration = isset($this->DURATION) ? VObject\DateTimeParser::parseDuration($this->DURATION) : null;
35        $due = isset($this->DUE) ? $this->DUE->getDateTime() : null;
36        $completed = isset($this->COMPLETED) ? $this->COMPLETED->getDateTime() : null;
37        $created = isset($this->CREATED) ? $this->CREATED->getDateTime() : null;
38
39        if ($dtstart) {
40            if ($duration) {
41                $effectiveEnd = $dtstart->add($duration);
42
43                return $start <= $effectiveEnd && $end > $dtstart;
44            } elseif ($due) {
45                return
46                    ($start < $due || $start <= $dtstart) &&
47                    ($end > $dtstart || $end >= $due);
48            } else {
49                return $start <= $dtstart && $end > $dtstart;
50            }
51        }
52        if ($due) {
53            return $start < $due && $end >= $due;
54        }
55        if ($completed && $created) {
56            return
57                ($start <= $created || $start <= $completed) &&
58                ($end >= $created || $end >= $completed);
59        }
60        if ($completed) {
61            return $start <= $completed && $end >= $completed;
62        }
63        if ($created) {
64            return $end > $created;
65        }
66
67        return true;
68    }
69
70    /**
71     * A simple list of validation rules.
72     *
73     * This is simply a list of properties, and how many times they either
74     * must or must not appear.
75     *
76     * Possible values per property:
77     *   * 0 - Must not appear.
78     *   * 1 - Must appear exactly once.
79     *   * + - Must appear at least once.
80     *   * * - Can appear any number of times.
81     *   * ? - May appear, but not more than once.
82     *
83     * @var array
84     */
85    public function getValidationRules()
86    {
87        return [
88            'UID' => 1,
89            'DTSTAMP' => 1,
90
91            'CLASS' => '?',
92            'COMPLETED' => '?',
93            'CREATED' => '?',
94            'DESCRIPTION' => '?',
95            'DTSTART' => '?',
96            'GEO' => '?',
97            'LAST-MODIFIED' => '?',
98            'LOCATION' => '?',
99            'ORGANIZER' => '?',
100            'PERCENT' => '?',
101            'PRIORITY' => '?',
102            'RECURRENCE-ID' => '?',
103            'SEQUENCE' => '?',
104            'STATUS' => '?',
105            'SUMMARY' => '?',
106            'URL' => '?',
107
108            'RRULE' => '?',
109            'DUE' => '?',
110            'DURATION' => '?',
111
112            'ATTACH' => '*',
113            'ATTENDEE' => '*',
114            'CATEGORIES' => '*',
115            'COMMENT' => '*',
116            'CONTACT' => '*',
117            'EXDATE' => '*',
118            'REQUEST-STATUS' => '*',
119            'RELATED-TO' => '*',
120            'RESOURCES' => '*',
121            'RDATE' => '*',
122        ];
123    }
124
125    /**
126     * Validates the node for correctness.
127     *
128     * The following options are supported:
129     *   Node::REPAIR - May attempt to automatically repair the problem.
130     *
131     * This method returns an array with detected problems.
132     * Every element has the following properties:
133     *
134     *  * level - problem level.
135     *  * message - A human-readable string describing the issue.
136     *  * node - A reference to the problematic node.
137     *
138     * The level means:
139     *   1 - The issue was repaired (only happens if REPAIR was turned on)
140     *   2 - An inconsequential issue
141     *   3 - A severe issue.
142     *
143     * @param int $options
144     *
145     * @return array
146     */
147    public function validate($options = 0)
148    {
149        $result = parent::validate($options);
150        if (isset($this->DUE) && isset($this->DTSTART)) {
151            $due = $this->DUE;
152            $dtStart = $this->DTSTART;
153
154            if ($due->getValueType() !== $dtStart->getValueType()) {
155                $result[] = [
156                    'level' => 3,
157                    'message' => 'The value type (DATE or DATE-TIME) must be identical for DUE and DTSTART',
158                    'node' => $due,
159                ];
160            } elseif ($due->getDateTime() < $dtStart->getDateTime()) {
161                $result[] = [
162                    'level' => 3,
163                    'message' => 'DUE must occur after DTSTART',
164                    'node' => $due,
165                ];
166            }
167        }
168
169        return $result;
170    }
171
172    /**
173     * This method should return a list of default property values.
174     *
175     * @return array
176     */
177    protected function getDefaults()
178    {
179        return [
180            'UID' => 'sabre-vobject-'.VObject\UUIDUtil::getUUID(),
181            'DTSTAMP' => date('Ymd\\THis\\Z'),
182        ];
183    }
184}
185