Completed
Pull Request — master (#86)
by
unknown
03:35
created

Shipping::getRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 8
Ratio 100 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 8
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Ups;
4
5
use DOMDocument;
6
use DOMNode;
7
use Exception;
8
use InvalidArgumentException;
9
use Psr\Log\LoggerInterface;
10
use SimpleXMLElement;
11
use Ups\Entity\Shipment;
12
use Ups\Entity\ShipmentRequestLabelSpecification;
13
use Ups\Entity\ShipmentRequestReceiptSpecification;
14
15
/**
16
 * Package Shipping API Wrapper
17
 * Based on UPS Developer Guide, dated: 31 Dec 2012.
18
 */
19
class Shipping extends Ups
20
{
21
    const REQ_VALIDATE = 'validate';
22
    const REQ_NONVALIDATE = 'nonvalidate';
23
24
    /**
25
     * @var string
26
     */
27
    private $shipConfirmEndpoint = '/ShipConfirm';
28
29
    /**
30
     * @var string
31
     */
32
    private $shipAcceptEndpoint = '/ShipAccept';
33
34
    /**
35
     * @var string
36
     */
37
    private $voidEndpoint = '/Void';
38
39
    /**
40
     * @var string
41
     */
42
    private $recoverLabelEndpoint = '/LabelRecovery';
43
44
    private $request;
45
46
    /**
47
     * @param string|null $accessKey UPS License Access Key
48
     * @param string|null $userId UPS User ID
49
     * @param string|null $password UPS User Password
50
     * @param bool $useIntegration Determine if we should use production or CIE URLs.
51
     * @param RequestInterface|null $request
52
     * @param LoggerInterface|null PSR3 compatible logger (optional)
53
     */
54 View Code Duplication
    public function __construct($accessKey = null, $userId = null, $password = null, $useIntegration = false, RequestInterface $request = null, LoggerInterface $logger = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
55
    {
56
        if (null !== $request) {
57
            $this->setRequest($request);
58
        }
59
        parent::__construct($accessKey, $userId, $password, $useIntegration, $logger);
60
    }
61
62
    /**
63
     * Create a Shipment Confirm request (generate a digest).
64
     *
65
     * @param string $validation A UPS_Shipping::REQ_* constant (or null)
66
     * @param Shipment $shipment Shipment data container.
67
     * @param ShipmentRequestLabelSpecification|null $labelSpec LabelSpecification data. Optional
68
     * @param ShipmentRequestReceiptSpecification|null $receiptSpec ShipmentRequestReceiptSpecification data. Optional
69
     *
70
     * @throws Exception
71
     *
72
     * @return stdClass
73
     */
74
    public function confirm(
75
        $validation,
76
        Shipment $shipment,
77
        ShipmentRequestLabelSpecification $labelSpec = null,
78
        ShipmentRequestReceiptSpecification $receiptSpec = null
79
    ) {
80
        $request = $this->createConfirmRequest($validation, $shipment, $labelSpec, $receiptSpec);
81
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->shipConfirmEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
82
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
83
84
        if (null === $response) {
85
            throw new Exception('Failure (0): Unknown error', 0);
86
        }
87
88
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
89
            throw new Exception(
90
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
91
                (int)$response->Response->Error->ErrorCode
92
            );
93
        } else {
94
            return $this->formatResponse($response);
95
        }
96
    }
97
98
    /**
99
     * Creates a ShipConfirm request.
100
     *
101
     * @param string $validation
102
     * @param Shipment $shipment
103
     * @param ShipmentRequestLabelSpecification|null $labelSpec
104
     * @param ShipmentRequestReceiptSpecification|null $receiptSpec
105
     *
106
     * @return string
107
     */
108
    private function createConfirmRequest(
109
        $validation,
110
        Shipment $shipment,
111
        ShipmentRequestLabelSpecification $labelSpec = null,
112
        ShipmentRequestReceiptSpecification $receiptSpec = null
113
    ) {
114
        $xml = new DOMDocument();
115
        $xml->formatOutput = true;
116
117
        // Page 45
118
        $container = $xml->appendChild($xml->createElement('ShipmentConfirmRequest'));
119
120
        // Page 45
121
        $request = $container->appendChild($xml->createElement('Request'));
122
123
        $node = $xml->importNode($this->createTransactionNode(), true);
124
        $request->appendChild($node);
125
126
        $request->appendChild($xml->createElement('RequestAction', 'ShipConfirm'));
127
        $request->appendChild($xml->createElement('RequestOption', $validation ?: 'nonvalidate'));
128
129
        // Page 47
130
        $shipmentNode = $container->appendChild($xml->createElement('Shipment'));
131
132
        if ($shipment->getDescription()) {
133
            $shipmentNode->appendChild($xml->createElement('Description', $shipment->getDescription()));
134
        }
135
136
        $returnService = $shipment->getReturnService();
137
        if (isset($returnService)) {
138
            $node = $shipmentNode->appendChild($xml->createElement('ReturnService'));
139
140
            $node->appendChild($xml->createElement('Code', $returnService->getCode()));
141
        }
142
143
        if ($shipment->getDocumentsOnly()) {
144
            $shipmentNode->appendChild($xml->createElement('DocumentsOnly'));
145
        }
146
147
        $shipperNode = $shipmentNode->appendChild($xml->createElement('Shipper'));
148
149
        $shipperNode->appendChild($xml->createElement('Name', $shipment->getShipper()->getName()));
150
151
        if ($shipment->getShipper()->getAttentionName()) {
152
            $shipperNode->appendChild($xml->createElement('AttentionName', $shipment->getShipper()->getAttentionName()));
153
        }
154
155
        if ($shipment->getShipper()->getCompanyName()) {
156
            $shipperNode->appendChild($xml->createElement('CompanyDisplayableName', $shipment->getShipper()->getCompanyName()));
157
        }
158
159
        $shipperNode->appendChild($xml->createElement('ShipperNumber', $shipment->getShipper()->getShipperNumber()));
160
161
        if ($shipment->getShipper()->getTaxIdentificationNumber()) {
162
            $shipperNode->appendChild($xml->createElement('TaxIdentificationNumber', $shipment->getShipper()->getTaxIdentificationNumber()));
163
        }
164
165
        if ($shipment->getShipper()->getPhoneNumber()) {
166
            $shipperNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipper()->getPhoneNumber()));
167
        }
168
169
        if ($shipment->getShipper()->getFaxNumber()) {
170
            $shipperNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipper()->getFaxNumber()));
