Blame view
sources/3rdparty/sabre/dav/lib/Sabre/CalDAV/CalendarQueryParser.php
8.49 KB
|
03e52840d
|
1 |
<?php |
|
6d9380f96
|
2 |
namespace Sabre\CalDAV; |
|
03e52840d
|
3 4 5 6 7 8 9 10 |
use Sabre\VObject; /** * Parses the calendar-query report request body. * * Whoever designed this format, and the CalDAV equivalent even more so, * has no feel for design. * |
|
6d9380f96
|
11 12 13 |
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License |
|
03e52840d
|
14 |
*/ |
|
6d9380f96
|
15 |
class CalendarQueryParser {
|
|
03e52840d
|
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/**
* List of requested properties the client wanted
*
* @var array
*/
public $requestedProperties;
/**
* List of property/component filters.
*
* @var array
*/
public $filters;
/**
|
|
6d9380f96
|
32 33 |
* This property will contain null if CALDAV:expand was not specified,
* otherwise it will contain an array with 2 elements (start, end). Each
|
|
03e52840d
|
34 35 |
* contain a DateTime object.
*
|
|
6d9380f96
|
36 37 |
* If expand is specified, recurring calendar objects are to be expanded
* into their individual components, and only the components that fall
|
|
03e52840d
|
38 39 40 |
* within the specified time-range are to be returned.
*
* For more details, see rfc4791, section 9.6.5.
|
|
6d9380f96
|
41 42 |
*
* @var null|array
|
|
03e52840d
|
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
*/
public $expand;
/**
* DOM Document
*
* @var DOMDocument
*/
protected $dom;
/**
* DOM XPath object
*
* @var DOMXPath
*/
protected $xpath;
/**
* Creates the parser
*
|
|
6d9380f96
|
63 |
* @param \DOMDocument $dom |
|
03e52840d
|
64 |
*/ |
|
6d9380f96
|
65 |
public function __construct(\DOMDocument $dom) {
|
|
03e52840d
|
66 67 |
$this->dom = $dom;
|
|
6d9380f96
|
68 69 |
$this->xpath = new \DOMXPath($dom);
$this->xpath->registerNameSpace('cal',Plugin::NS_CALDAV);
|
|
03e52840d
|
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
$this->xpath->registerNameSpace('dav','urn:DAV');
}
/**
* Parses the request.
*
* @return void
*/
public function parse() {
$filterNode = null;
$filter = $this->xpath->query('/cal:calendar-query/cal:filter');
if ($filter->length !== 1) {
|
|
6d9380f96
|
85 |
throw new \Sabre\DAV\Exception\BadRequest('Only one filter element is allowed');
|
|
03e52840d
|
86 87 88 89 |
}
$compFilters = $this->parseCompFilters($filter->item(0));
if (count($compFilters)!==1) {
|
|
6d9380f96
|
90 |
throw new \Sabre\DAV\Exception\BadRequest('There must be exactly 1 top-level comp-filter.');
|
|
03e52840d
|
91 92 93 |
}
$this->filters = $compFilters[0];
|
|
6d9380f96
|
94 |
$this->requestedProperties = array_keys(\Sabre\DAV\XMLUtil::parseProperties($this->dom->firstChild)); |
|
03e52840d
|
95 96 97 98 99 |
$expand = $this->xpath->query('/cal:calendar-query/dav:prop/cal:calendar-data/cal:expand');
if ($expand->length>0) {
$this->expand = $this->parseExpand($expand->item(0));
}
|
|
6d9380f96
|
100 |
|
|
03e52840d
|
101 102 103 104 105 106 |
}
/**
* Parses all the 'comp-filter' elements from a node
*
|
|
6d9380f96
|
107 |
* @param \DOMElement $parentNode |
|
03e52840d
|
108 109 |
* @return array
*/
|
|
6d9380f96
|
110 |
protected function parseCompFilters(\DOMElement $parentNode) {
|
|
03e52840d
|
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
$compFilterNodes = $this->xpath->query('cal:comp-filter', $parentNode);
$result = array();
for($ii=0; $ii < $compFilterNodes->length; $ii++) {
$compFilterNode = $compFilterNodes->item($ii);
$compFilter = array();
$compFilter['name'] = $compFilterNode->getAttribute('name');
$compFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $compFilterNode)->length>0;
$compFilter['comp-filters'] = $this->parseCompFilters($compFilterNode);
$compFilter['prop-filters'] = $this->parsePropFilters($compFilterNode);
$compFilter['time-range'] = $this->parseTimeRange($compFilterNode);
if ($compFilter['time-range'] && !in_array($compFilter['name'],array(
'VEVENT',
'VTODO',
'VJOURNAL',
'VFREEBUSY',
'VALARM',
))) {
|
|
6d9380f96
|
133 |
throw new \Sabre\DAV\Exception\BadRequest('The time-range filter is not defined for the ' . $compFilter['name'] . ' component');
|
|
03e52840d
|
134 135 136 137 138 139 140 141 142 143 144 145 146 |
};
$result[] = $compFilter;
}
return $result;
}
/**
* Parses all the prop-filter elements from a node
*
|
|
6d9380f96
|
147 |
* @param \DOMElement $parentNode |
|
03e52840d
|
148 149 |
* @return array
*/
|
|
6d9380f96
|
150 |
protected function parsePropFilters(\DOMElement $parentNode) {
|
|
03e52840d
|
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
$propFilterNodes = $this->xpath->query('cal:prop-filter', $parentNode);
$result = array();
for ($ii=0; $ii < $propFilterNodes->length; $ii++) {
$propFilterNode = $propFilterNodes->item($ii);
$propFilter = array();
$propFilter['name'] = $propFilterNode->getAttribute('name');
$propFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $propFilterNode)->length>0;
$propFilter['param-filters'] = $this->parseParamFilters($propFilterNode);
$propFilter['text-match'] = $this->parseTextMatch($propFilterNode);
$propFilter['time-range'] = $this->parseTimeRange($propFilterNode);
$result[] = $propFilter;
}
return $result;
}
/**
* Parses the param-filter element
*
|
|
6d9380f96
|
176 |
* @param \DOMElement $parentNode |
|
03e52840d
|
177 178 |
* @return array
*/
|
|
6d9380f96
|
179 |
protected function parseParamFilters(\DOMElement $parentNode) {
|
|
03e52840d
|
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
$paramFilterNodes = $this->xpath->query('cal:param-filter', $parentNode);
$result = array();
for($ii=0;$ii<$paramFilterNodes->length;$ii++) {
$paramFilterNode = $paramFilterNodes->item($ii);
$paramFilter = array();
$paramFilter['name'] = $paramFilterNode->getAttribute('name');
$paramFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $paramFilterNode)->length>0;
$paramFilter['text-match'] = $this->parseTextMatch($paramFilterNode);
$result[] = $paramFilter;
}
return $result;
}
/**
* Parses the text-match element
*
|
|
6d9380f96
|
203 |
* @param \DOMElement $parentNode |
|
03e52840d
|
204 205 |
* @return array|null
*/
|
|
6d9380f96
|
206 |
protected function parseTextMatch(\DOMElement $parentNode) {
|
|
03e52840d
|
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
$textMatchNodes = $this->xpath->query('cal:text-match', $parentNode);
if ($textMatchNodes->length === 0)
return null;
$textMatchNode = $textMatchNodes->item(0);
$negateCondition = $textMatchNode->getAttribute('negate-condition');
$negateCondition = $negateCondition==='yes';
$collation = $textMatchNode->getAttribute('collation');
if (!$collation) $collation = 'i;ascii-casemap';
return array(
'negate-condition' => $negateCondition,
'collation' => $collation,
'value' => $textMatchNode->nodeValue
);
}
/**
* Parses the time-range element
*
|
|
6d9380f96
|
230 |
* @param \DOMElement $parentNode |
|
03e52840d
|
231 232 |
* @return array|null
*/
|
|
6d9380f96
|
233 |
protected function parseTimeRange(\DOMElement $parentNode) {
|
|
03e52840d
|
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
$timeRangeNodes = $this->xpath->query('cal:time-range', $parentNode);
if ($timeRangeNodes->length === 0) {
return null;
}
$timeRangeNode = $timeRangeNodes->item(0);
if ($start = $timeRangeNode->getAttribute('start')) {
$start = VObject\DateTimeParser::parseDateTime($start);
} else {
$start = null;
}
if ($end = $timeRangeNode->getAttribute('end')) {
$end = VObject\DateTimeParser::parseDateTime($end);
} else {
$end = null;
}
if (!is_null($start) && !is_null($end) && $end <= $start) {
|
|
6d9380f96
|
254 |
throw new \Sabre\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the time-range filter');
|
|
03e52840d
|
255 256 257 258 259 260 261 262 263 264 265 |
}
return array(
'start' => $start,
'end' => $end,
);
}
/**
* Parses the CALDAV:expand element
|
|
6d9380f96
|
266 267 |
*
* @param \DOMElement $parentNode
|
|
03e52840d
|
268 269 |
* @return void
*/
|
|
6d9380f96
|
270 |
protected function parseExpand(\DOMElement $parentNode) {
|
|
03e52840d
|
271 272 273 |
$start = $parentNode->getAttribute('start');
if(!$start) {
|
|
6d9380f96
|
274 275 |
throw new \Sabre\DAV\Exception\BadRequest('The "start" attribute is required for the CALDAV:expand element');
}
|
|
03e52840d
|
276 277 278 279 |
$start = VObject\DateTimeParser::parseDateTime($start);
$end = $parentNode->getAttribute('end');
if(!$end) {
|
|
6d9380f96
|
280 281 |
throw new \Sabre\DAV\Exception\BadRequest('The "end" attribute is required for the CALDAV:expand element');
}
|
|
03e52840d
|
282 |
$end = VObject\DateTimeParser::parseDateTime($end); |
|
6d9380f96
|
283 |
|
|
03e52840d
|
284 |
if ($end <= $start) {
|
|
6d9380f96
|
285 |
throw new \Sabre\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the expand element.');
|
|
03e52840d
|
286 287 288 289 290 291 292 293 294 295 |
}
return array(
'start' => $start,
'end' => $end,
);
}
}
|