Passed
Pull Request — master (#374)
by Tim
11:54 queued 09:21
created

AbstractIndexedEndpointType::toXML()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 24
nop 1
dl 0
loc 28
rs 9.2222
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\SAML2\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\ArrayValidationException;
10
use SimpleSAML\SAML2\Type\SAMLAnyURIValue;
11
use SimpleSAML\XML\ArrayizableElementInterface;
12
use SimpleSAML\XML\Attribute as XMLAttribute;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\SerializableElementInterface;
15
use SimpleSAML\XML\Type\{BooleanValue, UnsignedShortValue};
16
17
use function array_filter;
18
use function array_key_exists;
19
use function array_keys;
20
21
/**
22
 * Class representing a SAML2 IndexedEndpointType.
23
 *
24
 * @package simplesamlphp/saml2
25
 */
26
abstract class AbstractIndexedEndpointType extends AbstractEndpointType implements ArrayizableElementInterface
27
{
28
    use IndexedElementTrait;
29
30
31
    /**
32
     * IndexedEndpointType constructor.
33
     *
34
     * Note: if you extend this class, the constructor must retain its signature. You cannot extend this class and
35
     * modify the signature of the constructor, unless you implement fromXML() yourself. This class provides
36
     * static methods to get its properties from a given \DOMElement for your convenience. Look at the implementation
37
     * of fromXML() to know how to use them.
38
     *
39
     * @param \SimpleSAML\XML\Type\UnsignedShortValue $index
40
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $binding
41
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $location
42
     * @param \SimpleSAML\XML\Type\BooleanValue|null $isDefault
43
     * @param \SimpleSAML\SAML2\Type\AnyURIValue|null $responseLocation
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\Type\AnyURIValue 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...
44
     * @param array $children
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
     */
47
    public function __construct(
48
        UnsignedShortValue $index,
49
        SAMLAnyURIValue $binding,
50
        SAMLAnyURIValue $location,
51
        ?BooleanValue $isDefault = null,
52
        ?SAMLAnyURIValue $responseLocation = null,
53
        array $children = [],
54
        array $attributes = [],
55
    ) {
56
        parent::__construct($binding, $location, $responseLocation, $children, $attributes);
57
58
        $this->setIndex($index);
59
        $this->setIsDefault($isDefault);
60
    }
61
62
63
    /**
64
     * Initialize an IndexedEndpointType.
65
     *
66
     * @param \DOMElement $xml The XML element we should load.
67
     * @return static
68
     *
69
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
70
     *   if the qualified name of the supplied element is wrong
71
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
72
     *   if the supplied element is missing any of the mandatory attributes
73
     */
74
    public static function fromXML(DOMElement $xml): static
75
    {
76
        $qualifiedName = static::getClassName(static::class);
77
        Assert::eq(
78
            $xml->localName,
79
            $qualifiedName,
80
            'Unexpected name for endpoint: ' . $xml->localName . '. Expected: ' . $qualifiedName . '.',
81
            InvalidDOMElementException::class,
82
        );
83
84
        return new static(
85
            self::getAttribute($xml, 'index', UnsignedShortValue::class),
86
            self::getAttribute($xml, 'Binding', SAMLAnyURIValue::class),
87
            self::getAttribute($xml, 'Location', SAMLAnyURIValue::class),
88
            self::getOptionalAttribute($xml, 'isDefault', BooleanValue::class, null),
89
            self::getOptionalAttribute($xml, 'ResponseLocation', SAMLAnyURIValue::class, null),
90
            self::getChildElementsFromXML($xml),
91
            self::getAttributesNSFromXML($xml),
92
        );
93
    }
94
95
96
    /**
97
     * Add this endpoint to an XML element.
98
     *
99
     * @param \DOMElement $parent The element we should append this endpoint to.
100
     * @return \DOMElement
101
     */
102
    public function toXML(?DOMElement $parent = null): DOMElement
103
    {
104
        $e = parent::instantiateParentElement($parent);
105
        $e->setAttribute('Binding', $this->getBinding()->getValue());
106
        $e->setAttribute('Location', $this->getLocation()->getValue());
107
108
        if ($this->getResponseLocation() !== null) {
109
            $e->setAttribute('ResponseLocation', $this->getResponseLocation()->getValue());
110
        }
111
112
        $e->setAttribute('index', $this->getIndex()->getValue());
113
114
        if ($this->getIsDefault() !== null) {
115
            $e->setAttribute('isDefault', $this->getIsDefault()->getValue());
116
        }
117
118
        foreach ($this->getAttributesNS() as $attr) {
119
            $attr->toXML($e);
120
        }
121
122
        /** @var \SimpleSAML\XML\SerializableElementInterface $child */
123
        foreach ($this->getElements() as $child) {
124
            if (!$child->isEmptyElement()) {
125
                $child->toXML($e);
126
            }
127
        }
128
129
        return $e;
130
    }
131
132
133
    /**
134
     * Create a class from an array
135
     *
136
     * @param array $data
137
     * @return static
138
     */
139
    public static function fromArray(array $data): static
140
    {
141
        $data = self::processArrayContents($data);
142
143
        return new static(
144
            UnsignedShortValue::fromInteger($data['index']),
145
            SAMLAnyURIValue::fromString($data['Binding']),
146
            SAMLAnyURIValue::fromString($data['Location']),
147
            $data['isDefault'] !== null ? BooleanValue::fromBoolean($data['isDefault']) : null,
148
            ($data['ResponseLocation'] ?? null) ? SAMLAnyURIValue::fromString($data['ResponseLocation']) : null,
149
            $data['children'] ?? [],
150
            $data['attributes'] ?? [],
151
        );
152
    }
153
154
155
    /**
156
     * Validates an array representation of this object and returns the same array with
157
     * rationalized keys (casing) and parsed sub-elements.
158
     *
159
     * @param array $data
160
     * @return array $data
161
     */
162
    private static function processArrayContents(array $data): array
163
    {
164
        $data = array_change_key_case($data, CASE_LOWER);
165
166
        // Make sure the array keys are known for this kind of object
167
        Assert::allOneOf(
168
            array_keys($data),
169
            ['index', 'binding', 'location', 'isdefault', 'responselocation', 'children', 'attributes'],
170
            ArrayValidationException::class,
171
        );
172
173
        // Make sure all the mandatory items exist
174
        Assert::keyExists($data, 'binding', ArrayValidationException::class);
175
        Assert::keyExists($data, 'location', ArrayValidationException::class);
176
        Assert::keyExists($data, 'index', ArrayValidationException::class);
177
178
        // Make sure the items have the correct data type
179
        Assert::integer($data['index'], ArrayValidationException::class);
180
        Assert::string($data['binding'], ArrayValidationException::class);
181
        Assert::string($data['location'], ArrayValidationException::class);
182
183
        $retval = [
184
            'Binding' => $data['binding'],
185
            'Location' => $data['location'],
186
            'index' => $data['index'],
187
        ];
188
189
        if (array_key_exists('isdefault', $data)) {
190
            Assert::boolean($data['isdefault'], ArrayValidationException::class);
191
            $retval['isDefault'] = $data['isdefault'];
192
        }
193
194
        if (array_key_exists('responselocation', $data)) {
195
            Assert::string($data['responselocation'], ArrayValidationException::class);
196
            $retval['ResponseLocation'] = $data['responselocation'];
197
        }
198
199
        if (array_key_exists('children', $data)) {
200
            Assert::isArray($data['children'], ArrayValidationException::class);
201
            Assert::allIsInstanceOf(
202
                $data['children'],
203
                SerializableElementInterface::class,
204
                ArrayValidationException::class,
205
            );
206
            $retval['children'] = $data['children'];
207
        }
208
209
        if (array_key_exists('attributes', $data)) {
210
            Assert::isArray($data['attributes'], ArrayValidationException::class);
211
            Assert::allIsArray($data['attributes'], ArrayValidationException::class);
212
            foreach ($data['attributes'] as $i => $attr) {
213
                $retval['attributes'][] = XMLAttribute::fromArray($attr);
214
            }
215
        }
216
217
        return $retval;
218
    }
219
220
221
    /**
222
     * Create an array from this class
223
     *
224
     * @return array
225
     */
226
    public function toArray(): array
227
    {
228
        $data = parent::toArray();
229
        $data['index'] = $this->getIndex()->toInteger();
230
        $data['isDefault'] = $this->getIsDefault()->toBoolean();
231
232
        return array_filter($data);
233
    }
234
}
235