171
        }
172
173
        if ($shipment->getShipper()->getEMailAddress()) {
174
            $shipperNode->appendChild($xml->createElement('EMailAddress', $shipment->getShipper()->getEMailAddress()));
175
        }
176
177
        $shipperNode->appendChild($shipment->getShipper()->getAddress()->toNode($xml));
178
179
        $shipToNode = $shipmentNode->appendChild($xml->createElement('ShipTo'));
180
181
        $shipToNode->appendChild($xml->createElement('CompanyName', $shipment->getShipTo()->getCompanyName()));
182
183
        if ($shipment->getShipTo()->getAttentionName()) {
184
            $shipToNode->appendChild($xml->createElement('AttentionName', $shipment->getShipTo()->getAttentionName()));
185
        }
186
187
        if ($shipment->getShipTo()->getPhoneNumber()) {
188
            $shipToNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipTo()->getPhoneNumber()));
189
        }
190
191
        if ($shipment->getShipTo()->getFaxNumber()) {
192
            $shipToNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipTo()->getFaxNumber()));
193
        }
194
195
        if ($shipment->getShipTo()->getEMailAddress()) {
196
            $shipToNode->appendChild($xml->createElement('EMailAddress', $shipment->getShipTo()->getEMailAddress()));
197
        }
198
199
        $addressNode = $shipment->getShipTo()->getAddress()->toNode($xml);
200
201
        if ($shipment->getShipTo()->getLocationID()) {
202
            $addressNode->appendChild($xml->createElement('LocationID', strtoupper($shipment->getShipTo()->getLocationID())));
203
        }
204
205
        $shipToNode->appendChild($addressNode);
206
207
        if ($shipment->getShipFrom()) {
208
            $shipFromNode = $shipmentNode->appendChild($xml->createElement('ShipFrom'));
209
210
            $shipFromNode->appendChild($xml->createElement('CompanyName', $shipment->getShipFrom()->getCompanyName()));
211
212
            if ($shipment->getShipFrom()->getAttentionName()) {
213
                $shipFromNode->appendChild($xml->createElement('AttentionName', $shipment->getShipFrom()->getAttentionName()));
214
            }
215
216
            if ($shipment->getShipFrom()->getPhoneNumber()) {
217
                $shipFromNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipFrom()->getPhoneNumber()));
