Passed
Push — master ( d3e6a5...90893b )
by Tim
02:27
created

ContactPerson::fromXML()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 31
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 22
nc 1
nop 1
dl 0
loc 31
rs 9.568
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\md;
6
7
use DOMElement;
8
use Exception;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\SAML2\Utils\XPath;
12
use SimpleSAML\SAML2\XML\ExtendableElementTrait;
13
use SimpleSAML\XML\DOMDocumentFactory;
14
use SimpleSAML\XML\Exception\InvalidDOMElementException;
15
use SimpleSAML\XML\Exception\TooManyElementsException;
16
use SimpleSAML\XML\ExtendableAttributesTrait;
17
use SimpleSAML\XML\Utils as XMLUtils;
18
19
use function array_map;
20
use function array_pop;
21
use function count;
22
use function filter_var;
23
use function preg_replace;
24
use function var_export;
25
26
/**
27
 * Class representing SAML 2 ContactPerson.
28
 *
29
 * @package simplesamlphp/saml2
30
 */
31
final class ContactPerson extends AbstractMdElement
32
{
33
    use ExtendableElementTrait;
34
    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: $namespaceURI, $nodeName, $attributes, $value
Loading history...
35
36
    /**
37
     * The several different contact types as defined per specification
38
     */
39
    public const CONTACT_TYPES = [
40
        'technical',
41
        'support',
42
        'administrative',
43
        'billing',
44
        'other',
45
    ];
46
47
    /**
48
     * The contact type.
49
     *
50
     * @var string
51
     */
52
    protected string $contactType;
53
54
    /**
55
     * The Company of this contact.
56
     *
57
     * @var \SimpleSAML\SAML2\XML\md\Company|null
58
     */
59
    protected ?Company $Company = null;
60
61
    /**
62
     * The GivenName of this contact.
63
     *
64
     * @var \SimpleSAML\SAML2\XML\md\GivenName|null
65
     */
66
    protected ?GivenName $GivenName = null;
67
68
    /**
69
     * The SurName of this contact.
70
     *
71
     * @var \SimpleSAML\SAML2\XML\md\SurName|null
72
     */
73
    protected ?SurName $SurName = null;
74
75
    /**
76
     * The EmailAddresses of this contact.
77
     *
78
     * @var \SimpleSAML\SAML2\XML\md\EmailAddress[]
79
     */
80
    protected array $EmailAddresses = [];
81
82
    /**
83
     * The TelephoneNumbers of this contact.
84
     *
85
     * @var \SimpleSAML\SAML2\XML\md\TelephoneNumber[]
86
     */
87
    protected array $TelephoneNumbers = [];
88
89
90
    /**
91
     * ContactPerson constructor.
92
     *
93
     * @param string                                      $contactType
94
     * @param \SimpleSAML\SAML2\XML\md\Company|null       $company
95
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null     $givenName
96
     * @param \SimpleSAML\SAML2\XML\md\SurName|null       $surName
97
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null    $extensions
98
     * @param \SimpleSAML\SAML2\XML\md\EmailAddress[]     $email
99
     * @param \SimpleSAML\SAML2\XML\md\TelephoneNumber[]  $telephone
100
     * @param \DOMAttr[]                                  $namespacedAttributes
101
     */
102
    public function __construct(
103
        string $contactType,
104
        ?Company $company = null,
105
        ?GivenName $givenName = null,
106
        ?SurName $surName = null,
107
        ?Extensions $extensions = null,
108
        array $email = [],
109
        array $telephone = [],
110
        array $namespacedAttributes = []
111
    ) {
112
        $this->setContactType($contactType);
113
        $this->setCompany($company);
114
        $this->setGivenName($givenName);
115
        $this->setSurName($surName);
116
        $this->setEmailAddresses($email);
117
        $this->setTelephoneNumbers($telephone);
118
        $this->setExtensions($extensions);
119
        $this->setAttributesNS($namespacedAttributes);
120
    }
121
122
123
    /**
124
     * Collect the value of the contactType-property
125
     *
126
     * @return string
127
     */
128
    public function getContactType(): string
129
    {
130
        return $this->contactType;
131
    }
132
133
134
    /**
135
     * Set the value of the contactType-property
136
     *
137
     * @param string $contactType
138
     * @throws \SimpleSAML\Assert\AssertionFailedException if $contactType is not one of the predefined values
139
     */
140
    protected function setContactType(string $contactType): void
141
    {
142
        Assert::oneOf($contactType, self::CONTACT_TYPES);
143
        $this->contactType = $contactType;
144
    }
145
146
147
    /**
148
     * Collect the value of the Company-property
149
     *
150
     * @return \SimpleSAML\SAML2\XML\md\Company|null
151
     */
152
    public function getCompany(): ?Company
153
    {
154
        return $this->Company;
155
    }
156
157
158
    /**
159
     * Set the value of the Company-property
160
     *
161
     * @param \SimpleSAML\SAML2\XML\md\Company|null $company
162
     */
163
    protected function setCompany(?Company $company): void
164
    {
165
        $this->Company = $company;
166
    }
167
168
169
    /**
170
     * Collect the value of the GivenName-property
171
     *
172
     * @return \SimpleSAML\SAML2\XML\md\GivenName|null
173
     */
174
    public function getGivenName(): ?GivenName
175
    {
176
        return $this->GivenName;
177
    }
178
179
180
    /**
181
     * Set the value of the GivenName-property
182
     *
183
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null $givenName
184
     */
185
    protected function setGivenName(?GivenName $givenName): void
186
    {
187
        $this->GivenName = $givenName;
188
    }
189
190
191
    /**
192
     * Collect the value of the SurName-property
193
     *
194
     * @return \SimpleSAML\SAML2\XML\md\SurName|null
195
     */
196
    public function getSurName(): ?SurName
197
    {
198
        return $this->SurName;
199
    }
200
201
202
    /**
203
     * Set the value of the SurName-property
204
     *
205
     * @param \SimpleSAML\SAML2\XML\md\SurName|null $surName
206
     */
207
    protected function setSurName(?SurName $surName): void
208
    {
209
        $this->SurName = $surName;
210
    }
211
212
213
    /**
214
     * Collect the value of the EmailAddress-property.
215
     *
216
     * @return \SimpleSAML\SAML2\XML\md\EmailAddress[]
217
     */
218
    public function getEmailAddresses(): array
219
    {
220
        return $this->EmailAddresses;
221
    }
222
223
224
    /**
225
     * Set the value of the EmailAddress-property
226
     *
227
     * @param \SimpleSAML\SAML2\XML\md\EmailAddress[] $emailAddresses
228
     * @throws \SimpleSAML\Assert\AssertionFailedException
229
     */
230
    protected function setEmailAddresses(array $emailAddresses): void
231
    {
232
        Assert::allIsInstanceOf($emailAddresses, EmailAddress::class);
233
        $this->EmailAddresses = $emailAddresses;
234
    }
235
236
237
    /**
238
     * Collect the value of the TelephoneNumber property
239
     *
240
     * @return \SimpleSAML\SAML2\XML\md\TelephoneNumber[]
241
     */
242
    public function getTelephoneNumbers(): array
243
    {
244
        return $this->TelephoneNumbers;
245
    }
246
247
248
    /**
249
     * Set the value of the TelephoneNumber property
250
     *
251
     * @param \SimpleSAML\SAML2\XML\md\TelephoneNumber[] $telephoneNumbers
252
     * @throws \SimpleSAML\Assert\AssertionFailedException
253
     */
254
    protected function setTelephoneNumbers(array $telephoneNumbers): void
255
    {
256
        Assert::allIsInstanceOf($telephoneNumbers, TelephoneNumber::class);
257
        $this->TelephoneNumbers = $telephoneNumbers;
258
    }
259
260
261
    /**
262
     * Initialize a ContactPerson element.
263
     *
264
     * @param \DOMElement $xml The XML element we should load.
265
     * @return self
266
     *
267
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
268
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
269
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
270
     */
271
    public static function fromXML(DOMElement $xml): static
272
    {
273
        Assert::same($xml->localName, 'ContactPerson', InvalidDOMElementException::class);
274
        Assert::same($xml->namespaceURI, ContactPerson::NS, InvalidDOMElementException::class);
275
276
        $contactType = self::getAttribute($xml, 'contactType');
277
278
        $company = Company::getChildrenOfClass($xml);
279
        Assert::maxCount($company, 1, 'More than one Company in md:ContactPerson');
280
281
        $givenName = GivenName::getChildrenOfClass($xml);
282
        Assert::maxCount($givenName, 1, 'More than one GivenName in md:ContactPerson');
283
284
        $surName = SurName::getChildrenOfClass($xml);
285
        Assert::maxCount($surName, 1, 'More than one SurName in md:ContactPerson');
286
287
        $email = EmailAddress::getChildrenOfClass($xml);
288
        $telephone = TelephoneNumber::getChildrenOfClass($xml);
289
290
        $extensions = Extensions::getChildrenOfClass($xml);
291
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
292
293
        return new static(
294
            $contactType,
295
            array_pop($company),
296
            array_pop($givenName),
297
            array_pop($surName),
298
            (count($extensions) === 1) ? $extensions[0] : null,
299
            $email,
300
            $telephone,
301
            self::getAttributesNSFromXML($xml)
302
        );
303
    }
304
305
306
    /**
307
     * Convert this ContactPerson to XML.
308
     *
309
     * @param \DOMElement|null $parent The element we should add this contact to.
310
     *
311
     * @return \DOMElement The new ContactPerson-element.
312
     */
313
    public function toXML(DOMElement $parent = null): DOMElement
314
    {
315
        $e = $this->instantiateParentElement($parent);
316
317
        $e->setAttribute('contactType', $this->getContactType());
318
319
        foreach ($this->getAttributesNS() as $attr) {
320
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
321
        }
322
323
        $this->getExtensions()?->toXML($e);
324
        $this->getCompany()?->toXML($e);
325
        $this->getGivenName()?->toXML($e);
326
        $this->getSurName()?->toXML($e);
327
328
        foreach ($this->getEmailAddresses() as $mail) {
329
            $mail->toXML($e);
330
        }
331
332
        foreach ($this->getTelephoneNumbers() as $telephone) {
333
            $telephone->toXML($e);
334
        }
335
336
        return $e;
337
    }
338
339
340
    /**
341
     * Create a class from an array
342
     *
343
     * @param array $data
344
     * @return self
345
     */
346
    public static function fromArray(array $data): static
347
    {
348
        Assert::keyExists($data, 'ContactType');
349
350
        $ContactType = $data['ContactType'];
351
        $Company = isset($data['Company']) ? new Company($data['Company']) : null;
352
        $GivenName = isset($data['GivenName']) ? new GivenName($data['GivenName']) : null;
353
        $SurName = isset($data['SurName']) ? new SurName($data['SurName']) : null;
354
        $Extensions = $data['Extensions'] ?? null;
355
356
        $EmailAddresses = [];
357
        foreach ($data['EmailAddresses'] as $mail) {
358
            $EmailAddresses[] = new EmailAddress($mail);
359
        }
360
361
        $TelephoneNumbers = [];
362
        foreach ($data['TelephoneNumbers'] as $telephone) {
363
            $TelephoneNumbers[] = new TelephoneNumber($telephone);
364
        }
365
366
        // Anything after this should be (namespaced) attributes
367
        unset(
368
            $data['ContactType'],
369
            $data['Company'],
370
            $data['GivenName'],
371
            $data['SurName'],
372
            $data['Extensions'],
373
            $data['EmailAddresses'],
374
            $data['TelephoneNumbers']
375
        );
376
377
        $attributes = [];
378
        foreach ($data as $ns => $attribute) {
379
            $name = array_key_first($attribute);
380
            $value = $attribute[$name];
381
382
            $doc = DOMDocumentFactory::create();
383
            $elt = $doc->createElement("placeholder");
384
            $elt->setAttributeNS($ns, $name, $value);
385
386
            $attributes[] = $elt->getAttributeNode($name);
387
        }
388
389
        return new static(
390
            $ContactType,
391
            $Company,
392
            $GivenName,
393
            $SurName,
394
            $Extensions,
395
            $EmailAddresses,
396
            $TelephoneNumbers,
397
            $attributes
398
        );
399
    }
400
401
402
    /**
403
     * Create an array from this class
404
     *
405
     * @return array
406
     */
407
    public function toArray(): array
408
    {
409
        $data = [
410
            'ContactType' => $this->contactType,
411
            'Company' => $this->Company->getContent(),
0 ignored issues
show
Bug introduced by
The method getContent() 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

411
            'Company' => $this->Company->/** @scrutinizer ignore-call */ getContent(),

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...
412
            'GivenName' => $this->GivenName->getContent(),
0 ignored issues
show
Bug introduced by
The method getContent() 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

412
            'GivenName' => $this->GivenName->/** @scrutinizer ignore-call */ getContent(),

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...
413
            'SurName' => $this->SurName->getContent(),
0 ignored issues
show
Bug introduced by
The method getContent() 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

413
            'SurName' => $this->SurName->/** @scrutinizer ignore-call */ getContent(),

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...
414
            'EmailAddresses' => $this->EmailAddresses,
415
            'TelephoneNumbers' => $this->TelephoneNumbers,
416
            'EmailAddresses' => [],
417
            'TelephoneNumbers' => [],
418
            'Extensions' => $this->Extensions,
419
        ];
420
421
        foreach ($this->EmailAddresses as $mail) {
422
            $data['EmailAddresses'] = array_merge($data['EmailAddresses'], $mail->toArray());
423
        }
424
425
        foreach ($this->TelephoneNumbers as $telephone) {
426
            $data['TelephoneNumbers'] = array_merge($data['TelephoneNumbers'], $telephone->toArray());
427
        }
428
429
        foreach ($this->getAttributesNS() as $a) {
430
            $data[$a['namespaceURI']] = [$a['qualifiedName'] => $a['value']];
431
        }
432
433
        return $data;
434
    }
435
}
436