Passed
Push — master ( 2b3130...72ff7b )
by Joël
01:27
created

Api::setSource()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Defro\Google\StreetView;
4
5
use Defro\Google\StreetView\Exception\BadStatusCodeException;
6
use Defro\Google\StreetView\Exception\RequestException;
7
use Defro\Google\StreetView\Exception\UnexpectedStatusException;
8
use Defro\Google\StreetView\Exception\UnexpectedValueException;
9
use GuzzleHttp\Client;
10
use GuzzleHttp\Exception\GuzzleException;
11
12
class Api
13
{
14
    const SOURCE_DEFAULT = 'default';
15
16
    const SOURCE_OUTDOOR = 'outdoor';
17
18
    /** @var string */
19
    private $endpointImage = 'https://maps.googleapis.com/maps/api/streetview';
20
21
    /** @var string */
22
    private $endpointMetadata = 'https://maps.googleapis.com/maps/api/streetview/metadata';
23
24
    /** @var \GuzzleHttp\Client */
25
    private $client;
26
27
    /** @var string */
28
    private $apiKey;
29
30
    /** @var string */
31
    private $signature;
32
33
    /** @var int */
34
    private $imageWidth = 600;
35
36
    /** @var int */
37
    private $imageHeight = 600;
38
39
    /** @var int */
40
    private $heading;
41
42
    /** @var int */
43
    private $cameraFov = 90;
44
45
    /** @var int */
46
    private $cameraPitch = 0;
47
48
    /** @var int */
49
    private $radius = 50;
50
51
    /** @var string */
52
    private $source = 'default';
53
54
55
    /**
56
     * Api constructor.
57
     *
58
     * @param Client $client
59
     */
60 21
    public function __construct(Client $client)
61
    {
62 21
        $this->client = $client;
63 21
    }
64
65
    /**
66
     * API key from your Google console
67
     *
68
     * @param string $apiKey
69
     * @return $this
70
     */
71
    public function setApiKey(string $apiKey): self
72
    {
73
        $this->apiKey = $apiKey;
74
75
        return $this;
76
    }
77
78
    /**
79
     * Digital signature used to verify that any site generating requests.
80
     *
81
     * @param string $signature
82
     * @return $this
83
     */
84
    public function setSignature(string $signature): self
85
    {
86
        $this->signature = $signature;
87
88
        return $this;
89
    }
90
91
    /**
92
     * Determines the horizontal field of view of the image.
93
     * The field of view is expressed in degrees, with a maximum allowed value of 120.
94
     * When dealing with a fixed-size viewport, as with a Street View image of a set size,
95
     * field of view in essence represents zoom, with smaller numbers indicating a higher level of zoom.
96
     *
97
     * @param int $cameraFov
98
     * @return $this
99
     * @throws UnexpectedValueException
100
     */
101 2
    public function setCameraFov(int $cameraFov): self
102
    {
103 2
        if ($cameraFov > 120) {
104 1
            throw new UnexpectedValueException(
105 1
                'Camera FOV value cannot exceed 120 degrees.'
106
            );
107
        }
108
109 1
        $this->cameraFov = $cameraFov;
110
111 1
        return $this;
112
    }
113
114
    /**
115
     * Specifies the up or down angle of the camera relative to the Street View vehicle.
116
     * This is often, but not always, flat horizontal.
117
     * Positive values angle the camera up (with 90 degrees indicating straight up);
118
     * negative values angle the camera down (with -90 indicating straight down).
119
     *
120
     * @param int $cameraPitch
121
     * @return $this
122
     * @throws UnexpectedValueException
123
     */
124 3
    public function setCameraPitch(int $cameraPitch):self
125
    {
126 3
        if ($cameraPitch > 90) {
127 1
            throw new UnexpectedValueException(
128 1
                'Camera pitch value for Google Street View cannot exceed 90 degrees.'
129
            );
130
        }
131 2
        if ($cameraPitch < -90) {
132 1
            throw new UnexpectedValueException(
133 1
                'Camera pitch value for Google Street View cannot be inferior of -90 degrees.'
134
            );
135
        }
136
137 1
        $this->cameraPitch = $cameraPitch;
138
139 1
        return $this;
140
    }
141
142
    /**
143
     * Sets a radius, specified in meters,
144
     * in which to search for a panorama, centered on the given latitude and longitude.
145
     * Valid values are non-negative integers.
146
     *
147
     * @param int $radius
148
     * @return $this
149
     * @throws UnexpectedValueException
150
     */
151 2
    public function setRadius(int $radius): self
152
    {
153 2
        if ($radius < 0) {
154 1
            throw new UnexpectedValueException(
155 1
                'Radius value cannot be negative.'
156
            );
157
        }
158
159 1
        $this->radius = $radius;
160
161 1
        return $this;
162
    }
163
164
    /**
165
     * Indicates the compass heading of the camera.
166
     * Accepted values are from 0 to 360 (both values indicating North, with 90 indicating East, and 180 South).
167
     *
168
     * @param int $heading
169
     * @return $this
170
     * @throws UnexpectedValueException
171
     */
172 3
    public function setHeading(int $heading): self
173
    {
174 3
        if ($heading < 0) {
175 1
            throw new UnexpectedValueException(
176 1
                'Heading value cannot be inferior to zero degree.'
177
            );
178
        }
179 2
        if ($heading > 360) {
180 1
            throw new UnexpectedValueException(
181 1
                'Heading value cannot exceed 360 degrees.'
182
            );
183
        }
184
185 1
        $this->heading = $heading;
186
187 1
        return $this;
188
    }
189
190
    /**
191
     * Limits Street View searches to selected sources. Valid values are:
192
     *  - default uses the default sources for Street View; searches are not limited to specific sources.
193
     *  - outdoor limits searches to outdoor collections.
194
     *
195
     * @param string $source
196
     * @return $this
197
     * @throws UnexpectedValueException
198
     */
199 2
    public function setSource(string $source): self
200
    {
201 2
        if (!in_array($source, [self::SOURCE_DEFAULT, self::SOURCE_OUTDOOR], true)) {
202 1
            throw new UnexpectedValueException(sprintf(
203 1
                'Source value "%s" is unknown, only "%s" or "%s" values expected.',
204 1
                $source, self::SOURCE_DEFAULT, self::SOURCE_OUTDOOR
205
            ));
206
        }
207
208 1
        $this->source = $source;
209
210 1
        return $this;
211
    }
212
213
    /**
214
     * @param int $height
215
     * @return $this
216
     * @throws UnexpectedValueException
217
     */
218 2
    public function setImageHeight(int $height): self
219
    {
220 2
        if ($height < 1) {
221 1
            throw new UnexpectedValueException(
222 1
                'Image height value cannot be negative or equal to zero.'
223
            );
224
        }
225
226 1
        $this->imageHeight = $height;
227
228 1
        return $this;
229
    }
230
231
    /**
232
     * @param int $width
233
     * @return $this
234
     * @throws UnexpectedValueException
235
     */
236 2
    public function setImageWidth(int $width): self
237
    {
238 2
        if ($width < 1) {
239 1
            throw new UnexpectedValueException(
240 1
                'Image height value cannot be negative or equal to zero.'
241
            );
242
        }
243
244 1
        $this->imageWidth = $width;
245
246 1
        return $this;
247
    }
248
249
    /**
250
     * Returns URL to a static (non-interactive) Street View panorama or thumbnail.
251
     *
252
     * @param string $location
253
     * @return string
254
     * @throws BadStatusCodeException
255
     */
256
    public function getImageUrlByLocation(string $location): string
257
    {
258
        $parameters = $this->getRequestParameters([
259
            'location' => $location
260
        ]);
261
262
        return $this->getImageUrl($parameters);
263
    }
264
265
    /**
266
     * Returns URL to a static (non-interactive) Street View panorama or thumbnail
267
     *
268
     * @param float $latitude
269
     * @param float $longitude
270
     * @return string
271
     * @throws BadStatusCodeException
272
     */
273
    public function getImageUrlByLatitudeAndLongitude(float $latitude, float $longitude): string
274
    {
275
        $parameters = $this->getRequestParameters([
276
            'location' => $latitude . ',' . $longitude
277
        ]);
278
279
        return $this->getImageUrl($parameters);
280
    }
281
282
    /**
283
     * Returns URL to a static (non-interactive) Street View panorama or thumbnail
284
     *
285
     * @param string $panoramaId
286
     * @return string
287
     * @throws BadStatusCodeException
288
     */
289
    public function getImageUrlByPanoramaId(string $panoramaId): string
290
    {
291
        $parameters = $this->getRequestParameters([
292
            'pano' => $panoramaId
293
        ]);
294
295
        return $this->getImageUrl($parameters);
296
    }
297
298
    /**
299
     * Returns URL to a static (non-interactive) Street View panorama or thumbnail
300
     * The viewport is defined with URL parameters sent through a standard HTTP request, and is returned as a static image.
301
     *
302
     * @param array $parameters
303
     * @return string
304
     * @throws BadStatusCodeException
305
     */
306
    private function getImageUrl(array $parameters): string
307
    {
308
        $uri = $this->endpointImage . '?' . http_build_query($parameters);
309
310
        $response = $this->client->get($uri);
311
312
        if ($response->getStatusCode() !== 200) {
313
            throw new BadStatusCodeException(
314
                'Could not connect to ' . $this->endpointImage,
315
                $response->getStatusCode()
316
            );
317
        }
318
319
        return $uri;
320
    }
321
322
    /**
323
     * Requests provide data about Street View panoramas.
324
     * Using the metadata, you can find out if a Street View image is available at a given location,
325
     * as well as getting programmatic access to the latitude and longitude,
326
     * the panorama ID, the date the photo was taken, and the copyright information for the image.
327
     * Accessing this metadata allows you to customize error behavior in your application.
328
     * Street View API metadata requests are free to use. No quota is consumed when you request metadata.
329
     *
330
     * @param string $location
331
     * @return array
332
     * @throws UnexpectedValueException
333
     * @throws RequestException
334
     * @throws BadStatusCodeException
335
     * @throws UnexpectedStatusException
336
     */
337 5
    public function getMetadata(string $location): array
338
    {
339 5
        $location = trim($location);
340
341 5
        if (empty($location)) {
342 1
            throw new UnexpectedValueException(
343 1
                'Location argument cannot be empty to request Google Street view API Metadata.'
344
            );
345
        }
346
347 4
        $payload = $this->getRequestPayload(compact('location'));
348
349
        try {
350 4
            $response = $this->client->request('GET', $this->endpointMetadata, $payload);
351
        }
352 1
        catch (GuzzleException $e) {
353 1
            throw new RequestException(
354 1
                'Guzzle http client request failed.', $e
0 ignored issues
show
Documentation introduced by
$e is of type object<GuzzleHttp\Exception\GuzzleException>, but the function expects a null|object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
355
            );
356
        }
357
358 3
        if ($response->getStatusCode() !== 200) {
359 1
            throw new BadStatusCodeException(
360 1
                'Could not connect to ' . $this->endpointMetadata,
361 1
                $response->getStatusCode()
362
            );
363
        }
364
365 2
        $response = json_decode($response->getBody());
366
367
        // Indicates that no errors occurred; a panorama is found and metadata is returned.
368 2
        if ($response->status === 'OK') {
369 1
            return $this->formatMetadataResponse($response);
370
        }
371
        // Indicates that no panorama could be found near the provided location.
372
        // This may occur if a non-existent or invalid panorama ID is given.
373 1
        if ($response->status === 'ZERO_RESULTS') {
374 1
            throw new UnexpectedStatusException('Google Street view return zero results.');
375
        }
376
        // Indicates that the address string provided in the location parameter could not be found.
377
        // This may occur if a non-existent address is given.
378
        if ($response->status === 'NOT_FOUND') {
379
            throw new UnexpectedStatusException('No Google Street view result found.');
380
        }
381
        // Indicates that you have exceeded your daily quota or per-second quota for this API.
382
        if ($response->status === 'OVER_QUERY_LIMIT') {
383
            throw new UnexpectedStatusException('Google Street view API quota exceed.');
384
        }
385
        // Indicates that your request was denied.
386
        // This may occur if you did not use an API key or client ID, or
387
        // if the Street View API is not activated in the Google Cloud Platform Console project containing your API key.
388
        if ($response->status === 'REQUEST_DENIED') {
389
            throw new UnexpectedStatusException('Google Street view denied the request.');
390
        }
391
        // Generally indicates that the query parameters (address or latlng or components) are missing.
392
        if ($response->status === 'INVALID_REQUEST') {
393
            throw new UnexpectedStatusException('Google Street view request is invalid.');
394
        }
395
        // Indicates that the request could not be processed due to a server error.
396
        // This is often a temporary status. The request may succeed if you try again.
397
        if ($response->status === 'UNKNOWN_ERROR') {
398
            throw new UnexpectedStatusException('Google Street view unknown error occurred. Please try again.');
399
        }
400
401
        throw new UnexpectedStatusException(
402
            'Google Street view respond an unknown status response : "' . $response->status . '".'
403
        );
404
    }
405
406 1
    protected function formatMetadataResponse($response): array
407
    {
408
        return [
409 1
            'lat'           => $response->location->lat,
410 1
            'lng'           => $response->location->lng,
411 1
            'date'          => $response->date,
412 1
            'copyright'     => $response->copyright,
413 1
            'panoramaId'    => $response->pano_id
414
        ];
415
    }
416
417 4
    private function getRequestPayload(array $parameters): array
418
    {
419 4
        return ['query' => $this->getRequestParameters($parameters)];
420
    }
421
422 4
    private function getRequestParameters(array $parameters): array
423
    {
424
        $defaultParameters = [
425 4
            'key'       => $this->apiKey,
426 4
            'size'      => $this->imageWidth . 'x' . $this->imageHeight,
427 4
            'fov'       => $this->cameraFov,
428 4
            'pitch'     => $this->cameraPitch,
429 4
            'radius'    => $this->radius,
430 4
            'source'    => $this->source
431
        ];
432
433
        // optional parameters which have not default value
434 4
        if ($this->heading) {
435
            $defaultParameters['heading'] = $this->heading;
436
        }
437 4
        if ($this->signature) {
438
            $defaultParameters['signature'] = $this->signature;
439
        }
440
441 4
        return array_merge($defaultParameters, $parameters);
442
    }
443
444
}
445