218
            }
219
220
            if ($shipment->getShipFrom()->getFaxNumber()) {
221
                $shipFromNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipFrom()->getFaxNumber()));
222
            }
223
224
            $shipFromNode->appendChild($shipment->getShipFrom()->getAddress()->toNode($xml));
225
        }
226
227
        if ($shipment->getSoldTo()) {
228
            $soldToNode = $shipmentNode->appendChild($xml->createElement('SoldTo'));
229
230
            if ($shipment->getSoldTo()->getOption()) {
231
                $soldToNode->appendChild($xml->createElement('Option', $shipment->getSoldTo()->getOption()));
232
            }
233
234
            $soldToNode->appendChild($xml->createElement('CompanyName', $shipment->getSoldTo()->getCompanyName()));
235
236
            if ($shipment->getSoldTo()->getAttentionName()) {
237
                $soldToNode->appendChild($xml->createElement('AttentionName', $shipment->getSoldTo()->getAttentionName()));
238
            }
239
240
            if ($shipment->getSoldTo()->getPhoneNumber()) {
241
                $soldToNode->appendChild($xml->createElement('PhoneNumber', $shipment->getSoldTo()->getPhoneNumber()));
242
            }
243
244
            if ($shipment->getSoldTo()->getFaxNumber()) {
245
                $soldToNode->appendChild($xml->createElement('FaxNumber', $shipment->getSoldTo()->getFaxNumber()));
246
            }
247
248
            if ($shipment->getSoldTo()->getAddress()) {
249
                $soldToNode->appendChild($shipment->getSoldTo()->getAddress()->toNode($xml));
250
            }
251
        }
252
253
        $alternate = $shipment->getAlternateDeliveryAddress();
254
        if (isset($alternate)) {
255
            $shipmentNode->appendChild($alternate->toNode($xml));
256
        }
257
258
        if ($shipment->getPaymentInformation()) {
259
            $paymentNode = $shipmentNode->appendChild($xml->createElement('PaymentInformation'));
260
261
            if ($shipment->getPaymentInformation()->getPrepaid()) {
262
                $node = $paymentNode->appendChild($xml->createElement('Prepaid'));
263
                $node = $node->appendChild($xml->createElement('BillShipper'));
264
265
                $billShipper = $shipment->getPaymentInformation()->getPrepaid()->getBillShipper();
266
                if (isset($billShipper) && $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getAccountNumber()) {
267
                    $node->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getAccountNumber()));
268
                } elseif (isset($billShipper) && $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()) {
269
                    $ccNode = $node->appendChild($xml->createElement('CreditCard'));
270
                    $ccNode->appendChild($xml->createElement('Type', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getType()));
271
                    $ccNode->appendChild($xml->createElement('Number', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getNumber()));
272
                    $ccNode->appendChild($xml->createElement('ExpirationDate', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getExpirationDate()));
273
274
                    if ($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getSecurityCode()) {
275
                        $ccNode->appendChild($xml->createElement('SecurityCode', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getSecurityCode()));
276
                    }
277
278
                    if ($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getAddress()) {
279
                        $ccNode->appendChild($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getAddress()->toNode($xml));
280
                    }
281
                }
282
            } elseif ($shipment->getPaymentInformation()->getBillThirdParty()) {
283
                $node = $paymentNode->appendChild($xml->createElement('BillThirdParty'));
284
                $btpNode = $node->appendChild($xml->createElement('BillThirdPartyShipper'));
285
                $btpNode->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getBillThirdParty()->getAccountNumber()));
286
287
                $tpNode = $btpNode->appendChild($xml->createElement('ThirdParty'));
288
                $addressNode = $tpNode->appendChild($xml->createElement('Address'));
289
290
                $thirdPartAddress = $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress();
291
                if (isset($thirdPartAddress) && $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getPostalCode()) {
292
                    $addressNode->appendChild($xml->createElement('PostalCode', $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getPostalCode()));
293
                }
294
295
                $addressNode->appendChild($xml->createElement('CountryCode', $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getCountryCode()));
296
            } elseif ($shipment->getPaymentInformation()->getFreightCollect()) {
297
                $node = $paymentNode->appendChild($xml->createElement('FreightCollect'));
298
                $brNode = $node->appendChild($xml->createElement('BillReceiver'));
299
                $brNode->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getFreightCollect()->getAccountNumber()));
