Completed
Push — master ( 5f65eb...5ec83a )
by Stefan
04:42
created

Tracking::createRequest()   C

Complexity

Conditions 8
Paths 128

Size

Total Lines 47
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 8.9115

Importance

Changes 0
Metric Value
dl 0
loc 47
ccs 25
cts 33
cp 0.7576
rs 5
c 0
b 0
f 0
cc 8
eloc 26
nc 128
nop 0
crap 8.9115
1
<?php
2
3
namespace Ups;
4
5
use DOMDocument;
6
use Exception;
7
use Psr\Log\LoggerInterface;
8
use SimpleXMLElement;
9
use stdClass;
10
use DateTime;
11
12
/**
13
 * Tracking API Wrapper.
14
 */
15
class Tracking extends Ups
16
{
17
    const ENDPOINT = '/Track';
18
19
    /**
20
     * @var RequestInterface
21
     */
22
    private $request;
23
24
    /**
25
     *
26
     * Workaround flag to handle Multiple shipment nodes in tracking response
27
     * See GitHub Issue #117
28
     *
29
     * fixme in next major release
30
     *
31
     * @var boolean
32
     */
33
    protected $allowMultipleShipments = false;
34
35
    /**
36
     * @var ResponseInterface
37
     *                        // todo make private
38
     */
39
    public $response;
40
41
    /**
42
     * @var string
43
     */
44
    private $trackingNumber;
45
46
    /**
47
     * @var string
48
     */
49
    private $referenceNumber;
50
51
    /**
52
     * @var string
53
     */
54
    private $requestOption;
55
56
    /**
57
     * @var string
58
     */
59
    private $shipperNumber;
60
61
    /**
62
     * @var \DateTime
63
     */
64
    private $beginDate;
65
66
    /**
67
     * @var \DateTime
68
     */
69
    private $endDate;
70
71
    /**
72
     * @param string|null $accessKey UPS License Access Key
73
     * @param string|null $userId UPS User ID
74
     * @param string|null $password UPS User Password
75
     * @param bool $useIntegration Determine if we should use production or CIE URLs.
76
     * @param RequestInterface|null $request
77
     * @param LoggerInterface|null $logger PSR3 compatible logger (optional)
78
     */
79 6 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...
80
    {
81 6
        if (null !== $request) {
82
            $this->setRequest($request);
83
        }
84 6
        parent::__construct($accessKey, $userId, $password, $useIntegration, $logger);
85 6
    }
86
87
    /**
88
     * Get package tracking information.
89
     *
90
     * @param string $trackingNumber The package's tracking number.
91
     * @param string $requestOption Optional processing. For Mail Innovations the only valid options are Last Activity and All activity.
92
     *
93
     * @throws Exception
94
     *
95
     * @return stdClass
96
     */
97 5 View Code Duplication
    public function track($trackingNumber, $requestOption = 'activity')
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...
98
    {
99 5
        $this->trackingNumber = $trackingNumber;
100 5
        $this->requestOption = $requestOption;
101
102 5
        $access = $this->createAccess();
103 5
        $request = $this->createRequest();
104
105 5
        $this->response = $this->getRequest()->request($access, $request, $this->compileEndpointUrl(self::ENDPOINT));
106 5
        $response = $this->response->getResponse();
107
108 5
        if (null === $response) {
109 2
            throw new Exception('Failure (0): Unknown error', 0);
110
        }
111
112 3
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
113
            throw new Exception(
114
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
115
                (int)$response->Response->Error->ErrorCode
116
            );
117
        } else {
118 3
            return $this->formatResponse($response);
119
        }
120
    }
121
122
    /**
123
     * Get package tracking information.
124
     *
125
     * @param string $referenceNumber Reference numbers can be a purchase order number, job number, etc. Reference number can be added when creating a shipment.
126
     * @param string $requestOption
127
     *
128
     * @throws Exception
129
     *
130
     * @return stdClass
131
     */
