Completed
Pull Request — master (#89)
by
unknown
03:17
created

Tracking::formatResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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
 * Tracking API Wrapper.
13
 */
14
class Tracking extends Ups
15
{
16
    const ENDPOINT = '/Track';
17
18
    /**
19
     * @var RequestInterface
20
     */
21
    private $request;
22
23
    /**
24
     * @var ResponseInterface
25
     *                        // todo make private
26
     */
27
    public $response;
28
29
    /**
30
     * @var string
31
     */
32
    private $trackingNumber;
33
34
    /**
35
     * @var string
36
     */
37
    private $referenceNumber;
38
39
    /**
40
     * @var string
41
     */
42
    private $requestOption;
43
44
    /**
45
     * @var string
46
     */
47
    private $shipperNumber;
48
49
    /**
50
     * @var string
51
     */
52
    private $beginDate;
53
54
    /**
55
     * @var string
56
     */
57
    private $endDate;
58
59
    /**
60
     * @param string|null $accessKey UPS License Access Key
61
     * @param string|null $userId UPS User ID
62
     * @param string|null $password UPS User Password
63
     * @param bool $useIntegration Determine if we should use production or CIE URLs.
64
     * @param RequestInterface|null $request
65
     * @param LoggerInterface|null $logger PSR3 compatible logger (optional)
66
     */
67 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...
68
    {
69 6
        if (null !== $request) {
70
            $this->setRequest($request);
71
        }
72 6
        parent::__construct($accessKey, $userId, $password, $useIntegration, $logger);
73 6
    }
74
75
    /**
76
     * Get package tracking information.
77
     *
78
     * @param string $trackingNumber The package's tracking number.
79
     * @param string $requestOption Optional processing. For Mail Innovations the only valid options are Last Activity and All activity.
80
     *
81
     * @throws Exception
82
     *
83
     * @return stdClass
84
     */
85 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...
86
    {
87 5
        $this->trackingNumber = $trackingNumber;
88 5
        $this->requestOption = $requestOption;
89
90 5
        $access = $this->createAccess();
91 5
        $request = $this->createRequest();
92
93 5
        $this->response = $this->getRequest()->request($access, $request, $this->compileEndpointUrl(self::ENDPOINT));
94 5
        $response = $this->response->getResponse();
95
96 5
        if (null === $response) {
97 2
            throw new Exception('Failure (0): Unknown error', 0);
98
        }
99
100 3
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
101
            throw new Exception(
102
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
103
                (int)$response->Response->Error->ErrorCode
104
            );
105
        } else {
106 3
            return $this->formatResponse($response);
107
        }
108
    }
109
110
    /**
111
     * Get package tracking information.
112
     *
113
     * @param string $referenceNumber Reference numbers can be a purchase order number, job number, etc. Reference number can be added when creating a shipment.
114
     * @param string $requestOption
115
     *
116
     * @throws Exception
117
     *
118
     * @return stdClass
119
     */
120 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...
121
    {
122 1
        $this->referenceNumber = $referenceNumber;
123 1
        $this->requestOption = $requestOption;
124
125 1
        $access = $this->createAccess();
126 1
        $request = $this->createRequest();
127
128 1
        $this->response = $this->getRequest()->request($access, $request, $this->compileEndpointUrl(self::ENDPOINT));
129 1
        $response = $this->response->getResponse();
130
131 1
        if (null === $response) {
132 1
            throw new Exception('Failure (0): Unknown error', 0);
133
        }
134
135
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
136
            throw new Exception(
137
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
138
                (int)$response->Response->Error->ErrorCode
139
            );
140
        } else {
141
            return $this->formatResponse($response);
142
        }
143
    }
144
145
    /**
146
     * Set shipper number
147
     *
148
     * @param string $shipperNumber
149
     *
150
     */
151
    public function setShipperNumber($shipperNumber)
152
    {
153
        $this->shipperNumber = $shipperNumber;
154
    }
155
156
    /**
157
     * Set begin date
158
     *
159
     * @param string $beginDate
160
     *
161
     */
162
    public function setBeginDate(DateTime $beginDate)
163
    {
164
        $this->beginDate = $beginDate;
0 ignored issues
show
Documentation Bug introduced by
It seems like $beginDate of type object<DateTime> is incompatible with the declared type string of property $beginDate.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
165
    }
166
167
    /**
168
     * Set end date
169
     *
170
     * @param string $endDate
171
     *
172
     */
173
    public function setEndDate(DateTime $endDate)
174
    {
175
        $this->endDate = $endDate;
0 ignored issues
show
Documentation Bug introduced by
It seems like $endDate of type object<DateTime> is incompatible with the declared type string of property $endDate.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
176
    }
177
178
    /**
179
     * Check if tracking number is for mail innovations.
180
     *
181
     * @return bool
182
     */
183 6
    private function isMailInnovations()
