Passed
Pull Request — master (#276)
by Tim
08:48 queued 06:08
created

ContactPerson::validateEmailAddress()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 10
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 InvalidArgumentException;
10
use SimpleSAML\Assert\Assert;
11
use SimpleSAML\SAML2\Constants;
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
/**
20
 * Class representing SAML 2 ContactPerson.
21
 *
22
 * @package simplesamlphp/saml2
23
 */
24
final class ContactPerson extends AbstractMdElement
25
{
26
    use ExtendableElementTrait;
27
    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...
28
29
    /**
30
     * The contact type.
31
     *
32
     * @var string
33
     */
34
    protected string $contactType;
35
36
    /**
37
     * The Company of this contact.
38
     *
39
     * @var \SimpleSAML\SAML2\XML\md\Company|null
40
     */
41
    protected ?Company $Company = null;
42
43
    /**
44
     * The GivenName of this contact.
45
     *
46
     * @var \SimpleSAML\SAML2\XML\md\GivenName|null
47
     */
48
    protected ?GivenName $GivenName = null;
49
50
    /**
51
     * The SurName of this contact.
52
     *
53
     * @var \SimpleSAML\SAML2\XML\md\SurName|null
54
     */
55
    protected ?SurName $SurName = null;
56
57
    /**
58
     * The EmailAddresses of this contact.
59
     *
60
     * @var \SimpleSAML\SAML2\XML\md\EmailAddress[]
61
     */
62
    protected array $EmailAddresses = [];
63
64
    /**
65
     * The TelephoneNumbers of this contact.
66
     *
67
     * @var \SimpleSAML\SAML2\XML\md\TelephoneNumber[]
68
     */
69
    protected array $TelephoneNumbers = [];
70
71
72
    /**
73
     * ContactPerson constructor.
74
     *
75
     * @param string                                      $contactType
76
     * @param \SimpleSAML\SAML2\XML\md\Company|null       $company
77
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null     $givenName
78
     * @param \SimpleSAML\SAML2\XML\md\SurName|null       $surName
79
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null    $extensions
80
     * @param \SimpleSAML\SAML2\XML\md\EmailAddress[]     $email
81
     * @param \SimpleSAML\SAML2\XML\md\TelephoneNumber[]  $telephone
82
     * @param \DOMAttr[]                                  $namespacedAttributes
83
     */
84
    public function __construct(
85
        string $contactType,
86
        ?Company $company = null,
87
        ?GivenName $givenName = null,
88
        ?SurName $surName = null,
89
        ?Extensions $extensions = null,
90
        array $email = [],
91
        array $telephone = [],
92
        array $namespacedAttributes = []
93
    ) {
94
        $this->setContactType($contactType);
95
        $this->setCompany($company);
96
        $this->setGivenName($givenName);
97
        $this->setSurName($surName);
98
        $this->setEmailAddresses($email);
99
        $this->setTelephoneNumbers($telephone);
100
        $this->setExtensions($extensions);
101
        $this->setAttributesNS($namespacedAttributes);
102
    }
103
104
105
    /**
106
     * Retrieve the value of a child \DOMElements as an array of strings.
107
     *
108
     * @param \DOMElement $parent The parent element.
109
     * @param string      $name The name of the child elements.
110
     *
111
     * @return string[]   The value of the child elements.
112
     */
113
    private static function getStringElements(DOMElement $parent, string $name): array
114
    {
115
        $e = XMLUtils::xpQuery($parent, './saml_metadata:' . $name);
116
117
        $ret = [];
118
        foreach ($e as $i) {
119
            $ret[] = $i->textContent;
120
        }
121
122
        return $ret;
123
    }
124
125
126
    /**
127
     * Retrieve the value of a child \DOMElement as a string.
128
     *
129
     * @param \DOMElement $parent The parent element.
130
     * @param string      $name The name of the child element.
131
     *
132
     * @return string|null The value of the child element.
133
     * @throws \SimpleSAML\Assert\AssertionFailedException
134
     */
135
    private static function getStringElement(DOMElement $parent, string $name): ?string
0 ignored issues
show
Unused Code introduced by
The method getStringElement() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
136
    {
137
        $e = self::getStringElements($parent, $name);
138
        if (empty($e)) {
139
            return null;
140
        }
141
142
        Assert::maxCount($e, 1, 'More than one ' . $name . ' in ' . $parent->tagName);
143
        return $e[0];
144
    }
145
146
147
    /**
148
     * Collect the value of the contactType-property
149
     *
150
     * @return string
151
     */
152
    public function getContactType(): string
153
    {
154
        return $this->contactType;
155
    }
156
157
158
    /**
159
     * Set the value of the contactType-property
160
     *
161
     * @param string $contactType
162
     * @throws \SimpleSAML\Assert\AssertionFailedException if $contactType is not one of the predefined values
163
     */
164
    protected function setContactType(string $contactType): void
165
    {
166
        Assert::oneOf($contactType, ['technical', 'support', 'administrative', 'billing', 'other']);
167
        $this->contactType = $contactType;
168
    }
169
170
171
    /**
172
     * Collect the value of the Company-property
173
     *
174
     * @return \SimpleSAML\SAML2\XML\md\Company|null
175
     */
176
    public function getCompany(): ?Company
177
    {
178
        return $this->Company;
179
    }
180
181
182
    /**
183
     * Set the value of the Company-property
184
     *
185
     * @param \SimpleSAML\SAML2\XML\md\Company|null $company
186
     */
187
    protected function setCompany(?Company $company): void
188
    {
189
        $this->Company = $company;
190
    }
191
192
193
    /**
194
     * Collect the value of the GivenName-property
195
     *
196
     * @return \SimpleSAML\SAML2\XML\md\GivenName|null
197
     */
198
    public function getGivenName(): ?GivenName
199
    {
200
        return $this->GivenName;
201
    }
202
203
204
    /**
205
     * Set the value of the GivenName-property
206
     *
207
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null $givenName
208
     */
209
    protected function setGivenName(?GivenName $givenName): void
210
    {
211
        $this->GivenName = $givenName;
212
    }
213
214
215
    /**
216
     * Collect the value of the SurName-property
217
     *
218
     * @return \SimpleSAML\SAML2\XML\md\SurName|null
219
     */
220
    public function getSurName(): ?SurName
221
    {
222
        return $this->SurName;
223
    }
224
225
226
    /**
227
     * Set the value of the SurName-property
228
     *
229
     * @param \SimpleSAML\SAML2\XML\md\SurName|null $surName
230
     */
231
    protected function setSurName(?SurName $surName): void
232
    {
233
        $this->SurName = $surName;
234
    }
235
236
237
    /**
238
     * Collect the value of the EmailAddress-property.
239
     *
240
     * @return \SimpleSAML\SAML2\XML\md\EmailAddress[]
241
     */
242
    public function getEmailAddresses(): array
243
    {
244
        return $this->EmailAddresses;
245
    }
246
247
248
    /**
249
     * Set the value of the EmailAddress-property
250
     *
251
     * @param \SimpleSAML\SAML2\XML\md\EmailAddress[] $emailAddresses
252
     * @throws \SimpleSAML\Assert\AssertionFailedException
253
     */
254
    protected function setEmailAddresses(array $emailAddresses): void
255
    {
256
        Assert::allIsInstanceOf($emailAddresses, EmailAddress::class);
257
        $this->EmailAddresses = $emailAddresses;
258
    }
259
260
261
    /**
262
     * Collect the value of the TelephoneNumber property
263
     *
264
     * @return \SimpleSAML\SAML2\XML\md\TelephoneNumber[]
265
     */
266
    public function getTelephoneNumbers(): array
267
    {
268
        return $this->TelephoneNumbers;
269
    }
270
271
272
    /**
273
     * Set the value of the TelephoneNumber property
274
     *
275
     * @param \SimpleSAML\SAML2\XML\md\TelephoneNumber[] $telephoneNumbers
276
     * @throws \SimpleSAML\Assert\AssertionFailedException
277
     */
278
    protected function setTelephoneNumbers(array $telephoneNumbers): void
279
    {
280
        Assert::allIsInstanceOf($telephoneNumbers, TelephoneNumber::class);
281
        $this->TelephoneNumbers = $telephoneNumbers;
282
    }
283
284
285
    /**
286
     * Initialize a ContactPerson element.
287
     *
288
     * @param \DOMElement $xml The XML element we should load.
289
     * @return self
290
     *
291
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
292
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
293
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
294
     */
295
    public static function fromXML(DOMElement $xml): object
296
    {
297
        Assert::same($xml->localName, 'ContactPerson', InvalidDOMElementException::class);
298
        Assert::same($xml->namespaceURI, ContactPerson::NS, InvalidDOMElementException::class);
299
300
        $contactType = self::getAttribute($xml, 'contactType');
301
302
        $company = Company::getChildrenOfClass($xml);
303
        Assert::maxCount($company, 1, 'More than one Company in md:ContactPerson');
304
305
        $givenName = GivenName::getChildrenOfClass($xml);
306
        Assert::maxCount($givenName, 1, 'More than one GivenName in md:ContactPerson');
307
308
        $surName = SurName::getChildrenOfClass($xml);
309
        Assert::maxCount($surName, 1, 'More than one SurName in md:ContactPerson');
310
311
        $email = EmailAddress::getChildrenOfClass($xml);
312
        $telephone = TelephoneNumber::getChildrenOfClass($xml);
313
314
        $extensions = Extensions::getChildrenOfClass($xml);
315
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
316
317
        return new self(
318
            $contactType,
319
            array_pop($company),
320
            array_pop($givenName),
321
            array_pop($surName),
322
            (count($extensions) === 1) ? $extensions[0] : null,
323
            $email,
324
            $telephone,
325
            self::getAttributesNSFromXML($xml)
326
        );
327
    }
328
329
330
    /**
331
     * Convert this ContactPerson to XML.
332
     *
333
     * @param \DOMElement|null $parent The element we should add this contact to.
334
     *
335
     * @return \DOMElement The new ContactPerson-element.
336
     */
337
    public function toXML(DOMElement $parent = null): DOMElement
338
    {
339
        $e = $this->instantiateParentElement($parent);
340
341
        $e->setAttribute('contactType', $this->contactType);
342
343
        foreach ($this->getAttributesNS() as $attr) {
344
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
345
        }
346
347
        if ($this->Extensions !== null) {
348
            $this->Extensions->toXML($e);
349
        }
350
351
        if ($this->Company !== null) {
352
            $this->Company->toXML($e);
353
        }
354
355
        if ($this->GivenName !== null) {
356
            $this->GivenName->toXML($e);
357
        }
358
        if ($this->SurName !== null) {
359
            $this->SurName->toXML($e);
360
        }
361
362
        foreach ($this->EmailAddresses as $mail) {
363
            $mail->toXML($e);
364
        }
365
366
        foreach ($this->TelephoneNumbers as $telephone) {
367
            $telephone->toXML($e);
368
        }
369
370
        return $e;
371
    }
372
373
374
    /**
375
     * Create a class from an array
376
     *
377
     * @param array $data
378
     * @return self
379
     */
380
    public static function fromArray(array $data): object
381
    {
382
        Assert::keyExists($data, 'ContactType');
383
384
        $ContactType = $data['ContactType'];
385
        $Company = isset($data['Company']) ? new Company($data['Company']) : null;
386
        $GivenName = isset($data['GivenName']) ? new GivenName($data['GivenName']) : null;
387
        $SurName = isset($data['SurName']) ? new SurName($data['SurName']) : null;
388
        $Extensions = $data['Extensions'] ?? null;
389
390
        $EmailAddresses = [];
391
        foreach ($data['EmailAddresses'] as $mail) {
392
            $EmailAddresses[] = new EmailAddress($mail);
393
        }
394
395
        $TelephoneNumbers = [];
396
        foreach ($data['TelephoneNumbers'] as $telephone) {
397
            $TelephoneNumbers[] = new TelephoneNumber($telephone);
398
        }
399
400
        // Anything after this should be (namespaced) attributes
401
        unset(
402
            $data['ContactType'],
403
            $data['Company'],
404
            $data['GivenName'],
405
            $data['SurName'],
406
            $data['Extensions'],
407
            $data['EmailAddresses'],
408
            $data['TelephoneNumbers']
409
        );
410
411
        $attributes = [];
412
        foreach ($data as $ns => $attribute) {
413
            $name = array_key_first($attribute);
414
            $value = $attribute[$name];
415
416
            $doc = DOMDocumentFactory::create();
417
            $elt = $doc->createElement("placeholder");
418
            $elt->setAttributeNS($ns, $name, $value);
419
420
            $attributes[] = $elt->getAttributeNode($name);
421
        }
422
423
        return new self(
424
            $ContactType,
425
            $Company,
426
            $GivenName,
427
            $SurName,
428
            $Extensions,
429
            $EmailAddresses,
430
            $TelephoneNumbers,
431
            $attributes
432
        );
433
    }
434
435
436
    /**
437
     * Create an array from this class
438
     *
439
     * @return array
440
     */
441
    public function toArray(): array
442
    {
443
        $data = [
444
            'ContactType' => $this->contactType,
445
            '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

445
            '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...
446
            '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

446
            '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...
447
            '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

447
            '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...
448
            'EmailAddresses' => $this->EmailAddresses,
449
            'TelephoneNumbers' => $this->TelephoneNumbers,
450
            'EmailAddresses' => [],
451
            'TelephoneNumbers' => [],
452
            'Extensions' => $this->Extensions,
453
        ];
454
455
        foreach ($this->EmailAddresses as $mail) {
456
            $data['EmailAddresses'] = array_merge($data['EmailAddresses'], $mail->toArray());
457
        }
458
459
        foreach ($this->TelephoneNumbers as $telephone) {
460
            $data['TelephoneNumbers'] = array_merge($data['TelephoneNumbers'], $telephone->toArray());
461
        }
462
463
        foreach ($this->getAttributesNS() as $a) {
464
            $data[$a['namespaceURI']] = [$a['qualifiedName'] => $a['value']];
465
        }
466
467
        return $data;
468
    }
469
}
470