Passed
Push — master ( 66592a...152b2f )
by Tim
02:08
created

Logo::processArrayContents()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 35
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 21
nc 2
nop 1
dl 0
loc 35
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\mdui;
6
7
use DOMElement;
8
use InvalidArgumentException;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\Exception\ArrayValidationException;
11
use SimpleSAML\XML\ArrayizableElementInterface;
12
use SimpleSAML\XML\Exception\InvalidDOMElementException;
13
use SimpleSAML\XML\Exception\MissingAttributeException;
14
use SimpleSAML\XML\StringElementTrait;
15
16
use function filter_var;
17
use function strval;
18
use function substr;
19
use function trim;
20
21
/**
22
 * Class for handling the Logo metadata extensions for login and discovery user interface
23
 *
24
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
25
 * @package simplesamlphp/saml2
26
 */
27
final class Logo extends AbstractMduiElement implements ArrayizableElementInterface
28
{
29
    use StringElementTrait;
30
31
32
    /**
33
     * Initialize a Logo.
34
     *
35
     * @param string $url
36
     * @param int $height
37
     * @param int $width
38
     * @param string|null $lang
39
     */
40
    public function __construct(
41
        protected string $url,
42
        protected int $height,
43
        protected int $width,
44
        protected ?string $lang = null,
45
    ) {
46
        $this->setContent($url);
47
    }
48
49
50
    /**
51
     * Validate the content of the element.
52
     *
53
     * @param string $content  The value to go in the XML textContent
54
     * @throws \InvalidArgumentException on failure
55
     * @return void
56
     */
57
    protected function validateContent(string $content): void
58
    {
59
        // NOTE:  we override the validateContent from the trait to be able to be less restrictive
60
        // Assert::validURI($content, SchemaViolationException::class); // Covers the empty string
61
        if (!filter_var(trim($content), FILTER_VALIDATE_URL) && substr(trim($content), 0, 5) !== 'data:') {
62
            throw new InvalidArgumentException('mdui:Logo is not a valid URL.');
63
        }
64
    }
65
66
67
    /**
68
     * Collect the value of the lang-property
69
     *
70
     * @return string|null
71
     */
72
    public function getLanguage(): ?string
73
    {
74
        return $this->lang;
75
    }
76
77
78
    /**
79
     * Collect the value of the height-property
80
     *
81
     * @return int
82
     */
83
    public function getHeight(): int
84
    {
85
        return $this->height;
86
    }
87
88
89
    /**
90
     * Collect the value of the width-property
91
     *
92
     * @return int
93
     */
94
    public function getWidth(): int
95
    {
96
        return $this->width;
97
    }
98
99
100
    /**
101
     * Convert XML into a Logo
102
     *
103
     * @param \DOMElement $xml The XML element we should load
104
     * @return static
105
     *
106
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
107
     *   if the qualified name of the supplied element is wrong
108
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
109
     *   if the supplied element is missing one of the mandatory attributes
110
     */
111
    public static function fromXML(DOMElement $xml): static
112
    {
113
        Assert::same($xml->localName, 'Logo', InvalidDOMElementException::class);
114
        Assert::same($xml->namespaceURI, Logo::NS, InvalidDOMElementException::class);
115
        Assert::stringNotEmpty($xml->textContent, 'Missing url value for Logo.');
116
117
        $Url = $xml->textContent;
118
        $Width = self::getIntegerAttribute($xml, 'width');
119
        $Height = self::getIntegerAttribute($xml, 'height');
120
        $lang = self::getOptionalAttribute($xml, 'xml:lang', null);
121
122
        return new static($Url, $Height, $Width, $lang);
123
    }
124
125
126
    /**
127
     * Convert this Logo to XML.
128
     *
129
     * @param \DOMElement|null $parent The element we should append this Logo to.
130
     * @return \DOMElement
131
     */
132
    public function toXML(DOMElement $parent = null): DOMElement
133
    {
134
        /** @psalm-var \DOMDocument $e->ownerDocument */
135
        $e = $this->instantiateParentElement($parent);
136
        $e->textContent = $this->getContent();
137
        $e->setAttribute('height', strval($this->getHeight()));
138
        $e->setAttribute('width', strval($this->getWidth()));
139
140
        if ($this->getLanguage() !== null) {
141
            $e->setAttribute('xml:lang', $this->getLanguage());
142
        }
143
144
        return $e;
145
    }
146
147
148
    /**
149
     * Create a class from an array
150
     *
151
     * @param array $data
152
     * @return static
153
     */
154
    public static function fromArray(array $data): static
155
    {
156
        $data = self::processArrayContents($data);
157
158
        return new static($data['url'], $data['height'], $data['width'], $data['lang'] ?? null);
159
    }
160
161
162
    /**
163
     * Validates an array representation of this object and returns the same array with
164
     * rationalized keys (casing) and parsed sub-elements.
165
     *
166
     * @param array $data
167
     * @return array $data
168
     */
169
    private static function processArrayContents(array $data): array
170
    {
171
        $data = array_change_key_case($data, CASE_LOWER);
172
173
        // Make sure the array keys are known for this kind of object
174
        Assert::allOneOf(
175
            array_keys($data),
176
            [
177
                'url',
178
                'height',
179
                'width',
180
                'lang',
181
            ],
182
            ArrayValidationException::class,
183
        );
184
185
        Assert::keyExists($data, 'url', ArrayValidationException::class);
186
        Assert::keyExists($data, 'height', ArrayValidationException::class);
187
        Assert::keyExists($data, 'width', ArrayValidationException::class);
188
189
        Assert::integer($data['height'], ArrayValidationException::class);
190
        Assert::integer($data['width'], ArrayValidationException::class);
191
192
        $retval = [
193
            'url' => $data['url'],
194
            'height' => $data['height'],
195
            'width' => $data['width'],
196
        ];
197
198
        if (array_key_exists('lang', $data)) {
199
            Assert::string($data['lang'], ArrayValidationException::class);
200
            $retval['lang'] = $data['lang'];
201
        }
202
203
        return $retval;
204
    }
205
206
207
    /**
208
     * Create an array from this class
209
     *
210
     * @return array
211
     */
212
    public function toArray(): array
213
    {
214
        $lang = $this->getLanguage();
215
216
        return [
217
            'url' => $this->getContent(),
218
            'width' => $this->getWidth(),
219
            'height' => $this->getHeight(),
220
        ] + (isset($lang) ? ['lang' => $lang] : []);
221
    }
222
}
223