Completed
Push — master ( 6297da...4ca00a )
by Antoine
02:04
created

Fetcher::extractBook()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 21
rs 9.3142
cc 2
eloc 16
nc 2
nop 1
1
<?php
2
3
namespace AntoineAugusti\Books;
4
5
use DateTime;
6
use GuzzleHttp\ClientInterface;
7
use InvalidArgumentException;
8
9
class Fetcher
10
{
11
    /**
12
     * @var ClientInterface
13
     */
14
    private $client;
15
16
    /**
17
     * @param ClientInterface $client
18
     */
19
    public function __construct(ClientInterface $client)
20
    {
21
        $this->client = $client;
22
    }
23
24
    /**
25
     * Retrieve information about a book given its ISBN.
26
     *
27
     * @param string $isbn
28
     *
29
     * @throws InvalidArgumentException When the ISBN has not the expected format
30
     * @throws InvalidResponseException When the client got an unexpected response
31
     *
32
     * @return Book
33
     */
34
    public function forISBN($isbn)
35
    {
36
        if (!$this->isValidISBN($isbn)) {
37
            throw new InvalidArgumentException('ISBN is not valid. Got: '.$isbn);
38
        }
39
40
        // Example: https://www.googleapis.com/books/v1/volumes?q=isbn:9780142181119
41
        $response = $this->client->request('GET', 'volumes', [
42
            'query'       => ['q' => 'isbn:'.$isbn],
43
            'http_errors' => false,
44
        ]);
45
46
        $status = $response->getStatusCode();
47
        if ($status != 200) {
48
            throw new InvalidResponseException('Invalid response. Status: '.$status.'. Body: '.$response->getBody());
49
        }
50
51
        $res = json_decode($response->getBody(), true);
52
53
        $totalItems = intval($res['totalItems']);
54
        if ($totalItems != 1) {
55
            throw new InvalidResponseException('Did not get 1 result. Got: '.$totalItems);
56
        }
57
58
        return $this->extractBook($res);
59
    }
60
61
    private function extractBook($res)
62
    {
63
        $item = $res['items'][0];
64
65
        $publishedDate = null;
66
        if (array_key_exists('publishedDate', $item['volumeInfo'])) {
67
            $publishedDate = DateTime::createFromFormat('Y-m-d', $item['volumeInfo']['publishedDate'])->setTime(0, 0);
68
        }
69
70
        return new Book($item['volumeInfo']['title'],
71
            $this->getOrDefault($item['volumeInfo'], 'subtitle', null),
72
            $this->getOrDefault($item['volumeInfo'], 'authors', null),
73
            $this->getOrDefault($item['volumeInfo'], 'printType', null),
74
            intval($this->getOrDefault($item['volumeInfo'], 'pageCount', null)),
75
            $this->getOrDefault($item['volumeInfo'], 'publisher', null),
76
            $publishedDate,
77
            $this->getOrDefault($item['volumeInfo'], 'averageRating', null),
78
            $item['volumeInfo']['imageLinks']['thumbnail'],
79
            $this->getOrDefault($item['volumeInfo'], 'language', null),
80
            $this->getOrDefault($item['volumeInfo'], 'categories', []));
81
    }
82
83
    private function getOrDefault($array, $key, $default)
84
    {
85
        if (array_key_exists($key, $array)) {
86
            return $array[$key];
87
        }
88
89
        return $default;
90
    }
91
92
    /**
93
     * Check if a given ISBN is valid.
94
     *
95
     * @param string $isbn
96
     *
97
     * @return bool
98
     */
99
    private function isValidISBN($isbn)
100
    {
101
        return preg_match('/[0-9]{10,13}/', $isbn);
102
    }
103
}
104