Passed
Pull Request — master (#337)
by Tim
02:20
created

AbstractIndexedEndpointType::validateArray()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 22
nc 16
nop 1
dl 0
loc 38
rs 8.9457
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\md;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Constants as C;
10
use SimpleSAML\XML\ArrayizableElementInterface;
11
use SimpleSAML\XML\Attribute as XMLAttribute;
12
use SimpleSAML\XML\Chunk;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\SerializableElementInterface;
15
16
use function array_filter;
17
use function array_key_exists;
18
use function array_keys;
19
use function is_bool;
20
use function strval;
21
22
/**
23
 * Class representing a SAML2 IndexedEndpointType.
24
 *
25
 * @package simplesamlphp/saml2
26
 */
27
abstract class AbstractIndexedEndpointType extends AbstractEndpointType implements ArrayizableElementInterface
28
{
29
    use IndexedElementTrait;
30
31
32
    /**
33
     * IndexedEndpointType constructor.
34
     *
35
     * Note: if you extend this class, the constructor must retain its signature. You cannot extend this class and
36
     * modify the signature of the constructor, unless you implement fromXML() yourself. This class provides
37
     * static methods to get its properties from a given \DOMElement for your convenience. Look at the implementation
38
     * of fromXML() to know how to use them.
39
     *
40
     * @param int $index
41
     * @param string $binding
42
     * @param string $location
43
     * @param bool|null $isDefault
44
     * @param string|null $responseLocation
45
     * @param list<\SimpleSAML\XML\Attribute> $attributes
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\md\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
46
     * @param array $children
47
     */
48
    public function __construct(
49
        int $index,
50
        string $binding,
51
        string $location,
52
        ?bool $isDefault = null,
53
        ?string $responseLocation = null,
54
        array $attributes = [],
55
        array $children = [],
56
    ) {
57
        parent::__construct($binding, $location, $responseLocation, $attributes, $children);
58
59
        $this->setIndex($index);
60
        $this->setIsDefault($isDefault);
61
    }
62
63
64
    /**
65
     * Initialize an IndexedEndpointType.
66
     *
67
     * @param \DOMElement $xml The XML element we should load.
68
     * @return static
69
     *
70
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
71
     *   if the qualified name of the supplied element is wrong
72
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
73
     *   if the supplied element is missing any of the mandatory attributes
74
     */
75
    public static function fromXML(DOMElement $xml): static
76
    {
77
        $qualifiedName = static::getClassName(static::class);
78
        Assert::eq(
79
            $xml->localName,
80
            $qualifiedName,
81
            'Unexpected name for endpoint: ' . $xml->localName . '. Expected: ' . $qualifiedName . '.',
82
            InvalidDOMElementException::class,
83
        );
84
85
        $index = self::getIntegerAttribute($xml, 'index');
86
        $binding = self::getAttribute($xml, 'Binding');
87
        $location = self::getAttribute($xml, 'Location');
88
89
        $children = [];
90
        foreach ($xml->childNodes as $child) {
91
            if ($child->namespaceURI === C::NS_MD) {
92
                continue;
93
            } elseif (!($child instanceof DOMElement)) {
94
                continue;
95
            }
96
97
            $children[] = new Chunk($child);
98
        }
99
100
        return new static(
101
            $index,
102
            $binding,
103
            $location,
104
            self::getOptionalBooleanAttribute($xml, 'isDefault', null),
105
            self::getOptionalAttribute($xml, 'ResponseLocation', null),
106
            self::getAttributesNSFromXML($xml),
107
            $children,
108
        );
109
    }
110
111
112
    /**
113
     * Add this endpoint to an XML element.
114
     *
115
     * @param \DOMElement $parent The element we should append this endpoint to.
116
     * @return \DOMElement
117
     */
118
    public function toXML(DOMElement $parent = null): DOMElement
119
    {
120
        $e = parent::instantiateParentElement($parent);
121
122
        $e->setAttribute('Binding', $this->getBinding());
123
        $e->setAttribute('Location', $this->getLocation());
124
        if ($this->getResponseLocation() !== null) {
125
            $e->setAttribute('ResponseLocation', $this->getResponseLocation());
126
        }
127
128
        $e->setAttribute('index', strval($this->getIndex()));
129
130
        if (is_bool($this->getIsDefault())) {
131
            $e->setAttribute('isDefault', $this->getIsDefault() ? 'true' : 'false');
132
        }
133
134
        foreach ($this->getAttributesNS() as $attr) {
135
            $attr->toXML($e);
136
        }
137
138
        /** @var \SimpleSAML\XML\SerializableElementInterface $child */
139
        foreach ($this->getElements() as $child) {
140
            if (!$child->isEmptyElement()) {
141
                $child->toXML($e);
142
            }
143
        }
144
145
        return $e;
146
    }
147
148
149
    /**
150
     * Create a class from an array
151
     *
152
     * @param array $data
153
     * @return static
154
     */
155
    public static function fromArray(array $data): static
156
    {
157
        self::validateArray($data);
158
159
        $responseLocation = array_key_exists('ResponseLocation', $data) ? $data['ResponseLocation'] : null;
160
        $Extensions = array_key_exists('Extensions', $data) ? $data['Extensions'] : null;
161
162
        $attributes = [];
163
        if (array_key_exists('attributes', $data)) {
164
            foreach ($data['attributes'] as $attr) {
165
                $attributes[] = new XMLAttribute(
166
                    $attr['namespaceURI'],
167
                    $attr['namespacePrefix'],
168
                    $attr['attrName'],
169
                    $attr['attrValue'],
170
                );
171
            }
172
        }
173
174
        return new static(
175
            $data['index'],
176
            $data['Binding'],
177
            $data['Location'],
178
            array_key_exists('isDefault', $data) ? $data['isDefault'] : null,
179
            $responseLocation,
180
            $attributes,
181
            $Extensions,
0 ignored issues
show
Bug introduced by
It seems like $Extensions can also be of type null; however, parameter $children of SimpleSAML\SAML2\XML\md\...ointType::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

181
            /** @scrutinizer ignore-type */ $Extensions,
Loading history...
182
        );
183
    }
184
185
186
    /**
187
     * Validate an array
188
     *
189
     * @param array $data
190
     * @return void
191
     */
192
    public static function validateArray(array $data): void
193
    {
194
        // Make sure the array keys are known for this kind of object
195
        Assert::allOneOf(
196
            array_keys($data),
197
            ['index', 'Binding', 'Location', 'isDefault', 'ResponseLocation', 'attributes', 'Extensions'],
198
        );
199
200
        // Make sure all the mandatory items exist
201
        Assert::keyExists($data, 'Binding');
202
        Assert::keyExists($data, 'Location');
203
        Assert::keyExists($data, 'index');
204
205
        // Make sure the items have the correct data type
206
        Assert::integer($data['index']);
207
        Assert::range($data['index'], 0, 65535);
208
        Assert::string($data['Binding']);
209
        Assert::string($data['Location']);
210
211
        if (array_key_exists('isDefault', $data)) {
212
            Assert::boolean($data['isDefault']);
213
        }
214
215
        if (array_key_exists('ResponseLocation', $data)) {
216
            Assert::string($data['ResponseLocation']);
217
        }
218
219
        if (array_key_exists('attributes', $data)) {
220
            Assert::isArray($data['attributes']);
221
            Assert::allIsArray($data['attributes']);
222
            foreach ($data['attributes'] as $attr) {
223
                XMLAttribute::validateArray($attr);
224
            }
225
        }
226
227
        if (array_key_exists('Extensions', $data)) {
228
            Assert::isArray($data['Extensions']);
229
            Assert::allIsInstanceOf($data['Extensions'], SerializableElementInterface::class);
230
        }
231
    }
232
233
234
    /**
235
     * Create an array from this class
236
     *
237
     * @return array
238
     */
239
    public function toArray(): array
240
    {
241
        $data = parent::toArray();
242
        $data['index'] = $this->getIndex();
243
        $data['isDefault'] = $this->getIsDefault();
244
245
        return array_filter($data);
246
    }
247
}
248