Passed
Pull Request — master (#267)
by Tim
04:21
created

ContactPerson::getStringElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 9
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 string[]
61
     */
62
    protected array $EmailAddresses = [];
63
64
    /**
65
     * The TelephoneNumbers of this contact.
66
     *
67
     * @var string[]
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 string[]                                  $email
81
     * @param string[]                                  $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
     * Collect the value of the contactType-property
107
     *
108
     * @return string
109
     */
110
    public function getContactType(): string
111
    {
112
        return $this->contactType;
113
    }
114
115
116
    /**
117
     * Set the value of the contactType-property
118
     *
119
     * @param string $contactType
120
     * @throws \SimpleSAML\Assert\AssertionFailedException if $contactType is not one of the predefined values
121
     */
122
    protected function setContactType(string $contactType): void
123
    {
124
        Assert::oneOf($contactType, ['technical', 'support', 'administrative', 'billing', 'other']);
125
        $this->contactType = $contactType;
126
    }
127
128
129
    /**
130
     * Collect the value of the Company-property
131
     *
132
     * @return \SimpleSAML\SAML2\XML\md\Company|null
133
     */
134
    public function getCompany(): ?Company
135
    {
136
        return $this->Company;
137
    }
138
139
140
    /**
141
     * Set the value of the Company-property
142
     *
143
     * @param \SimpleSAML\SAML2\XML\md\Company|null $company
144
     */
145
    protected function setCompany(?Company $company): void
146
    {
147
        $this->Company = $company;
148
    }
149
150
151
    /**
152
     * Collect the value of the GivenName-property
153
     *
154
     * @return \SimpleSAML\SAML2\XML\md\GivenName|null
155
     */
156
    public function getGivenName(): ?GivenName
157
    {
158
        return $this->GivenName;
159
    }
160
161
162
    /**
163
     * Set the value of the GivenName-property
164
     *
165
     * @param \SimpleSAML\SAML2\XML\md\GivenName|null $givenName
166
     */
167
    protected function setGivenName(?GivenName $givenName): void
168
    {
169
        $this->GivenName = $givenName;
170
    }
171
172
173
    /**
174
     * Collect the value of the SurName-property
175
     *
176
     * @return \SimpleSAML\SAML2\XML\md\SurName|null
177
     */
178
    public function getSurName(): ?SurName
179
    {
180
        return $this->SurName;
181
    }
182
183
184
    /**
185
     * Set the value of the SurName-property
186
     *
187
     * @param \SimpleSAML\SAML2\XML\md\SurName|null $surName
188
     */
189
    protected function setSurName(?SurName $surName): void
190
    {
191
        $this->SurName = $surName;
192
    }
193
194
    /**
195
     * Collect the value of the EmailAddress-property.
196
     *
197
     * @return string[]
198
     */
199
    public function getEmailAddresses(): array
200
    {
201
        return $this->EmailAddresses;
202
    }
203
204
    /**
205
     * Remove a "mailto:" prefix on an email address, if present.
206
     * Check the address for syntactical validity. If not, throw an exception.
207
     *
208
     * @param string $emailAddress
209
     * @return string
210
     * @throws \InvalidArgumentException if supplied email address is not valid
211
     */
212
    private function validateEmailAddress(string $emailAddress): string
213
    {
214
        $address = preg_replace('/^mailto:/i', '', $emailAddress);
215
        if (filter_var($address, FILTER_VALIDATE_EMAIL) === false) {
216
            throw new InvalidArgumentException("Invalid email address for ContactPerson: " . var_export($address, true));
217
        }
218
        return $address;
219
    }
220
221
    /**
222
     * Set the value of the EmailAddress-property
223
     *
224
     * @param string[] $emailAddresses
225
     * @throws \SimpleSAML\Assert\AssertionFailedException
226
     */
227
    protected function setEmailAddresses(array $emailAddresses): void
228
    {
229
        $addresses = array_map([$this, 'validateEmailAddress'], $emailAddresses);
230
        Assert::allEmail($addresses, 'Invalid email addresses found.');
231
        $this->EmailAddresses = $addresses;
232
    }
233
234
235
    /**
236
     * Collect the value of the TelephoneNumber property
237
     *
238
     * @return string[]
239
     */
240
    public function getTelephoneNumbers(): array
241
    {
242
        return $this->TelephoneNumbers;
243
    }
244
245
246
    /**
247
     * Set the value of the TelephoneNumber property
248
     *
249
     * @param string[] $telephoneNumbers
250
     * @throws \SimpleSAML\Assert\AssertionFailedException
251
     */
252
    protected function setTelephoneNumbers(array $telephoneNumbers): void
253
    {
254
        Assert::allString($telephoneNumbers, 'Incorrect type for telephone number.');
255
        $this->TelephoneNumbers = $telephoneNumbers;
256
    }
257
258
259
    /**
260
     * Initialize a ContactPerson element.
261
     *
262
     * @param \DOMElement $xml The XML element we should load.
263
     * @return self
264
     *
265
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
266
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
267
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
268
     */
269
    public static function fromXML(DOMElement $xml): object
270
    {
271
        Assert::same($xml->localName, 'ContactPerson', InvalidDOMElementException::class);
272
        Assert::same($xml->namespaceURI, ContactPerson::NS, InvalidDOMElementException::class);
273
274
        $contactType = self::getAttribute($xml, 'contactType');
275
276
        $company = Company::getChildrenOfClass($xml);
277
        Assert::maxCount($company, 1, 'More than one Company in md:ContactPerson');
278
279
        $givenName = GivenName::getChildrenOfClass($xml);
280
        Assert::maxCount($givenName, 1, 'More than one GivenName in md:ContactPerson');
281
282
        $surName = SurName::getChildrenOfClass($xml);
283
        Assert::maxCount($surName, 1, 'More than one SurName in md:ContactPerson');
284
285
        $email = EmailAddress::getChildrenOfClass($xml);
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\md\EmailAddress 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...
286
        $telephone = TelephoneNumber::getChildrenOfClass($xml);
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\md\TelephoneNumber 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...
287
        $extensions = Extensions::getChildrenOfClass($xml);
288
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
289
290
        return new self(
291
            $contactType,
292
            array_pop($company),
293
            array_pop($givenName),
294
            array_pop($surName),
295
            (count($extensions) === 1) ? $extensions[0] : null,
296
            $email,
297
            $telephone,
298
            self::getAttributesNSFromXML($xml)
299
        );
300
    }
301
302
303
    /**
304
     * Convert this ContactPerson to XML.
305
     *
306
     * @param \DOMElement|null $parent The element we should add this contact to.
307
     *
308
     * @return \DOMElement The new ContactPerson-element.
309
     */
310
    public function toXML(DOMElement $parent = null): DOMElement
311
    {
312
        $e = $this->instantiateParentElement($parent);
313
314
        $e->setAttribute('contactType', $this->contactType);
315
316
        foreach ($this->getAttributesNS() as $attr) {
317
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
318
        }
319
320
        if ($this->Extensions !== null) {
321
            $this->Extensions->toXML($e);
322
        }
323
324
        if ($this->Company !== null) {
325
            $this->Company->toXML($e);
326
        }
327
328
        if ($this->GivenName !== null) {
329
            $this->GivenName->toXML($e);
330
        }
331
        if ($this->SurName !== null) {
332
            $this->SurName->toXML($e);
333
        }
334
335
        $addresses = preg_filter('/^/', 'mailto:', $this->EmailAddresses);
336
        XMLUtils::addStrings($e, Constants::NS_MD, 'md:EmailAddress', false, $addresses);
337
338
        XMLUtils::addStrings($e, Constants::NS_MD, 'md:TelephoneNumber', false, $this->TelephoneNumbers);
339
340
        return $e;
341
    }
342
343
344
    /**
345
     * Create a class from an array
346
     *
347
     * @param array $data
348
     * @return self
349
     */
350
    public static function fromArray(array $data): object
351
    {
352
        Assert::keyExists($data, 'ContactType');
353
354
        $ContactType = $data['ContactType'];
355
        $Company = isset($data['Company']) ? new Company($data['Company']) : null;
356
        $GivenName = isset($data['GivenName']) ? new GivenName($data['GivenName']) : null;
357
        $SurName = isset($data['SurName']) ? new SurName($data['SurName']) : null;
358
        $Extensions = $data['Extensions'] ?? null;
359
        $EmailAddresses = $data['EmailAddresses'] ?? [];
360
        $TelephoneNumbers = $data['TelephoneNumbers'] ?? [];
361
362
        // Anything after this should be (namespaced) attributes
363
        unset(
364
            $data['ContactType'],
365
            $data['Company'],
366
            $data['GivenName'],
367
            $data['SurName'],
368
            $data['Extensions'],
369
            $data['EmailAddresses'],
370
            $data['TelephoneNumbers']
371
        );
372
373
        $attributes = [];
374
        foreach ($data as $ns => $attribute) {
375
            $name = array_key_first($attribute);
376
            $value = $attribute[$name];
377
378
            $doc = DOMDocumentFactory::create();
379
            $elt = $doc->createElement("placeholder");
380
            $elt->setAttributeNS($ns, $name, $value);
381
382
            $attributes[] = $elt->getAttributeNode($name);
383
        }
384
385
        return new self(
386
            $ContactType,
387
            $Company,
388
            $GivenName,
389
            $SurName,
390
            $Extensions,
391
            $EmailAddresses,
392
            $TelephoneNumbers,
393
            $attributes
394
        );
395
    }
396
397
398
    /**
399
     * Create an array from this class
400
     *
401
     * @return array
402
     */
403
    public function toArray(): array
404
    {
405
        $data = [
406
            'ContactType' => $this->contactType,
407
            '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

407
            '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...
408
            '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

408
            '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...
409
            '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

409
            '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...
410
            'EmailAddresses' => $this->EmailAddresses,
411
            'TelephoneNumbers' => $this->TelephoneNumbers,
412
            'Extensions' => $this->Extensions,
413
        ];
414
415
        foreach ($this->getAttributesNS() as $a) {
416
            $data[$a['namespaceURI']] = [$a['qualifiedName'] => $a['value']];
417
        }
418
419
        return $data;
420
    }
421
}
422