Passed
Pull Request — master (#55)
by Tim
02:09
created

Chunk::getQualifiedName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 2
b 0
f 0
nc 2
nop 0
dl 0
loc 8
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XML;
6
7
use DOMElement;
8
use SimpleSAML\XML\Assert\Assert;
9
use SimpleSAML\XML\DOMDocumentFactory;
10
use SimpleSAML\XML\Exception\MissingAttributeException;
11
use SimpleSAML\XML\Exception\SchemaViolationException;
12
use SimpleSAML\XML\SerializableElementTrait;
13
use SimpleSAML\XML\Type\{StringValue, ValueTypeInterface};
14
15
/**
16
 * Serializable class used to hold an XML element.
17
 *
18
 * @package simplesamlphp/xml-common
19
 */
20
final class Chunk implements SerializableElementInterface
21
{
22
    use SerializableElementTrait;
23
24
25
    /**
26
     * The localName of the element.
27
     *
28
     * @var string
29
     */
30
    protected string $localName;
31
32
    /**
33
     * The namespaceURI of this element.
34
     *
35
     * @var string|null
36
     */
37
    protected ?string $namespaceURI;
38
39
    /**
40
     * The prefix of this element.
41
     *
42
     * @var string
43
     */
44
    protected string $prefix;
45
46
47
    /**
48
     * Create an XML Chunk from a copy of the given \DOMElement.
49
     *
50
     * @param \DOMElement $xml The element we should copy.
51
     */
52
    public function __construct(
53
        protected DOMElement $xml,
54
    ) {
55
        $this->setLocalName($xml->localName);
56
        $this->setNamespaceURI($xml->namespaceURI);
57
        $this->setPrefix($xml->prefix);
58
    }
59
60
61
    /**
62
     * Collect the value of the localName-property
63
     *
64
     * @return string
65
     */
66
    public function getLocalName(): string
67
    {
68
        return $this->localName;
69
    }
70
71
72
    /**
73
     * Set the value of the localName-property
74
     *
75
     * @param string $localName
76
     * @throws \SimpleSAML\Assert\AssertionFailedException if $localName is an empty string
77
     */
78
    public function setLocalName(string $localName): void
79
    {
80
        Assert::validNCName($localName, SchemaViolationException::class); // Covers the empty string
81
        $this->localName = $localName;
82
    }
83
84
85
    /**
86
     * Collect the value of the namespaceURI-property
87
     *
88
     * @return string|null
89
     */
90
    public function getNamespaceURI(): ?string
91
    {
92
        return $this->namespaceURI;
93
    }
94
95
96
    /**
97
     * Set the value of the namespaceURI-property
98
     *
99
     * @param string|null $namespaceURI
100
     */
101
    protected function setNamespaceURI(?string $namespaceURI = null): void
102
    {
103
        Assert::nullOrValidURI($namespaceURI, SchemaViolationException::class);
104
        $this->namespaceURI = $namespaceURI;
105
    }
106
107
108
    /**
109
     * Get this \DOMElement.
110
     *
111
     * @return \DOMElement This element.
112
     */
113
    public function getXML(): DOMElement
114
    {
115
        return $this->xml;
116
    }
117
118
119
    /**
120
     * Collect the value of the prefix-property
121
     *
122
     * @return string
123
     */
124
    public function getPrefix(): string
125
    {
126
        return $this->prefix;
127
    }
128
129
130
    /**
131
     * Set the value of the prefix-property
132
     *
133
     * @param string|null $prefix
134
     */
135
    protected function setPrefix(?string $prefix = null): void
136
    {
137
        $this->prefix = strval($prefix);
138
    }
139
140
141
    /**
142
     * Get the XML qualified name (prefix:name, or just name when not prefixed)
143
     *  of the element represented by this class.
144
     *
145
     * @return string
146
     */
147
    public function getQualifiedName(): string
148
    {
149
        $prefix = $this->getPrefix();
150
151
        if (empty($prefix)) {
152
            return $this->getLocalName();
153
        } else {
154
            return $prefix . ':' . $this->getLocalName();
155
        }
156
    }
157
158
159
    /**
160
     * Get the value of an attribute from a given element.
161
     *
162
     * @template T of \SimpleSAML\XML\Type\ValueTypeInterface
163
     * @param \DOMElement     $xml The element where we should search for the attribute.
164
     * @param string          $name The name of the attribute.
165
     * @param class-string<T> $type The type of the attribute value.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
166
     * @return T
167
     *
168
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the attribute is missing from the element
169
     */
170
    public static function getAttribute(
171
        DOMElement $xml,
172
        string $name,
173
        string $type = StringValue::class,
174
    ): ValueTypeInterface {
175
        Assert::isAOf($type, ValueTypeInterface::class);
176
177
        Assert::true(
178
            $xml->hasAttribute($name),
179
            'Missing \'' . $name . '\' attribute on ' . $xml->prefix . ':' . $xml->localName . '.',
180
            MissingAttributeException::class,
181
        );
182
183
        $value = $xml->getAttribute($name);
184
        return $type::fromString($value);
185
    }
186
187
188
    /**
189
     * Get the value of an attribute from a given element.
190
     *
191
     * @template T of \SimpleSAML\XML\Type\ValueTypeInterface
192
     * @param \DOMElement  $xml The element where we should search for the attribute.
193
     * @param string       $name The name of the attribute.
194
     * @param class-string<T> $type The type of the attribute value.
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
195
     * @param \SimpleSAML\XML\Type\ValueTypeInterface|null $default
196
     *   The default to return in case the attribute does not exist and it is optional.
197
     * @return ($default is \SimpleSAML\XML\Type\ValueTypeInterface ? T : T|null)
198
     */
199
    public static function getOptionalAttribute(
200
        DOMElement $xml,
201
        string $name,
202
        string $type = StringValue::class,
203
        ?ValueTypeInterface $default = null,
204
    ): ?ValueTypeInterface {
205
        if (!$xml->hasAttribute($name)) {
206
            return $default;
207
        }
208
209
        return self::getAttribute($xml, $name, $type);
210
    }
211
212
213
    /**
214
     * Test if an object, at the state it's in, would produce an empty XML-element
215
     *
216
     * @return bool
217
     */
218
    public function isEmptyElement(): bool
219
    {
220
        /** @var \DOMElement $xml */
221
        $xml = $this->getXML();
222
        return ($xml->childNodes->length === 0) && ($xml->attributes->count() === 0);
0 ignored issues
show
Bug introduced by
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

222
        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...
223
    }
224
225
226
    /**
227
     * @param \DOMElement $xml
228
     * @return static
229
     */
230
    public static function fromXML(DOMElement $xml): static
231
    {
232
        return new static($xml);
233
    }
234
235
236
    /**
237
     * Append this XML element to a different XML element.
238
     *
239
     * @param  \DOMElement|null $parent The element we should append this element to.
240
     * @return \DOMElement The new element.
241
     */
242
    public function toXML(?DOMElement $parent = null): DOMElement
243
    {
244
        if ($parent === null) {
245
            $doc = DOMDocumentFactory::create();
246
        } else {
247
            $doc = $parent->ownerDocument;
248
            Assert::notNull($doc);
249
        }
250
251
        if ($parent === null) {
252
            $parent = $doc;
253
        }
254
255
        $parent->appendChild($doc->importNode($this->getXML(), true));
0 ignored issues
show
Bug introduced by
The method appendChild() 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

255
        $parent->/** @scrutinizer ignore-call */ 
256
                 appendChild($doc->importNode($this->getXML(), true));

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...
256
257
        return $doc->documentElement;
258
    }
259
}
260