DiscoHints   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 29
eloc 88
dl 0
loc 264
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A addChild() 0 3 1
A fromArray() 0 9 1
A getIPHint() 0 3 1
A toXML() 0 22 5
A getDomainHint() 0 3 1
A fromXML() 0 17 2
A getGeolocationHint() 0 3 1
A isEmptyElement() 0 6 4
A __construct() 0 14 1
A toArray() 0 22 4
B processArrayContents() 0 53 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\mdui;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\ArrayValidationException;
10
use SimpleSAML\SAML2\Utils\XPath;
11
use SimpleSAML\XML\ArrayizableElementInterface;
12
use SimpleSAML\XML\Chunk;
13
use SimpleSAML\XML\Constants as C;
14
use SimpleSAML\XML\Exception\InvalidDOMElementException;
15
use SimpleSAML\XML\ExtendableElementTrait;
16
use SimpleSAML\XML\SchemaValidatableElementInterface;
17
use SimpleSAML\XML\SchemaValidatableElementTrait;
18
use SimpleSAML\XML\SerializableElementInterface;
19
use SimpleSAML\XML\XsNamespace as NS;
20
21
use function array_filter;
22
use function array_key_exists;
23
use function array_keys;
24
25
/**
26
 * Class for handling the metadata extensions for login and discovery user interface
27
 *
28
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
29
 * @package simplesamlphp/saml2
30
 */
31
final class DiscoHints extends AbstractMduiElement implements
32
    ArrayizableElementInterface,
33
    SchemaValidatableElementInterface
