Completed
Push — master ( 3444f2...316fc7 )
by Tim
15s queued 12s
created

AbstractElement::getClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
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 SimpleSAML\XML\Exception\SchemaViolationException;
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 AbstractElement extends AbstractSerializableElement
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
        $ncName = join('', array_slice(explode('\\', $class), -1));
143
        Assert::validNCName($ncName, SchemaViolationException::class);
144
        return $ncName;
145
    }
146
147
148
    /**
149
     * Get the XML qualified name (prefix:name) of the element represented by this class.
150
     *
151
     * @return string
152
     */
153
    public function getQualifiedName(): string
154
    {
155
        $qName = static::getNamespacePrefix() . ':' . static::getLocalName();
156
        Assert::validQName($qName, SchemaViolationException::class);
157
        return $qName;
158
    }
159
160
161
    /**
162
     * Extract localized names from the children of a given element.
163
     *
164
     * @param \DOMElement $parent The element we want to search.
165
     * @return static[] An array of objects of this class.
166
     */
167
    public static function getChildrenOfClass(DOMElement $parent): array
168
    {
169
        $ret = [];
170
        foreach ($parent->childNodes as $node) {
171
            if (
172
                $node->namespaceURI === static::getNamespaceURI()
173
                && $node->localName === static::getLocalName()
174
            ) {
175
                /** @psalm-var \DOMElement $node */
176
                $ret[] = static::fromXML($node);
177
            }
178
        }
179
        return $ret;
180
    }
181
182
183
    /**
184
     * Get the namespace for the element.
185
     *
186
     * @return string
187
     */
188
    public static function getNamespaceURI(): string
189
    {
190
        Assert::true(
191
            defined('static::NS'),
192
            self::getClassName(static::class)
193
            . '::NS constant must be defined and set to the namespace for the XML-class it represents.',
194
            RuntimeException::class,
195
        );
196
        Assert::validURI(static::NS, SchemaViolationException::class);
1 ignored issue
show
Bug introduced by
The constant SimpleSAML\XML\AbstractElement::NS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
197
        return static::NS;
198
    }
199
200
201
    /**
202
     * Get the namespace-prefix for the element.
203
     *
204
     * @return string
205
     */
206
    public static function getNamespacePrefix(): string
207
    {
208
        Assert::true(
209
            defined('static::NS_PREFIX'),
210
            self::getClassName(static::class)
211
            . '::NS_PREFIX constant must be defined and set to the namespace prefix for the XML-class it represents.',
212
            RuntimeException::class,
213
        );
214
        return static::NS_PREFIX;
1 ignored issue
show
Bug introduced by
The constant SimpleSAML\XML\AbstractElement::NS_PREFIX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
215
    }
216
217
218
    /**
219
     * Get the local name for the element.
220
     *
221
     * @return string
222
     */
223
    public static function getLocalName(): string
224
    {
225
        if (defined('static::LOCALNAME')) {
226
            $ncName = static::LOCALNAME;
1 ignored issue
show
Bug introduced by
The constant SimpleSAML\XML\AbstractElement::LOCALNAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
227
        } else {
228
            $ncName = self::getClassName(static::class);
229
        }
230
231
        Assert::validNCName($ncName, SchemaViolationException::class);
232
        return $ncName;
233
    }
234
235
236
    /**
237
     * Test if an object, at the state it's in, would produce an empty XML-element
238
     *
239
     * @return bool
240
     */
241
    public function isEmptyElement(): bool
242
    {
243
        return false;
244
    }
245
246
247
    /**
248
     * Create a class from an array
249
     *
250
     * @param array $data
251
     * @return self
252
     */
253
    public static function fromArray(/** @scrutinizer ignore-unused */array $data): object
254
    {
255
        throw new RuntimeException('Not implemented.');
256
    }
257
258
259
    /**
260
     * Create an array from this class
261
     *
262
     * @return array
263
     */
264
    public function toArray(): array
265
    {
266
        throw new RuntimeException('Not implemented');
267
    }
268
}
269