Completed
Branch v4 (4e54dd)
by Pieter
03:26
created

MockApiResourceDataLayer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 54
dl 0
loc 164
rs 10
c 0
b 0
f 0
wmc 16

10 Methods

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