Completed
Push — master ( 2851a0...d0aa61 )
by Taosikai
10:36
created

USPSTracker::track()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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