Passed
Branch feature/php83 (cb5cde)
by Tim
14:20
created

UIInfo::toArray()   F

Complexity

Conditions 14
Paths 8192

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 27
nc 8192
nop 0
dl 0
loc 42
rs 2.1
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\mdui;
6
7
use DOMElement;
8
use SimpleSAML\SAML2\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\ArrayValidationException;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\XML\ArrayizableElementInterface;
12
use SimpleSAML\XML\Constants as C;
13
use SimpleSAML\XML\ExtendableElementTrait;
14
use SimpleSAML\XML\SchemaValidatableElementInterface;
15
use SimpleSAML\XML\SchemaValidatableElementTrait;
16
use SimpleSAML\XML\SerializableElementInterface;
17
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;
18
use SimpleSAML\XMLSchema\XML\Constants\NS;
19
20
use function array_filter;
21
use function array_key_exists;
22
use function array_keys;
23
use function array_map;
24
use function array_merge;
25
use function array_unique;
26
27
/**
28
 * Class for handling the metadata extensions for login and discovery user interface
29
 *
30
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
31
 *
32
 * @package simplesamlphp/saml2
33
 */
34
final class UIInfo extends AbstractMduiElement implements
35
    ArrayizableElementInterface,
36
    SchemaValidatableElementInterface
