GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

TPayload::serializeOptionalAttribute()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 2
1
<?php
2
/**
3
 * Copyright (c) 2013-2014 eBay Enterprise, Inc.
4
 *
5
 * NOTICE OF LICENSE
6
 *
7
 * This source file is subject to the Open Software License (OSL 3.0)
8
 * that is bundled with this package in the file LICENSE.md.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * @copyright   Copyright (c) 2013-2014 eBay Enterprise, Inc. (http://www.ebayenterprise.com/)
13
 * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
14
 */
15
16
namespace eBayEnterprise\RetailOrderManagement\Payload;
17
18
use DateTime;
19
use DOMDocument;
20
use DOMXPath;
21
use eBayEnterprise\RetailOrderManagement\Payload\Payment\TStrings;
22
23
/**
24
 * Generic implementation strategies for things payloads have to do.
25
 *
26
 * trait TPayload
27
 * @package eBayEnterprise\RetailOrderManagement\Payload
28
 */
29
trait TPayload
30
{
31
    use TStrings;
32
33
    /** @var IPayloadFactory */
34
    protected $payloadFactory;
35
    /** @var IPayloadMap */
36
    protected $payloadMap;
37
    /** @var ISchemaValidator */
38
    protected $schemaValidator;
39
    /** @var IValidatorIterator */
40
    protected $validators;
41
    /** @var IPayload */
42
    protected $parentPayload;
43
    /** @var array XPath expressions to extract required data from the serialized payload (XML) */
44
    protected $extractionPaths = [];
45
    /** @var array */
46
    protected $optionalExtractionPaths = [];
47
    /** @var array property/XPath pairs that take boolean values */
48
    protected $booleanExtractionPaths = [];
49
    /** @var array pair address lines properties with xpaths for extraction */
50
    protected $addressLinesExtractionMap = [];
51
    /** @var array extracting node value and assigned the property as DateTime */
52
    protected $datetimeExtractionPaths = [];
53
    /**
54
     * @var array property/XPath pairs. if property is a payload, first node matched
55
     *            will be deserialized by that payload
56
     */
57
    protected $subpayloadExtractionPaths = [];
58
    /** @var LoggerInterface enabled PSR-3 logging */
59
    protected $logger;
60
    /** @var bool flag to determine to either serialize empty node not or to serialize empty node. */
61
    protected $isSerializeEmptyNode = true;
62
63
    /**
64
     * Fill out this payload object with data from the supplied string.
65
     *
66
     * @throws Exception\InvalidPayload
67
     * @param string $serializedPayload
68
     * @return $this
69
     */
70
    public function deserialize($serializedPayload)
71
    {
72
        // make sure we received a valid serialization of the payload.
73
        $this->schemaValidate($serializedPayload);
74
        $xpath = $this->getPayloadAsXPath($serializedPayload);
75
        foreach ($this->extractionPaths as $property => $path) {
76
            $this->$property = $xpath->evaluate($path);
77
        }
78
        // When optional nodes are not included in the serialized data,
79
        // they should not be set in the payload. Fortunately, these
80
        // are all string values so no additional type conversion is necessary.
81
        foreach ($this->optionalExtractionPaths as $property => $path) {
82
            $foundNode = $xpath->query($path)->item(0);
83
            if ($foundNode) {
84
                $this->$property = $foundNode->nodeValue;
85
            }
86
        }
87
        $this->deserializeDatetime($xpath);
88
        // boolean values have to be handled specially
89
        foreach ($this->booleanExtractionPaths as $property => $path) {
90
            $value = $xpath->evaluate($path);
91
            $this->$property = $this->convertStringToBoolean($value);
92
        }
93
        $this->addressLinesFromXPath($xpath);
94
        $this->deserializeLineItems($serializedPayload);
0 ignored issues
show
Unused Code introduced by
The call to the method eBayEnterprise\RetailOrd...:deserializeLineItems() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
95
        foreach ($this->subpayloadExtractionPaths as $property => $path) {
96
            $foundNode = $xpath->query($path)->item(0);
97
            if ($foundNode && $this->$property instanceof IPayload) {
98
                $this->$property->deserialize($foundNode->C14N());
99
            }
100
        }
101
        $this->deserializeExtra($serializedPayload);
0 ignored issues
show
Unused Code introduced by
The call to the method eBayEnterprise\RetailOrd...oad::deserializeExtra() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
102
        // payload is only valid if the unserialized data is also valid
103
        $this->validate();
104
        return $this;
105
    }
106
107
    /**
108
     * Validate the serialized data via the schema validator.
109
     * @param  string $serializedData
110
     * @return $this
111
     */
112
    protected function schemaValidate($serializedData)
113
    {
114
        if ($this->schemaValidator) {
115
            $this->schemaValidator->validate($serializedData);
116
        }
117
        return $this;
118
    }
119
120
    /**
121
     * Load the payload XML into a DOMXPath for querying.
122
     * @param string $xmlString
123
     * @return \DOMXPath
124
     */
125
    protected function getPayloadAsXPath($xmlString)
126
    {
127
        $xpath = new DOMXPath($this->getPayloadAsDoc($xmlString));
128
        $xpath->registerNamespace('x', $this->getXmlNamespace());
129
        return $xpath;
130
    }
131
132
    /**
133
     * Load the payload XML into a DOMDocument
134
     * @param  string $xmlString
135
     * @return \DOMDocument
136
     */
137
    protected function getPayloadAsDoc($xmlString)
138
    {
139
        $d = new DOMDocument();
140
        try {
141
            $d->loadXML($xmlString);
142
        } catch (\Exception $e) {
143
            throw $e;
144
        }
145
        return $d;
146
    }
147
148
    /**
149
     * Get Line1 through Line4 for an Address
150
     * Find all of the nodes in the address node that
151
     * start with 'Line' and add their value to the
152
     * proper address lines array
153
     *
154
     * @param \DOMXPath $domXPath
155
     */
156
    protected function addressLinesFromXPath(\DOMXPath $domXPath)
157
    {
158
        foreach ($this->addressLinesExtractionMap as $address) {
159
            $lines = $domXPath->query($address['xPath']);
160
            $property = $address['property'];
161
            $this->$property = $this->addressLinesFromNodeList($lines);
162
        }
163
    }
164
165
    /**
166
     * Get address lines from node list
167
     * Return null instead of an empty array
168
     *
169
     * @param \DOMNodeList
170
     * @param string
171
     * @return array|null
172
     */
173
    protected function addressLinesFromNodeList(\DOMNodeList $lines)
174
    {
175
        $result = [];
176
        foreach ($lines as $line) {
177
            $result[] = $line->nodeValue;
178
        }
179
        return $result ?: null;
180
    }
181
182
    /**
183
     * Additional deserialization of the payload data. May contain any
184
     * special case deserialization that cannot be expressed by the supported
185
     * deserialization paths. Default implementation is a no-op. Expected to
186
     * be overridden by payloads that need it.
187
     *
188
     * @param string
189
     * @return self
190
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
191
     */
192
    protected function deserializeExtra($serializedPayload)
0 ignored issues
show
Unused Code introduced by
The parameter $serializedPayload is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
193
    {
194
        return $this;
195
    }
196
197
    /**
198
     * convert line item substrings into line item objects
199
     * @param  string $serializedPayload
200
     * @return self
201
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
202
     */
203
    protected function deserializeLineItems($serializedPayload)
0 ignored issues
show
Unused Code introduced by
The parameter $serializedPayload is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
204
    {
205
        return $this;
206
    }
207
208
    /**
209
     * Extract the node and if the value in the node is a non-empty
210
     * string value, then assigned the class property to a DateTime object
211
     * passing in the extracted value, otherwise assigned it to null.
212
     *
213
     * @param \DOMXPath $xpath
214
     * @return self
215
     */
216
    protected function deserializeDatetime(\DOMXPath $xpath)
217
    {
218 View Code Duplication
        foreach ($this->datetimeExtractionPaths as $property => $path) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219
            $value = $xpath->evaluate($path);
220
            $this->$property = $value ? new DateTime($value) : null;
221
        }
222
223
        return $this;
224
    }
