AbstractRoutingQuery::addWaypoint()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace DH\NavigationBundle\Contract\Routing;
4
5
use DateTime;
6
use DH\NavigationBundle\Exception\InvalidArgumentException;
7
use DH\NavigationBundle\Exception\ResponseException;
8
use DH\NavigationBundle\Exception\WaypointException;
9
use DH\NavigationBundle\Provider\ProviderInterface;
10
use Psr\Http\Message\ResponseInterface;
11
12
abstract class AbstractRoutingQuery implements RoutingQueryInterface
13
{
14
    /**
15
     * @var ProviderInterface
16
     */
17
    private $provider;
18
19
    /**
20
     * @var array
21
     */
22
    protected $waypoints;
23
24
    /**
25
     * @var DateTime|null
26
     */
27
    private $departure_time;
28
29
    /**
30
     * @var DateTime|null
31
     */
32
    private $arrival_time;
33
34
    /**
35
     * @var string|null
36
     */
37
    private $language;
38
39
    /**
40
     * RoutingQuery constructor.
41
     */
42
    public function __construct(ProviderInterface $provider)
43
    {
44
        $this->provider = $provider;
45
        $this->waypoints = [];
46
    }
47
48
    public function getProvider(): ProviderInterface
49
    {
50
        return $this->provider;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getDepartureTime(): ?DateTime
57
    {
58
        return $this->departure_time;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function setDepartureTime(DateTime $departureTime): RoutingQueryInterface
65
    {
66
        $this->departure_time = $departureTime;
67
68
        return $this;
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74
    public function getArrivalTime(): ?DateTime
75
    {
76
        return $this->arrival_time;
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82
    public function setArrivalTime(DateTime $arrivalTime): RoutingQueryInterface
83
    {
84
        $this->arrival_time = $arrivalTime;
85
86
        return $this;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function setLanguage(string $language): RoutingQueryInterface
93
    {
94
        $this->language = $language;
95
96
        return $this;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getLanguage(): string
103
    {
104
        return $this->language ?? 'en-US';
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function addWaypoint(string $waypoint): RoutingQueryInterface
111
    {
112
        $this->waypoints[] = $waypoint;
113
114
        return $this;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function getWaypoints(): array
121
    {
122
        return $this->waypoints;
123
    }
124
125
    /**
126
     * @throws ResponseException
127
     * @throws WaypointException
128
     * @throws \GuzzleHttp\Exception\GuzzleException
129
     * @throws InvalidArgumentException
130
     *
131
     * {@inheritdoc}
132
     */
133
    public function execute(): RoutingResponseInterface
134
    {
135
        $this->validateRequest();
136
        $request = $this->buildRequest();
137
        $rawResponse = $this->request('GET', $request);
138
        $response = $this->buildResponse($rawResponse);
139
        $this->validateResponse($response);
140
141
        return $response;
142
    }
143
144
    abstract protected function buildRequest(): string;
145
146
    abstract protected function buildResponse(ResponseInterface $response): RoutingResponseInterface;
147
148
    /**
149
     * @throws \GuzzleHttp\Exception\GuzzleException
150
     */
151
    private function request(string $method, string $url): ResponseInterface
152
    {
153
        $client = $this->getProvider()->getClient();
154
        $response = $client->request($method, $url);
155
156
        if (200 !== $response->getStatusCode()) {
157
            throw new \Exception('Response with status code '.$response->getStatusCode());
158
        }
159
160
        return $response;
161
    }
162
163
    /**
164
     * @throws ResponseException
165
     */
166
    private function validateResponse(RoutingResponseInterface $response): void
167
    {
168
        switch ($response->getStatus()) {
169
            case RoutingResponseInterface::RESPONSE_STATUS_OK:
170
                break;
171
            case RoutingResponseInterface::RESPONSE_STATUS_INVALID_REQUEST:
172
                throw new ResponseException('Invalid request.', 1);
173
                break;
174
            case RoutingResponseInterface::RESPONSE_STATUS_MAX_ELEMENTS_EXCEEDED:
175
                throw new ResponseException('The product of the origin and destination exceeds the limit per request.', 2);
176
                break;
177
            case RoutingResponseInterface::RESPONSE_STATUS_OVER_QUERY_LIMIT:
178
                throw new ResponseException('The service has received too many requests from your application in the allowed time range.', 3);
179
                break;
180
            case RoutingResponseInterface::RESPONSE_STATUS_REQUEST_DENIED:
181
                throw new ResponseException('The service denied the use of the Distance Matrix API service by your application.', 4);
182
                break;
183
            case RoutingResponseInterface::RESPONSE_STATUS_UNKNOWN_ERROR:
184
                throw new ResponseException('Unknown error.', 5);
185
                break;
186
            default:
187
                throw new ResponseException(sprintf('Unknown status code: %s', $response->getStatus()), 6);
188
                break;
189
        }
190
    }
191
192
    /**
193
     * @throws InvalidArgumentException
194
     * @throws WaypointException
195
     */
196
    private function validateRequest(): void
197
    {
198
        if (empty($this->getWaypoints()) || \count($this->getWaypoints()) < 2) {
199
            throw new WaypointException('At least two waypoints must be set.');
200
        }
201
202
        if (null !== $this->getDepartureTime() && null !== $this->getArrivalTime()) {
203
            throw new InvalidArgumentException('departure_time and arrival_time cannot be both specified at the same time.');
204
        }
205
    }
206
}
207