Completed
Push — master ( 68eeec...2e94f3 )
by Giacomo "Mr. Wolf"
02:45
created

SegmentManager   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 456
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 60
eloc 181
dl 0
loc 456
rs 3.6
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B getItems() 0 48 8
A create() 0 23 4
B getItemsCategory() 0 48 8
B getItemsDataProvider() 0 48 8
B getItem() 0 32 7
A delete() 0 24 4
B getItemsDataConsumer() 0 48 8
B manageClientException() 0 41 8
A __construct() 0 4 1
A update() 0 23 4

How to fix   Complexity   

Complex Class

Complex classes like SegmentManager 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 SegmentManager, 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\Segment;
7
use Audiens\AdForm\Entity\SegmentHydrator;
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 SegmentManager
15
{
16
    /** @var HttpClient */
17
    protected $httpClient;
18
19
    /** @var CacheInterface */
20
    protected $cache;
21
22
    /** @var string */
23
    protected $cachePrefix = 'segment';
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 $segmentId ID of the category
35
     *
36
     * @throws EntityNotFoundException if the API call fails
37
     *
38
     * @return Segment
39
     */
40
    public function getItem($segmentId): Segment
41
    {
42
        // Endpoint URI
43
        $uri = sprintf('v1/segments/%d', $segmentId);
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 SegmentHydrator::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($segmentId, $responseBody, $responseCode);
72
        }
73
    }
74
75
    /**
76
     * Returns an array of segments
77
     *
78
     * @param int $limit
79
     * @param int $offset
80
     *
81
     * @throws ApiException if the API call fails
82
     *
83
     * @return Segment[]
84
     */
85
    public function getItems(int $limit = 1000, int $offset = 0): array
86
    {
87
        // Endpoint URI
88
        $uri = 'v1/segments';
89
90
        $options = [
91
            'query' => [
92
                'limit' => $limit,
93
                'offset' => $offset,
94
            ],
95
        ];
96
97
        $segments = [];
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
                $segments[] = SegmentHydrator::fromStdClass($class);
120
            }
121
        } catch (ClientException $e) {
122
            $response = $e->getResponse();
123
            if ($response === null) {
124
                throw $e;
125
            }
126
            $responseBody = $response->getBody()->getContents();
127
            $responseCode = $response->getStatusCode();
128
129
            throw ApiException::translate($responseBody, $responseCode);
130
        }
131
132
        return $segments;
133
    }
134
135
    /**
136
     * Returns an array of segments for a Data Provider
137
     *
138
     * @param int $dataProviderId
139
     * @param int $limit
140
     * @param int $offset
141
142
     * @throws ApiException if the API call fails
143
     *
144
     * @return Segment[]
145
     */
146
    public function getItemsDataProvider(int $dataProviderId, int $limit = 1000, int $offset = 0): array
147
    {
148
        // Endpoint URI
149
        $uri = sprintf('v1/dataproviders/%d/segments', $dataProviderId);
150
151
        $options = [
152
            'query' => [
153
                'limit' => $limit,
154
                'offset' => $offset,
155
            ],
156
        ];
157
158
        $segments = [];
159
160
        try {
161
            $data = null;
162
163
            // try to get from cache
164
            if ($this->cache) {
165
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
166
            }
167
168
            // load from API
169
            if (!$data) {
170
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
171
172
                if ($this->cache && $data) {
173
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
174
                }
175
            }
176
177
            $classArray = \json_decode($data);
178
179
            foreach ($classArray as $class) {
180
                $segments[] = SegmentHydrator::fromStdClass($class);
181
            }
182
        } catch (ClientException $e) {
183
            $response = $e->getResponse();
184
            if ($response === null) {
185
                throw $e;
186
            }
187
            $responseBody = $response->getBody()->getContents();
188
            $responseCode = $response->getStatusCode();
189
190
            throw ApiException::translate($responseBody, $responseCode);
191
        }
192
193
        return $segments;
194
    }
195
196
    /**
197
     * Returns an array of segments for a Category
198
     *
199
     * @param int $categoryId
200
     * @param int $limit
201
     * @param int $offset
202
     *
203
     * @throws ApiException if the API call fails
204
     *
205
     * @return Segment[]
206
     */
207
    public function getItemsCategory(int $categoryId, int $limit = 1000, int $offset = 0): array
208
    {
209
        // Endpoint URI
210
        $uri = sprintf('v1/categories/%d/segments', $categoryId);
211
212
        $options = [
213
            'query' => [
214
                'limit' => $limit,
215
                'offset' => $offset,
216
            ],
217
        ];
218
219
        $segments = [];
220
221
        try {
222
            $data = null;
223
224
            // try to get from cache
225
            if ($this->cache) {
226
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
227
            }
228
229
            // load from API
230
            if (!$data) {
231
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
232
233
                if ($this->cache && $data) {
234
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
235
                }
236
            }
237
238
            $classArray = \json_decode($data);
239
240
            foreach ($classArray as $class) {
241
                $segments[] = SegmentHydrator::fromStdClass($class);
242
            }
243
        } catch (ClientException $e) {
244
            $response = $e->getResponse();
245
            if ($response === null) {
246
                throw $e;
247
            }
248
            $responseBody = $response->getBody()->getContents();
249
            $responseCode = $response->getStatusCode();
250
251
            throw ApiException::translate($responseBody, $responseCode);
252
        }
253
254
        return $segments;
255
    }
256
257
    /**
258
     * Returns an array of segments for a Data Consumer
259
     *
260
     * @param int $dataConsumerId
261
     * @param int $limit
262
     * @param int $offset
263
     *
264
     * @throws ApiException if the API call fails
265
     *
266
     * @return Segment[]
267
     */