300
301
                if ($shipment->getPaymentInformation()->getFreightCollect()->getBillReceiverAddress()) {
302
                    $addressNode = $brNode->appendChild($xml->createElement('Address'));
303
                    $addressNode->appendChild($xml->createElement('PostalCode', $shipment->getPaymentInformation()->getFreightCollect()->getBillReceiverAddress()->getPostalCode()));
304
                }
305
            } elseif ($shipment->getPaymentInformation()->getConsigneeBilled()) {
306
                $paymentNode->appendChild($xml->createElement('ConsigneeBilled'));
307
            }
308
//         TODO: create ItemizedPaymentInformation class and required subclasses for node processing
309
//        } elseif ($shipment->getItemizedPaymentInformation()) {
310
//            $paymentNode = $shipmentNode->appendChild($xml->createElement('ItemizedPaymentInformation'));
311
        }
312
313
        if ($shipment->getGoodsNotInFreeCirculationIndicator()) {
314
            $shipmentNode->appendChild($xml->createElement('GoodsNotInFreeCirculationIndicator'));
315
        }
316
317
        if ($shipment->getMovementReferenceNumber()) {
318
            $shipmentNode->appendChild($xml->createElement('MovementReferenceNumber', $shipment->getMovementReferenceNumber()));
319
        }
320
321
        $serviceNode = $shipmentNode->appendChild($xml->createElement('Service'));
322
        $serviceNode->appendChild($xml->createElement('Code', $shipment->getService()->getCode()));
323
324
        if ($shipment->getService()->getDescription()) {
325
            $serviceNode->appendChild($xml->createElement('Description', $shipment->getService()->getDescription()));
326
        }
327
328
        if ($shipment->getInvoiceLineTotal()) {
329
            $shipmentNode->appendChild($shipment->getInvoiceLineTotal()->toNode($xml));
330
        }
331
332
        if ($shipment->getNumOfPiecesInShipment()) {
333
            $shipmentNode->appendChild($xml->createElement('NumOfPiecesInShipment', $shipment->getNumOfPiecesInShipment()));
334
        }
335
336
        if ($shipment->getRateInformation()) {
337
            $node = $shipmentNode->appendChild($xml->createElement('RateInformation'));
338
            $node->appendChild($xml->createElement('NegotiatedRatesIndicator'));
339
        }
340
341
        foreach ($shipment->getPackages() as $package) {
342
            $shipmentNode->appendChild($xml->importNode($package->toNode($xml), true));
343
        }
344
345
        $shipmentServiceOptions = $shipment->getShipmentServiceOptions();
346
        if (isset($shipmentServiceOptions)) {
347
            $shipmentNode->appendChild($shipmentServiceOptions->toNode($xml));
348
        }
349
350
        $referenceNumber = $shipment->getReferenceNumber();
351
        if (isset($referenceNumber)) {
352
            $shipmentNode->appendChild($referenceNumber->toNode($xml));
353
        }
354
        
355
        $referenceNumber2 = $shipment->getReferenceNumber2();
356
        if (isset($referenceNumber2)) {
357
            $shipmentNode->appendChild($referenceNumber2->toNode($xml));
358
        }
359
360
        if ($labelSpec) {
361
            $container->appendChild($xml->importNode($this->compileLabelSpecificationNode($labelSpec), true));
362
        }
363
364
        $shipmentIndicationType = $shipment->getShipmentIndicationType();
365
        if (isset($shipmentIndicationType)) {
366
            $shipmentNode->appendChild($shipmentIndicationType->toNode($xml));
367
        }
368
369
        if ($receiptSpec) {
370
            $container->appendChild($xml->importNode($this->compileReceiptSpecificationNode($receiptSpec), true));
371
        }
372
373
        return $xml->saveXML();
374
    }
375
376
    /**
377
     * Create a Shipment Accept request (generate a shipping label).
378
     *
379
     * @param string $shipmentDigest The UPS Shipment Digest received from a ShipConfirm request.
380
     *
381
     * @throws Exception
382
     *
383
     * @return \stdClass
384
     */
385
    public function accept($shipmentDigest)
