1<?php
2
3declare(strict_types=1);
4
5namespace Sabre\DAV\Xml\Property;
6
7use Sabre\DAV\Browser\HtmlOutput;
8use Sabre\DAV\Browser\HtmlOutputHelper;
9use Sabre\Uri;
10use Sabre\Xml\Element;
11use Sabre\Xml\Reader;
12use Sabre\Xml\Writer;
13
14/**
15 * Href property.
16 *
17 * This class represents any WebDAV property that contains a {DAV:}href
18 * element, and there are many.
19 *
20 * It can support either 1 or more hrefs. If while unserializing no valid
21 * {DAV:}href elements were found, this property will unserialize itself as
22 * null.
23 *
24 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
25 * @author Evert Pot (http://www.rooftopsolutions.nl/)
26 * @license http://sabre.io/license/ Modified BSD License
27 */
28class Href implements Element, HtmlOutput
29{
30    /**
31     * List of uris.
32     *
33     * @var array
34     */
35    protected $hrefs;
36
37    /**
38     * Constructor.
39     *
40     * You must either pass a string for a single href, or an array of hrefs.
41     *
42     * If auto-prefix is set to false, the hrefs will be treated as absolute
43     * and not relative to the servers base uri.
44     *
45     * @param string|string[] $hrefs
46     */
47    public function __construct($hrefs)
48    {
49        if (is_string($hrefs)) {
50            $hrefs = [$hrefs];
51        }
52        $this->hrefs = $hrefs;
53    }
54
55    /**
56     * Returns the first Href.
57     *
58     * @return string|null
59     */
60    public function getHref()
61    {
62        return $this->hrefs[0] ?? null;
63    }
64
65    /**
66     * Returns the hrefs as an array.
67     *
68     * @return array
69     */
70    public function getHrefs()
71    {
72        return $this->hrefs;
73    }
74
75    /**
76     * The xmlSerialize method is called during xml writing.
77     *
78     * Use the $writer argument to write its own xml serialization.
79     *
80     * An important note: do _not_ create a parent element. Any element
81     * implementing XmlSerializable should only ever write what's considered
82     * its 'inner xml'.
83     *
84     * The parent of the current element is responsible for writing a
85     * containing element.
86     *
87     * This allows serializers to be re-used for different element names.
88     *
89     * If you are opening new elements, you must also close them again.
90     */
91    public function xmlSerialize(Writer $writer)
92    {
93        foreach ($this->getHrefs() as $href) {
94            $href = Uri\resolve($writer->contextUri, $href);
95            $writer->writeElement('{DAV:}href', $href);
96        }
97    }
98
99    /**
100     * Generate html representation for this value.
101     *
102     * The html output is 100% trusted, and no effort is being made to sanitize
103     * it. It's up to the implementor to sanitize user provided values.
104     *
105     * The output must be in UTF-8.
106     *
107     * The baseUri parameter is a url to the root of the application, and can
108     * be used to construct local links.
109     *
110     * @return string
111     */
112    public function toHtml(HtmlOutputHelper $html)
113    {
114        $links = [];
115        foreach ($this->getHrefs() as $href) {
116            $links[] = $html->link($href);
117        }
118
119        return implode('<br />', $links);
120    }
121
122    /**
123     * The deserialize method is called during xml parsing.
124     *
125     * This method is called statically, this is because in theory this method
126     * may be used as a type of constructor, or factory method.
127     *
128     * Often you want to return an instance of the current class, but you are
129     * free to return other data as well.
130     *
131     * You are responsible for advancing the reader to the next element. Not
132     * doing anything will result in a never-ending loop.
133     *
134     * If you just want to skip parsing for this element altogether, you can
135     * just call $reader->next();
136     *
137     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
138     * the next element.
139     *
140     * @return mixed
141     */
142    public static function xmlDeserialize(Reader $reader)
143    {
144        $hrefs = [];
145        foreach ((array) $reader->parseInnerTree() as $elem) {
146            if ('{DAV:}href' !== $elem['name']) {
147                continue;
148            }
149
150            $hrefs[] = $elem['value'];
151        }
152        if ($hrefs) {
153            return new self($hrefs);
154        }
155    }
156}
157