Passed
Pull Request — master (#24)
by
unknown
03:26
created

AbstractCoreApiClient   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
wmc 14
lcom 2
cbo 8
dl 0
loc 191
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 2
_doRequest() 0 1 ?
B makeRequest() 0 36 4
A deserialize() 0 4 1
B buildJsonParameters() 0 18 6
A generateCacheKey() 0 4 1
serializeResponse() 0 1 ?
unserializeResponse() 0 1 ?
1
<?php
2
3
namespace MovingImage\Client\VMPro\ApiClient;
4
5
use GuzzleHttp\ClientInterface;
6
use JMS\Serializer\Serializer;
7
use MovingImage\Client\VMPro\Exception;
8
use MovingImage\Client\VMPro\Util\Logging\Traits\LoggerAwareTrait;
9
use Psr\Cache\CacheItemPoolInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Log\LoggerAwareInterface;
12
use Symfony\Component\Cache\Adapter\NullAdapter;
13
14
/**
15
 * Class AbstractCoreApiClient.
16
 *
17
 * @author Ruben Knol <[email protected]>
18
 */
19
abstract class AbstractCoreApiClient implements LoggerAwareInterface
20
{
21
    use LoggerAwareTrait;
22
23
    /**
24
     * @const string
25
     */
26
    const OPT_VIDEO_MANAGER_ID = 'videoManagerId';
27
28
    /**
29
     * @var ClientInterface The Guzzle HTTP client
30
     */
31
    protected $httpClient;
32
33
    /**
34
     * @var Serializer The JMS Serializer instance
35
     */
36
    protected $serializer;
37
38
    /**
39
     * @var CacheItemPoolInterface PSR6 cache pool implementation
40
     */
41
    protected $cacheItemPool;
42
43
    /**
44
     * @var mixed time-to-live for cached responses
45
     * The type of this property might be integer, \DateInterval or null.
46
     * @see CacheItemInterface::expiresAfter()
47
     */
48
    protected $cacheTtl;
49
50
    /**
51
     * ApiClient constructor.
52
     *
53
     * @param ClientInterface        $httpClient
54
     * @param Serializer             $serializer
55
     * @param CacheItemPoolInterface $cacheItemPool
56
     * @param integer                $cacheTtl
57
     */
58
    public function __construct(
59
        ClientInterface $httpClient,
60
        Serializer $serializer,
61
        CacheItemPoolInterface $cacheItemPool = null,
62
        $cacheTtl = null
63
    ) {
64
        $this->httpClient = $httpClient;
65
        $this->serializer = $serializer;
66
        $this->cacheItemPool = $cacheItemPool ?: new NullAdapter();
67
        $this->cacheTtl = $cacheTtl;
68
    }
69
70
    /**
71
     * Perform the actual request in the implementation classes.
72
     *
73
     * @param string $method
74
     * @param string $uri
75
     * @param array  $options
76
     *
77
     * @return mixed
78
     */
79
    abstract protected function _doRequest($method, $uri, $options);
80
81
    /**
82
     * Make a request to the API and serialize the result according to our
83
     * serialization strategy.
84
     *
85
     * @param string $method
86
     * @param string $uri
87
     * @param array  $options
88
     *
89
     * @return object|ResponseInterface
90
     */
91
    protected function makeRequest($method, $uri, $options)
92
    {
93
        $logger = $this->getLogger();
94
95
        try {
96
            // Automagically pre-pend videoManagerId if the option is present in the
97
            // options for sending the request
98
            if (isset($options[self::OPT_VIDEO_MANAGER_ID])) {
99
                $uri = sprintf('%d/%s', $options[self::OPT_VIDEO_MANAGER_ID], $uri);
100
            }
101
102
            $cacheKey = $this->generateCacheKey($method, $uri, $options);
103
            $cacheItem = $this->cacheItemPool->getItem($cacheKey);
104
            if ($cacheItem->isHit()) {
105
                $logger->info(sprintf('Getting response from cache for %s request to %s', $method, $uri), [$uri]);
106
                return $this->unserializeResponse($cacheItem->get());
107
            }
108
109
            $logger->info(sprintf('Making API %s request to %s', $method, $uri), [$uri]);
110
111
            /** @var ResponseInterface $response */
112
            $response = $this->_doRequest($method, $uri, $options);
113
114
            $cacheItem->set($this->serializeResponse($response));
115
            $cacheItem->expiresAfter($this->cacheTtl);
116
            $this->cacheItemPool->save($cacheItem);
117
118
119
            $logger->debug('Response from HTTP call was status code:', [$response->getStatusCode()]);
120
            $logger->debug('Response JSON was:', [$response->getBody()]);
121
122
            return $response;
123
        } catch (\Exception $e) {
124
            throw $e; // Just rethrow for now
125
        }
126
    }
127
128
    /**
129
     * Deserialize a response into an instance of it's associated class.
130
     *
131
     * @param string $data
132
     * @param string $serialisationClass
133
     *
134
     * @return object
135
     */
136
    protected function deserialize($data, $serialisationClass)
137
    {
138
        return $this->serializer->deserialize($data, $serialisationClass, 'json');
139
    }
140
141
    /**
142
     * Helper method to build the JSON data array for making a request
143
     * with ::makeRequest(). Optional parameters with empty or null value will be
144
     * omitted from the return value.
145
     *
146
     * Examples:
147
     *
148
     * $this->buildJsonParameters(['title' => 'test'], ['description' => '', 'bla' => 'test'])
149
     *
150
     * Would result in:
151
     *
152
     * [
153
     *     'title' => 'test',
154
     *     'bla' => 'test',
155
     * ]
156
     *
157
     * @param array $required
158
     * @param array $optional
159
     *
160
     * @return array
161
     */
162
    protected function buildJsonParameters(array $required, array $optional)
163
    {
164
        foreach ($required as $key => $value) {
165
            if (empty($value)) {
166
                throw new Exception(sprintf('Required parameter \'%s\' is missing..', $key));
167
            }
168
        }
169
170
        $json = $required;
171
172
        foreach ($optional as $key => $value) {
173
            if (!empty($value) || $value === false) {
174
                $json[$key] = $value;
175
            }
176
        }
177
178
        return $json;
179
    }
180
181
    /**
182
     * Generates the cache key based on request method, uri and options.
183
     * @param string $method
184
     * @param string $uri
185
     * @param array $options
186
     * @return string
187
     */
188
    private function generateCacheKey($method, $uri, array $options = [])
189
    {
190
        return sha1(sprintf('%s.%s.%s', $method, $uri, json_encode($options)));
191
    }
192
193
    /**
194
     * Serializes the provided response to a string, suitable for caching.
195
     * The type of the $response argument varies depending on the guzzle version.
196
     * @param mixed $response
197
     * @return string
198
     */
199
    abstract protected function serializeResponse($response);
200
201
    /**
202
     * Unserializes the serialized response into a response object.
203
     * The return type varies depending on the guzzle version.
204
     * @param string $serialized
205
     * @return mixed
206
     * @throws Exception
207
     */
208
    abstract protected function unserializeResponse($serialized);
209
}
210