1<?php
2
3declare(strict_types=1);
4
5namespace Sabre\DAVACL\Xml\Property;
6
7use Sabre\DAV;
8use Sabre\DAV\Browser\HtmlOutputHelper;
9use Sabre\DAV\Exception\BadRequest;
10use Sabre\Xml\Reader;
11use Sabre\Xml\Writer;
12
13/**
14 * Principal property.
15 *
16 * The principal property represents a principal from RFC3744 (ACL).
17 * The property can be used to specify a principal or pseudo principals.
18 *
19 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
20 * @author Evert Pot (http://evertpot.com/)
21 * @license http://sabre.io/license/ Modified BSD License
22 */
23class Principal extends DAV\Xml\Property\Href
24{
25    /**
26     * To specify a not-logged-in user, use the UNAUTHENTICATED principal.
27     */
28    const UNAUTHENTICATED = 1;
29
30    /**
31     * To specify any principal that is logged in, use AUTHENTICATED.
32     */
33    const AUTHENTICATED = 2;
34
35    /**
36     * Specific principals can be specified with the HREF.
37     */
38    const HREF = 3;
39
40    /**
41     * Everybody, basically.
42     */
43    const ALL = 4;
44
45    /**
46     * Principal-type.
47     *
48     * Must be one of the UNAUTHENTICATED, AUTHENTICATED or HREF constants.
49     *
50     * @var int
51     */
52    protected $type;
53
54    /**
55     * Creates the property.
56     *
57     * The 'type' argument must be one of the type constants defined in this class.
58     *
59     * 'href' is only required for the HREF type.
60     *
61     * @param int         $type
62     * @param string|null $href
63     */
64    public function __construct($type, $href = null)
65    {
66        $this->type = $type;
67        if (self::HREF === $type && is_null($href)) {
68            throw new DAV\Exception('The href argument must be specified for the HREF principal type.');
69        }
70        if ($href) {
71            $href = rtrim($href, '/').'/';
72            parent::__construct($href);
73        }
74    }
75
76    /**
77     * Returns the principal type.
78     *
79     * @return int
80     */
81    public function getType()
82    {
83        return $this->type;
84    }
85
86    /**
87     * The xmlSerialize method is called during xml writing.
88     *
89     * Use the $writer argument to write its own xml serialization.
90     *
91     * An important note: do _not_ create a parent element. Any element
92     * implementing XmlSerializable should only ever write what's considered
93     * its 'inner xml'.
94     *
95     * The parent of the current element is responsible for writing a
96     * containing element.
97     *
98     * This allows serializers to be re-used for different element names.
99     *
100     * If you are opening new elements, you must also close them again.
101     */
102    public function xmlSerialize(Writer $writer)
103    {
104        switch ($this->type) {
105            case self::UNAUTHENTICATED:
106                $writer->writeElement('{DAV:}unauthenticated');
107                break;
108            case self::AUTHENTICATED:
109                $writer->writeElement('{DAV:}authenticated');
110                break;
111            case self::HREF:
112                parent::xmlSerialize($writer);
113                break;
114            case self::ALL:
115                $writer->writeElement('{DAV:}all');
116                break;
117        }
118    }
119
120    /**
121     * Generate html representation for this value.
122     *
123     * The html output is 100% trusted, and no effort is being made to sanitize
124     * it. It's up to the implementor to sanitize user provided values.
125     *
126     * The output must be in UTF-8.
127     *
128     * The baseUri parameter is a url to the root of the application, and can
129     * be used to construct local links.
130     *
131     * @return string
132     */
133    public function toHtml(HtmlOutputHelper $html)
134    {
135        switch ($this->type) {
136            case self::UNAUTHENTICATED:
137                return '<em>unauthenticated</em>';
138            case self::AUTHENTICATED:
139                return '<em>authenticated</em>';
140            case self::HREF:
141                return parent::toHtml($html);
142            case self::ALL:
143                return '<em>all</em>';
144        }
145    }
146
147    /**
148     * The deserialize method is called during xml parsing.
149     *
150     * This method is called staticly, this is because in theory this method
151     * may be used as a type of constructor, or factory method.
152     *
153     * Often you want to return an instance of the current class, but you are
154     * free to return other data as well.
155     *
156     * Important note 2: You are responsible for advancing the reader to the
157     * next element. Not doing anything will result in a never-ending loop.
158     *
159     * If you just want to skip parsing for this element altogether, you can
160     * just call $reader->next();
161     *
162     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
163     * the next element.
164     *
165     * @return mixed
166     */
167    public static function xmlDeserialize(Reader $reader)
168    {
169        $tree = $reader->parseInnerTree()[0];
170
171        switch ($tree['name']) {
172            case '{DAV:}unauthenticated':
173                return new self(self::UNAUTHENTICATED);
174            case '{DAV:}authenticated':
175                return new self(self::AUTHENTICATED);
176            case '{DAV:}href':
177                return new self(self::HREF, $tree['value']);
178            case '{DAV:}all':
179                return new self(self::ALL);
180            default:
181                throw new BadRequest('Unknown or unsupported principal type: '.$tree['name']);
182        }
183    }
184}
185