Passed
Push — master ( 7a371e...4a8d98 )
by Tim
02:17
created

UIInfo::getDisplayName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\ProtocolViolationException;
10
use SimpleSAML\SAML2\Utils\XPath;
11
use SimpleSAML\XML\Chunk;
12
use SimpleSAML\XML\Constants as C;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\ExtendableElementTrait;
15
16
use function array_map;
17
use function array_merge;
18
use function array_unique;
19
20
/**
21
 * Class for handling the metadata extensions for login and discovery user interface
22
 *
23
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
24
 * @package simplesamlphp/saml2
25
 */
26
final class UIInfo extends AbstractMduiElement
27
{
28
    use ExtendableElementTrait;
29
30
    /** The namespace-attribute for the xs:any element */
31
    public const NAMESPACE = C::XS_ANY_NS_OTHER;
32
33
    /**
34
     * Create a UIInfo element.
35
     *
36
     * @param \SimpleSAML\SAML2\XML\mdui\DisplayName[] $displayName
37
     * @param \SimpleSAML\SAML2\XML\mdui\Description[] $description
38
     * @param \SimpleSAML\SAML2\XML\mdui\InformationURL[] $informationURL
39
     * @param \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[] $privacyStatementURL
40
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords[] $keywords
41
     * @param \SimpleSAML\SAML2\XML\mdui\Logo[] $logo
42
     * @param \SimpleSAML\XML\Chunk[] $children
43
     */
44
    public function __construct(
45
        protected array $displayName = [],
46
        protected array $description = [],
47
        protected array $informationURL = [],
48
        protected array $privacyStatementURL = [],
49
        protected array $keywords = [],
50
        protected array $logo = [],
51
        array $children = [],
52
    ) {
53
        Assert::allIsInstanceOf($displayName, DisplayName::class);
54
        /**
55
         * 2.1.2:  There MUST NOT be more than one <mdui:DisplayName>,
56
         *         within a given <mdui:UIInfo>, for a given language
57
         */
58
        $this->testLocalizedElements($displayName);
59
60
        Assert::allIsInstanceOf($description, Description::class);
61
        /**
62
         * 2.1.3:  There MUST NOT be more than one <mdui:Description>,
63
         *         within a given <mdui:UIInfo>, for a given language
64
         */
65
        $this->testLocalizedElements($description);
66
67
        Assert::allIsInstanceOf($keywords, Keywords::class);
68
        /**
69
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
70
         *         within a given <mdui:UIInfo>, for a given language
71
         */
72
        $this->testLocalizedElements($keywords);
73
74
        Assert::allIsInstanceOf($informationURL, InformationURL::class);
75
        /**
76
         * 2.1.6:  There MUST NOT be more than one <mdui:InformationURL>,
77
         *         within a given <mdui:UIInfo>, for a given language
78
         */
79
        $this->testLocalizedElements($informationURL);
80
81
        Assert::allIsInstanceOf($privacyStatementURL, PrivacyStatementURL::class);
82
        /**
83
         * 2.1.7:  There MUST NOT be more than one <mdui:PrivacyStatementURL>,
84
         *         within a given <mdui:UIInfo>, for a given language
85
         */
86
        $this->testLocalizedElements($privacyStatementURL);
87
88
        Assert::allIsInstanceOf($logo, Logo::class);
89
90
        $this->setElements($children);
91
    }
92
93
94
    /**
95
     * Collect the value of the Keywords-property
96
     *
97
     * @return \SimpleSAML\SAML2\XML\mdui\Keywords[]
98
     */
99
    public function getKeywords(): array
100
    {
101
        return $this->keywords;
102
    }
103
104
105
    /**
106
     * Add the value to the Keywords-property
107
     *
108
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords $keyword
109
     */
110
    public function addKeyword(Keywords $keyword): void
111
    {
112
        /**
113
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
114
         *         within a given <mdui:UIInfo>, for a given language
115
         */
116
        $keywords = array_merge($this->keywords, [$keyword]);
117
        $this->testLocalizedElements($keywords);
118
        $this->keywords = $keywords;
119
    }
120
121
122
    /**
123
     * Collect the value of the DisplayName-property
124
     *
125
     * @return \SimpleSAML\SAML2\XML\mdui\DisplayName[]
126
     */
127
    public function getDisplayName(): array
128
    {
129
        return $this->displayName;
130
    }
131
132
133
    /**
134
     * Collect the value of the Description-property
135
     *
136
     * @return \SimpleSAML\SAML2\XML\mdui\Description[]
137
     */
138
    public function getDescription(): array
139
    {
140
        return $this->description;
141
    }
142
143
144
    /**
145
     * Collect the value of the InformationURL-property
146
     * @return \SimpleSAML\SAML2\XML\mdui\InformationURL[]
147
     */
148
    public function getInformationURL(): array
149
    {
150
        return $this->informationURL;
151
    }
152
153
154
    /**
155
     * Collect the value of the PrivacyStatementURL-property
156
     *
157
     * @return \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[]
158
     */
159
    public function getPrivacyStatementURL(): array
160
    {
161
        return $this->privacyStatementURL;
162
    }
163
164
165
    /**
166
     * Collect the value of the Logo-property
167
     *
168
     * @return \SimpleSAML\SAML2\XML\mdui\Logo[]
169
     */
170
    public function getLogo(): array
171
    {
172
        return $this->logo;
173
    }
174
175
176
    /**
177
     * Add the value to the Logo-property
178
     *
179
     * @param \SimpleSAML\SAML2\XML\mdui\Logo $logo
180
     */
181
    public function addLogo(Logo $logo): void
182
    {
183
        $this->logo[] = $logo;
184
    }
185
186
187
    /**
188
     * Add the value to the elements-property
189
     *
190
     * @param \SimpleSAML\XML\Chunk $child
191
     */
192
    public function addChild(Chunk $child): void
193
    {
194
        $this->elements[] = $child;
195
    }
196
197
198
    /**
199
     * Test if an object, at the state it's in, would produce an empty XML-element
200
     *
201
     * @return bool
202
     */
203
    public function isEmptyElement(): bool
204
    {
205
        return (
206
            empty($this->displayName)
207
            && empty($this->description)
208
            && empty($this->informationURL)
209
            && empty($this->privacyStatementURL)
210
            && empty($this->keywords)
211
            && empty($this->logo)
212
            && empty($this->elements)
213
        );
214
    }
215
216
217
    /**
218
     * Test localized elements for multiple items with the same language
219
     *
220
     * @param (\SimpleSAML\SAML2\XML\md\AbstractLocalizedURL|
221
     *         \SimpleSAML\SAML2\XML\md\AbstractLocalizedName|
222
     *         \SimpleSAML\XML\SAML2\mdui\Keywords)[] $items
223
     * @return void
224
     */
225
    private function testLocalizedElements(array $elements)
226
    {
227
        if (!empty($elements)) {
228
            $types = array_map('get_class', $elements);
229
            Assert::maxCount(array_unique($types), 1, 'Multiple class types cannot be used.');
230
231
            $languages = array_map(
232
                function ($elt) {
233
                    return $elt->getLanguage();
234
                },
235
                $elements,
236
            );
237
            Assert::uniqueValues(
238
                $languages,
239
                'There MUST NOT be more than one <' . $elements[0]->getQualifiedName() . '>,'
240
                . ' within a given <mdui:UIInfo>, for a given language',
241
                ProtocolViolationException::class,
242
            );
243
        }
244
    }
245
246
247
    /**
248
     * Convert XML into a UIInfo
249
     *
250
     * @param \DOMElement $xml The XML element we should load
251
     * @return self
252
     *
253
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
254
     *   if the qualified name of the supplied element is wrong
255
     */
256
    public static function fromXML(DOMElement $xml): static
257
    {
258
        Assert::same($xml->localName, 'UIInfo', InvalidDOMElementException::class);
259
        Assert::same($xml->namespaceURI, UIInfo::NS, InvalidDOMElementException::class);
260
261
        $DisplayName = DisplayName::getChildrenOfClass($xml);
262
        $Description = Description::getChildrenOfClass($xml);
263
        $InformationURL = InformationURL::getChildrenOfClass($xml);
264
        $PrivacyStatementURL = PrivacyStatementURL::getChildrenOfClass($xml);
265
        $Keywords = Keywords::getChildrenOfClass($xml);
266
        $Logo = Logo::getChildrenOfClass($xml);
267
        $children = [];
268
269
        /** @var \DOMElement $node */
270
        foreach (XPath::xpQuery($xml, './*', XPath::getXPath($xml)) as $node) {
271
            if ($node->namespaceURI !== UIInfo::NS) {
272
                $children[] = new Chunk($node);
273
            }
274
        }
275
276
        return new static(
277
            $DisplayName,
278
            $Description,
279
            $InformationURL,
280
            $PrivacyStatementURL,
281
            $Keywords,
282
            $Logo,
283
            $children,
284
        );
285
    }
286
287
288
    /**
289
     * Convert this UIInfo to XML.
290
     *
291
     * @param \DOMElement|null $parent The element we should append to.
292
     * @return \DOMElement
293
     */
294
    public function toXML(DOMElement $parent = null): DOMElement
295
    {
296
        $e = $this->instantiateParentElement($parent);
297
298
        foreach ($this->getDisplayName() as $child) {
299
            $child->toXML($e);
300
        }
301
302
        foreach ($this->getDescription() as $child) {
303
            $child->toXML($e);
304
        }
305
306
        foreach ($this->getInformationURL() as $child) {
307
            $child->toXML($e);
308
        }
309
310
        foreach ($this->getPrivacyStatementURL() as $child) {
311
            $child->toXML($e);
312
        }
313
314
        foreach ($this->getKeywords() as $child) {
315
            $child->toXML($e);
316
        }
317
318
        foreach ($this->getLogo() as $child) {
319
            $child->toXML($e);
320
        }
321
322
        foreach ($this->getElements() as $child) {
323
            $child->toXML($e);
324
        }
325
326
        return $e;
327
    }
328
329
330
    /**
331
     * Create a class from an array
332
     *
333
     * NOTE: this method does not support passing additional child-objects
334
     *
335
     * @param array $data
336
     * @return self
337
     */
338
    public static function fromArray(array $data): static
339
    {
340
        $DisplayName = [];
341
        if (!empty($data['DisplayName'])) {
342
            foreach ($data['DisplayName'] as $l => $k) {
343
                $DisplayName[] = DisplayName::fromArray([$l => $k]);
344
            }
345
        }
346
347
        $Description = [];
348
        if (!empty($data['Description'])) {
349
            foreach ($data['Description'] as $l => $k) {
350
                $Description[] = Description::fromArray([$l => $k]);
351
            }
352
        }
353
354
        $InformationURL = [];
355
        if (!empty($data['InformationURL'])) {
356
            foreach ($data['InformationURL'] as $l => $k) {
357
                $InformationURL[] = InformationURL::fromArray([$l => $k]);
358
            }
359
        }
360
361
        $PrivacyStatementURL = [];
362
        if (!empty($data['PrivacyStatementURL'])) {
363
            foreach ($data['PrivacyStatementURL'] as $l => $k) {
364
                $PrivacyStatementURL[] = PrivacyStatementURL::fromArray([$l => $k]);
365
            }
366
        }
367
368
        $Keywords = [];
369
        if (!empty($data['Keywords'])) {
370
            foreach ($data['Keywords'] as $l => $k) {
371
                $Keywords[] = Keywords::fromArray([$l => $k]);
372
            }
373
        }
374
375
        $Logo = [];
376
        if (!empty($data['Logo'])) {
377
            foreach ($data['Logo'] as $l) {
378
                $Logo[] = Logo::fromArray($l);
379
            }
380
        }
381
382
        return new static(
383
            $DisplayName,
384
            $Description,
385
            $InformationURL,
386
            $PrivacyStatementURL,
387
            $Keywords,
388
            $Logo,
389
        );
390
    }
391
392
393
    /**
394
     * Create an array from this class
395
     *
396
     * NOTE: this method does not support passing additional child-objects
397
     *
398
     * @return array
399
     */
400
    public function toArray(): array
401
    {
402
        $displayName = [];
403
        foreach ($this->getDisplayName() as $child) {
404
            $displayName = array_merge($displayName, $child->toArray());
405
        }
406
407
        $description = [];
408
        foreach ($this->getDescription() as $child) {
409
            $description = array_merge($description, $child->toArray());
410
        }
411
412
        $infoUrl = [];
413
        foreach ($this->getInformationURL() as $child) {
414
            $infoUrl = array_merge($infoUrl, $child->toArray());
415
        }
416
417
        $privacyUrl = [];
418
        foreach ($this->getPrivacyStatementURL() as $child) {
419
            $privacyUrl = array_merge($privacyUrl, $child->toArray());
420
        }
421
422
        $keywords = [];
423
        foreach ($this->getKeywords() as $child) {
424
            $keywords = array_merge($keywords, $child->toArray());
425
        }
426
427
        $logo = [];
428
        foreach ($this->getLogo() as $child) {
429
            $logo[] = $child->toArray();
430
        }
431
432
        return [
433
            'DisplayName' => $displayName,
434
            'Description' => $description,
435
            'InformationURL' => $infoUrl,
436
            'PrivacyStatementURL' => $privacyUrl,
437
            'Keywords' => $keywords,
438
            'Logo' => $logo,
439
        ];
440
    }
441
}
442