Passed
Push — v3.x ( 2fbc6e...8e9931 )
by Chad
02:26
created

Client::send()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 13
nc 4
nop 3
1
<?php
2
3
namespace Chadicus\Marvel\Api;
4
5
use GuzzleHttp;
6
use Psr\SimpleCache\CacheInterface;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * PHP Client for the Marvel API.
11
 */
12
class Client implements ClientInterface
13
{
14
    /**
15
     * The default ttl for cached responses (24 hours).
16
     *
17
     * @link http://developer.marvel.com/documentation/attribution Marvel's rules for caching.
18
     *
19
     * @const integer
20
     */
21
    const MAX_TTL = 86400;
22
23
    /**
24
     * The public api key issued by Marvel.
25
     *
26
     * @var string
27
     */
28
    private $publicApiKey;
29
30
    /**
31
     * The private api key issued by Marvel.
32
     *
33
     * @var string
34
     */
35
    private $privateApiKey;
36
37
    /**
38
     * Guzzle HTTP Client implementation.
39
     *
40
     * @var GuzzleHttp\ClientInterface
41
     */
42
    private $guzzleClient;
43
44
    /**
45
     * Cache implementation.
46
     *
47
     * @var CacheInterface
48
     */
49
    private $cache;
50
51
    /**
52
     * The Marvel API url.
53
     *
54
     * @const string
55
     */
56
    const BASE_URL = 'http://gateway.marvel.com/v1/public/';
57
58
    /**
59
     * Construct a new Client.
60
     *
61
     * @param string                     $privateApiKey The private api key issued by Marvel.
62
     * @param string                     $publicApiKey  The public api key issued by Marvel.
63
     * @param GuzzleHttp\ClientInterface $guzzleClient  Implementation of a Guzzle HTTP client.
64
     * @param CacheInterface             $cache         Implementation of Cache.
65
     */
66
    final public function __construct(
67
        string $privateApiKey,
68
        string $publicApiKey,
69
        GuzzleHttp\ClientInterface $guzzleClient = null,
70
        CacheInterface $cache = null
71
    ) {
72
        $this->privateApiKey = $privateApiKey;
73
        $this->publicApiKey = $publicApiKey;
74
        $this->guzzleClient = $guzzleClient ?: new GuzzleHttp\Client();
75
        $this->cache = $cache ?: new Cache\NullCache();
76
    }
77
78
    /**
79
     * Execute a search request against the Marvel API.
80
     *
81
     * @param string $resource The API resource to search for.
82
     * @param array  $filters  Array of search criteria to use in request.
83
     *
84
     * @return null|DataWrapper
85
     *
86
     * @throws \InvalidArgumentException Thrown if $resource is empty or not a string.
87
     */
88 View Code Duplication
    final public function search(string $resource, array $filters = [])
89
    {
90
        $response = $this->send($resource, null, $filters);
91
        if ($response->getStatusCode() !== 200) {
92
            return null;
93
        }
94
95
        return DataWrapper::fromJson((string)$response->getBody());
96
    }
97
98
    /**
99
     * Execute a GET request against the Marvel API for a single resource.
100
     *
101
     * @param string  $resource The API resource to search for.
102
     * @param integer $id       The id of the API resource.
103
     *
104
     * @return null|DataWrapper
105
     */
106 View Code Duplication
    final public function get(string $resource, int $id)
107
    {
108
        $response =  $this->send($resource, $id);
109
        if ($response->getStatusCode() !== 200) {
110
            return null;
111
        }
112
113
        return DataWrapper::fromJson((string)$response->getBody());
114
    }
115
116
    /**
117
     * Send the given API url request.
118
     *
119
     * @param string  $resource The API resource to search for.
120
     * @param integer $id       The id of a specific API resource.
121
     * @param array   $query    Array of search criteria to use in request.
122
     *
123
     * @return ResponseInterface
124
     */
125
    final private function send(string $resource, int $id = null, array $query = []) : ResponseInterface
126
    {
127
        $query['apikey'] = $this->publicApiKey;
128
        $query['ts'] = time();
129
        $query['hash'] = md5($query['ts'] . $this->privateApiKey . $this->publicApiKey);
130
131
        $url = self::BASE_URL . urlencode($resource) . ($id !== null ? "/{$id}" : '') . '?' . http_build_query($query);
132
133
        $response = $this->cache->get($url);
134
        if ($response === null) {
135
            $response = $this->guzzleClient->request(
136
                'GET',
137
                $url,
138
                ['http_errors' => false, 'headers' => ['Accept' =>  'application/json']]
139
            );
140
141
            $this->cache->set($url, $response, self::MAX_TTL);
142
        }
143
144
        return $response;
145
    }
146
147
    /**
148
     * Allow calls such as $client->characters();
149
     *
150
     * @param string $name      The name of the api resource.
151
     * @param array  $arguments The parameters to pass to get() or search().
152
     *
153
     * @return Collection|EntityInterface|null
154
     */
155
    final public function __call(string $name, array $arguments)
156
    {
157
        $resource = strtolower($name);
158
        $idOrFilters = array_shift($arguments) ?: [];
159
160
        if (is_array($idOrFilters)) {
161
            return new Collection($this, $resource, $idOrFilters);
162
        }
163
164
        $dataWrapper = $this->get($resource, $idOrFilters);
165
        if ($dataWrapper === null) {
166
            return null;
167
        }
168
169
        $results = $dataWrapper->getData()->getResults();
170
        return array_shift($results);
171
    }
172
}
173