Passed
Push — master ( 7cad03...ad42db )
by Tim
01:42
created

ExtendableElementTrait::setNamespace()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 15
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XML;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\XML\Constants;
10
11
/**
12
 * Trait grouping common functionality for elements implementing the xs:any element.
13
 *
14
 * @package simplesamlphp/xml-common
15
 */
16
trait ExtendableElementTrait
17
{
18
    /** @var \SimpleSAML\XML\XMLElementInterface[] */
19
    protected array $elements = [];
20
21
22
    /**
23
     * Set an array with all elements present.
24
     *
25
     * @param array \SimpleSAML\XML\XMLElementInterface[]
26
     */
27
    public function setElements(array $elements): void
28
    {
29
        Assert::allIsInstanceOf($elements, XMLElementInterface::class);
30
        $namespace = $this->getNamespace();
31
32
        // Validate namespace value
33
        Assert::true(is_array($namespace) || is_string($namespace));
34
        if (!is_array($namespace)) {
35
            // Must be one of the predefined values
36
            Assert::oneOf($namespace, Constants::XS_ANY_NS);
37
        } else {
38
            // Array must be non-empty and cannot contain ##any or ##other
39
            Assert::notEmpty($namespace);
40
            Assert::allNotSame($namespace, Constants::XS_ANY_NS_ANY);
41
            Assert::allNotSame($namespace, Constants::XS_ANY_NS_OTHER);
42
        }
43
44
        // Get namespaces for all elements
45
        $actual_namespaces = array_map(
46
            function($elt) {
47
                return $elt->getNamespaceURI();
48
            },
49
            $elements
50
        );
51
52
        if ($namespace === Constants::XS_ANY_NS_LOCAL) {
53
            // If ##local then all namespaces must be null
54
            Assert::allNull($actual_namespaces);
55
        } elseif (is_array($namespace)) {
56
            // Make a local copy of the property that we can edit
57
            $allowed_namespaces = $namespace;
58
59
            // Replace the ##targetedNamespace with the actual namespace
60
            if (($key = array_search(Constants::XS_ANY_NS_TARGET, $allowed_namespaces)) !== false) {
61
                $allowed_namespaces[$key] = static::NS;
1 ignored issue
show
Bug introduced by
The constant SimpleSAML\XML\ExtendableElementTrait::NS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
62
            }
63
64
            // Replace the ##local with null
65
            if (($key = array_search(Constants::XS_ANY_NS_LOCAL, $allowed_namespaces)) !== false) {
66
                $allowed_namespaces[$key] = null;
67
            }
68
69
            $diff = array_diff($actual_namespaces, $allowed_namespaces);
70
            Assert::isEmpty(
71
                $diff,
72
                sprintf(
73
                    'Elements from namespaces [ %s ] are not allowed inside a %s element.',
74
                    rtrim(implode(', ', $diff)),
75
                    static::NS
76
                )
77
            );
78
        } else {
79
            // All elements must be namespaced, ergo non-null
80
            Assert::allNotNull($actual_namespaces);
81
82
            if ($namespace === Constants::XS_ANY_NS_OTHER) {
83
                // Must be any namespace other than the parent element
84
                Assert::allNotSame($actual_namespaces, static::NS);
85
            } elseif ($namespace === Constants::XS_ANY_NS_TARGET) {
86
                // Must be the same namespace as the one of the parent element
87
                Assert::allSame($actual_namespaces, static::NS);
88
            }
89
        }
90
91
        $this->elements = $elements;
92
    }
93
94
95
    /**
96
     * Get an array with all elements present.
97
     *
98
     * @return \SimpleSAML\XML\XMLElementInterface[]
99
     */
100
    public function getElements(): array
101
    {
102
        return $this->elements;
103
    }
104
105
106
    /**
107
     * @return array|string
108
     */
109
    abstract public function getNamespace();
110
}
111