132 1 View Code Duplication
    public function trackByReference($referenceNumber, $requestOption = 'activity')
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...
133
    {
134 1
        $this->referenceNumber = $referenceNumber;
135 1
        $this->requestOption = $requestOption;
136
137 1
        $access = $this->createAccess();
138 1
        $request = $this->createRequest();
139
140 1
        $this->response = $this->getRequest()->request($access, $request, $this->compileEndpointUrl(self::ENDPOINT));
141 1
        $response = $this->response->getResponse();
142
143 1
        if (null === $response) {
144 1
            throw new Exception('Failure (0): Unknown error', 0);
145
        }
146
147
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
148
            throw new Exception(
149
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
150
                (int)$response->Response->Error->ErrorCode
151
            );
152
        } else {
153
            return $this->formatResponse($response);
154
        }
155
    }
156
157
    /**
158
     * Set shipper number
159
     *
160
     * @param string $shipperNumber
161
     *
162
     */
163
    public function setShipperNumber($shipperNumber)
164
    {
165
        $this->shipperNumber = $shipperNumber;
166
    }
167
168
    /**
169
     * Set begin date
170
     *
171
     * @param string $beginDate
172
     *
173
     */
174
    public function setBeginDate(DateTime $beginDate)
175
    {
176
        $this->beginDate = $beginDate;
177
    }
178
179
    /**
180
     * Set end date
181
     *
182
     * @param string $endDate
183
     *
184
     */
185
    public function setEndDate(DateTime $endDate)
186
    {
187
        $this->endDate = $endDate;
188
    }
189
190
    /**
191
     * Check if tracking number is for mail innovations.
192
     *
193
     * @return bool
194
     */
195 6
    private function isMailInnovations()
196
    {
197
        $patterns = [
198
199
            // UPS Mail Innovations tracking numbers
200 6
            '/^MI\d{6}\d{1,22}$/',// MI 000000 00000000+
201
202
            // USPS - Certified Mail
203 6
            '/^94071\d{17}$/',    // 9407 1000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
204 6
            '/^7\d{19}$/',        // 7000 0000 0000 0000 0000
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
205
206
            // USPS - Collect on Delivery
207 6
            '/^93033\d{17}$/',    // 9303 3000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
208 6
            '/^M\d{9}$/',         // M000 0000 00
209
210
            // USPS - Global Express Guaranteed
211 6
            '/^82\d{10}$/',       // 82 000 000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
212
213
            // USPS - Priority Mail Express International
214 6
            '/^EC\d{9}US$/',      // EC 000 000 000 US
215
216
            // USPS Innovations Expedited
217 6
            '/^927\d{23}$/',      // 9270 8900 8900 8900 8900 8900 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
218
            
219
            // USPS - Priority Mail Express
220 6
            '/^927\d{19}$/',      // 9270 1000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
221 6
            '/^EA\d{9}US$/',      // EA 000 000 000 US
222
223
            // USPS - Priority Mail International
224 6
            '/^CP\d{9}US$/',      // CP 000 000 000 US
225
226
            // USPS - Priority Mail
227 6
            '/^92055\d{17}$/',    // 9205 5000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
228 6
            '/^14\d{18}$/',       // 1400 0000 0000 0000 0000
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
229
230
            // USPS - Registered Mail
231 6
            '/^92088\d{17}$/',    // 9208 8000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
232 6
            '/^RA\d{9}US$/',      // RA 000 000 000 US
233
234
            // USPS - Signature Confirmation
235 6
            '/^9202\d{16}US$/',   // 9202 1000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
236 6
            '/^23\d{16}US$/',     // 2300 0000 0000 0000 0000
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
237
238
            // USPS - Tracking
239 6
            '/^94\d{20}$/',       // 9400 1000 0000 0000 0000 00
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
240
            '/^03\d{18}$/'        // 0300 0000 0000 0000 0000
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
241 6
        ];
242
243 6
        foreach ($patterns as $pattern) {
244 6
            if (preg_match($pattern, $this->trackingNumber)) {
245 1
                return true;
246
            }
247 6
        }
248
249 5
        return false;
250
    }
