Passed
Push — master ( 91cc00...2493b9 )
by Tim
01:47
created

src/Chunk.php (1 issue)

Labels
Severity
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\Exception\MissingAttributeException;
10
use SimpleSAML\XML\Exception\SchemaViolationException;
11
use SimpleSAML\XML\SerializableElementTrait;
12
13
use function in_array;
14
use function intval;
15
16
/**
17
 * Serializable class used to hold an XML element.
18
 *
19
 * @package simplesamlphp/xml-common
20
 */
21
final class Chunk implements SerializableElementInterface
22
{
23
    use SerializableElementTrait;
24
25
26
    /**
27
     * The localName of the element.
28
     *
29
     * @var string
30
     */
31
    protected string $localName;
32
33
    /**
34
     * The namespaceURI of this element.
35
     *
36
     * @var string|null
37
     */
38
    protected ?string $namespaceURI;
39
40
    /**
41
     * The prefix of this element.
42
     *
43
     * @var string
44
     */
45
    protected string $prefix;
46
47
48
    /**
49
     * Create an XML Chunk from a copy of the given \DOMElement.
50
     *
51
     * @param \DOMElement $xml The element we should copy.
52
     */
53
    public function __construct(
54
        protected DOMElement $xml
55
    ) {
56
        $this->setLocalName($xml->localName);
57
        $this->setNamespaceURI($xml->namespaceURI);
58
        $this->setPrefix($xml->prefix);
59
    }
60
61
62
    /**
63
     * Collect the value of the localName-property
64
     *
65
     * @return string
66
     */
67
    public function getLocalName(): string
68
    {
69
        return $this->localName;
70
    }
71
72
73
    /**
74
     * Set the value of the localName-property
75
     *
76
     * @param string $localName
77
     * @throws \SimpleSAML\Assert\AssertionFailedException if $localName is an empty string
78
     */
79
    public function setLocalName(string $localName): void
80
    {
81
        Assert::validNCName($localName, SchemaViolationException::class); // Covers the empty string
82
        $this->localName = $localName;
83
    }
84
85
86
    /**
87
     * Collect the value of the namespaceURI-property
88
     *
89
     * @return string|null
90
     */
91
    public function getNamespaceURI(): ?string
92
    {
93
        return $this->namespaceURI;
94
    }
95
96
97
    /**
98
     * Set the value of the namespaceURI-property
99
     *
100
     * @param string|null $namespaceURI
101
     */
102
    protected function setNamespaceURI(string $namespaceURI = null): void
103
    {
104
        Assert::nullOrValidURI($namespaceURI, SchemaViolationException::class);
105
        $this->namespaceURI = $namespaceURI;
106
    }
107
108
109
    /**
110
     * Get this \DOMElement.
111
     *
112
     * @return \DOMElement This element.
113
     */
114
    public function getXML(): DOMElement
115
    {
116
        return $this->xml;
117
    }
118
119
120
    /**
121
     * Collect the value of the prefix-property
122
     *
123
     * @return string
124
     */
125
    public function getPrefix(): string
126
    {
127
        return $this->prefix;
128
    }
129
130
131
    /**
132
     * Set the value of the prefix-property
133
     *
134
     * @param string|null $prefix
135
     */
136
    protected function setPrefix(string $prefix = null): void
137
    {
138
        $this->prefix = strval($prefix);
139
    }
140
141
142
    /**
143
     * Get the XML qualified name (prefix:name, or just name when not prefixed)
144
     *  of the element represented by this class.
145
     *
146
     * @return string
147
     */
148
    public function getQualifiedName(): string
149
    {
150
        $prefix = $this->getPrefix();
151
152
        if (empty($prefix)) {
153
            return $this->getLocalName();
154
        } else {
155
            return $prefix . ':' . $this->getLocalName();
156
        }
157
    }
158
159
160
    /**
161
     * @param \DOMElement $xml The element where we should search for the attribute.
162
     * @param string      $name The name of the attribute.
163
     * @return string
164
     *
165
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the attribute is missing from the element
166
     */
167
    public static function getAttribute(DOMElement $xml, string $name): string
168
    {
169
        Assert::true(
170
            $xml->hasAttribute($name),
171
            'Missing \'' . $name . '\' attribute on ' . $xml->prefix . ':' . $xml->localName . '.',
172
            MissingAttributeException::class,
173
        );
174
175
        return $xml->getAttribute($name);
176
    }
177
178
179
    /**
180
     * @param \DOMElement $xml The element where we should search for the attribute.
181
     * @param string      $name The name of the attribute.
182
     * @param string|null $default The default to return in case the attribute does not exist and it is optional.
183
     * @psalm-return ($default is string ? string : null)
184
     */
185
    public static function getOptionalAttribute(DOMElement $xml, string $name, ?string $default = null): ?string
186
    {
187
        if (!$xml->hasAttribute($name)) {
188
            return $default;
189
        }
190
191
        return $xml->getAttribute($name);
192
    }
193
194
195
    /**
196
     * @param \DOMElement $xml The element where we should search for the attribute.
197
     * @param string      $name The name of the attribute.
198
     * @return bool
199
     *
200
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the attribute is missing from the element
201
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not a boolean
202
     */
203
    public static function getBooleanAttribute(DOMElement $xml, string $name): bool
204
    {
205
        $value = self::getAttribute($xml, $name);
206
207
        Assert::oneOf(
208
            $value,
209
            ['0', '1', 'false', 'true'],
210
            'The \'' . $name . '\' attribute of ' . $xml->prefix . ':' . $xml->localName . ' must be boolean.',
211
        );
212
213
        return in_array($value, ['1', 'true'], true);
214
    }
215
216
217
    /**
218
     * @param \DOMElement $xml The element where we should search for the attribute.
219
     * @param string      $name The name of the attribute.
220
     * @param bool|null   $default The default to return in case the attribute does not exist and it is optional.
221
     * @psalm-return ($default is bool ? bool : null)
222
     *
223
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not a boolean
224
     */
225
    public static function getOptionalBooleanAttribute(DOMElement $xml, string $name, ?bool $default = null): ?bool
226
    {
227
        if (!$xml->hasAttribute($name)) {
228
            return $default;
229
        }
230
231
        return self::getBooleanAttribute($xml, $name);
232
    }
233
234
235
    /**
236
     * Get the integer value of an attribute from a given element.
237
     *
238
     * @param \DOMElement $xml The element where we should search for the attribute.
239
     * @param string      $name The name of the attribute.
240
     * @return int
241
     *
242
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the attribute is missing from the element
243
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not an integer
244
     */
245
    public static function getIntegerAttribute(DOMElement $xml, string $name): int
246
    {
247
        $value = self::getAttribute($xml, $name);
248
249
        Assert::numeric(
250
            $value,
251
            'The \'' . $name . '\' attribute of ' . $xml->prefix . ':' . $xml->localName . ' must be numerical.',
252
        );
253
254
        return intval($value);
255
    }
256
257
258
    /**
259
     * Get the integer value of an attribute from a given element.
260
     *
261
     * @param \DOMElement $xml The element where we should search for the attribute.
262
     * @param string      $name The name of the attribute.
263
     * @param int|null    $default The default to return in case the attribute does not exist and it is optional.
264
     * @psalm-return ($default is int ? int : null)
265
     *
266
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not an integer
267
     */
268
    public static function getOptionalIntegerAttribute(DOMElement $xml, string $name, ?int $default = null): ?int
269
    {
270
        if (!$xml->hasAttribute($name)) {
271
            return $default;
272
        }
273
274
        return self::getIntegerAttribute($xml, $name);
275
    }
276
277
278
    /**
279
     * Test if an object, at the state it's in, would produce an empty XML-element
280
     *
281
     * @return bool
282
     */
283
    public function isEmptyElement(): bool
284
    {
285
        /** @var \DOMElement $xml */
286
        $xml = $this->getXML();
287
        return ($xml->childNodes->length === 0) && ($xml->attributes->count() === 0);
0 ignored issues
show
The method count() does not exist on null. ( Ignorable by Annotation )

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

287
        return ($xml->childNodes->length === 0) && ($xml->attributes->/** @scrutinizer ignore-call */ count() === 0);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
288
    }
289
290
291
    /**
292
     * @param \DOMElement $xml
293
     * @return static
294
     */
295
    public static function fromXML(DOMElement $xml): static
296
    {
297
        return new static($xml);
298
    }
299
300
301
    /**
302
     * Append this XML element to a different XML element.
303
     *
304
     * @param  \DOMElement|null $parent The element we should append this element to.
305
     * @return \DOMElement The new element.
306
     */
307
    public function toXML(DOMElement $parent = null): DOMElement
308
    {
309
        if ($parent === null) {
310
            $doc = DOMDocumentFactory::create();
311
        } else {
312
            $doc = $parent->ownerDocument;
313
            Assert::notNull($doc);
314
        }
315
316
        if ($parent === null) {
317
            $parent = $doc;
318
        }
319
320
        /**
321
         * @psalm-var \DOMDocument $parent
322
         * @psalm-var \DOMDocument $doc
323
         */
324
        $parent->appendChild($doc->importNode($this->getXML(), true));
325
326
        return $doc->documentElement;
327
    }
328
}
329