Passed
Branch 3.0.0 (0ebb76)
by Pieter
02:27
created

MemoryDataLayer   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 37
c 0
b 0
f 0
dl 0
loc 119
rs 10
wmc 13

6 Methods

Rating   Name   Duplication   Size   Complexity  
A persistNew() 0 17 4
A persistExisting() 0 9 2
A remove() 0 4 2
A retrieve() 0 7 2
A __construct() 0 4 1
A retrieveAll() 0 9 2
1
<?php
2
namespace W2w\Lib\Apie\Plugins\Core\DataLayers;
3
4
use Symfony\Component\PropertyAccess\PropertyAccess;
5
use Symfony\Component\PropertyAccess\PropertyAccessor;
6
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
7
use W2w\Lib\Apie\Core\IdentifierExtractor;
8
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterFromMetadataTrait;
9
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterHelper;
10
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterRequest;
11
use W2w\Lib\Apie\Exceptions\CanNotDetermineIdException;
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
17
/**
18
 * Persists and retrieves from an array in memory. Only useful for unit tests.
19
 */
20
class MemoryDataLayer implements ApiResourcePersisterInterface, ApiResourceRetrieverInterface, SearchFilterProviderInterface
21
{
22
    use SearchFilterFromMetadataTrait;
23
24
    /**
25
     * @var PropertyAccessorInterface
26
     */
27
    private $propertyAccessor;
28
29
    /**
30
     * @var IdentifierExtractor
31
     */
32
    private $identifierExtractor;
33
34
    /**
35
     * @var mixed[]
36
     */
37
    private $persisted = [];
38
39
    public function __construct(PropertyAccessor $propertyAccessor = null, IdentifierExtractor $identifierExtractor = null)
40
    {
41
        $this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
42
        $this->identifierExtractor = $identifierExtractor ?? new IdentifierExtractor($this->propertyAccessor);
43
    }
44
    /**
45
     * Persist a new API resource. Should return the new API resource.
46
     *
47
     * @param mixed $resource
48
     * @param array $context
49
     * @return mixed
50
     */
51
    public function persistNew($resource, array $context = [])
52
    {
53
        $className = get_class($resource);
54
        $identifier = $this->identifierExtractor->getIdentifierKey($resource, $context) ?? 'id';
55
        $keepReference = $context['keep_reference'] ?? false;
56
        if (!$this->propertyAccessor->isReadable($resource, $identifier)) {
57
            throw new CanNotDetermineIdException($resource, $identifier);
58
        }
59
        $id = (string) $this->propertyAccessor->getValue($resource, $identifier);
60
        if (empty($this->persisted[$className])) {
61
            $this->persisted[$className] = [];
62
        }
63
        if (!$keepReference) {
64
            $resource = clone $resource;
65
        }
66
        $this->persisted[$className][$id] = $resource;
67
        return $resource;
68
    }
69
70
    /**
71
     * Persist an existing API resource. The input resource is the modified API resource. Should return the new API
72
     * resource.
73
     *
74
     * @param mixed $resource
75
     * @param string|int $int
76
     * @param array $context
77
     * @return mixed
78
     */
79
    public function persistExisting($resource, $int, array $context = [])
80
    {
81
        $className = get_class($resource);
82
        $keepReference = $context['keep_reference'] ?? false;
83
        if (!$keepReference) {
84
            $resource = clone $resource;
85
        }
86
        $this->persisted[$className][(string) $int] = $resource;
87
        return $resource;
88
    }
89
90
    /**
91
     * Removes an existing API resource.
92
     *
93
     * @param string $resourceClass
94
     * @param string|int $id
95
     * @param array $context
96
     * @return mixed
97
     */
98
    public function remove(string $resourceClass, $id, array $context)
99
    {
100
        if (!empty($this->persisted[$resourceClass][$id])) {
101
            unset($this->persisted[$resourceClass][$id]);
102
        }
103
    }
104
105
    /**
106
     * Retrieves a single resource by some identifier.
107
     *
108
     * @param string $resourceClass
109
     * @param string|int $id
110
     * @param array $context
111
     * @return mixed
112
     */
113
    public function retrieve(string $resourceClass, $id, array $context)
114
    {
115
        $id = (string) $id;
116
        if (empty($this->persisted[$resourceClass][$id])) {
117
            throw new ResourceNotFoundException($id);
118
        }
119
        return $this->persisted[$resourceClass][$id];
120
    }
121
122
    /**
123
     * Retrieves a list of resources with some pagination.
124
     *
125
     * @param string $resourceClass
126
     * @param array $context
127
     * @param SearchFilterRequest $searchFilterRequest
128
     * @return iterable
129
     */
130
    public function retrieveAll(string $resourceClass, array $context, SearchFilterRequest $searchFilterRequest): iterable
131
    {
132
        if (empty($this->persisted[$resourceClass])) {
133
            return [];
134
        }
135
        return SearchFilterHelper::applySearchFilter(
136
            $this->persisted[$resourceClass],
137
            $searchFilterRequest,
138
            $this->propertyAccessor
139
        );
140
    }
141
}
142