Passed
Push — master ( 314ee7...e7a650 )
by Radosław
02:20
created

Bing::handleErrorResponse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 11
c 0
b 0
f 0
ccs 7
cts 7
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Radowoj\Searcher\SearchProvider;
4
5
use stdClass;
6
7
use GuzzleHttp\Client as GuzzleClient;
8
use GuzzleHttp\Psr7\Response as GuzzleResponse;
9
10
use Radowoj\Searcher\SearchResult\Collection;
11
use Radowoj\Searcher\SearchResult\ICollection;
12
use Radowoj\Searcher\SearchResult\Item;
13
use Radowoj\Searcher\SearchResult\IItem;
14
15
use Radowoj\Searcher\Exceptions\Exception;
16
use Radowoj\Searcher\Exceptions\QuotaExceededException;
17
use Radowoj\Searcher\Exceptions\RateLimitExceededException;
18
19
class Bing extends SearchProvider implements ISearchProvider
20
{
21
    const URI = 'https://api.cognitive.microsoft.com/bing/v5.0/search?';
22
    const API_KEY_HEADER = 'Ocp-Apim-Subscription-Key';
23
24
    protected $apiKey = null;
25
26
    protected $guzzle = null;
27
28 10
    public function __construct(GuzzleClient $guzzle, string $apiKey)
29
    {
30 10
        $this->apiKey = $apiKey;
31 10
        $this->guzzle = $guzzle;
32 10
    }
33
34
35 9
    protected function searchRequest(string $query, int $limit, int $offset) : stdClass
36
    {
37
        $params = [
38 9
            'q' => $query,
39 9
            'count' => $limit,
40 9
            'offset' => $offset
41
        ];
42
43 9
        $queryString = http_build_query($params);
44
45 9
        $uri = self::URI . $queryString;
46
47 9
        $result = $this->guzzle->request(
48 9
            'GET',
49
            $uri, [
50
                'headers' => [
51 9
                    self::API_KEY_HEADER => $this->apiKey,
52 9
                ],
53
                'http_errors' => false,
54
            ]
55
        );
56
57 9
        if ($result->getStatusCode() !== 200) {
58 3
            $this->handleErrorResponse($result);
0 ignored issues
show
Compatibility introduced by
$result of type object<Psr\Http\Message\ResponseInterface> is not a sub-type of object<GuzzleHttp\Psr7\Response>. It seems like you assume a concrete implementation of the interface Psr\Http\Message\ResponseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
59
        }
60
61 6
        return json_decode($result->getBody());
62
    }
63
64
65
    /**
66
     * Handle 4xx responses (usually quota or rate limit, so authorisation and other stuff will be thrown as
67
     * generic Searcher exception)
68
     * @param  GuzzleResponse $result result from Guzzle
69
     * @TODO this should be called in base SearchProvider search() template method, needs refactoring
70
     */
71 3
    protected function handleErrorResponse(GuzzleResponse $result)
72
    {
73 3
        switch($result->getStatusCode()) {
74 3
            case 403:   //Out of call volume quota
75 1
                throw new QuotaExceededException($result->getReasonPhrase());
76 2
            case 429:   //Rate limit is exceeded
77 1
                throw new RateLimitExceededException($result->getReasonPhrase());
78
            default:
79 1
                throw new Exception("Bing API responded with HTTP status {$result->getStatusCode()} - {$result->getReasonPhrase()}");
80
        }
81
    }
82
83
84 6
    protected function validateRequestResult(stdClass $result)
85
    {
86 6
        if (!isset($result->_type) || $result->_type !== 'SearchResponse') {
87 1
            throw new Exception("Invalid Bing API response: " . print_r($result, 1));
88
        }
89 5
    }
90
91
92 5
    protected function enforceLimit(stdClass $result, int $limit) : stdClass
93
    {
94 5
        if (!isset($result->webPages->value)) {
95 1
            return $result;
96
        }
97 4
        $result->webPages->value = array_slice($result->webPages->value, 0, $limit);
98 4
        return $result;
99
    }
100
101
102 5
    protected function extractResults(stdClass $result) : array
103
    {
104 5
        return isset($result->webPages->value)
105 4
            ? $result->webPages->value
106 5
            : [];
107
    }
108
109
110 5
    protected function extractTotalMatches(stdClass $result) : int
111
    {
112 5
        return isset($result->webPages->totalEstimatedMatches)
113 4
            ? $result->webPages->totalEstimatedMatches
114 5
            : 0;
115
    }
116
117
118 1
    protected function populateItem(stdClass $item) : IItem
119
    {
120 1
        return new Item([
121 1
            'url' => preg_match('/^https?:\/\//', $item->url)
122 1
                ? $item->url
123 1
                : "http://{$item->url}",
124 1
            'title' => $item->name,
125 1
            'description' => $item->snippet,
126
        ]);
127
    }
128
129
}
130