Passed
Pull Request — master (#337)
by Tim
02:05
created

ContactPerson::fromArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 12
nc 2
nop 1
dl 0
loc 16
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\md;
6
7
use DOMDocument;
8
use DOMElement;
9
use Exception;
10
use SimpleSAML\Assert\Assert;
11
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
12
use SimpleSAML\SAML2\Utils\XPath;
13
use SimpleSAML\SAML2\XML\ExtendableElementTrait;
14
use SimpleSAML\XML\ArrayizableElementInterface;
15
use SimpleSAML\XML\Attribute as XMLAttribute;
16
use SimpleSAML\XML\Constants as C;
17
use SimpleSAML\XML\Exception\InvalidDOMElementException;
18
use SimpleSAML\XML\Exception\TooManyElementsException;
19
use SimpleSAML\XML\ExtendableAttributesTrait;
20
use SimpleSAML\XML\SerializableElementInterface;
21
use SimpleSAML\XML\Utils as XMLUtils;
22
23
use function array_filter;
24
use function array_change_key_case;
25
use function array_key_exists;
26
use function array_keys;
27
use function array_map;
28
use function array_pop;
29
use function count;
30
use function filter_var;
31
use function preg_replace;
32
use function var_export;
33
34
/**
35
 * Class representing SAML 2 ContactPerson.
36
 *
37
 * @package simplesamlphp/saml2
38
 */
39
final class ContactPerson extends AbstractMdElement implements ArrayizableElementInterface
40
{
41
    use ExtendableAttributesTrait;
1 ignored issue
show
introduced by
The trait SimpleSAML\XML\ExtendableAttributesTrait requires some properties which are not provided by SimpleSAML\SAML2\XML\md\ContactPerson: $localName, $nodeValue, $namespaceURI, $prefix, $attributes
Loading history...
42
    use ExtendableElementTrait;
43
44
    /** The namespace-attribute for the xs:anyAttribute element */
45
    public const XS_ANY_ATTR_NAMESPACE = C::XS_ANY_NS_OTHER;
46
47
48
    /**
49
     * The several different contact types as defined per specification
50
     */
51
    public const CONTACT_TYPES = [
52
        'technical',
53
        'support',
54
        'administrative',
55
        'billing',
56
        'other',
57
    ];
58
59
60
    /**
61
     * ContactPerson constructor.
62
     *
63
     * @param string $contactType
64
     * @param \SimpleSAML\SAML2\XML\md\Company|null $company
65
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null $givenName
66
     * @param \SimpleSAML\SAML2\XML\md\SurName|null $surName
67
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions
68
     * @param \SimpleSAML\SAML2\XML\md\EmailAddress[] $emailAddress
69
     * @param \SimpleSAML\SAML2\XML\md\TelephoneNumber[] $telephoneNumber
70
     * @param list<\SimpleSAML\XML\Attribute> $namespacedAttribute
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\md\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
71
     */
72
    public function __construct(
73
        protected string $contactType,
74
        protected ?Company $company = null,
75
        protected ?GivenName $givenName = null,
76
        protected ?SurName $surName = null,
77
        ?Extensions $extensions = null,
78
        protected array $emailAddress = [],
79
        protected array $telephoneNumber = [],
80
        array $namespacedAttribute = [],
81
    ) {
82
        Assert::oneOf($contactType, self::CONTACT_TYPES);
83
        Assert::allIsInstanceOf($emailAddress, EmailAddress::class);
84
        Assert::allIsInstanceOf($telephoneNumber, TelephoneNumber::class);
85
86
        $this->setExtensions($extensions);
87
        $this->setAttributesNS($namespacedAttribute);
88
    }
89
90
91
    /**
92
     * Collect the value of the contactType-property
93
     *
94
     * @return string
95
     */
96
    public function getContactType(): string
97
    {
98
        return $this->contactType;
99
    }
100
101
102
    /**
103
     * Collect the value of the Company-property
104
     *
105
     * @return \SimpleSAML\SAML2\XML\md\Company|null
106
     */
107
    public function getCompany(): ?Company
108
    {
109
        return $this->company;
110
    }
111
112
113
    /**
114
     * Collect the value of the GivenName-property
115
     *
116
     * @return \SimpleSAML\SAML2\XML\md\GivenName|null
117
     */
118
    public function getGivenName(): ?GivenName
119
    {
120
        return $this->givenName;
121
    }
122
123
124
    /**
125
     * Collect the value of the SurName-property
126
     *
127
     * @return \SimpleSAML\SAML2\XML\md\SurName|null
128
     */
129
    public function getSurName(): ?SurName
130
    {
131
        return $this->surName;
132
    }
133
134
135
    /**
136
     * Collect the value of the EmailAddress-property.
137
     *
138
     * @return \SimpleSAML\SAML2\XML\md\EmailAddress[]
139
     */
140
    public function getEmailAddress(): array
141
    {
142
        return $this->emailAddress;
143
    }
144
145
146
    /**
147
     * Collect the value of the TelephoneNumber property
148
     *
149
     * @return \SimpleSAML\SAML2\XML\md\TelephoneNumber[]
150
     */
151
    public function getTelephoneNumber(): array
152
    {
153
        return $this->telephoneNumber;
154
    }
155
156
157
    /**
158
     * Initialize a ContactPerson element.
159
     *
160
     * @param \DOMElement $xml The XML element we should load.
161
     * @return static
162
     *
163
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
164
     *   if the qualified name of the supplied element is wrong
165
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
166
     *   if the supplied element is missing one of the mandatory attributes
167
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException
168
     *   if too many child-elements of a type are specified
169
     */
170
    public static function fromXML(DOMElement $xml): static
171
    {
172
        Assert::same($xml->localName, 'ContactPerson', InvalidDOMElementException::class);
173
        Assert::same($xml->namespaceURI, ContactPerson::NS, InvalidDOMElementException::class);
174
175
        $contactType = self::getAttribute($xml, 'contactType');
176
177
        $company = Company::getChildrenOfClass($xml);
178
        Assert::maxCount($company, 1, 'More than one Company in md:ContactPerson');
179
180
        $givenName = GivenName::getChildrenOfClass($xml);
181
        Assert::maxCount($givenName, 1, 'More than one GivenName in md:ContactPerson');
182
183
        $surName = SurName::getChildrenOfClass($xml);
184
        Assert::maxCount($surName, 1, 'More than one SurName in md:ContactPerson');
185
186
        $email = EmailAddress::getChildrenOfClass($xml);
187
        $telephone = TelephoneNumber::getChildrenOfClass($xml);
188
189
        $extensions = Extensions::getChildrenOfClass($xml);
190
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
191
192
        return new static(
193
            $contactType,
194
            array_pop($company),
195
            array_pop($givenName),
196
            array_pop($surName),
197
            (count($extensions) === 1) ? $extensions[0] : null,
198
            $email,
199
            $telephone,
200
            self::getAttributesNSFromXML($xml),
201
        );
202
    }
203
204
205
    /**
206
     * Convert this ContactPerson to XML.
207
     *
208
     * @param \DOMElement|null $parent The element we should add this contact to.
209
     *
210
     * @return \DOMElement The new ContactPerson-element.
211
     */
212
    public function toXML(DOMElement $parent = null): DOMElement
213
    {
214
        $e = $this->instantiateParentElement($parent);
215
216
        $e->setAttribute('contactType', $this->getContactType());
217
218
        foreach ($this->getAttributesNS() as $attr) {
219
            $attr->toXML($e);
220
        }
221
222
        $this->getExtensions()?->toXML($e);
223
        $this->getCompany()?->toXML($e);
224
        $this->getGivenName()?->toXML($e);
225
        $this->getSurName()?->toXML($e);
226
227
        foreach ($this->getEmailAddress() as $mail) {
228
            $mail->toXML($e);
229
        }
230
231
        foreach ($this->getTelephoneNumber() as $telephone) {
232
            $telephone->toXML($e);
233
        }
234
235
        return $e;
236
    }
237
238
239
    /**
240
     * Create a class from an array
241
     *
242
     * @param array $data
243
     * @return static
244
     */
245
    public static function fromArray(array $data): static
246
    {
247
        $data = self::validateArray($data);
248
249
        $ContactType = $data['contactType'];
250
        $Extensions = array_key_exists('Extensions', $data) ? new Extensions($data['Extensions']) : null;
251
252
        return new static(
253
            $ContactType,
254
            $data['Company'],
255
            $data['GivenName'],
256
            $data['SurName'],
257
            $Extensions,
258
            $data['EmailAddress'],
259
            $data['TelephoneNumber'],
260
            $data['attributes'],
261
        );
262
    }
263
264
265
    /**
266
     * Validates an array representation of this object and returns the same array with
267
     * rationalized keys (casing) and parsed sub-elements.
268
     *
269
     * @param array $data
270
     * @return array $data
271
     */
272
    private static function validateArray(array $data): array
273
    {
274
        $data = array_change_key_case($data, CASE_LOWER);
275
276
        // Make sure the array keys are known for this kind of object
277
        Assert::allOneOf(
278
            array_keys($data),
279
            [
280
                'contacttype',
281
                'company',
282
                'givenname',
283
                'surname',
284
                'emailaddress',
285
                'telephonenumber',
286
                'extensions',
287
                'attributes',
288
            ],
289
        );
290
291
        Assert::keyExists($data, 'contacttype');
292
        Assert::string($data['contacttype']);
293
294
        $retval = ['contactType' => $data['contacttype']];
295
296
        if (array_key_exists('company', $data)) {
297
            Assert::string($data['company']);
298
            $retval['Company'] = new Company($data['company']);
299
        }
300
301
        if (array_key_exists('givenname', $data)) {
302
            Assert::string($data['givenname']);
303
            $retval['GivenName'] = new GivenName($data['givenname']);
304
        }
305
306
        if (array_key_exists('surname', $data)) {
307
            Assert::string($data['surname']);
308
            $retval['SurName'] = new SurName($data['surname']);
309
        }
310
311
        if (array_key_exists('emailaddress', $data)) {
312
            Assert::isArray($data['emailaddress']);
313
            Assert::allString($data['emailaddress']);
314
            foreach ($data['emailaddress'] as $email) {
315
                $retval['EmailAddress'][] = new EmailAddress($email);
316
            }
317
        }
318
319
        if (array_key_exists('telephonenumber', $data)) {
320
            Assert::isArray($data['telephonenumber']);
321
            Assert::allString($data['telephonenumber']);
322
            foreach ($data['telephonenumber'] as $telephone) {
323
                $retval['TelephoneNumber'][] = new TelephoneNumber($telephone);
324
            }
325
        }
326
327
        if (array_key_exists('extensions', $data)) {
328
            Assert::isArray($data['extensions']);
329
            Assert::allIsInstanceOf($data['extensions'], SerializableElementInterface::class);
330
            $retval['Extensions'] = $data['extensions'];
331
        }
332
333
        if (array_key_exists('attributes', $data)) {
334
            Assert::isArray($data['attributes']);
335
            Assert::allIsArray($data['attributes']);
336
            foreach ($data['attributes'] as $i => $attr) {
337
                $retval['attributes'][] = XMLAttribute::fromArray($attr);
338
            }
339
        }
340
341
        return $retval;
342
    }
343
344
345
    /**
346
     * Create an array from this class
347
     *
348
     * @return array
349
     */
350
    public function toArray(): array
351
    {
352
        $data = [
353
            'ContactType' => $this->getContactType(),
354
            'Company' => $this->getCompany()?->getContent(),
355
            'GivenName' => $this->getGivenName()?->getContent(),
356
            'SurName' => $this->getSurName()?->getContent(),
357
            'EmailAddress' => [],
358
            'TelephoneNumber' => [],
359
            'Extensions' => $this?->Extensions->getList(),
0 ignored issues
show
Bug introduced by
The method getList() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

359
            'Extensions' => $this?->Extensions->/** @scrutinizer ignore-call */ getList(),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getList() does not exist on SimpleSAML\XML\AbstractElement. It seems like you code against a sub-type of SimpleSAML\XML\AbstractElement such as SimpleSAML\SAML2\XML\md\Extensions or SimpleSAML\SAML2\XML\samlp\Extensions. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

359
            'Extensions' => $this?->Extensions->/** @scrutinizer ignore-call */ getList(),
Loading history...
360
            'attributes' => [],
361
        ];
362
363
        foreach ($this->getEmailAddress() as $mail) {
364
            $data['EmailAddress'] = array_merge($data['EmailAddress'], $mail->toArray());
365
        }
366
367
        foreach ($this->getTelephoneNumber() as $telephone) {
368
            $data['TelephoneNumber'] = array_merge($data['TelephoneNumber'], $telephone->toArray());
369
        }
370
371
        foreach ($this->getAttributesNS() as $attr) {
372
            $data['attributes'][] = $attr->toArray();
373
        }
374
375
        return array_filter($data);
376
    }
377
}
378