225
226
    /**
227
     * Build a new IPayload for the given interface.
228
     *
229
     * @param string
230
     * @return IPayload
231
     */
232
    protected function buildPayloadForInterface($interface)
233
    {
234
        return $this->payloadFactory->buildPayload(
235
            $this->payloadMap->getConcreteType($interface),
236
            $this->payloadMap,
237
            $this,
238
            $this->logger
239
        );
240
    }
241
242
    /**
243
     * Validate that the payload meets the requirements
244
     * for transmission. This can be over and above what
245
     * is required for serialization.
246
     *
247
     * @throws Exception\InvalidPayload
248
     */
249
    public function validate()
250
    {
251
        foreach ($this->validators as $validator) {
252
            $validator->validate($this);
253
        }
254
        return $this;
255
    }
256
257
    /**
258
     * Return the string form of the payload data for transmission.
259
     * Validation is implied.
260
     *
261
     * @throws Exception\InvalidPayload
262
     * @return string
263
     */
264
    public function serialize()
265
    {
266
        // validate the payload data
267
        $this->validate();
268
        $canonicalXml = '';
269
        $contents = $this->serializeContents();
270
        if ($this->isSerializeEmptyNode || $contents) {
271
            $xmlString = sprintf('<%s %s>%s</%1$s>', $this->getRootNodeName(), $this->serializeRootAttributes(), $contents);
272
            $canonicalXml = $this->getPayloadAsDoc($xmlString)->C14N();
273
            $this->schemaValidate($canonicalXml);
274
        }
275
        return $canonicalXml;
276
    }
