Completed
Push — master ( b27094...afbc6d )
by Julien
05:50 queued 01:38
created

EntityRepository::__call()   C

Complexity

Conditions 10
Paths 35

Size

Total Lines 74
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 10.0363

Importance

Changes 0
Metric Value
cc 10
eloc 47
nc 35
nop 2
dl 0
loc 74
ccs 39
cts 42
cp 0.9286
crap 10.0363
rs 5.8102
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Mapado\RestClientSdk;
4
5
use Mapado\RestClientSdk\Exception\SdkException;
6
use Mapado\RestClientSdk\Helper\ArrayHelper;
7
8
class EntityRepository
9
{
10
    /**
11
     * REST Client.
12
     *
13
     * @var RestClient
14
     */
15
    protected $restClient;
16
17
    /**
18
     * SDK Client.
19
     *
20
     * @var SdkClient
21
     */
22
    protected $sdk;
23
24
    /**
25
     * @var string
26
     */
27
    protected $entityName;
28
29
    /**
30
     * classMetadataCache
31
     *
32
     * @var \Mapado\RestClientSdk\Mapping\ClassMetadata
33
     */
34
    private $classMetadataCache;
35
36
    /**
37
     * unitOfWork
38
     *
39
     * @var UnitOfWork
40
     */
41
    private $unitOfWork;
42
43
    /**
44
     * EntityRepository constructor
45
     *
46
     * @param SdkClient  $sdkClient  The client to connect to the datasource with
47
     * @param RestClient $restClient The client to process the http requests
48
     * @param string     $entityName The entity to work with
49
     */
50
    public function __construct(SdkClient $sdkClient, RestClient $restClient, UnitOfWork $unitOfWork, $entityName)
51
    {
52 1
        $this->sdk = $sdkClient;
53 1
        $this->restClient = $restClient;
54 1
        $this->unitOfWork = $unitOfWork;
55 1
        $this->entityName = $entityName;
56 1
    }
57
58
    /**
59
     * Adds support for magic finders.
60
     *
61
     * @param string $method
62
     * @param mixed  $arguments
63
     *
64
     * @return array|object the found entity/entities
65
     */
66
    public function __call($method, $arguments)
67
    {
68
        switch (true) {
69 1
            case 0 === strpos($method, 'findBy'):
70 1
                $fieldName = strtolower(substr($method, 6));
71 1
                $methodName = 'findBy';
72 1
                break;
73
74 1
            case 0 === strpos($method, 'findOneBy'):
75 1
                $fieldName = strtolower(substr($method, 9));
76 1
                $methodName = 'findOneBy';
77 1
                break;
78
79
            default:
80
                throw new \BadMethodCallException(
81
                    'Undefined method \'' . $method . '\'. The method name must start with
82
                    either findBy or findOneBy!'
83
                );
84
        }
85
86 1
        if (empty($arguments)) {
87
            throw new SdkException('You need to pass a parameter to ' . $method);
88
        }
89
90 1
        $mapping = $this->sdk->getMapping();
91 1
        $key = $mapping->getKeyFromModel($this->entityName);
92 1
        $prefix = $mapping->getIdPrefix();
93 1
        $path = empty($prefix) ? '/' . $key : $prefix . '/' . $key;
94
95 1
        if (!empty($fieldName)) {
96 1
            $queryParams = [$fieldName => current($arguments)];
97
        } else {
98 1
            $queryParams = current($arguments);
99
        }
100 1
        $path .= '?' . http_build_query($this->convertQueryParameters($queryParams));
101
102
        // if entityList is found in cache, return it
103 1
        $entityListFromCache = $this->fetchFromCache($path);
104 1
        if (false !== $entityListFromCache) {
105 1
            return $entityListFromCache;
106
        }
107
108 1
        $data = $this->restClient->get($path);
109
110 1
        $hydrator = $this->sdk->getModelHydrator();
111
112 1
        if ('findOneBy' == $methodName) {
113
            // If more results are found but one is requested return the first hit.
114 1
            $collectionKey = $mapping->getConfig()['collectionKey'];
115 1
            $entityList = ArrayHelper::arrayGet($data, $collectionKey);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $array of Mapado\RestClientSdk\Hel...ArrayHelper::arrayGet() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

115
            $entityList = ArrayHelper::arrayGet(/** @scrutinizer ignore-type */ $data, $collectionKey);
Loading history...
116 1
            if (!empty($entityList)) {
117 1
                $data = current($entityList);
0 ignored issues
show
Bug introduced by
It seems like $entityList can also be of type Psr\Http\Message\ResponseInterface; however, parameter $array of current() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
                $data = current(/** @scrutinizer ignore-type */ $entityList);
Loading history...
118 1
                $hydratedData = $hydrator->hydrate($data, $this->entityName);
119
120 1
                $identifier = $hydratedData->{$this->getClassMetadata()->getIdGetter()}();
121 1
                $this->unitOfWork->registerClean($identifier, $hydratedData);
122 1
                $this->saveToCache($identifier, $hydratedData);
123
            } else {
124 1
                $hydratedData = null;
125
            }
126
        } else {
127 1
            $hydratedData = $hydrator->hydrateList($data, $this->entityName);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $data of Mapado\RestClientSdk\Mod...Hydrator::hydrateList() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

127
            $hydratedData = $hydrator->hydrateList(/** @scrutinizer ignore-type */ $data, $this->entityName);
Loading history...
128
129
            // then cache each entity from list
130 1
            foreach ($hydratedData as $entity) {
131 1
                $identifier = $entity->{$this->getClassMetadata()->getIdGetter()}();
132 1
                $this->saveToCache($identifier, $entity);
133 1
                $this->unitOfWork->registerClean($identifier, $entity);
134
            }
135
        }
136
137 1
        $this->saveToCache($path, $hydratedData);
138
139 1
        return $hydratedData;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $hydratedData also could return the type Mapado\RestClientSdk\Collection\Collection which is incompatible with the documented return type object|array.
Loading history...
140
    }
141
142
    /**
143
     * find - finds one item of the entity based on the @REST\Id field in the entity
144
     *
145
     * @param string $id          id of the element to fetch
146
     * @param array  $queryParams query parameters to add to the query
147
     *
148
     * @return object
149
     */
150
    public function find($id, $queryParams = [])
151
    {
152 1
        $hydrator = $this->sdk->getModelHydrator();
153 1
        $id = $hydrator->convertId($id, $this->entityName);
154
155 1
        $id = $this->addQueryParameter($id, $queryParams);
156
157
        // if entity is found in cache, return it
158 1
        $entityFromCache = $this->fetchFromCache($id);
159 1
        if (false != $entityFromCache) {
160 1
            return $entityFromCache;
161
        }
162
163 1
        $data = $this->restClient->get($id);
164 1
        $entity = $hydrator->hydrate($data, $this->entityName);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $data of Mapado\RestClientSdk\Mod...odelHydrator::hydrate() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
        $entity = $hydrator->hydrate(/** @scrutinizer ignore-type */ $data, $this->entityName);
Loading history...
165
166
        // cache entity
167 1
        $this->saveToCache($id, $entity);
168 1
        $this->unitOfWork->registerClean($id, $entity);
169
170 1
        return $entity;
171
    }
172
173
    /**
174
     * findAll
175
     *
176
     * @return array|object
177
     */
178
    public function findAll()
179
    {
180 1
        $mapping = $this->sdk->getMapping();
181 1
        $key = $this->getClassMetadata()->getKey();
182 1
        $prefix = $mapping->getIdPrefix();
183 1
        $path = empty($prefix) ? '/' . $key : $prefix . '/' . $key;
184
185 1
        $entityListFromCache = $this->fetchFromCache($path);
186
187
        // if entityList is found in cache, return it
188 1
        if (false !== $entityListFromCache) {
189 1
            return $entityListFromCache;
190
        }
191
192 1
        $data = $this->restClient->get($path);
193
194 1
        $hydrator = $this->sdk->getModelHydrator();
195 1
        $entityList = $hydrator->hydrateList($data, $this->entityName);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $data of Mapado\RestClientSdk\Mod...Hydrator::hydrateList() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
        $entityList = $hydrator->hydrateList(/** @scrutinizer ignore-type */ $data, $this->entityName);
Loading history...
196
197
        // cache entity list
198 1
        $this->saveToCache($path, $entityList);
199
200
        // then cache each entity from list
201 1
        foreach ($entityList as $entity) {
202 1
            $identifier = $entity->{$this->getClassMetadata()->getIdGetter()}();
203 1
            $this->unitOfWork->registerClean($identifier, $entity);
204 1
            $this->saveToCache($identifier, $entity);
205
        }
206
207 1
        return $entityList;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entityList returns the type Mapado\RestClientSdk\Collection\Collection which is incompatible with the documented return type object|array.
Loading history...
208
    }
209
210
    /**
211
     * remove
212
     *
213
     * @param object $model
214
     *
215
     * @TODO STILL NEEDS TO BE CONVERTED TO ENTITY MODEL
216
     */
217
    public function remove($model)
218
    {
219 1
        $identifier = $model->{$this->getClassMetadata()->getIdGetter()}();
220 1
        $this->removeFromCache($identifier);
221 1
        $this->unitOfWork->clear($identifier);
222
223 1
        $this->restClient->delete($identifier);
224 1
    }
225
226
    /**
227
     * update
228
     *
229
     * @param object $model
230
     *
231
     * @return object
232
     */
233
    public function update($model, $serializationContext = [], $queryParams = [])
234
    {
235 1
        $identifier = $model->{$this->getClassMetadata()->getIdGetter()}();
236 1
        $serializer = $this->sdk->getSerializer();
237 1
        $newSerializedModel = $serializer->serialize($model, $this->entityName, $serializationContext);
238
239 1
        $oldModel = $this->unitOfWork->getDirtyEntity($identifier);
240 1
        if ($oldModel) {
241 1
            $oldSerializedModel = $serializer->serialize($oldModel, $this->entityName, $serializationContext);
242 1
            $newSerializedModel = $this->unitOfWork->getDirtyData($newSerializedModel, $oldSerializedModel, $this->getClassMetadata());
243
        }
244
245 1
        $data = $this->restClient->put(
246 1
            $this->addQueryParameter($identifier, $queryParams),
247 1
            $newSerializedModel
248
        );
249
250 1
        $this->removeFromCache($identifier);
251 1
        $this->unitOfWork->registerClean($identifier, $newSerializedModel);
0 ignored issues
show
Bug introduced by
$newSerializedModel of type array is incompatible with the type object expected by parameter $entity of Mapado\RestClientSdk\UnitOfWork::registerClean(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

251
        $this->unitOfWork->registerClean($identifier, /** @scrutinizer ignore-type */ $newSerializedModel);
Loading history...
252
253 1
        $hydrator = $this->sdk->getModelHydrator();
254
255 1
        return $hydrator->hydrate($data, $this->entityName);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $data of Mapado\RestClientSdk\Mod...odelHydrator::hydrate() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

255
        return $hydrator->hydrate(/** @scrutinizer ignore-type */ $data, $this->entityName);
Loading history...
256
    }
257
258
    /**
259
     * persist
260
     *
261
     * @param object $model
262
     *
263
     * @return object
264
     */
265
    public function persist($model, $serializationContext = [], $queryParams = [])
266
    {
267 1
        $mapping = $this->sdk->getMapping();
268 1
        $prefix = $mapping->getIdPrefix();
269 1
        $key = $mapping->getKeyFromModel($this->entityName);
270
271 1
        $path = empty($prefix) ? '/' . $key : $prefix . '/' . $key;
272
273 1
        $oldSerializedModel = $this->getClassMetadata()->getDefaultSerializedModel();
274 1
        $newSerializedModel = $this->sdk->getSerializer()
275 1
            ->serialize($model, $this->entityName, $serializationContext);
276
277 1
        $diff = $this->unitOfWork
278 1
            ->getDirtyData($newSerializedModel, $oldSerializedModel, $this->getClassMetadata());
279
280 1
        $data = $this->restClient->post(
281 1
            $this->addQueryParameter($path, $queryParams),
282 1
            $diff
283
        );
284
285 1
        $hydrator = $this->sdk->getModelHydrator();
286
287 1
        return $hydrator->hydrate($data, $this->entityName);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type Psr\Http\Message\ResponseInterface; however, parameter $data of Mapado\RestClientSdk\Mod...odelHydrator::hydrate() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

287
        return $hydrator->hydrate(/** @scrutinizer ignore-type */ $data, $this->entityName);
Loading history...
288
    }
289
290
    /**
291
     * fetchFromCache
292
     *
293
     * @param string $key
294
     *
295
     * @return object|false
296
     */
297
    protected function fetchFromCache($key)
298
    {
299 1
        $key = $this->normalizeCacheKey($key);
300 1
        $cacheItemPool = $this->sdk->getCacheItemPool();
301 1
        if ($cacheItemPool) {
0 ignored issues
show
introduced by
$cacheItemPool is of type Psr\Cache\CacheItemPoolInterface, thus it always evaluated to true.
Loading history...
302 1
            $cacheKey = $this->sdk->getCachePrefix() . $key;
303 1
            if ($cacheItemPool->hasItem($cacheKey)) {
304 1
                $cacheItem = $cacheItemPool->getItem($cacheKey);
305 1
                $cacheData = $cacheItem->get();
306
307 1
                return $cacheData;
308
            }
309
        }
310
311 1
        return false;
312
    }
313
314
    /**
315
     * saveToCache
316
     *
317
     * @return object
318
     */
319
    protected function saveToCache($key, $value)
320
    {
321 1
        $key = $this->normalizeCacheKey($key);
322 1
        $cacheItemPool = $this->sdk->getCacheItemPool();
323 1
        if ($cacheItemPool) {
0 ignored issues
show
introduced by
$cacheItemPool is of type Psr\Cache\CacheItemPoolInterface, thus it always evaluated to true.
Loading history...
324 1
            $cacheKey = $this->sdk->getCachePrefix() . $key;
325
326 1
            if (!$cacheItemPool->hasItem($cacheKey)) {
327 1
                $cacheItem = $cacheItemPool->getItem($cacheKey);
328 1
                $cacheItem->set($value);
329 1
                $cacheItemPool->save($cacheItem);
330
            }
331
        }
332 1
    }
333
334
    /**
335
     * removeFromCache
336
     *
337
     * @param string $key
338
     *
339
     * @return bool true if no cache or cache successfully cleared, false otherwise
340
     */
341
    protected function removeFromCache($key)
342
    {
343 1
        $key = $this->normalizeCacheKey($key);
344 1
        $cacheItemPool = $this->sdk->getCacheItemPool();
345 1
        if ($cacheItemPool) {
0 ignored issues
show
introduced by
$cacheItemPool is of type Psr\Cache\CacheItemPoolInterface, thus it always evaluated to true.
Loading history...
346 1
            $cacheKey = $this->sdk->getCachePrefix() . $key;
347
348 1
            if ($cacheItemPool->hasItem($cacheKey)) {
349 1
                return $cacheItemPool->deleteItem($cacheKey);
350
            }
351
        }
352
353 1
        return true;
354
    }
355
356
    /**
357
     * addQueryParameter
358
     *
359
     * @param string $path path to call
360
     * @param array $params query parameters to add
361
     *
362
     * @return string
363
     */
364
    protected function addQueryParameter($path, $params = [])
365
    {
366 1
        if (empty($params)) {
367 1
            return $path;
368
        }
369
370 1
        return $path . '?' . http_build_query($params);
371
    }
372
373
    /**
374
     * convertQueryParameters
375
     *
376
     * @param array $queryParameters
377
     *
378
     * @return array
379
     */
380
    private function convertQueryParameters($queryParameters)
381
    {
382 1
        $mapping = $this->sdk->getMapping();
383
384 1
        return array_map(
385 1
            function ($item) use ($mapping) {
386 1
                if (is_object($item)) {
387 1
                    $classname = get_class($item);
388
389 1
                    if ($mapping->hasClassMetadata($classname)) {
390 1
                        $idAttr = $mapping->getClassMetadata($classname)
391 1
                            ->getIdentifierAttribute();
392
393 1
                        if ($idAttr) {
0 ignored issues
show
introduced by
$idAttr is of type Mapado\RestClientSdk\Mapping\Attribute, thus it always evaluated to true.
Loading history...
394 1
                            $idGetter = 'get' . ucfirst($idAttr->getAttributeName());
395
396 1
                            return $item->{$idGetter}();
397
                        }
398
                    }
399
400 1
                    if (method_exists($item, 'getId')) {
401 1
                        return call_user_func([$item, 'getId']);
402
                    }
403
                }
404
405 1
                return $item;
406 1
            },
407 1
            $queryParameters
408
        );
409
    }
410
411
    /**
412
     * normalizeCacheKey
413
     *
414
     * @return string
415
     */
416
    private function normalizeCacheKey($key)
417
    {
418 1
        return preg_replace('~[\\/\{\}@:\(\)]~', '_', $key);
419
    }
420
421
    private function getClassMetadata()
422
    {
423 1
        if (!isset($this->classMetadata)) {
0 ignored issues
show
Bug introduced by
The property classMetadata does not exist on Mapado\RestClientSdk\EntityRepository. Did you mean classMetadataCache?
Loading history...
424 1
            $this->classMetadataCache = $this->sdk
425 1
                ->getMapping()
426 1
                ->getClassMetadata($this->entityName);
427
        }
428
429 1
        return $this->classMetadataCache;
430
    }
431
}
432