34
{
35
    use ExtendableElementTrait;
36
    use SchemaValidatableElementTrait;
37
38
39
    /** The namespace-attribute for the xs:any element */
40
    public const XS_ANY_ELT_NAMESPACE = NS::OTHER;
41
42
43
    /**
44
     * Create a DiscoHints element.
45
     *
46
     * @param \SimpleSAML\XML\Chunk[] $children
47
     * @param \SimpleSAML\SAML2\XML\mdui\IPHint[] $ipHint
48
     * @param \SimpleSAML\SAML2\XML\mdui\DomainHint[] $domainHint
49
     * @param \SimpleSAML\SAML2\XML\mdui\GeolocationHint[] $geolocationHint
50
     */
51
    public function __construct(
52
        array $children = [],
53
        protected array $ipHint = [],
54
        protected array $domainHint = [],
55
        protected array $geolocationHint = [],
56
    ) {
57
        Assert::maxCount($ipHint, C::UNBOUNDED_LIMIT);
58
        Assert::maxCount($domainHint, C::UNBOUNDED_LIMIT);
59
        Assert::maxCount($geolocationHint, C::UNBOUNDED_LIMIT);
60
        Assert::allIsInstanceOf($ipHint, IPHint::class);
61
        Assert::allIsInstanceOf($domainHint, DomainHint::class);
62
        Assert::allIsInstanceOf($geolocationHint, GeolocationHint::class);
63
64
        $this->setElements($children);
65
    }
66
67
68
    /**
69
     * Collect the value of the IPHint-property
70
     *
71
     * @return \SimpleSAML\SAML2\XML\mdui\IPHint[]
72
     */
73
    public function getIPHint(): array
74
    {
75
        return $this->ipHint;
76
    }
77
78
79
    /**
80
     * Collect the value of the DomainHint-property
81
     *
82
     * @return \SimpleSAML\SAML2\XML\mdui\DomainHint[]
83
     */
84
    public function getDomainHint(): array
85
    {
86
        return $this->domainHint;
87
    }
88
89
90
    /**
91
     * Collect the value of the GeolocationHint-property
92
     *
93
     * @return \SimpleSAML\SAML2\XML\mdui\GeolocationHint[]
94
     */
95
    public function getGeolocationHint(): array
96
    {
97
        return $this->geolocationHint;
98
    }
99
100
101
    /**
102
     * Add the value to the elements-property
103
     *
104
     * @param \SimpleSAML\XML\Chunk $child
105
     */
106
    public function addChild(Chunk $child): void
107
    {
108
        $this->elements[] = $child;
109
    }
110
111
112
    /**
113
     * Test if an object, at the state it's in, would produce an empty XML-element
114
     *
115
     * @return bool
116
     */
117
    public function isEmptyElement(): bool
118
    {
119
        return empty($this->elements)
120
            && empty($this->ipHint)
121
            && empty($this->domainHint)
122
            && empty($this->geolocationHint);
123
    }
124
125
126
    /**
127
     * Convert XML into a DiscoHints
128
     *
129
     * @param \DOMElement $xml The XML element we should load
130
     * @return static
131
     *
132
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
133
     *   if the qualified name of the supplied element is wrong
134
     */
135
    public static function fromXML(DOMElement $xml): static
136
    {
137
        Assert::same($xml->localName, 'DiscoHints', InvalidDOMElementException::class);
138
        Assert::same($xml->namespaceURI, DiscoHints::NS, InvalidDOMElementException::class);
139
140
        $IPHint = IPHint::getChildrenOfClass($xml);
141
        $DomainHint = DomainHint::getChildrenOfClass($xml);
142
        $GeolocationHint = GeolocationHint::getChildrenOfClass($xml);
143
        $children = [];
144
145
        /** @var \DOMElement[] $nodes */
146
        $nodes = XPath::xpQuery($xml, "./*[namespace-uri()!='" . DiscoHints::NS . "']", XPath::getXPath($xml));
147
        foreach ($nodes as $node) {
148
            $children[] = new Chunk($node);
149
        }
150
151
        return new static($children, $IPHint, $DomainHint, $GeolocationHint);
152
    }
153
154
155
    /**
156
     * Convert this DiscoHints to XML.
157
     *
158
     * @param \DOMElement|null $parent The element we should append to.
159
     * @return \DOMElement
160
     */
161
    public function toXML(?DOMElement $parent = null): DOMElement
162
    {
163
        $e = $this->instantiateParentElement($parent);
164
165
        foreach ($this->getIPHint() as $hint) {
166
            $hint->toXML($e);
167
        }
168
169
        foreach ($this->getDomainHint() as $hint) {
170
            $hint->toXML($e);
171
        }
172
173
        foreach ($this->getGeolocationHint() as $hint) {
174
            $hint->toXML($e);
175
        }
176
177
        /** @var \SimpleSAML\XML\SerializableElementInterface $child */
178
        foreach ($this->getElements() as $child) {
179
            $child->toXML($e);
180
        }
181
182
        return $e;
183
    }
184
185
186
    /**
187
     * Create a class from an array
188
     *
189
     * @param array $data
190
     * @return static
191
     */
192
    public static function fromArray(array $data): static
193
    {
194
        $data = self::processArrayContents($data);
195
196
        return new static(
197
            $data['children'] ?? [],
198
            $data['IPHint'] ?? [],
199
            $data['DomainHint'] ?? [],
200
            $data['GeolocationHint'] ?? [],
201
        );
202
    }
203
204
205
    /**
206
     * Validates an array representation of this object and returns the same array with
207
     * rationalized keys (casing) and parsed sub-elements.
208
     *
209
     * @param array $data
210
     * @return array $data
211
     */
212
    private static function processArrayContents(array $data): array
213
    {
214
        $data = array_change_key_case($data, CASE_LOWER);
215
216
        // Make sure the array keys are known for this kind of object
217
        Assert::allOneOf(
218
            array_keys($data),
219
            [
220
                'iphint',
221
                'domainhint',
222
                'geolocationhint',
223
                'children',
224
            ],
225
            ArrayValidationException::class,
226
        );
227
228
        $retval = [];
229
230
        if (array_key_exists('iphint', $data)) {
231
            Assert::isArray($data['iphint'], ArrayValidationException::class);
232
            Assert::allString($data['iphint'], ArrayValidationException::class);
233
            foreach ($data['iphint'] as $hint) {
234
                $retval['IPHint'][] = new IPHint($hint);
235
            }
236
        }
237
238
        if (array_key_exists('domainhint', $data)) {
239
            Assert::isArray($data['domainhint'], ArrayValidationException::class);
240
            Assert::allString($data['domainhint'], ArrayValidationException::class);
241
            foreach ($data['domainhint'] as $hint) {
242
                $retval['DomainHint'][] = new DomainHint($hint);
243
            }
244
        }
245
246
        if (array_key_exists('geolocationhint', $data)) {
247
            Assert::isArray($data['geolocationhint'], ArrayValidationException::class);
248
            Assert::allString($data['geolocationhint'], ArrayValidationException::class);
249
            foreach ($data['geolocationhint'] as $hint) {
250
                $retval['GeolocationHint'][] = new GeolocationHint($hint);
251
            }
252
        }
253
254
        if (array_key_exists('children', $data)) {
255
            Assert::isArray($data['children'], ArrayValidationException::class);
256
            Assert::allIsInstanceOf(
257
                $data['children'],
258
                SerializableElementInterface::class,
259
                ArrayValidationException::class,
260
            );
261
            $retval['children'] = $data['children'];
262
        }
263
264
        return $retval;
265
    }
266
267
268
    /**
269
     * Create an array from this class
270
     *
271
     * @return array
272
     */
273
    public function toArray(): array
274
    {
275
        $data = [
276
            'IPHint' => [],
277
            'DomainHint' => [],
278
            'GeolocationHint' => [],
279
            'children' => $this->getElements(),
280
        ];
281
282
        foreach ($this->getIPHint() as $hint) {
283
            $data['IPHint'][] = $hint->getContent();
284
        }
285
286
        foreach ($this->getDomainHint() as $hint) {
287
            $data['DomainHint'][] = $hint->getContent();
288
        }
289
290
        foreach ($this->getGeolocationHint() as $hint) {
291
            $data['GeolocationHint'][] = $hint->getContent();
292
        }
293
294
        return array_filter($data);
295
    }
296
}
297