Passed
Push — master ( 6db269...70aff8 )
by Jaime Pérez
02:49
created

ContactPerson::toXML()   A

Complexity

Conditions 6
Paths 32

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 16
c 1
b 0
f 0
nc 32
nop 1
dl 0
loc 31
rs 9.1111
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SAML2\XML\md;
6
7
use DOMElement;
8
use Exception;
9
use InvalidArgumentException;
10
use SAML2\Constants;
11
use SAML2\Utils;
12
use SAML2\XML\ExtendableAttributesTrait;
13
use SAML2\XML\ExtendableElementTrait;
14
use Webmozart\Assert\Assert;
15
16
/**
17
 * Class representing SAML 2 ContactPerson.
18
 *
19
 * @package simplesamlphp/saml2
20
 */
21
final class ContactPerson extends AbstractMdElement
22
{
23
    use ExtendableElementTrait;
24
    use ExtendableAttributesTrait {
0 ignored issues
show
introduced by
The trait SAML2\XML\ExtendableAttributesTrait requires some properties which are not provided by SAML2\XML\md\ContactPerson: $namespaceURI, $nodeName, $attributes, $value
Loading history...
25
        ExtendableAttributesTrait::setAttributesNS as setAttributesNSConflict;
26
    }
27
28
    /**
29
     * The contact type.
30
     *
31
     * @var string
32
     */
33
    protected $contactType;
34
35
    /**
36
     * The Company of this contact.
37
     *
38
     * @var string|null
39
     */
40
    protected $Company = null;
41
42
    /**
43
     * The GivenName of this contact.
44
     *
45
     * @var string|null
46
     */
47
    protected $GivenName = null;
48
49
    /**
50
     * The SurName of this contact.
51
     *
52
     * @var string|null
53
     */
54
    protected $SurName = null;
55
56
    /**
57
     * The EmailAddresses of this contact.
58
     *
59
     * @var array
60
     */
61
    protected $EmailAddresses = [];
62
63
    /**
64
     * The TelephoneNumbers of this contact.
65
     *
66
     * @var array
67
     */
68
    protected $TelephoneNumbers = [];
69
70
71
    /**
72
     * ContactPerson constructor.
73
     *
74
     * @param string                         $contactType
75
     * @param string|null                    $company
76
     * @param string|null                    $givenName
77
     * @param string|null                    $surName
78
     * @param \SAML2\XML\md\Extensions|null  $extensions
79
     * @param string[]                       $email
80
     * @param string[]                       $telephone
81
     * @param \DOMAttr[]                     $namespacedAttributes
82
     */
83
    public function __construct(
84
        string $contactType,
85
        ?string $company = null,
86
        ?string $givenName = null,
87
        ?string $surName = null,
88
        ?Extensions $extensions = null,
89
        array $email = [],
90
        array $telephone = [],
91
        array $namespacedAttributes = []
92
    ) {
93
        $this->setContactType($contactType);
94
        $this->setCompany($company);
95
        $this->setGivenName($givenName);
96
        $this->setSurName($surName);
97
        $this->setEmailAddresses($email);
98
        $this->setTelephoneNumbers($telephone);
99
        $this->setExtensions($extensions);
100
        $this->setAttributesNS($namespacedAttributes);
101
    }
102
103
104
    /**
105
     * Initialize a ContactPerson element.
106
     *
107
     * @param \DOMElement $xml The XML element we should load.
108
     *
109
     * @return self
110
     * @throws \InvalidArgumentException if the qualified name of the supplied element is wrong
111
     * @throws \InvalidArgumentException if the mandatory contactType attribute is missing
112
     */
113
    public static function fromXML(DOMElement $xml): object
114
    {
115
        Assert::same($xml->localName, 'ContactPerson');
116
        Assert::same($xml->namespaceURI, ContactPerson::NS);
117
        Assert::true($xml->hasAttribute('contactType'), 'Missing contactType on ContactPerson.');
118
119
        $contactType = $xml->getAttribute('contactType');
120
        $company = self::getStringElement($xml, 'Company');
121
        $givenName = self::getStringElement($xml, 'GivenName');
122
        $surName = self::getStringElement($xml, 'SurName');
123
        $email = self::getStringElements($xml, 'EmailAddress');
124
        $telephone = self::getStringElements($xml, 'TelephoneNumber');
125
        $extensions = Extensions::getChildrenOfClass($xml);
126
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.');
127
128
        return new self(
129
            $contactType,
130
            $company,
131
            $givenName,
132
            $surName,
133
            (count($extensions) === 1) ? $extensions[0] : null,
134
            $email,
135
            $telephone,
136
            self::getAttributesNSFromXML($xml)
0 ignored issues
show
Bug introduced by
It seems like self::getAttributesNSFromXML($xml) can also be of type null; however, parameter $namespacedAttributes of SAML2\XML\md\ContactPerson::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

136
            /** @scrutinizer ignore-type */ self::getAttributesNSFromXML($xml)
Loading history...
137
        );
138
    }
139
140
141
    /**
142
     * Retrieve the value of a child \DOMElements as an array of strings.
143
     *
144
     * @param \DOMElement $parent The parent element.
145
     * @param string      $name The name of the child elements.
146
     *
147
     * @return string[]   The value of the child elements.
148
     */
149
    private static function getStringElements(DOMElement $parent, string $name): array
150
    {
151
        $e = Utils::xpQuery($parent, './saml_metadata:' . $name);
152
153
        $ret = [];
154
        foreach ($e as $i) {
155
            $ret[] = $i->textContent;
156
        }
157
158
        return $ret;
159
    }
160
161
162
    /**
163
     * Retrieve the value of a child \DOMElement as a string.
164
     *
165
     * @param \DOMElement $parent The parent element.
166
     * @param string      $name The name of the child element.
167
     *
168
     * @return string|null The value of the child element.
169
     * @throws \InvalidArgumentException
170
     */
171
    private static function getStringElement(DOMElement $parent, string $name): ?string
172
    {
173
        $e = self::getStringElements($parent, $name);
174
        if (empty($e)) {
175
            return null;
176
        }
177
178
        Assert::maxCount($e, 1, 'More than one ' . $name . ' in ' . $parent->tagName);
179
        return $e[0];
180
    }
181
182
183
    /**
184
     * Collect the value of the contactType-property
185
     *
186
     * @return string
187
     */
188
    public function getContactType(): string
189
    {
190
        return $this->contactType;
191
    }
192
193
194
    /**
195
     * Set the value of the contactType-property
196
     *
197
     * @param string $contactType
198
     * @return void
199
     * @throws \InvalidArgumentException if $contactType is not one of the predefined values
200
     */
201
    protected function setContactType(string $contactType): void
202
    {
203
        Assert::oneOf($contactType, ['technical', 'support', 'administrative', 'billing', 'other']);
204
        $this->contactType = $contactType;
205
    }
206
207
208
    /**
209
     * Collect the value of the Company-property
210
     *
211
     * @return string|null
212
     */
213
    public function getCompany(): ?string
214
    {
215
        return $this->Company;
216
    }
217
218
219
    /**
220
     * Set the value of the Company-property
221
     *
222
     * @param string|null $company
223
     * @return void
224
     */
225
    protected function setCompany(?string $company): void
226
    {
227
        $this->Company = $company;
228
    }
229
230
231
    /**
232
     * Collect the value of the GivenName-property
233
     *
234
     * @return string|null
235
     */
236
    public function getGivenName(): ?string
237
    {
238
        return $this->GivenName;
239
    }
240
241
242
    /**
243
     * Set the value of the GivenName-property
244
     *
245
     * @param string|null $givenName
246
     * @return void
247
     */
248
    protected function setGivenName(?string $givenName): void
249
    {
250
        $this->GivenName = $givenName;
251
    }
252
253
254
    /**
255
     * Collect the value of the SurName-property
256
     *
257
     * @return string|null
258
     */
259
    public function getSurName(): ?string
260
    {
261
        return $this->SurName;
262
    }
263
264
265
    /**
266
     * Set the value of the SurName-property
267
     *
268
     * @param string|null $surName
269
     * @return void
270
     */
271
    protected function setSurName(?string $surName): void
272
    {
273
        $this->SurName = $surName;
274
    }
275
276
    /**
277
     * Collect the value of the EmailAddress-property.
278
     *
279
     * @return string[]
280
     */
281
    public function getEmailAddresses(): array
282
    {
283
        return $this->EmailAddresses;
284
    }
285
286
    /**
287
     * Remove a "mailto:" prefix on an email address, if present.
288
     * Check the address for syntactical validity. If not, throw an exception.
289
     *
290
     * @param string $emailAddress
291
     * @return string
292
     * @throws \InvalidArgumentException if supplied email address is not valid
293
     */
294
    private function validateEmailAddress(string $emailAddress): string
295
    {
296
        $address = preg_replace('/^mailto:/i', '', $emailAddress);
297
        if (filter_var($address, FILTER_VALIDATE_EMAIL) === false) {
298
            throw new InvalidArgumentException("Invalid email address for ContactPerson: " . var_export($address, true));
299
        }
300
        return $address;
301
    }
302
303
    /**
304
     * Set the value of the EmailAddress-property
305
     *
306
     * @param string[] $emailAddresses
307
     * @return void
308
     * @throws \InvalidArgumentException
309
     */
310
    protected function setEmailAddresses(array $emailAddresses): void
311
    {
312
        $addresses = array_map([$this, 'validateEmailAddress'], $emailAddresses);
313
        Assert::allEmail($addresses, 'Invalid email addresses found.');
314
        $this->EmailAddresses = $addresses;
315
    }
316
317
318
    /**
319
     * Collect the value of the TelephoneNumber property
320
     *
321
     * @return string[]
322
     */
323
    public function getTelephoneNumbers(): array
324
    {
325
        return $this->TelephoneNumbers;
326
    }
327
328
329
    /**
330
     * Set the value of the TelephoneNumber property
331
     *
332
     * @param string[] $telephoneNumbers
333
     * @throws \InvalidArgumentException
334
     */
335
    protected function setTelephoneNumbers(array $telephoneNumbers): void
336
    {
337
        Assert::allString($telephoneNumbers, 'Incorrect type for telephone number.');
338
        $this->TelephoneNumbers = $telephoneNumbers;
339
    }
340
341
342
    /**
343
     * Convert this ContactPerson to XML.
344
     *
345
     * @param \DOMElement|null $parent The element we should add this contact to.
346
     *
347
     * @return \DOMElement The new ContactPerson-element.
348
     */
349
    public function toXML(DOMElement $parent = null): DOMElement
350
    {
351
        $e = $this->instantiateParentElement($parent);
352
353
        $e->setAttribute('contactType', $this->contactType);
354
355
        foreach ($this->getAttributesNS() as $attr) {
356
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
357
        }
358
359
        if ($this->Extensions !== null) {
360
            $this->Extensions->toXML($e);
361
        }
362
363
        if ($this->Company !== null) {
364
            Utils::addString($e, Constants::NS_MD, 'md:Company', $this->Company);
365
        }
366
        if ($this->GivenName !== null) {
367
            Utils::addString($e, Constants::NS_MD, 'md:GivenName', $this->GivenName);
368
        }
369
        if ($this->SurName !== null) {
370
            Utils::addString($e, Constants::NS_MD, 'md:SurName', $this->SurName);
371
        }
372
373
        /** @var string[] $addresses */
374
        $addresses = preg_filter('/^/', 'mailto:', $this->EmailAddresses);
375
        Utils::addStrings($e, Constants::NS_MD, 'md:EmailAddress', false, $addresses);
376
377
        Utils::addStrings($e, Constants::NS_MD, 'md:TelephoneNumber', false, $this->TelephoneNumbers);
378
379
        return $e;
380
    }
381
}
382