386
    {
387
        $request = $this->createAcceptRequest($shipmentDigest);
388
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->shipAcceptEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
389
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
390
391
        if (null === $response) {
392
            throw new Exception('Failure (0): Unknown error', 0);
393
        }
394
395
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
396
            throw new Exception(
397
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
398
                (int)$response->Response->Error->ErrorCode
399
            );
400
        } else {
401
            return $this->formatResponse($response->ShipmentResults);
402
        }
403
    }
404
405
    /**
406
     * Creates a ShipAccept request.
407
     *
408
     * @param string $shipmentDigest
409
     *
410
     * @return string
411
     */
412
    private function createAcceptRequest($shipmentDigest)
413
    {
414
        $xml = new DOMDocument();
415
        $xml->formatOutput = true;
416
417
        $container = $xml->appendChild($xml->createElement('ShipmentAcceptRequest'));
418
        $request = $container->appendChild($xml->createElement('Request'));
419
420
        $node = $xml->importNode($this->createTransactionNode(), true);
421
        $request->appendChild($node);
422
423
        $request->appendChild($xml->createElement('RequestAction', 'ShipAccept'));
424
        $container->appendChild($xml->createElement('ShipmentDigest', $shipmentDigest));
425
426
        return $xml->saveXML();
427
    }
428
429
    /**
430
     * Void a shipping label / request.
431
     *
432
     * @param string|array $shipmentData Either the UPS Shipment Identification Number or an array of
433
     *                                   expanded shipment data [shipmentId:, trackingNumbers:[...]]
434
     *
435
     * @throws Exception
436
     *
437
     * @return \stdClass
438
     */
439
    public function void($shipmentData)
440
    {
441
        if (is_array($shipmentData) && !isset($shipmentData['shipmentId'])) {
442
            throw new InvalidArgumentException('$shipmentData parameter is required to contain a key `shipmentId`.');
443
        }
444
445
        $request = $this->createVoidRequest($shipmentData);
446
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->voidEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
447
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
448
449
        if ($response->Response->ResponseStatusCode == 0) {
450
            throw new Exception(
451
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
452
                (int)$response->Response->Error->ErrorCode
453
            );
454
        } else {
455
            unset($response->Response);
456
457
            return $this->formatResponse($response);
458
        }
459
    }
460
461
    /**
462
     * Creates a void shipment request.
463
     *
464
     * @param string|array $shipmentData
465
     *
466
     * @return string
467
     */
468
    private function createVoidRequest($shipmentData)
469
    {
470
        $xml = new DOMDocument();
471
        $xml->formatOutput = true;
472
473
        $container = $xml->appendChild($xml->createElement('VoidShipmentRequest'));
474
        $request = $container->appendChild($xml->createElement('Request'));
475
476
        $node = $xml->importNode($this->createTransactionNode(), true);
477
        $request->appendChild($node);
478
479
        $request->appendChild($xml->createElement('RequestAction', '1'));
480
481
        if (is_string($shipmentData)) {
482
            $container->appendChild($xml->createElement('ShipmentIdentificationNumber', strtoupper($shipmentData)));
483
        } else {
484
            $expanded = $container->appendChild($xml->createElement('ExpandedVoidShipment'));
485
            $expanded->appendChild($xml->createElement('ShipmentIdentificationNumber', strtoupper($shipmentData['shipmentId'])));
486
487
            if (array_key_exists('trackingNumbers', $shipmentData)) {
488
                foreach ($shipmentData['trackingNumbers'] as $tn) {
489
                    $expanded->appendChild($xml->createElement('TrackingNumber', strtoupper($tn)));
490
                }
491
            }
492
        }
493
494
        return $xml->saveXML();
495
    }
496
497
    /**
498
     * Recover a shipping label.
499
     *
500
     * @param string|array $trackingData Either the tracking number or a map of ReferenceNumber data
501
     *                                         [value:, shipperNumber:]
502
     * @param array|null $labelSpecification Map of label specification data for this request. Optional.
503
     *                                         [userAgent:, imageFormat: 'HTML|PDF']
504
     * @param array|null $labelDelivery All elements are optional. [link:]
505
     * @param array|null $translate Map of translation data. Optional. [language:, dialect:]
506
     *
507
     * @throws Exception|InvalidArgumentException
508
     *
509
     * @return \stdClass
510
     */
511
    public function recoverLabel($trackingData, $labelSpecification = null, $labelDelivery = null, $translate = null)