37
{
38
    use ExtendableElementTrait;
39
    use SchemaValidatableElementTrait;
40
41
42
    /** The namespace-attribute for the xs:any element */
43
    public const string XS_ANY_ELT_NAMESPACE = NS::OTHER;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 43 at column 24
Loading history...
44
45
46
    /**
47
     * Create a UIInfo element.
48
     *
49
     * @param \SimpleSAML\SAML2\XML\mdui\DisplayName[] $displayName
50
     * @param \SimpleSAML\SAML2\XML\mdui\Description[] $description
51
     * @param \SimpleSAML\SAML2\XML\mdui\InformationURL[] $informationURL
52
     * @param \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[] $privacyStatementURL
53
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords[] $keywords
54
     * @param \SimpleSAML\SAML2\XML\mdui\Logo[] $logo
55
     * @param \SimpleSAML\XML\SerializableElementInterface[] $children
56
     */
57
    public function __construct(
58
        protected array $displayName = [],
59
        protected array $description = [],
60
        protected array $informationURL = [],
61
        protected array $privacyStatementURL = [],
62
        protected array $keywords = [],
63
        protected array $logo = [],
64
        array $children = [],
65
    ) {
66
        Assert::maxCount($displayName, C::UNBOUNDED_LIMIT);
67
        Assert::allIsInstanceOf($displayName, DisplayName::class);
68
        /**
69
         * 2.1.2:  There MUST NOT be more than one <mdui:DisplayName>,
70
         *         within a given <mdui:UIInfo>, for a given language
71
         */
72
        $this->testLocalizedElements($displayName);
73
74
        Assert::maxCount($description, C::UNBOUNDED_LIMIT);
75
        Assert::allIsInstanceOf($description, Description::class);
76
        /**
77
         * 2.1.3:  There MUST NOT be more than one <mdui:Description>,
78
         *         within a given <mdui:UIInfo>, for a given language
79
         */
80
        $this->testLocalizedElements($description);
81
82
        Assert::maxCount($keywords, C::UNBOUNDED_LIMIT);
83
        Assert::allIsInstanceOf($keywords, Keywords::class);
84
        /**
85
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
86
         *         within a given <mdui:UIInfo>, for a given language
87
         */
88
        $this->testLocalizedElements($keywords);
89
90
        Assert::maxCount($informationURL, C::UNBOUNDED_LIMIT);
91
        Assert::allIsInstanceOf($informationURL, InformationURL::class);
92
        /**
93
         * 2.1.6:  There MUST NOT be more than one <mdui:InformationURL>,
94
         *         within a given <mdui:UIInfo>, for a given language
95
         */
96
        $this->testLocalizedElements($informationURL);
97
98
        Assert::maxCount($privacyStatementURL, C::UNBOUNDED_LIMIT);
99
        Assert::allIsInstanceOf($privacyStatementURL, PrivacyStatementURL::class);
100
        /**
101
         * 2.1.7:  There MUST NOT be more than one <mdui:PrivacyStatementURL>,
102
         *         within a given <mdui:UIInfo>, for a given language
103
         */
104
        $this->testLocalizedElements($privacyStatementURL);
105
106
        Assert::maxCount($logo, C::UNBOUNDED_LIMIT);
107
        Assert::allIsInstanceOf($logo, Logo::class);
108
109
        $this->setElements($children);
110
    }
111
112
113
    /**
114
     * Collect the value of the Keywords-property
115
     *
116
     * @return \SimpleSAML\SAML2\XML\mdui\Keywords[]
117
     */
118
    public function getKeywords(): array
119
    {
120
        return $this->keywords;
121
    }
122
123
124
    /**
125
     * Add the value to the Keywords-property
126
     *
127
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords $keyword
128
     */
129
    public function addKeyword(Keywords $keyword): void
130
    {
131
        /**
132
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
133
         *         within a given <mdui:UIInfo>, for a given language
134
         */
135
        $keywords = array_merge($this->keywords, [$keyword]);
136
        $this->testLocalizedElements($keywords);
137
        $this->keywords = $keywords;
138
    }
139
140
141
    /**
142
     * Collect the value of the DisplayName-property
143
     *
144
     * @return \SimpleSAML\SAML2\XML\mdui\DisplayName[]
145
     */
146
    public function getDisplayName(): array
147
    {
148
        return $this->displayName;
149
    }
150
151
152
    /**
153
     * Collect the value of the Description-property
154
     *
155
     * @return \SimpleSAML\SAML2\XML\mdui\Description[]
156
     */
157
    public function getDescription(): array
158
    {
159
        return $this->description;
160
    }
161
162
163
    /**
164
     * Collect the value of the InformationURL-property
165
     * @return \SimpleSAML\SAML2\XML\mdui\InformationURL[]
166
     */
167
    public function getInformationURL(): array
168
    {
169
        return $this->informationURL;
170
    }
171
172
173
    /**
174
     * Collect the value of the PrivacyStatementURL-property
175
     *
176
     * @return \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[]
177
     */
178
    public function getPrivacyStatementURL(): array
179
    {
180
        return $this->privacyStatementURL;
181
    }
182
183
184
    /**
185
     * Collect the value of the Logo-property
186
     *
187
     * @return \SimpleSAML\SAML2\XML\mdui\Logo[]
188
     */
189
    public function getLogo(): array
190
    {
191
        return $this->logo;
192
    }
193
194
195
    /**
196
     * Add the value to the Logo-property
197
     *
198
     * @param \SimpleSAML\SAML2\XML\mdui\Logo $logo
199
     */
200
    public function addLogo(Logo $logo): void
201
    {
202
        $this->logo[] = $logo;
203
    }
204
205
206
    /**
207
     * Add the value to the elements-property
208
     *
209
     * @param \SimpleSAML\XML\SerializableElementInterface $child
210
     */
211
    public function addChild(SerializableElementInterface $child): void
212
    {
213
        $this->elements[] = $child;
214
    }
215
216
217
    /**
218
     * Test if an object, at the state it's in, would produce an empty XML-element
219
     *
220
     * @return bool
221
     */
222
    public function isEmptyElement(): bool
223
    {
224
        return empty($this->getDisplayName())
225
            && empty($this->getDescription())
226
            && empty($this->getInformationURL())
227
            && empty($this->getPrivacyStatementURL())
228
            && empty($this->getKeywords())
229
            && empty($this->getLogo())
230
            && empty($this->getElements());
231
    }
232
233
234
    /**
235
     * Test localized elements for multiple items with the same language
236
     *
237
     * @param (
238
     *   \SimpleSAML\SAML2\XML\md\AbstractLocalizedURI|
239
     *   \SimpleSAML\SAML2\XML\md\AbstractLocalizedName|
240
     *   \SimpleSAML\SAML2\XML\mdui\Keywords
241
     * )[] $elements
242
     */
243
    private function testLocalizedElements(array $elements)
244
    {
245
        if (!empty($elements)) {
246
            $types = array_map('get_class', $elements);
247
            Assert::maxCount(array_unique($types), 1, 'Multiple class types cannot be used.');
248
249
            $languages = array_map(
250
                function ($elt) {
251
                    return $elt->getLanguage();
252
                },
253
                $elements,
254
            );
255
            Assert::uniqueValues(
256
                $languages,
257
                'There MUST NOT be more than one <' . $elements[0]->getQualifiedName() . '>,'
258
                . ' within a given <mdui:UIInfo>, for a given language',
259
                ProtocolViolationException::class,
260
            );
261
        }
262
    }
263
264
265
    /**
266
     * Convert XML into a UIInfo
267
     *
268
     * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
269
     *   if the qualified name of the supplied element is wrong
270
     */
271
    public static function fromXML(DOMElement $xml): static
272
    {
273
        Assert::same($xml->localName, 'UIInfo', InvalidDOMElementException::class);
274
        Assert::same($xml->namespaceURI, UIInfo::NS, InvalidDOMElementException::class);
275
276
        $DisplayName = DisplayName::getChildrenOfClass($xml);
277
        $Description = Description::getChildrenOfClass($xml);
278
        $InformationURL = InformationURL::getChildrenOfClass($xml);
279
        $PrivacyStatementURL = PrivacyStatementURL::getChildrenOfClass($xml);
280
        $Keywords = Keywords::getChildrenOfClass($xml);
281
        $Logo = Logo::getChildrenOfClass($xml);
282
        $children = self::getChildElementsFromXML($xml);
283
284
        return new static(
285
            $DisplayName,
286
            $Description,
287
            $InformationURL,
288
            $PrivacyStatementURL,
289
            $Keywords,
290
            $Logo,
291
            $children,
292
        );
293
    }
294
295
296
    /**
297
     * Convert this UIInfo to XML.
298
     */
299
    public function toXML(?DOMElement $parent = null): DOMElement
300
    {
301
        $e = $this->instantiateParentElement($parent);
302
303
        foreach ($this->getDisplayName() as $child) {
304
            $child->toXML($e);
305
        }
306
307
        foreach ($this->getDescription() as $child) {
308
            $child->toXML($e);
309
        }
310
311
        foreach ($this->getInformationURL() as $child) {
312
            $child->toXML($e);
313
        }
314
315
        foreach ($this->getPrivacyStatementURL() as $child) {
316
            $child->toXML($e);
317
        }
318
319
        foreach ($this->getKeywords() as $child) {
320
            $child->toXML($e);
321
        }
322
323
        foreach ($this->getLogo() as $child) {
324
            $child->toXML($e);
325
        }
326
327
        /** @var \SimpleSAML\XML\SerializableElementInterface $child */
328
        foreach ($this->getElements() as $child) {
329
            $child->toXML($e);
330
        }
331
332
        return $e;
333
    }
334
335
336
    /**
337
     * Create a class from an array
338
     *
339
     * @param array{
340
     *   'DisplayName'?: array,
341
     *   'Description'?: array,
342
     *   'InformationURL'?: array,
343
     *   'PrivacyStatementURL'?: array,
344
     *   'Keywords'?: array,
345
     *   'Logo'?: array,
346
     *   'children'?: array,
347
     * } $data
348
     */
349
    public static function fromArray(array $data): static
350
    {
351
        $data = self::processArrayContents($data);
352
353
        return new static(
354
            $data['DisplayName'] ?? [],
355
            $data['Description'] ?? [],
356
            $data['InformationURL'] ?? [],
357
            $data['PrivacyStatementURL'] ?? [],
358
            $data['Keywords'] ?? [],
359
            $data['Logo'] ?? [],
360
            $data['children'] ?? [],
361
        );
362
    }
363
364
365
    /**
366
     * Validates an array representation of this object and returns the same array with
367
     * rationalized keys (casing) and parsed sub-elements.
368
     *
369
     * @param array{
370
     *   'DisplayName'?: array,
371
     *   'Description'?: array,
372
     *   'InformationURL'?: array,
373
     *   'PrivacyStatementURL'?: array,
374
     *   'Keywords'?: array,
375
     *   'Logo'?: array,
376
     *   'children'?: array,
377
     * } $data
378
     * @return array{
379
     *   'DisplayName'?: array,
380
     *   'Description'?: array,
381
     *   'InformationURL'?: array,
382
     *   'PrivacyStatementURL'?: array,
383
     *   'Keywords'?: array,
384
     *   'Logo'?: array,
385
     *   'children'?: array,
386
     * }
387
     */
388
    private static function processArrayContents(array $data): array
389
    {
390
        $data = array_change_key_case($data, CASE_LOWER);
391
392
        // Make sure the array keys are known for this kind of object
393
        Assert::allOneOf(
394
            array_keys($data),
395
            [
396
                'displayname',
397
                'description',
398
                'informationurl',
399
                'privacystatementurl',
400
                'keywords',
401
                'logo',
402
                'children',
403
            ],
404
            ArrayValidationException::class,
405
        );
406
407
        $retval = [];
408
409
        if (array_key_exists('displayname', $data)) {
410
            foreach ($data['displayname'] as $l => $displayName) {
411
                $retval['DisplayName'][] = DisplayName::fromArray([$l => $displayName]);
412
            }
413
        }
414
415
        if (array_key_exists('description', $data)) {
416
            foreach ($data['description'] as $l => $description) {
417
                $retval['Description'][] = Description::fromArray([$l => $description]);
418
            }
419
        }
420
421
        if (array_key_exists('informationurl', $data)) {
422
            foreach ($data['informationurl'] as $l => $iu) {
423
                $retval['InformationURL'][] = InformationURL::fromArray([$l => $iu]);
424
            }
425
        }
426
427
        if (array_key_exists('privacystatementurl', $data)) {
428
            foreach ($data['privacystatementurl'] as $l => $psu) {
429
                $retval['PrivacyStatementURL'][] = PrivacyStatementURL::fromArray([$l => $psu]);
430
            }
431
        }
432
433
        if (array_key_exists('keywords', $data)) {
434
            foreach ($data['keywords'] as $l => $keywords) {
435
                $retval['Keywords'][] = Keywords::fromArray([$l => $keywords]);
436
            }
437
        }
438
439
        if (array_key_exists('logo', $data)) {
440
            foreach ($data['logo'] as $logo) {
441
                $retval['Logo'][] = Logo::fromArray($logo);
442
            }
443
        }
444
445
        if (array_key_exists('children', $data)) {
446
            Assert::isArray($data['children'], ArrayValidationException::class);
447
            Assert::allIsInstanceOf(
448
                $data['children'],
449
                SerializableElementInterface::class,
450
                ArrayValidationException::class,
451
            );
452
            $retval['children'] = $data['children'];
453
        }
454
455
        return array_filter($retval);
456
    }
457
458
459
    /**
460
     * Create an array from this class
461
     *
462
     * @return array{
463
     *   'DisplayName'?: array,
464
     *   'Description'?: array,
465
     *   'InformationURL'?: array,
466
     *   'PrivacyStatementURL'?: array,
467
     *   'Keywords'?: array,
468
     *   'Logo'?: array,
469
     *   'children'?: array,
470
     * }
471
     */
472
    public function toArray(): array
473
    {
474
        $displayName = [];
475
        foreach ($this->getDisplayName() as $child) {
476
            $displayName = array_merge($displayName, $child->toArray());
477
        }
478
479
        $description = [];
480
        foreach ($this->getDescription() as $child) {
481
            $description = array_merge($description, $child->toArray());
482
        }
483
484
        $infoUrl = [];
485
        foreach ($this->getInformationURL() as $child) {
486
            $infoUrl = array_merge($infoUrl, $child->toArray());
487
        }
488
489
        $privacyUrl = [];
490
        foreach ($this->getPrivacyStatementURL() as $child) {
491
            $privacyUrl = array_merge($privacyUrl, $child->toArray());
492
        }
493
494
        $keywords = [];
495
        foreach ($this->getKeywords() as $child) {
496
            $keywords = array_merge($keywords, $child->toArray());
497
        }
498
499
        $logo = [];
500
        foreach ($this->getLogo() as $child) {
501
            $logo[] = $child->toArray();
502
        }
503
504
        $children = $this->getElements();
505
506
        return [] +
507
            (empty($displayName) ? [] : ['DisplayName' => $displayName]) +
508
            (empty($description) ? [] : ['Description' => $description]) +
509
            (empty($infoUrl) ? [] : ['InformationURL' => $infoUrl]) +
510
            (empty($privacyUrl) ? [] : ['PrivacyStatementURL' => $privacyUrl]) +
511
            (empty($keywords) ? [] : ['Keywords' => $keywords]) +
512
            (empty($logo) ? [] : ['Logo' => $logo]) +
513
            (empty($children) ? [] : ['children' => $children]);
514
    }
515
}
516