CategoryManager   B
last analyzed

Complexity

Total Complexity 50

Size/Duplication

Total Lines 383
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 50
eloc 142
dl 0
loc 383
rs 8.4
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B manageClientException() 0 41 8
B getItemsDataConsumer() 0 41 7
A manageClientExceptionSimple() 0 10 2
A create() 0 23 4
B getItems() 0 41 7
B getItem() 0 32 7
B getItemsDataProvider() 0 41 7
A update() 0 23 4
A delete() 0 16 3
A __construct() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like CategoryManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CategoryManager, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace Audiens\AdForm\Manager;
4
5
use Audiens\AdForm\Cache\CacheInterface;
6
use Audiens\AdForm\Entity\Category;
7
use Audiens\AdForm\Entity\CategoryHydrator;
8
use Audiens\AdForm\Exception\ApiException;
9
use Audiens\AdForm\Exception\EntityInvalidException;
10
use Audiens\AdForm\Exception\EntityNotFoundException;
11
use Audiens\AdForm\HttpClient;
12
use GuzzleHttp\Exception\ClientException;
13
14
class CategoryManager
15
{
16
    /** @var HttpClient */
17
    protected $httpClient;
18
19
    /** @var CacheInterface|null */
20
    protected $cache;
21
22
    /** @var string */
23
    protected $cachePrefix = 'category';
24
25
    public function __construct(HttpClient $httpClient, CacheInterface $cache = null)
26
    {
27
        $this->httpClient = $httpClient;
28
        $this->cache = $cache;
29
    }
30
31
    /**
32
     * Return a category based on ID
33
     *
34
     * @param int $categoryId ID of the category
35
     *
36
     * @throws EntityNotFoundException if the API call fails
37
     *
38
     * @return Category
39
     */
40
    public function getItem(int $categoryId): ?Category
41
    {
42
        // Endpoint URI
43
        $uri = sprintf('v1/categories/%d', $categoryId);
44
45
        try {
46
            $data = null;
47
48
            // try to get from cache
49
            if ($this->cache) {
50
                $data = $this->cache->get($this->cachePrefix, $uri, []);
51
            }
52
53
            // load from API
54
            if (!$data) {
55
                $data = $this->httpClient->get($uri)->getBody()->getContents();
56
57
                if ($this->cache && $data) {
58
                    $this->cache->put($this->cachePrefix, $uri, [], $data);
59
                }
60
            }
61
62
            return CategoryHydrator::fromStdClass(\json_decode($data));
63
        } catch (ClientException $e) {
64
            $response = $e->getResponse();
65
            if ($response === null) {
66
                throw $e;
67
            }
68
            $responseBody = $response->getBody()->getContents();
69
            $responseCode = $response->getStatusCode();
70
71
            throw EntityNotFoundException::translate($categoryId, $responseBody, $responseCode);
72
        }
73
    }
74
75
    /**
76
     * Returns an array of categories
77
     *
78
     * @param int $limit
79
     * @param int $offset
80
     *
81
     * @throws ApiException if the API call fails
82
     *
83
     * @return Category[]
84
     */
85
    public function getItems(int $limit = 1000, int $offset = 0): array
86
    {
87
        // Endpoint URI
88
        $uri = 'v1/categories';
89
90
        $options = [
91
            'query' => [
92
                'limit' => $limit,
93
                'offset' => $offset,
94
            ],
95
        ];
96
97
        $categories = [];
98
99
        try {
100
            $data = null;
101
102
            // try to get from cache
103
            if ($this->cache) {
104
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
105
            }
106
107
            // load from API
108
            if (!$data) {
109
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
110
111
                if ($this->cache && $data) {
112
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
113
                }
114
            }
115
116
            $classArray = \json_decode($data);
117
118
            foreach ($classArray as $class) {
119
                $categories[] = CategoryHydrator::fromStdClass($class);
120
            }
121
        } catch (ClientException $e) {
122
            $this->manageClientExceptionSimple($e);
123
        }
124
125
        return $categories;
126
    }
127
128
    /**
129
     * Returns an array of categories for a Data Provider
130
     *
131
     * @param int $dataProviderId
132
     * @param int $limit
133
     * @param int $offset
134
     *
135
     * @throws ApiException if the API call fails
136
     *
137
     * @return Category[]
138
     */
139
    public function getItemsDataProvider(int $dataProviderId, int $limit = 1000, int $offset = 0): array
140
    {
141
        // Endpoint URI
142
        $uri = sprintf('v1/dataproviders/%d/categories', $dataProviderId);
143
144
        $options = [
145
            'query' => [
146
                'limit' => $limit,
147
                'offset' => $offset,
148
            ],
149
        ];
150
151
        $categories = [];
152
153
        try {
154
            $data = null;
155
156
            // try to get from cache
157
            if ($this->cache) {
158
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
159
            }
160
161
            // load from API
162
            if (!$data) {
163
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
164
165
                if ($this->cache && $data) {
166
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
167
                }
168
            }
169
170
            $classArray = \json_decode($data);
171
172
            foreach ($classArray as $class) {
173
                $categories[] = CategoryHydrator::fromStdClass($class);
174
            }
175
        } catch (ClientException $e) {
176
            $this->manageClientExceptionSimple($e);
177
        }
178
179
        return $categories;
180
    }
181
182
    /**
183
     * Returns an array of categories for a Data Consumer
184
     *
185
     * @param int $dataConsumerId
186
     * @param int $limit
187
     * @param int $offset
188
     *
189
     * @throws ApiException if the API call fails
190
     *
191
     * @return Category[]
192
     */
193
    public function getItemsDataConsumer(int $dataConsumerId, int $limit = 1000, int $offset = 0): array
194
    {
195
        // Endpoint URI
196
        $uri = sprintf('v1/dataconsumers/%d/categories', $dataConsumerId);
197
198
        $options = [
199
            'query' => [
200
                'limit' => $limit,
201
                'offset' => $offset,
202
            ],
203
        ];
204
205
        $categories = [];
206
207
        try {
208
            $data = null;
209
210
            // try to get from cache
211
            if ($this->cache) {
212
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
213
            }
214
215
            // load from API
216
            if (!$data) {
217
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
218
219
                if ($this->cache && $data) {
220
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
221
                }
222
            }
223
224
            $classArray = \json_decode($data);
225
226
            foreach ($classArray as $class) {
227
                $categories[] = CategoryHydrator::fromStdClass($class);
228
            }
229
        } catch (ClientException $e) {
230
            $this->manageClientExceptionSimple($e);
231
        }
232
233
        return $categories;
234
    }
235
236
    /**
237
     * Create a category
238
     *
239
     * @param Category $category
240
     *
241
     * @throws EntityInvalidException if the API returns a validation error
242
     * @throws ApiException if the API call fails
243
     *
244
     * @return Category
245
     */
246
    public function create(Category $category): Category
247
    {
248
        // Endpoint URI
249
        $uri = 'v1/categories';
250
251
        $options = [
252
            'json' => $category,
253
        ];
254
255
        try {
256
            $data = $this->httpClient->post($uri, $options)->getBody()->getContents();
257
258
            $category = CategoryHydrator::fromStdClass(json_decode($data));
259
260
            if ($this->cache && $data) {
261
                $this->cache->invalidate($this->cachePrefix);
262
                $this->cache->put($this->cachePrefix, $uri.'/'.$category->getId(), [], $data);
263
            }
264
        } catch (ClientException $e) {
265
            $this->manageClientException($e);
266
        }
267
268
        return $category;
269
    }
270
271
    /**
272
     * Update a category
273
     *
274
     * @param Category $category
275
     *
276
     * @throws EntityInvalidException if the API returns a validation error
277
     * @throws ApiException if the API call fails
278
     *
279
     * @return Category
280
     */
281
    public function update(Category $category): Category
282
    {
283
        // Endpoint URI
284
        $uri = sprintf('v1/categories/%d', $category->getId());
285
286
        $options = [
287
            'json' => $category,
288
        ];
289
290
        try {
291
            $data = $this->httpClient->put($uri, $options)->getBody()->getContents();
292
293
            $category = CategoryHydrator::fromStdClass(json_decode($data));
294
295
            if ($this->cache && $data) {
296
                $this->cache->invalidate($this->cachePrefix);
297
                $this->cache->put($this->cachePrefix, $uri.'/'.$category->getId(), [], $data);
298
            }
299
        } catch (ClientException $e) {
300
            $this->manageClientException($e);
301
        }
302
303
        return $category;
304
    }
305
306
    /**
307
     * Delete a category
308
     *
309
     * @param Category $category
310
     *
311
     * @throws ApiException if the API call fails
312
     *
313
     * @return bool
314
     */
315
    public function delete(Category $category): bool
316
    {
317
        // Endpoint URI
318
        $uri = sprintf('v1/categories/%d', $category->getId());
319
320
        try {
321
            $this->httpClient->delete($uri);
322
323
            if ($this->cache) {
324
                $this->cache->invalidate($this->cachePrefix);
325
            }
326
        } catch (ClientException $e) {
327
            $this->manageClientExceptionSimple($e);
328
        }
329
330
        return true;
331
    }
332
333
    /**
334
     * @param ClientException $exception
335
     *
336
     * @throws EntityInvalidException
337
     * @throws ApiException
338
     */
339
    protected function manageClientException(ClientException $exception): void
340
    {
341
        $response = $exception->getResponse();
342
343
        if ($response === null) {
344
            throw $exception;
345
        }
346
347
        $responseBody = $response->getBody()->getContents();
348
        $responseCode = $response->getStatusCode();
349
350
        $error = \json_decode($responseBody);
351
352
        // Validation
353
        if (isset($error->modelState)) {
354
            throw EntityInvalidException::invalid($responseBody, $responseCode, $error->modelState);
355
        }
356
357
        if (isset($error->reason, $error->params) && $error->reason === 'validationFailed') {
358
            $errorMessages = [];
359
            foreach ($error->params as $paramName => $paramArr) {
360
                if (!\is_array($paramArr)) {
361
                    $errorMessages[] = $paramName;
362
363
                    continue;
364
                }
365
366
                foreach ($paramArr as $paramObj) {
367
                    $errorMessages[] = $paramObj->message ?? $paramName;
368
                }
369
            }
370
371
            throw EntityInvalidException::invalid(
372
                $responseBody,
373
                $responseCode,
374
                $errorMessages
375
            );
376
        }
377
378
        // Generic exception
379
        throw ApiException::translate($responseBody, $responseCode);
380
    }
381
382
    /**
383
     * @param ClientException $exception
384
     *
385
     * @throws ApiException
386
     */
387
    protected function manageClientExceptionSimple(ClientException $exception): void
388
    {
389
        $response = $exception->getResponse();
390
        if ($response === null) {
391
            throw $exception;
392
        }
393
        $responseBody = $response->getBody()->getContents();
394
        $responseCode = $response->getStatusCode();
395
396
        throw ApiException::translate($responseBody, $responseCode);
397
    }
398
}
399