512
    {
513
        if (is_array($trackingData)) {
514
            if (!isset($trackingData['value'])) {
515
                throw new InvalidArgumentException('$trackingData parameter is required to contain `value`.');
516
            }
517
518
            if (!isset($trackingData['shipperNumber'])) {
519
                throw new InvalidArgumentException('$trackingData parameter is required to contain `shipperNumber`.');
520
            }
521
        }
522
523
        if (!empty($translate)) {
524
            if (!isset($translateOpts['language'])) {
0 ignored issues
show
Bug introduced by
The variable $translateOpts seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
525
                $translateOpts['language'] = 'eng';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$translateOpts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $translateOpts = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
526
            }
527
528
            if (!isset($translateOpts['dialect'])) {
529
                $translateOpts['dialect'] = 'US';
530
            }
531
        }
532
533
        $request = $this->createRecoverLabelRequest($trackingData, $labelSpecification, $labelDelivery, $translate);
534
        $response = $this->request($this->createAccess(), $request, $this->compileEndpointUrl($this->recoverLabelEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The method Ups\Ups::request() has been deprecated with message: Untestable

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
535
536
        if ($response->Response->ResponseStatusCode == 0) {
537
            throw new Exception(
538
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
539
                (int)$response->Response->Error->ErrorCode
540
            );
541
        } else {
542
            unset($response->Response);
543
544
            return $this->formatResponse($response);
545
        }
546
    }
547
548
    /**
549
     * Creates a label recovery request.
550
     *
551
     * @param string|array $trackingData
552
     * @param array|null $labelSpecificationOpts
553
     * @param array|null $labelDeliveryOpts
554
     * @param array|null $translateOpts
555
     *
556
     * @return string
557
     */
558
    private function createRecoverLabelRequest($trackingData, $labelSpecificationOpts = null, $labelDeliveryOpts = null, $translateOpts = null)
0 ignored issues
show
Unused Code introduced by
The parameter $trackingData 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...
559
    {
560
        $xml = new DOMDocument();
561
        $xml->formatOutput = true;
562
563
        $container = $xml->appendChild($xml->createElement('LabelRecoveryRequest'));
564
        $request = $container->appendChild($xml->createElement('Request'));
565
566
        $node = $xml->importNode($this->createTransactionNode(), true);
567
        $request->appendChild($node);
568
569
        $request->appendChild($xml->createElement('RequestAction', 'LabelRecovery'));
570
571
        if (!empty($labelSpecificationOpts)) {
572
            $labelSpec = $request->appendChild($xml->createElement('LabelSpecification'));
573
574
            if (isset($labelSpecificationOpts['userAgent'])) {
575
                $labelSpec->appendChild($xml->createElement('HTTPUserAgent', $labelSpecificationOpts['userAgent']));
576
            }
577
578
            if (isset($labelSpecificationOpts['imageFormat'])) {
579
                $format = $labelSpec->appendChild($xml->createElement('LabelImageFormat'));
580
                $format->appendChild($xml->createElement('Code', $labelSpecificationOpts['imageFormat']));
581
            }
582
        }
583
584
        if (!empty($labelDeliveryOpts)) {
585
            $labelDelivery = $request->appendChild($xml->createElement('LabelDelivery'));
586
            $labelDelivery->appendChild($xml->createElement('LabelLinkIndicator', $labelDeliveryOpts['link']));
587
        }
588
589
        if (!empty($translateOpts)) {
590
            $translate = $request->appendChild($xml->createElement('Translate'));
591
            $translate->appendChild($xml->createElement('LanguageCode', $translateOpts['language']));
592
            $translate->appendChild($xml->createElement('DialectCode', $translateOpts['dialect']));
593
            $translate->appendChild($xml->createElement('Code', '01'));
594
        }
595
596
        return $xml->saveXML();
597
    }
598
599
    /**
600
     * Format the response.
601
     *
602
     * @param SimpleXMLElement $response
603
     *
604
     * @return \stdClass
605
     */
606
    private function formatResponse(SimpleXMLElement $response)
607
    {
608
        return $this->convertXmlObject($response);
609
    }
610
611
    /**
612
     * @return RequestInterface
613
     */
614 View Code Duplication
    public function getRequest()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
615
    {
616
        if (null === $this->request) {
617
            $this->request = new Request($this->logger);
618
        }
619
620
        return $this->request;
621
    }
622
623
    /**
624
     * @param RequestInterface $request
625
     *
626
     * @return $this
627
     */
628
    public function setRequest(RequestInterface $request)
629
    {
630
        $this->request = $request;
631
632
        return $this;
633
    }
634
635
    /**
636
     * @return ResponseInterface
637
     */
638
    public function getResponse()
639
    {
640
        return $this->response;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->response; of type Ups\ResponseInterface|SimpleXMLElement adds the type SimpleXMLElement to the return on line 640 which is incompatible with the return type documented by Ups\Shipping::getResponse of type Ups\ResponseInterface.
Loading history...
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
641
    }
642
643
    /**
644
     * @param ResponseInterface $response
645
     *
646
     * @return $this
647
     */
648
    public function setResponse(ResponseInterface $response)
649
    {
650
        $this->response = $response;
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
651
652
        return $this;
653
    }
654
655
    /**
656
     * @param ShipmentRequestReceiptSpecification $receiptSpec
657
     * @return DOMNode
658
     */
659
    private function compileReceiptSpecificationNode(ShipmentRequestReceiptSpecification $receiptSpec)
660
    {
661
        $xml = new DOMDocument();
662
        $xml->formatOutput = true;
663
664
        $receiptSpecNode = $xml->appendChild($xml->createElement('ReceiptSpecification'));
665
666
        $imageFormatNode = $receiptSpecNode->appendChild($xml->createElement('ImageFormat'));
667
        $imageFormatNode->appendChild($xml->createElement('Code', $receiptSpec->getImageFormatCode()));
668
669
        if ($receiptSpec->getImageFormatDescription()) {
670
            $imageFormatNode->appendChild($xml->createElement('Description', $receiptSpec->getImageFormatDescription()));
671
        }
672
673
        return $receiptSpecNode->cloneNode(true);
674
    }
675
676
    /**
677
     * @param ShipmentRequestLabelSpecification $labelSpec
678
     * @return DOMNode
679
     */
680
    private function compileLabelSpecificationNode(ShipmentRequestLabelSpecification $labelSpec)
681
    {
682
        $xml = new DOMDocument();
683
        $xml->formatOutput = true;
684
685
        $labelSpecNode = $xml->appendChild($xml->createElement('LabelSpecification'));
686
687
        $printMethodNode = $labelSpecNode->appendChild($xml->createElement('LabelPrintMethod'));
688
        $printMethodNode->appendChild($xml->createElement('Code', $labelSpec->getPrintMethodCode()));
689
690
        if ($labelSpec->getPrintMethodDescription()) {
691
            $printMethodNode->appendChild($xml->createElement('Description', $labelSpec->getPrintMethodDescription()));
692
        }
693
694
        if ($labelSpec->getHttpUserAgent()) {
695
            $labelSpecNode->appendChild($xml->createElement('HTTPUserAgent', $labelSpec->getHttpUserAgent()));
696
        }
697
698
        //Label print method is required only for GIF label formats
699
        if ($labelSpec->getPrintMethodCode() == ShipmentRequestLabelSpecification::IMG_FORMAT_CODE_GIF) {
700
            $imageFormatNode = $labelSpecNode->appendChild($xml->createElement('LabelImageFormat'));
701
            $imageFormatNode->appendChild($xml->createElement('Code', $labelSpec->getImageFormatCode()));
702
703
            if ($labelSpec->getImageFormatDescription()) {
704
                $imageFormatNode->appendChild($xml->createElement('Description', $labelSpec->getImageFormatDescription()));
705
            }
706
        } else {
707
            //Label stock size is required only for non-GIF label formats
708
            $stockSizeNode = $labelSpecNode->appendChild($xml->createElement('LabelStockSize'));
709
710
            $stockSizeNode->appendChild($xml->createElement('Height', $labelSpec->getStockSizeHeight()));
711
            $stockSizeNode->appendChild($xml->createElement('Width', $labelSpec->getStockSizeWidth()));
712
        }
713
714
        if ($labelSpec->getInstructionCode()) {
715
            $instructionNode = $labelSpecNode->appendChild($xml->createElement('Instruction'));
716
            $instructionNode->appendChild($xml->createElement('Code', $labelSpec->getInstructionCode()));
717
718
            if ($labelSpec->getInstructionDescription()) {
719
                $instructionNode->appendChild($xml->createElement('Description', $labelSpec->getInstructionDescription()));
720
            }
721
        }
722
723
        return $labelSpecNode->cloneNode(true);
724
    }
725
}
726