Client::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 4
nop 4
1
<?php
2
3
namespace Chadicus\Marvel\Api;
4
5
use GuzzleHttp;
6
use Psr\SimpleCache\CacheInterface;
7
8
/**
9
 * PHP Client for the Marvel API.
10
 */
11
class Client implements ClientInterface
12
{
13
    /**
14
     * The default ttl for cached responses (24 hours).
15
     *
16
     * @link http://developer.marvel.com/documentation/attribution Marvel's rules for caching.
17
     *
18
     * @const integer
19
     */
20
    const MAX_TTL = 86400;
21
22
    /**
23
     * The public API key issued by Marvel.
24
     *
25
     * @var string
26
     */
27
    private $publicApiKey;
28
29
    /**
30
     * The private API key issued by Marvel.
31
     *
32
     * @var string
33
     */
34
    private $privateApiKey;
35
36
    /**
37
     * Guzzle HTTP Client implementation.
38
     *
39
     * @var GuzzleHttp\ClientInterface
40
     */
41
    private $guzzleClient;
42
43
    /**
44
     * Cache implementation.
45
     *
46
     * @var CacheInterface
47
     */
48
    private $cache;
49
50
    /**
51
     * Default Guzzle request options.
52
     *
53
     * @var array
54
     */
55
    private static $guzzleRequestOptions = [
56
        'http_errors' => false,
57
        'headers' => [
58
            'Accept' =>  'application/json',
59
            'Accept-Encoding' => 'gzip,deflate',
60
        ],
61
    ];
62
63
    /**
64
     * The Marvel API URL.
65
     *
66
     * @const string
67
     */
68
    const BASE_URL = 'http://gateway.marvel.com/v1/public/';
69
70
    /**
71
     * Construct a new Client.
72
     *
73
     * @param string                     $privateApiKey The private API key issued by Marvel.
74
     * @param string                     $publicApiKey  The public API key issued by Marvel.
75
     * @param GuzzleHttp\ClientInterface $guzzleClient  Implementation of a Guzzle HTTP client.
76
     * @param CacheInterface             $cache         Implementation of Cache.
77
     */
78
    final public function __construct(
79
        string $privateApiKey,
80
        string $publicApiKey,
81
        GuzzleHttp\ClientInterface $guzzleClient = null,
82
        CacheInterface $cache = null
83
    ) {
84
        $this->privateApiKey = $privateApiKey;
85
        $this->publicApiKey = $publicApiKey;
86
        $this->guzzleClient = $guzzleClient ?: new GuzzleHttp\Client();
87
        $this->cache = $cache ?: new Cache\NullCache();
88
    }
89
90
    /**
91
     * Execute a search request against the Marvel API.
92
     *
93
     * @param string $resource The API resource to search for.
94
     * @param array  $filters  Array of search criteria to use in request.
95
     *
96
     * @return null|DataWrapper
97
     */
98
    final public function search(string $resource, array $filters = [])
99
    {
100
        return $this->send($resource, null, $filters);
101
    }
102
103
    /**
104
     * Execute a GET request against the Marvel API for a single resource.
105
     *
106
     * @param string  $resource The API resource to search for.
107
     * @param integer $id       The id of the API resource.
108
     *
109
     * @return null|DataWrapper
110
     */
111
    final public function get(string $resource, int $id)
112
    {
113
        return $this->send($resource, $id);
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 null|DataWrapperInterface
124
     */
125
    final private function send(string $resource, int $id = null, array $query = [])
126
    {
127
        $query['apikey'] = $this->publicApiKey;
128
        $query['ts'] = time();
129
        $query['hash'] = md5("{$query['ts']}{$this->privateApiKey}{$this->publicApiKey}");
130
        $cacheKey = urlencode($resource) . ($id !== null ? "/{$id}" : '') . '?' . http_build_query($query);
131
        $url = self::BASE_URL . $cacheKey;
132
133
        $response = $this->cache->get($cacheKey);
134
        if ($response === null) {
135
            $response = $this->guzzleClient->request('GET', $url, self::$guzzleRequestOptions);
136
        }
137
138
        if ($response->getStatusCode() !== 200) {
139
            return null;
140
        }
141
142
        $this->cache->set($cacheKey, $response, self::MAX_TTL);
143
144
        return DataWrapper::fromJson((string)$response->getBody());
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->send($resource, $idOrFilters);
165
        if ($dataWrapper === null) {
166
            return null;
167
        }
168
169
        $results = $dataWrapper->getData()->getResults();
170
        return array_shift($results);
171
    }
172
}
173