1<?php
2
3namespace Sabre\DAV\Xml\Request;
4
5use Sabre\Xml\Element;
6use Sabre\Xml\Reader;
7use Sabre\Xml\Writer;
8
9/**
10 * WebDAV PROPPATCH request parser.
11 *
12 * This class parses the {DAV:}propertyupdate request, as defined in:
13 *
14 * https://tools.ietf.org/html/rfc4918#section-14.20
15 *
16 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
17 * @author Evert Pot (http://www.rooftopsolutions.nl/)
18 * @license http://sabre.io/license/ Modified BSD License
19 */
20class PropPatch implements Element {
21
22    /**
23     * The list of properties that will be updated and removed.
24     *
25     * If a property will be removed, it's value will be set to null.
26     *
27     * @var array
28     */
29    public $properties = [];
30
31    /**
32     * The xmlSerialize method is called during xml writing.
33     *
34     * Use the $writer argument to write its own xml serialization.
35     *
36     * An important note: do _not_ create a parent element. Any element
37     * implementing XmlSerializable should only ever write what's considered
38     * its 'inner xml'.
39     *
40     * The parent of the current element is responsible for writing a
41     * containing element.
42     *
43     * This allows serializers to be re-used for different element names.
44     *
45     * If you are opening new elements, you must also close them again.
46     *
47     * @param Writer $writer
48     * @return void
49     */
50    function xmlSerialize(Writer $writer) {
51
52        foreach ($this->properties as $propertyName => $propertyValue) {
53
54            if (is_null($propertyValue)) {
55                $writer->startElement("{DAV:}remove");
56                $writer->write(['{DAV:}prop' => [$propertyName => $propertyValue]]);
57                $writer->endElement();
58            } else {
59                $writer->startElement("{DAV:}set");
60                $writer->write(['{DAV:}prop' => [$propertyName => $propertyValue]]);
61                $writer->endElement();
62            }
63
64        }
65
66    }
67
68    /**
69     * The deserialize method is called during xml parsing.
70     *
71     * This method is called statically, this is because in theory this method
72     * may be used as a type of constructor, or factory method.
73     *
74     * Often you want to return an instance of the current class, but you are
75     * free to return other data as well.
76     *
77     * You are responsible for advancing the reader to the next element. Not
78     * doing anything will result in a never-ending loop.
79     *
80     * If you just want to skip parsing for this element altogether, you can
81     * just call $reader->next();
82     *
83     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
84     * the next element.
85     *
86     * @param Reader $reader
87     * @return mixed
88     */
89    static function xmlDeserialize(Reader $reader) {
90
91        $self = new self();
92
93        $elementMap = $reader->elementMap;
94        $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop';
95        $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue';
96        $elementMap['{DAV:}remove'] = 'Sabre\Xml\Element\KeyValue';
97
98        $elems = $reader->parseInnerTree($elementMap);
99
100        foreach ($elems as $elem) {
101            if ($elem['name'] === '{DAV:}set') {
102                $self->properties = array_merge($self->properties, $elem['value']['{DAV:}prop']);
103            }
104            if ($elem['name'] === '{DAV:}remove') {
105
106                // Ensuring there are no values.
107                foreach ($elem['value']['{DAV:}prop'] as $remove => $value) {
108                    $self->properties[$remove] = null;
109                }
110
111            }
112        }
113
114        return $self;
115
116    }
117
118}
119