268
    public function getItemsDataConsumer(int $dataConsumerId, int $limit = 1000, int $offset = 0): array
269
    {
270
        // Endpoint URI
271
        $uri = sprintf('v1/dataconsumers/%d/segments', $dataConsumerId);
272
273
        $options = [
274
            'query' => [
275
                'limit' => $limit,
276
                'offset' => $offset,
277
            ],
278
        ];
279
280
        $segments = [];
281
282
        try {
283
            $data = null;
284
285
            // try to get from cache
286
            if ($this->cache) {
287
                $data = $this->cache->get($this->cachePrefix, $uri, $options);
288
            }
289
290
            // load from API
291
            if (!$data) {
292
                $data = $this->httpClient->get($uri, $options)->getBody()->getContents();
293
294
                if ($this->cache && $data) {
295
                    $this->cache->put($this->cachePrefix, $uri, $options, $data);
296
                }
297
            }
298
299
            $classArray = \json_decode($data);
300
301
            foreach ($classArray as $class) {
302
                $segments[] = SegmentHydrator::fromStdClass($class);
303
            }
304
        } catch (ClientException $e) {
305
            $response = $e->getResponse();
306
            if ($response === null) {
307
                throw $e;
308
            }
309
            $responseBody = $response->getBody()->getContents();
310
            $responseCode = $response->getStatusCode();
311
312
            throw ApiException::translate($responseBody, $responseCode);
313
        }
314
315
        return $segments;
316
    }
317
318
    /**
319
     * Create a category
320
     *
321
     * @param Segment $segment
322
     *
323
     * @throws EntityInvalidException if the API returns a validation error
324
     * @throws ApiException if the API call fails
325
     *
326
     * @return Segment
327
     */
328
    public function create(Segment $segment): Segment
329
    {
330
        // Endpoint URI
331
        $uri = 'v1/segments';
332
333
        $options = [
334
            'json' => $segment,
335
        ];
336
337
        try {
338
            $data = $this->httpClient->post($uri, $options)->getBody()->getContents();
339
340
            $segment = SegmentHydrator::fromStdClass(json_decode($data));
341
342
            if ($this->cache && $data) {
343
                $this->cache->invalidate($this->cachePrefix);
344
                $this->cache->put($this->cachePrefix, $uri.'/'.$segment->getId(), [], $data);
345
            }
346
        } catch (ClientException $e) {
347
            $this->manageClientException($e);
348
        }
349
350
        return $segment;
351
    }
352
353
    /**
354
     * Update a category
355
     *
356
     * @param Segment $segment
357
     *
358
     * @throws EntityInvalidException if the API returns a validation error
359
     * @throws ApiException if the API call fails
360
     *
361
     * @return Segment
362
     */
363
    public function update(Segment $segment): Segment
364
    {
365
        // Endpoint URI
366
        $uri = sprintf('v1/segments/%d', $segment->getId());
367
368
        $options = [
369
            'json' => $segment,
370
        ];
371
372
        try {
373
            $data = $this->httpClient->put($uri, $options)->getBody()->getContents();
374
375
            $segment = SegmentHydrator::fromStdClass(json_decode($data));
376
377
            if ($this->cache && $data) {
378
                $this->cache->invalidate($this->cachePrefix);
379
                $this->cache->put($this->cachePrefix, $uri.'/'.$segment->getId(), [], $data);
380
            }
381
        } catch (ClientException $e) {
382
            $this->manageClientException($e);
383
        }
384
385
        return $segment;
386
    }
387
388
    /**
389
     * Delete a category
390
     *
391
     * @param Segment $segment
392
     *
393
     * @throws ApiException if the API call fails
394
     *
395
     * @return bool
396
     */
397
    public function delete(Segment $segment): bool
398
    {
399
        // Endpoint URI
400
        $uri = sprintf('v1/segments/%d', $segment->getId());
401
402
        try {
403
404
            $this->httpClient->delete($uri);
405
406
            if ($this->cache) {
407
                $this->cache->invalidate($this->cachePrefix);
408
            }
409
        } catch (ClientException $e) {
410
            $response = $e->getResponse();
411
            if ($response === null) {
412
                throw $e;
413
            }
414
            $responseBody = $response->getBody()->getContents();
415
            $responseCode = $response->getStatusCode();
416
417
            throw ApiException::translate($responseBody, $responseCode);
418
        }
419
420
        return true;
421
    }
422
423
    /**
424
     * @param ClientException $exception
425
     *
426
     * @throws EntityInvalidException
427
     * @throws ApiException
428
     */
429
    protected function manageClientException(ClientException $exception): void
430
    {
431
        $response = $exception->getResponse();
432
433
        if ($response === null) {
434
            throw $exception;
435
        }
436
437
        $responseBody = $response->getBody()->getContents();
438
        $responseCode = $response->getStatusCode();
439
440
        $error = \json_decode($responseBody);
441
442
        // Validation
443
        if (isset($error->modelState)) {
444
            throw EntityInvalidException::invalid($responseBody, $responseCode, $error->modelState);
445
        }
446
447
        if (isset($error->reason, $error->params) && $error->reason === 'validationFailed') {
448
            $errorMessages = [];
449
            foreach ($error->params as $paramName => $paramArr) {
450
                if (!\is_array($paramArr)) {
451
                    $errorMessages[] = $paramName;
452
453
                    continue;
454
                }
455
456
                foreach ($paramArr as $paramObj) {
457
                    $errorMessages[] = $paramObj->message ?? $paramName;
458
                }
459
            }
460
461
            throw EntityInvalidException::invalid(
462
                $responseBody,
463
                $responseCode,
464
                $errorMessages
465
            );
466
        }
467
468
        // Generic exception
469
        throw ApiException::translate($responseBody, $responseCode);
470
    }
471
}
472