Completed
Push — master ( ed1e7e...e83944 )
by Tim
16s queued 13s
created

ExtendableElementTrait::getElements()   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
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XML;
6
7
use DOMElement;
8
use RuntimeException;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\XML\Chunk;
11
use SimpleSAML\XML\Constants as C;
12
13
use function array_diff;
14
use function array_map;
15
use function array_search;
16
use function defined;
17
use function implode;
18
use function is_array;
19
use function rtrim;
20
use function sprintf;
21
22
/**
23
 * Trait grouping common functionality for elements implementing the xs:any element.
24
 *
25
 * @package simplesamlphp/xml-common
26
 */
27
trait ExtendableElementTrait
28
{
29
    /** @var \SimpleSAML\XML\ElementInterface[] */
30
    protected array $elements = [];
31
32
33
    /**
34
     * Set an array with all elements present.
35
     *
36
     * @param \SimpleSAML\XML\ElementInterface[] $elements
37
     * @return void
38
     */
39
    protected function setElements(array $elements): void
40
    {
41
        Assert::allIsInstanceOf($elements, ElementInterface::class);
42
        $namespace = $this->getElementNamespace();
43
44
        // Validate namespace value
45
        if (!is_array($namespace)) {
46
            // Must be one of the predefined values
47
            Assert::oneOf($namespace, C::XS_ANY_NS);
48
        } else {
49
            // Array must be non-empty and cannot contain ##any or ##other
50
            Assert::notEmpty($namespace);
51
            Assert::allNotSame($namespace, C::XS_ANY_NS_ANY);
52
            Assert::allNotSame($namespace, C::XS_ANY_NS_OTHER);
53
        }
54
55
        // Get namespaces for all elements
56
        $actual_namespaces = array_map(
57
            /**
58
             * @param \SimpleSAML\XML\ElementInterface $elt
59
             * @return string|null
60
             */
61
            function (ElementInterface $elt) {
62
                /** @psalm-var \SimpleSAML\XML\Chunk|\SimpleSAML\XML\AbstractElement $elt */
63
                return ($elt instanceof Chunk) ? $elt->getNamespaceURI() : $elt::getNamespaceURI();
0 ignored issues
show
Bug introduced by
The method getNamespaceURI() does not exist on SimpleSAML\XML\ElementInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to SimpleSAML\XML\ElementInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

63
                return ($elt instanceof Chunk) ? $elt->getNamespaceURI() : $elt::/** @scrutinizer ignore-call */ getNamespaceURI();
Loading history...
64
            },
65
            $elements
66
        );
67
68
        if ($namespace === C::XS_ANY_NS_LOCAL) {
69
            // If ##local then all namespaces must be null
70
            Assert::allNull($actual_namespaces);
71
        } elseif (is_array($namespace)) {
72
            // Make a local copy of the property that we can edit
73
            $allowed_namespaces = $namespace;
74
75
            // Replace the ##targetedNamespace with the actual namespace
76
            if (($key = array_search(C::XS_ANY_NS_TARGET, $allowed_namespaces)) !== false) {
77
                $allowed_namespaces[$key] = static::NS;
78
            }
79
80
            // Replace the ##local with null
81
            if (($key = array_search(C::XS_ANY_NS_LOCAL, $allowed_namespaces)) !== false) {
82
                $allowed_namespaces[$key] = null;
83
            }
84
85
            $diff = array_diff($actual_namespaces, $allowed_namespaces);
86
            Assert::isEmpty(
87
                $diff,
88
                sprintf(
89
                    'Elements from namespaces [ %s ] are not allowed inside a %s element.',
90
                    rtrim(implode(', ', $diff)),
91
                    static::NS,
92
                ),
93
            );
94
        } else {
95
            // All elements must be namespaced, ergo non-null
96
            Assert::allNotNull($actual_namespaces);
97
98
            if ($namespace === C::XS_ANY_NS_OTHER) {
99
                // Must be any namespace other than the parent element
100
                Assert::allNotSame($actual_namespaces, static::NS);
101
            } elseif ($namespace === C::XS_ANY_NS_TARGET) {
102
                // Must be the same namespace as the one of the parent element
103
                Assert::allSame($actual_namespaces, static::NS);
104
            }
105
        }
106
107
        $this->elements = $elements;
108
    }
109
110
111
    /**
112
     * Get an array with all elements present.
113
     *
114
     * @return \SimpleSAML\XML\ElementInterface[]
115
     */
116
    public function getElements(): array
117
    {
118
        return $this->elements;
119
    }
120
121
122
    /**
123
     * @return array|string
124
     */
125
    public function getElementNamespace(): array|string
126
    {
127
        Assert::true(
128
            defined('static::XS_ANY_ELT_NAMESPACE'),
129
            self::getClassName(static::class)
130
            . '::XS_ANY_ELT_NAMESPACE constant must be defined and set to the namespace for the xs:any element.',
131
            RuntimeException::class,
132
        );
133
134
        return static::XS_ANY_ELT_NAMESPACE;
1 ignored issue
show
Bug introduced by
The constant SimpleSAML\XML\Extendabl...t::XS_ANY_ELT_NAMESPACE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
135
    }
136
}
137