Issues (21)

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