Passed
Pull Request — master (#55)
by Tim
01:52
created

Chunk   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 235
Duplicated Lines 0 %

Importance

Changes 13
Bugs 0 Features 0
Metric Value
wmc 19
eloc 43
c 13
b 0
f 0
dl 0
loc 235
rs 10

14 Methods

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

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

254
        $parent->/** @scrutinizer ignore-call */ 
255
                 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...
255
256
        return $doc->documentElement;
257
    }
258
}
259