Issues (33)

src/XML/Attribute.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XML;
6
7
use DOMAttr;
8
use DOMElement;
9
use SimpleSAML\XML\Assert\Assert;
10
use SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface;
11
use SimpleSAML\XMLSchema\Type\StringValue;
12
13
use function array_keys;
14
use function strval;
15
16
/**
17
 * Class to represent an arbitrary namespaced attribute.
18
 *
19
 * @package simplesamlphp/xml-common
20
 */
21
final class Attribute implements ArrayizableElementInterface
22
{
23
    /**
24
     * Create an Attribute class
25
     *
26
     * @param string|null $namespaceURI
27
     * @param string|null $namespacePrefix
28
     * @param string $attrName
29
     * @param \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface $attrValue
30
     */
31
    public function __construct(
32
        protected ?string $namespaceURI,
33
        protected ?string $namespacePrefix,
34
        protected string $attrName,
35
        protected ValueTypeInterface $attrValue,
36
    ) {
37
        Assert::nullOrValidAnyURI($namespaceURI);
38
        if ($namespaceURI !== null) {
39
            Assert::nullOrValidNCName($namespacePrefix);
40
        }
41
        Assert::validNCName($attrName);
42
    }
43
44
45
    /**
46
     * Collect the value of the namespaceURI-property
47
     *
48
     * @return string|null
49
     */
50
    public function getNamespaceURI(): ?string
51
    {
52
        return $this->namespaceURI;
53
    }
54
55
56
    /**
57
     * Collect the value of the namespacePrefix-property
58
     *
59
     * @return string|null
60
     */
61
    public function getNamespacePrefix(): ?string
62
    {
63
        return $this->namespacePrefix;
64
    }
65
66
67
    /**
68
     * Collect the value of the localName-property
69
     *
70
     * @return string
71
     */
72
    public function getAttrName(): string
73
    {
74
        return $this->attrName;
75
    }
76
77
78
    /**
79
     * Collect the value of the value-property
80
     *
81
     * @return \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface
82
     */
83
    public function getAttrValue(): ValueTypeInterface
84
    {
85
        return $this->attrValue;
86
    }
87
88
89
    /**
90
     * Create a class from XML
91
     *
92
     * @param \DOMAttr $attr
93
     * @return static
94
     */
95
    public static function fromXML(DOMAttr $attr): static
96
    {
97
        return new static($attr->namespaceURI, $attr->prefix, $attr->localName, StringValue::fromString($attr->value));
98
    }
99
100
101
102
    /**
103
     * Create XML from this class
104
     *
105
     * @param \DOMElement $parent
106
     * @return \DOMElement
107
     */
108
    public function toXML(DOMElement $parent): DOMElement
109
    {
110
        if ($this->getNamespaceURI() !== null && !$parent->lookupPrefix($this->getNamespacePrefix())) {
111
            $parent->setAttributeNS(
112
                'http://www.w3.org/2000/xmlns/',
113
                'xmlns:' . $this->getNamespacePrefix(),
114
                $this->getNamespaceURI(),
115
            );
116
        }
117
118
        $parent->setAttributeNS(
119
            $this->getNamespaceURI(),
120
            !in_array($this->getNamespacePrefix(), ['', null])
121
                ? ($this->getNamespacePrefix() . ':' . $this->getAttrName())
122
                : $this->getAttrName(),
123
            strval($this->getAttrValue()),
124
        );
125
126
        return $parent;
127
    }
128
129
130
    /**
131
     * Create a class from an array
132
     *
133
     * @param array{
134
     *   namespaceURI: string,
135
     *   namespacePrefix: string|null,
136
     *   attrName: string,
137
     *   attrValue:  \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface,
138
     * } $data
139
     * @return static
140
     */
141
    public static function fromArray(array $data): static
142
    {
143
        $data = self::processArrayContents($data);
144
145
        return new static(
146
            $data['namespaceURI'],
147
            $data['namespacePrefix'],
148
            $data['attrName'],
149
            StringValue::fromString($data['attrValue']),
150
        );
151
    }
152
153
154
    /**
155
     * Validates an array representation of this object and returns the same array with rationalized keys
156
     *
157
     * @param array{namespaceURI: string, namespacePrefix: string|null, attrName: string, attrValue: mixed} $data
158
     * @return array{namespaceURI: string, namespacePrefix: string|null, attrName: string, attrValue: mixed}
159
     */
160
    private static function processArrayContents(array $data): array
161
    {
162
        $data = array_change_key_case($data, CASE_LOWER);
163
164
        /** @var array{namespaceuri: string, namespaceprefix: string|null, attrname: string, attrvalue: mixed} $data */
165
        Assert::allOneOf(
166
            array_keys($data),
167
            ['namespaceuri', 'namespaceprefix', 'attrname', 'attrvalue'],
168
        );
169
170
        Assert::keyExists($data, 'namespaceuri');
171
        Assert::keyExists($data, 'namespaceprefix');
172
        Assert::keyExists($data, 'attrname');
173
        Assert::keyExists($data, 'attrvalue');
174
175
        Assert::nullOrValidAnyURI($data['namespaceuri']);
176
        Assert::nullOrValidNCName($data['namespaceprefix']);
177
        Assert::nullOrValidNCName($data['attrname']);
178
        Assert::string($data['attrvalue']);
179
180
        return [
181
            'namespaceURI' => $data['namespaceuri'],
182
            'namespacePrefix' => $data['namespaceprefix'],
183
            'attrName' => $data['attrname'],
184
            'attrValue' => $data['attrvalue'],
185
        ];
186
    }
187
188
189
    /**
190
     * Create an array from this class
191
     *
192
     * @return array{
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{ at position 2 could not be parsed: the token is null at position 2.
Loading history...
193
     *   attrName: string,
194
     *   attrValue: string,
195
     *   namespacePrefix: string,
196
     *   namespaceURI: null|string,
197
     * }
198
     */
199
    public function toArray(): array
200
    {
201
        return [
202
            'namespaceURI' => $this->getNamespaceURI(),
203
            'namespacePrefix' => $this->getNamespacePrefix(),
204
            'attrName' => $this->getAttrName(),
205
            'attrValue' => $this->getAttrValue()->getValue(),
206
        ];
207
    }
208
}
209