Passed
Branch v2 (d444af)
by Pieter
02:38
created

MockApiResourceDataLayer::persistNew()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 2
dl 0
loc 13
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace W2w\Lib\Apie\Mocks;
4
5
use Psr\Cache\CacheItemPoolInterface;
6
use ReflectionClass;
7
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
8
use W2w\Lib\Apie\Exceptions\ResourceNotFoundException;
9
use W2w\Lib\Apie\IdentifierExtractor;
10
use W2w\Lib\Apie\Persisters\ApiResourcePersisterInterface;
11
use W2w\Lib\Apie\Retrievers\ApiResourceRetrieverInterface;
12
use W2w\Lib\Apie\Retrievers\SearchFilterFromMetadataTrait;
13
use W2w\Lib\Apie\Retrievers\SearchFilterProviderInterface;
14
use W2w\Lib\Apie\SearchFilters\SearchFilterHelper;
15
use W2w\Lib\Apie\SearchFilters\SearchFilterRequest;
16
17
/**
18
 * If the implementation of a REST API is mocked this is the class that persists and retrieves all API resources.
19
 *
20
 * It does this by persisting it with a cache pool.
21
 */
22
class MockApiResourceDataLayer implements ApiResourcePersisterInterface, ApiResourceRetrieverInterface, SearchFilterProviderInterface
23
{
24
    use SearchFilterFromMetadataTrait;
25
26
    /**
27
     * @var CacheItemPoolInterface
28
     */
29
    private $cacheItemPool;
30
31
    /**
32
     * @var IdentifierExtractor
33
     */
34
    private $identifierExtractor;
35
36
    /**
37
     * @var PropertyAccessorInterface
38
     */
39
    private $propertyAccessor;
40
41
    public function __construct(
42
        CacheItemPoolInterface $cacheItemPool,
43
        IdentifierExtractor $identifierExtractor,
44
        PropertyAccessorInterface $propertyAccessor
45
    ) {
46
        $this->cacheItemPool = $cacheItemPool;
47
        $this->identifierExtractor = $identifierExtractor;
48
        $this->propertyAccessor = $propertyAccessor;
49
    }
50
51
    /**
52
     * @param mixed $resource
53
     * @param array $context
54
     * @return mixed
55
     */
56
    public function persistNew($resource, array $context = [])
57
    {
58
        $id = $this->identifierExtractor->getIdentifierValue($resource, $context);
59
        if (is_null($id)) {
60
            return $resource;
61
        }
62
63
        $cacheKey = 'mock-server.' . $this->shortName($resource) . '.' . $id;
64
        $cacheItem = $this->cacheItemPool->getItem($cacheKey)->set(serialize($resource));
65
        $this->addId(get_class($resource), $id);
66
        $this->cacheItemPool->save($cacheItem);
67
        $this->cacheItemPool->commit();
68
        return $resource;
69
    }
70
71
    /**
72
     * @param mixed $resource
73
     * @param string|int $int
74
     * @param array $context
75
     * @return mixed
76
     */
77
    public function persistExisting($resource, $int, array $context = [])
78
    {
79
        $cacheKey = 'mock-server.' . $this->shortName($resource) . '.' . $int;
80
        $cacheItem = $this->cacheItemPool->getItem($cacheKey)->set(serialize($resource));
81
        $this->addId(get_class($resource), $int);
82
        $this->cacheItemPool->save($cacheItem);
83
        $this->cacheItemPool->commit();
84
        return $resource;
85
    }
86
87
    /**
88
     * @param string $resourceClass
89
     * @param string|int $id
90
     * @param array $context
91
     */
92
    public function remove(string $resourceClass, $id, array $context)
93
    {
94
        $cacheKey = 'mock-server.' . $this->shortName($resourceClass) . '.' . $id;
95
        $this->cacheItemPool->deleteItem($cacheKey);
96
        $this->removeId($resourceClass, $id);
97
        $this->cacheItemPool->commit();
98
    }
99
100
    /**
101
     * @param string $resourceClass
102
     * @param string|int $id
103
     * @param array $context
104
     * @return mixed
105
     */
106
    public function retrieve(string $resourceClass, $id, array $context)
107
    {
108
        $cacheKey = 'mock-server.' . $this->shortName($resourceClass) . '.' . $id;
109
        $cacheItem = $this->cacheItemPool->getItem($cacheKey);
110
        if (!$cacheItem->isHit()) {
111
            throw new ResourceNotFoundException((string) $id);
112
        }
113
        return unserialize($cacheItem->get());
114
    }
115
116
    /**
117
     * @param string $resourceClass
118
     * @param array $context
119
     * @param SearchFilterRequest $searchFilterRequest
120
     * @return iterable
121
     */
122
    public function retrieveAll(string $resourceClass, array $context, SearchFilterRequest $searchFilterRequest): iterable
123
    {
124
        $cacheKey = 'mock-server-all.' . $this->shortName($resourceClass);
125
        $cacheItem = $this->cacheItemPool->getItem($cacheKey);
126
        if (!$cacheItem->isHit()) {
127
            return [];
128
        }
129
        return array_map(
130
            function ($id) use (&$resourceClass, &$context) {
131
                return $this->retrieve($resourceClass, $id, $context);
132
            },
133
            SearchFilterHelper::applySearchFilter($cacheItem->get(), $searchFilterRequest, $this->propertyAccessor)
134
        );
135
    }
136
137
    /**
138
     * Marks an id as found, so the get all can retrieve it.
139
     *
140
     * @param string $resourceClass
141
     * @param string|int $id
142
     */
143
    private function addId(string $resourceClass, $id)
144
    {
145
        $cacheKey = 'mock-server-all.' . $this->shortName($resourceClass);
146
        $cacheItem = $this->cacheItemPool->getItem($cacheKey);
147
        $ids = [];
148
        if ($cacheItem->isHit()) {
149
            $ids = $cacheItem->get();
150
        }
151
        $ids[$id] = $id;
152
        $this->cacheItemPool->save($cacheItem->set($ids));
153
    }
154
155
    /**
156
     * Marks an id as not found, so the get all will no longer retrieve it.
157
     *
158
     * @param string $resourceClass
159
     * @param string|int $id
160
     */
161
    private function removeId(string $resourceClass, $id)
162
    {
163
        $cacheKey = 'mock-server-all.' . $this->shortName($resourceClass);
164
        $cacheItem = $this->cacheItemPool->getItem($cacheKey);
165
        $ids = [];
166
        if ($cacheItem->isHit()) {
167
            $ids = $cacheItem->get();
168
        }
169
        unset($ids[$id]);
170
        $this->cacheItemPool->save($cacheItem->set($ids));
171
    }
172
173
    /**
174
     * Returns a short name of a resource or a resource class.
175
     *
176
     * @param mixed $resourceOrResourceClass
177
     * @return string
178
     */
179
    private function shortName($resourceOrResourceClass): string
180
    {
181
        if (is_string($resourceOrResourceClass)) {
182
            $refl = new ReflectionClass($resourceOrResourceClass);
183
184
            return $refl->getShortName();
185
        }
186
187
        return $this->shortName(get_class($resourceOrResourceClass));
188
    }
189
}
190