Passed
Push — master ( 0cd9de...ba1253 )
by Tim
02:15
created

AbstractXMLElement::isEmptyElement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XML;
6
7
use DOMElement;
8
use RuntimeException;
9
use SimpleSAML\XML\DOMDocumentFactory;
10
use SimpleSAML\XML\Exception\MissingAttributeException;
11
use Serializable;
12
use SimpleSAML\Assert\Assert;
13
14
use function array_slice;
15
use function defined;
16
use function explode;
17
use function in_array;
18
use function intval;
19
use function join;
20
21
/**
22
 * Abstract class to be implemented by all classes
23
 *
24
 * @package simplesamlphp/xml-common
25
 */
26
abstract class AbstractXMLElement extends AbstractSerializableXML
27
{
28
    /**
29
     * Create a document structure for this element
30
     *
31
     * @param \DOMElement|null $parent The element we should append to.
32
     * @return \DOMElement
33
     */
34
    public function instantiateParentElement(DOMElement $parent = null): DOMElement
35
    {
36
        $qualifiedName = $this->getQualifiedName();
37
        $namespace = static::getNamespaceURI();
38
39
        if ($parent === null) {
40
            $doc = DOMDocumentFactory::create();
41
            $e = $doc->createElementNS($namespace, $qualifiedName);
42
            $doc->appendChild($e);
43
        } else {
44
            $doc = $parent->ownerDocument;
45
            Assert::notNull($doc);
46
47
            /** @psalm-var \DOMDocument $doc */
48
            $e = $doc->createElementNS($namespace, $qualifiedName);
49
            $parent->appendChild($e);
50
        }
51
52
        return $e;
53
    }
54
55
56
    /**
57
     * Get the value of an attribute from a given element.
58
     *
59
     * @param \DOMElement $xml The element where we should search for the attribute.
60
     * @param string      $name The name of the attribute.
61
     * @param string|null $default The default to return in case the attribute does not exist and it is optional.
62
     * @return string|null
63
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is missing from the element
64
     */
65
    public static function getAttribute(DOMElement $xml, string $name, ?string $default = ''): ?string
66
    {
67
        if (!$xml->hasAttribute($name)) {
68
            Assert::nullOrStringNotEmpty(
69
                $default,
70
                'Missing \'' . $name . '\' attribute on ' . static::getNamespacePrefix() . ':'
71
                    . self::getLocalName() . '.',
72
                MissingAttributeException::class,
73
            );
74
75
            return $default;
76
        }
77
78
        return $xml->getAttribute($name);
79
    }
80
81
82
    /**
83
     * @param \DOMElement $xml The element where we should search for the attribute.
84
     * @param string      $name The name of the attribute.
85
     * @param string|null $default The default to return in case the attribute does not exist and it is optional.
86
     * @return bool|null
87
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not a boolean
88
     */
89
    public static function getBooleanAttribute(DOMElement $xml, string $name, ?string $default = ''): ?bool
90
    {
91
        $value = self::getAttribute($xml, $name, $default);
92
        if ($value === null) {
93
            return null;
94
        }
95
96
        Assert::oneOf(
97
            $value,
98
            ['0', '1', 'false', 'true'],
99
            'The \'' . $name . '\' attribute of ' . static::getNamespacePrefix() . ':' . self::getLocalName() .
100
            ' must be boolean.',
101
        );
102
103
        return in_array($value, ['1', 'true'], true);
104
    }
105
106
107
    /**
108
     * Get the integer value of an attribute from a given element.
109
     *
110
     * @param \DOMElement $xml The element where we should search for the attribute.
111
     * @param string      $name The name of the attribute.
112
     * @param string|null $default The default to return in case the attribute does not exist and it is optional.
113
     *
114
     * @return int|null
115
     * @throws \SimpleSAML\Assert\AssertionFailedException if the attribute is not an integer
116
     */
117
    public static function getIntegerAttribute(DOMElement $xml, string $name, ?string $default = ''): ?int
118
    {
119
        $value = self::getAttribute($xml, $name, $default);
120
        if ($value === null) {
121
            return null;
122
        }
123
124
        Assert::numeric(
125
            $value,
126
            'The \'' . $name . '\' attribute of ' . static::getNamespacePrefix() . ':' . self::getLocalName()
127
                . ' must be numerical.',
128
        );
129
130
        return intval($value);
131
    }
132
133
134
    /**
135
     * Static method that processes a fully namespaced class name and returns the name of the class from it.
136
     *
137
     * @param string $class
138
     * @return string
139
     */
140
    public static function getClassName(string $class): string
141
    {
142
        return join('', array_slice(explode('\\', $class), -1));
143
    }
144
145
146
    /**
147
     * Get the XML qualified name (prefix:name) of the element represented by this class.
148
     *
149
     * @return string
150
     */
151
    public function getQualifiedName(): string
152
    {
153
        return static::getNamespacePrefix() . ':' . static::getLocalName();
154
    }
155
156
157
    /**
158
     * Extract localized names from the children of a given element.
159
     *
160
     * @param \DOMElement $parent The element we want to search.
161
     * @return \SimpleSAML\XML\AbstractXMLElement[] An array of objects of this class.
162
     */
163
    public static function getChildrenOfClass(DOMElement $parent): array
164
    {
165
        $ret = [];
166
        foreach ($parent->childNodes as $node) {
167
            if (
168
                $node->namespaceURI === static::getNamespaceURI()
169
                && $node->localName === static::getLocalName()
170
            ) {
171
                /** @psalm-var \DOMElement $node */
172
                $ret[] = static::fromXML($node);
173
            }
174
        }
175
        return $ret;
176
    }
177
178
179
    /**
180
     * Get the namespace for the element.
181
     *
182
     * @return string
183
     */
184
    public static function getNamespaceURI(): string
185
    {
186
        Assert::true(
187
            defined('static::NS'),
188
            self::getClassName(static::class)
189
            . '::NS constant must be defined and set to the namespace for the XML-class it represents.',
190
            RuntimeException::class,
191
        );
192
        return static::NS;
0 ignored issues
show
Bug introduced by
The constant SimpleSAML\XML\AbstractXMLElement::NS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
193
    }
194
195
196
    /**
197
     * Get the namespace-prefix for the element.
198
     *
199
     * @return string
200
     */
201
    public static function getNamespacePrefix(): string
202
    {
203
        Assert::true(
204
            defined('static::NS_PREFIX'),
205
            self::getClassName(static::class)
206
            . '::NS_PREFIX constant must be defined and set to the namespace prefix for the XML-class it represents.',
207
            RuntimeException::class,
208
        );
209
        return static::NS_PREFIX;
0 ignored issues
show
Bug introduced by
The constant SimpleSAML\XML\AbstractXMLElement::NS_PREFIX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
210
    }
211
212
213
    /**
214
     * Get the local name for the element.
215
     *
216
     * @return string
217
     */
218
    public static function getLocalName(): string
219
    {
220
        if (defined('static::LOCALNAME')) {
221
            return static::LOCALNAME;
0 ignored issues
show
Bug introduced by
The constant SimpleSAML\XML\AbstractXMLElement::LOCALNAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
222
        }
223
224
        return self::getClassName(static::class);
225
    }
226
227
228
    /**
229
     * Test if an object, at the state it's in, would produce an empty XML-element
230
     *
231
     * @return bool
232
     */
233
    public function isEmptyElement(): bool
234
    {
235
        return false;
236
    }
237
238
239
    /**
240
     * Create a class from an array
241
     *
242
     * @param array $data
243
     * @return self
244
     */
245
    public static function fromArray(/** @scrutinizer ignore-unused */array $data): object
246
    {
247
        throw new RuntimeException('Not implemented.');
248
    }
249
250
251
    /**
252
     * Create an array from this class
253
     *
254
     * @return array
255
     */
256
    public function toArray(): array
257
    {
258
        throw new RuntimeException('Not implemented');
259
    }
260
}
261