184
    {
185
        $patterns = [
186
187
            // UPS Mail Innovations tracking numbers
188 6
            '/^MI\d{6}\d{1,22}$/',// MI 000000 00000000+
189
190
            // USPS - Certified Mail
191 6
            '/^94071\d{17}$/',    // 9407 1000 0000 0000 0000 00
192 6
            '/^7\d{19}$/',        // 7000 0000 0000 0000 0000
193
194
            // USPS - Collect on Delivery
195 6
            '/^93033\d{17}$/',    // 9303 3000 0000 0000 0000 00
196 6
            '/^M\d{9}$/',         // M000 0000 00
197
198
            // USPS - Global Express Guaranteed
199 6
            '/^82\d{10}$/',       // 82 000 000 00
200
201
            // USPS - Priority Mail Express International
202 6
            '/^EC\d{9}US$/',      // EC 000 000 000 US
203
204
            // USPS - Priority Mail Express
205 6
            '/^927\d{19}$/',      // 9270 1000 0000 0000 0000 00
206 6
            '/^EA\d{9}US$/',      // EA 000 000 000 US
207
208
            // USPS - Priority Mail International
209 6
            '/^CP\d{9}US$/',      // CP 000 000 000 US
210
211
            // USPS - Priority Mail
212 6
            '/^92055\d{17}$/',    // 9205 5000 0000 0000 0000 00
213 6
            '/^14\d{18}$/',       // 1400 0000 0000 0000 0000
214
215
            // USPS - Registered Mail
216 6
            '/^92088\d{17}$/',    // 9208 8000 0000 0000 0000 00
217 6
            '/^RA\d{9}US$/',      // RA 000 000 000 US
218
219
            // USPS - Signature Confirmation
220 6
            '/^9202\d{16}US$/',   // 9202 1000 0000 0000 0000 00
221 6
            '/^23\d{16}US$/',     // 2300 0000 0000 0000 0000
222
223
            // USPS - Tracking
224 6
            '/^94\d{20}$/',       // 9400 1000 0000 0000 0000 00
225
            '/^03\d{18}$/'        // 0300 0000 0000 0000 0000
226 6
        ];
227
228 6
        foreach ($patterns as $pattern) {
229 6
            if (preg_match($pattern, $this->trackingNumber)) {
230 1
                return true;
231
            }
232 6
        }
233
234 5
        return false;
235
    }
236
237
    /**
238
     * Create the Tracking request.
239
     *
240
     * @return string
241
     */
242 6
    private function createRequest()
243
    {
244 6
        $xml = new DOMDocument();
245 6
        $xml->formatOutput = true;
246
247 6
        $trackRequest = $xml->appendChild($xml->createElement('TrackRequest'));
248 6
        $trackRequest->setAttribute('xml:lang', 'en-US');
249
250 6
        $request = $trackRequest->appendChild($xml->createElement('Request'));
251
252 6
        $node = $xml->importNode($this->createTransactionNode(), true);
253 6
        $request->appendChild($node);
254
255 6
        $request->appendChild($xml->createElement('RequestAction', 'Track'));
256
257 6
        if (null !== $this->requestOption) {
258 6
            $request->appendChild($xml->createElement('RequestOption', $this->requestOption));
259 6
        }
260
261 6
        if (null !== $this->trackingNumber) {
262 5
            $trackRequest->appendChild($xml->createElement('TrackingNumber', $this->trackingNumber));
263 5
        }
264
265 6
        if ($this->isMailInnovations()) {
266 1
            $trackRequest->appendChild($xml->createElement('IncludeMailInnovationIndicator'));
267 1
        }
268
269 6
        if (null !== $this->referenceNumber) {
270 1
            $trackRequest->appendChild($xml->createElement('ReferenceNumber'))->appendChild($xml->createElement('Value', $this->referenceNumber));
271 1
        }
272
273 6
        if (null !== $this->shipperNumber) {
274
            $trackRequest->appendChild($xml->createElement('ShipperNumber', $this->shipperNumber));
275
        }
276
277 6
        if (null !== $this->beginDate) {
278
            $beginDate = $this->beginDate->format('Ymd');
0 ignored issues
show
Bug introduced by
The method format cannot be called on $this->beginDate (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
279
            $trackRequest->appendChild($xml->createElement('BeginDate', $beginDate));
280
        }
281
282 6
        if (null !== $this->endDate) {
283
            $endDate = $this->endDate->format('Ymd');
0 ignored issues
show
Bug introduced by
The method format cannot be called on $this->endDate (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
284
            $trackRequest->appendChild($xml->createElement('EndDate', $endDate));
285
        }
286
287 6
        return $xml->saveXML();
288
    }
289
290
    /**
291
     * Format the response.
292
     *
293
     * @param SimpleXMLElement $response
294
     *
295
     * @return stdClass
296
     */
297 3
    private function formatResponse(SimpleXMLElement $response)
298
    {
299 3
        return $this->convertXmlObject($response->Shipment);
300
    }
301
302
    /**
303
     * @return RequestInterface
304
     */
305 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...
306
    {
307 6
        if (null === $this->request) {
308
            $this->request = new Request($this->logger);
309
        }
310
311 6
        return $this->request;
312
    }
313
314
    /**
315
     * @param RequestInterface $request
316
     *
317
     * @return $this
318
     */
319 6
    public function setRequest(RequestInterface $request)
320
    {
321 6
        $this->request = $request;
322
323 6
        return $this;
324
    }
325
326
    /**
327
     * @return ResponseInterface
328
     */
329 2
    public function getResponse()
330
    {
331 2
        return $this->response;
332
    }
333
334
    /**
335
     * @param ResponseInterface $response
336
     *
337
     * @return $this
338
     */
339
    public function setResponse(ResponseInterface $response)
340
    {
341
        $this->response = $response;
342
343
        return $this;
344
    }
345
}
346