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