Completed
Pull Request — master (#3)
by
unknown
01:27
created

GoogleBooks   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 23
c 3
b 0
f 1
lcom 1
cbo 7
dl 0
loc 147
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 17 6
C raw() 0 43 8
A getItem() 0 4 1
A chunk() 0 8 2
B listItems() 0 21 6
1
<?php
2
3
namespace Scriptotek\GoogleBooks;
4
5
use GuzzleHttp\Client;
6
7
class GoogleBooks
8
{
9
    /**
10
     * @var string
11
     */
12
    protected $baseUri = 'https://www.googleapis.com/books/v1/';
13
14
    /**
15
     * @var integer (Number of results to retrieve per batch, between 1 and 40)
16
     */
17
    protected $batchSize = 40;
18
19
    /**
20
     * @var Client
21
     */
22
    protected $http;
23
24
    /**
25
     * @var key string API key
26
     */
27
    protected $key;
28
29
    /**
30
     * @var country string 2 letter ISO 639 country code.
31
     *
32
     * The Books API must honor copyright laws from various countries, and have
33
     * country-specific rights from publishers. It uses the IP address of the
34
     * client to geo-locate the user, but if this fails for some reason, it will
35
     * return 403 Forbidden with reason "unknownLocation". To avoid this, we can
36
     * manually set the country code.
37
     */
38
    protected $country;
39
40
    /**
41
     * @var Volumes
42
     */
43
    public $volumes;
44
45
    /**
46
     * @var Bookshelves
47
     */
48
    public $bookshelves;
49
    
50
    /**
51
     * @var maxResults
52
     */
53
    public $maxResults;
54
55
    public function __construct($options = [])
56
    {
57
        $this->http = new Client([
58
            'base_uri' => $this->baseUri,
59
            'handler' => isset($options['handler']) ? $options['handler'] : null,
60
        ]);
61
62
        $this->key = isset($options['key']) ? $options['key'] : null;
63
        $this->country = isset($options['country']) ? $options['country'] : null;
64
65
        $this->volumes = new Volumes($this);
66
        $this->bookshelves = new Bookshelves($this);
67
68
        $this->batchSize = isset($options['batchSize']) ? $options['batchSize'] : 40;
69
70
        $this->maxResults = isset($options['maxResults']) ? $options['maxResults'] : null;
71
    }
72
73
    protected function raw($endpoint, $params = [], $method='GET')
74
    {
75
        if (!is_null($this->key)) {
76
            $params['key'] = $this->key;
77
        }
78
        if (!is_null($this->country)) {
79
            $params['country'] = $this->country;
80
        }
81
82
        if (!is_null($this->maxResults)) {
83
            $params['maxResults'] = $this->maxResults;
84
        }
85
86
        try {
87
            $response = $this->http->request($method, $endpoint, [
88
                'query' => $params,
89
            ]);
90
        } catch (\GuzzleHttp\Exception\ClientException $e) {
91
            // 400 level errors
92
            if ($e->getResponse()->getStatusCode() == 403) {
93
                $json = json_decode($e->getResponse()->getBody());
94
95
                $domain = $json->error->errors[0]->domain;
96
                $reason = $json->error->errors[0]->reason;
97
                $message = $json->error->errors[0]->message;
98
99
                if ($domain == 'usageLimits') {
100
                    throw new Exceptions\UsageLimitExceeded($message, $reason);
101
                }
102
            }
103
104
            throw $e;
105
106
        } catch (\GuzzleHttp\Exception\RequestException $e) {
107
            // networking error (connection timeout, DNS errors, etc.)
108
109
            // TODO: sleep and retry
110
111
            throw $e;
112
        }
113
114
        return json_decode($response->getBody());
115
    }
116
117
    public function getItem($path)
118
    {
119
        return $this->raw($path);
120
    }
121
122
    public function chunk(\Generator $generator, int $chunkInt)
123
    {
124
        $chunk = [];
125
        foreach ($generator as $gen) {
126
            $chunk[] = $generator->current();
127
        }
128
        return array_chunk($chunk, $chunkInt);
129
    }
130
131
    public function listItems($endpoint, $params = [])
132
    {
133
        $params['maxResults'] = $this->batchSize;
134
135
        $i = 0;
136
        while (true) {
137
            $n = $i % $this->batchSize;
138
            if ($n == 0) {
139
                $params['startIndex'] = $i;
140
                $response = $this->raw($endpoint, $params);
141
            }
142
            if (isset($response->totalItems) && $i >= $response->totalItems) {
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
143
                return;
144
            }
145
            if (!isset($response->items[$n])) {
146
                return;
147
            }
148
            yield $response->items[$n];
149
            $i++;
150
        }
151
    }
152
153
}
154