277
278
    public function getParentPayload()
279
    {
280
        return $this->parentPayload;
281
    }
282
283
    protected function getAncestorPayloadOfType($type)
284
    {
285
        $pl = $this;
286
        while ($pl = $pl->getParentPayload()) {
287
            if ($pl instanceof $type) {
288
                return $pl;
289
            }
290
        }
291
        return null;
292
    }
293
294
    /**
295
     * Return the name of the xml root node.
296
     *
297
     * @return string
298
     */
299
    abstract protected function getRootNodeName();
300
301
    /**
302
     * Serialize Root Attributes
303
     */
304
    protected function serializeRootAttributes()
305
    {
306
        $rootAttributes = $this->getRootAttributes();
307
        $qualifyAttributes = function ($name) use ($rootAttributes) {
308
            return sprintf('%s="%s"', $name, $this->xmlEncode($rootAttributes[$name]));
309
        };
310
        $qualifiedAttributes = array_map($qualifyAttributes, array_keys($rootAttributes));
311
        return implode(' ', $qualifiedAttributes);
312
    }
313
314
    /**
315
     * XML Namespace of the document.
316
     *
317
     * @return string
318
     */
319
    abstract protected function getXmlNamespace();
320
321
    /**
322
     * Name, value pairs of root attributes
323
     *
324
     * @return array
325
     */
326
    protected function getRootAttributes()
327
    {
328
        return [];
329
    }
330
331
    /**
332
     * Serialize the various parts of the payload into XML strings and concatenate them together.
333
     *
334
     * @return string
335
     */
336
    abstract protected function serializeContents();
337
338
    /**
339
     * Serialize the value as an xml element with the given node name. When
340
     * given an empty value, returns an empty string instead of an empty
341
     * element.
342
     *
343
     * @param string
344
     * @param mixed
345
     * @return string
346
     */
347
    protected function serializeOptionalValue($nodeName, $value)
348
    {
349
        return !is_null($value) ? $this->serializeRequiredValue($nodeName, $value) : '';
350
    }
351
352
    /**
353
     * Serialize the value as an XML attribute with the given name. When
354
     * given an empty value, returns an empty string.
355
     *
356
     * @param string
357
     * @param mixed
358
     * @return string
359
     */
360
    protected function serializeOptionalAttribute($attributeName, $value)
361
    {
362
        return !is_null($value) ? " $attributeName='$value' " : '';
363
    }
364
365
    /**
366
     * Serialize the currency amount as an XML node with the provided name.
367
     * When the amount is not set, returns an empty string.
368
     *
369
     * @param string
370
     * @param float
371
     * @return string
372
     */
373
    protected function serializeOptionalAmount($nodeName, $amount)
374
    {
375
        return !is_null($amount) ? "<$nodeName>{$this->formatAmount($amount)}</$nodeName>" : '';
0 ignored issues
show
Bug introduced by
It seems like formatAmount() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
376
    }
377
378
    /**
379
     * Serialize an optional date time value. When a DateTime value is given,
380
     * serialize the DateTime object as an XML node containing the DateTime
381
     * formatted with the given format. When no DateTime is given, return
382
     * an empty string.
383
     *
384
     * @param string
385
     * @param string
386
     * @param DateTime
387
     * @return string
388
     */
389
    protected function serializeOptionalDateValue($nodeName, $format, DateTime $date = null)
390
    {
391
        return $date ? "<$nodeName>{$date->format($format)}</$nodeName>" : '';
392
    }
393
394
    /**
395
     * Get a new PayloadFactory instance.
396
     *
397
     * @return PayloadFactory
398
     */
399
    protected function getNewPayloadFactory()
400
    {
401
        return new PayloadFactory();
402
    }
403
404
    /**
405
     * Serialize a value with a given name. Value will be XML encoded before
406
     * being serialized.
407
     *
408
     * @param string
409
     * @param string
410
     * @return string
411
     */
412
    protected function serializeXmlEncodedValue($name, $value)
413
    {
414
        return $this->serializeRequiredValue($name, $this->xmlEncode($value));
415
    }
416
417
    /**
418
     * Serialize an optional element containing a string. The value will be
419
     * xml-encoded if is not null.
420
     *
421
     * @param string
422
     * @param string
423
     * @return string
424
     */
425
    protected function serializeOptionalXmlEncodedValue($name, $value)
426
    {
427
        return $this->serializeOptionalValue($name, $this->xmlEncode($value));
428
    }
429
430
    /**
431
     * serialize a required field to an xml string
432
     *
433
     * @param string
434
     * @param string
435
     * @return string
436
     */
437
    protected function serializeRequiredValue($name, $value)
438
    {
439
        return "<$name>$value</$name>";
440
    }
441
}
442