USPSTracker   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 9
dl 0
loc 139
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 2
A getUserId() 0 4 1
A setUserId() 0 5 1
A request() 0 4 1
A buildXml() 0 11 1
B track() 0 25 6
C buildShipment() 0 41 12
1
<?php
2
/**
3
 * Slince shipment tracker library
4
 * @author Tao <[email protected]>
5
 */
6
namespace Slince\ShipmentTracking\USPS;
7
8
use Carbon\Carbon;
9
use Psr\Http\Message\ResponseInterface;
10
use Slince\ShipmentTracking\Foundation\Exception\TrackException;
11
use Slince\ShipmentTracking\Foundation\HttpAwareTracker;
12
use GuzzleHttp\Client as HttpClient;
13
use Slince\ShipmentTracking\Foundation\Shipment;
14
use Slince\ShipmentTracking\Utility;
15
16
class USPSTracker extends HttpAwareTracker
17
{
18
    const TRACKING_ENDPOINT  = 'http://production.shippingapis.com/ShippingAPI.dll';
19
20
    /**
21
     * @var string
22
     */
23
    protected $userId;
24
25
    /**
26
     * You can get your userID from the following url
27
     * {@link https://www.usps.com/business/web-tools-apis/welcome.htm}
28
     */
29
    public function __construct($userId, HttpClient $httpClient = null)
30
    {
31
        $this->userId = $userId;
32
        $httpClient && $this->setHttpClient($httpClient);
33
    }
34
35
    /**
36
     * @return string
37
     */
38
    public function getUserId()
39
    {
40
        return $this->userId;
41
    }
42
43
    /**
44
     * @param string $userId
45
     * @return USPSTracker
46
     */
47
    public function setUserId($userId)
48
    {
49
        $this->userId = $userId;
50
        return $this;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function track($trackingNumber)
57
    {
58
        try {
59
            $response = $this->request([
60
                'query' => [
61
                    'API' => 'TrackV2',
62
                    'XML' => static::buildXml($this->userId, $trackingNumber)
63
                ]
64
            ]);
65
            $array = Utility::parseXml($response->getBody());
66
        } catch (\Exception $exception) {
67
            throw new TrackException($exception->getMessage());
68
        }
69
        if (!isset($array['TrackInfo'])) {
70
            throw new TrackException($array['Description']);
71
        }
72
        if (isset($array['TrackInfo']['Error'])) {
73
            throw new TrackException($array['TrackInfo']['Error']['Description']);
74
        }
75
        if (!isset($array['TrackInfo']['TrackSummary']) && !isset($array['TrackInfo']['TrackDetail'])) {
76
            throw new TrackException('Cannot find any events');
77
        }
78
        $shipment = static::buildShipment($array);
79
        return $shipment;
80
    }
81
82
    /**
83
     * @param array $options
84
     * @return ResponseInterface
85
     * @codeCoverageIgnore
86
     */
87
    protected function request($options)
88
    {
89
        return $this->getHttpClient()->get(static::TRACKING_ENDPOINT, $options);
90
    }
91
92
    /**
93
     * @param string $userId
94
     * @param string $trackID
95
     * @return string
96
     */
97
    protected static function buildXml($userId, $trackID)
98
    {
99
        $xmlTemplate = <<<XML
100
<?xml version="1.0" encoding="UTF-8" ?>
101
<TrackFieldRequest USERID="%s">
102
  <ClientIp>111.0.0.1</ClientIp>
103
  <TrackID ID="%s"></TrackID>
104
</TrackFieldRequest>
105
XML;
106
        return sprintf($xmlTemplate, $userId, $trackID);
107
    }
108
109
    /**
110
     * @param array $array
111
     * @return Shipment
112
     */
113
    protected static function buildShipment($array)
114
    {
115
        if (!empty($array['TrackInfo']['TrackDetail'])) {
116
            $trackDetails = is_numeric(key($array['TrackInfo']['TrackDetail']))
117
                ? $array['TrackInfo']['TrackDetail']
118
                : [$array['TrackInfo']['TrackDetail']];
119
        } else {
120
            $trackDetails =  [];
121
        }
122
        //The track summary is also valid
123
        if (isset($array['TrackInfo']['TrackSummary'])) {
124
            array_unshift($trackDetails, $array['TrackInfo']['TrackSummary']);
125
        }
126
        $events = array_map(function($eventData){
127
            $time = empty($eventData['EventTime']) ? '' : $eventData['EventTime'];
128
            $day = empty($eventData['EventDate']) ? '' : $eventData['EventDate'];
129
            $country = empty($eventData['EventCountry']) ? '' : $eventData['EventCountry'];
130
            $state = empty($eventData['EventState']) ? '' : $eventData['EventState'];
131
            $city = empty($eventData['EventCity']) ? '' : $eventData['EventCity'];
132
            $zipCode = empty($eventData['EventZIPCode']) ? '' : $eventData['EventZIPCode'];
133
            return ShipmentEvent::fromArray([
134
                'day' => $day,
135
                'city' => $city,
136
                'state' => $state,
137
                'country' => $country,
138
                'date' => Carbon::parse("{$day} {$time}"),
139
                'location' => new Location($country, $state, $city),
140
                'description' => $eventData['Event'],
141
                'zipCode' => $zipCode
142
            ]);
143
        }, array_reverse($trackDetails));
144
        
145
        $shipment = new Shipment($events);
146
        if (isset($array['TrackInfo']['TrackSummary']['DeliveryAttributeCode'])) {
147
            $shipment->setIsDelivered($array['TrackInfo']['TrackSummary']['DeliveryAttributeCode'] == '01');
148
        }
149
        if ($firstEvent = reset($events)) {
150
            $shipment->setDeliveredAt($firstEvent->getDate());
151
        }
152
        return $shipment;
153
    }
154
}