251
252
    /**
253
     * Create the Tracking request.
254
     *
255
     * @return string
256
     */
257 6
    private function createRequest()
258
    {
259 6
        $xml = new DOMDocument();
260 6
        $xml->formatOutput = true;
261
262 6
        $trackRequest = $xml->appendChild($xml->createElement('TrackRequest'));
263 6
        $trackRequest->setAttribute('xml:lang', 'en-US');
264
265 6
        $request = $trackRequest->appendChild($xml->createElement('Request'));
266
267 6
        $node = $xml->importNode($this->createTransactionNode(), true);
268 6
        $request->appendChild($node);
269
270 6
        $request->appendChild($xml->createElement('RequestAction', 'Track'));
271
272 6
        if (null !== $this->requestOption) {
273 6
            $request->appendChild($xml->createElement('RequestOption', $this->requestOption));
274 6
        }
275
276 6
        if (null !== $this->trackingNumber) {
277 5
            $trackRequest->appendChild($xml->createElement('TrackingNumber', $this->trackingNumber));
278 5
        }
279
280 6
        if ($this->isMailInnovations()) {
281 1
            $trackRequest->appendChild($xml->createElement('IncludeMailInnovationIndicator'));
282 1
        }
283
284 6
        if (null !== $this->referenceNumber) {
285 1
            $trackRequest->appendChild($xml->createElement('ReferenceNumber'))->appendChild($xml->createElement('Value', $this->referenceNumber));
286 1
        }
287
288 6
        if (null !== $this->shipperNumber) {
289
            $trackRequest->appendChild($xml->createElement('ShipperNumber', $this->shipperNumber));
290
        }
291
292 6
        if (null !== $this->beginDate) {
293
            $beginDate = $this->beginDate->format('Ymd');
294
            $trackRequest->appendChild($xml->createElement('BeginDate', $beginDate));
295
        }
296
297 6
        if (null !== $this->endDate) {
298
            $endDate = $this->endDate->format('Ymd');
299
            $trackRequest->appendChild($xml->createElement('EndDate', $endDate));
300
        }
301
302 6
        return $xml->saveXML();
303
    }
304
305
    /**
306
     * Format the response.
307
     *
308
     * @param SimpleXMLElement $response
309
     *
310
     * @return stdClass
311
     */
312 3
    private function formatResponse(SimpleXMLElement $response)
313
    {
314 3
        if ($this->allowMultipleShipments) {
315
            $response = $this->convertXmlObject($response);
316
            if (!is_array($response->Shipment)) {
317
                $response->Shipment = [$response->Shipment];
318
            }
319
            return $response;
320
        }
321
322 3
        return $this->convertXmlObject($response->Shipment);
323
    }
324
325
    /**
326
     * @return RequestInterface
327
     */
328 6 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...
329
    {
330 6
        if (null === $this->request) {
331
            $this->request = new Request($this->logger);
332
        }
333
334 6
        return $this->request;
335
    }
336
337
    /**
338
     * @param RequestInterface $request
339
     *
340
     * @return $this
341
     */
342 6
    public function setRequest(RequestInterface $request)
343
    {
344 6
        $this->request = $request;
345
346 6
        return $this;
347
    }
348
349
    /**
350
     * @return ResponseInterface
351
     */
352 2
    public function getResponse()
353
    {
354 2
        return $this->response;
355
    }
356
357
    /**
358
     * @param ResponseInterface $response
359
     *
360
     * @return $this
361
     */
362
    public function setResponse(ResponseInterface $response)
363
    {
364
        $this->response = $response;
365
366
        return $this;
367
    }
368
369
    /**
370
     * @param bool $value
371
     * @return $this
372
     */
373
    public function allowMultipleShipments($value = true)
374
    {
375
        $this->allowMultipleShipments = $value ? true : false;
376
377
        return $this;
378
    }
379
}
380