FileStorageDataLayer::retrieveAll()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
namespace W2w\Lib\Apie\Plugins\FileStorage\DataLayers;
3
4
use Pagerfanta\Pagerfanta;
5
use ReflectionClass;
6
use Symfony\Component\Finder\Finder;
7
use W2w\Lib\Apie\Core\IdentifierExtractor;
8
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterFromMetadataTrait;
9
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterRequest;
10
use W2w\Lib\Apie\Exceptions\CouldNotMakeDirectoryException;
11
use W2w\Lib\Apie\Exceptions\CouldNotRemoveFileException;
12
use W2w\Lib\Apie\Exceptions\CouldNotWriteFileException;
13
use W2w\Lib\Apie\Exceptions\InvalidIdException;
14
use W2w\Lib\Apie\Exceptions\ResourceNotFoundException;
15
use W2w\Lib\Apie\Interfaces\ApiResourcePersisterInterface;
16
use W2w\Lib\Apie\Interfaces\ApiResourceRetrieverInterface;
17
use W2w\Lib\Apie\Interfaces\SearchFilterProviderInterface;
18
use W2w\Lib\Apie\Plugins\FileStorage\Pagers\FilestoragePager;
19
20
class FileStorageDataLayer implements ApiResourcePersisterInterface, ApiResourceRetrieverInterface, SearchFilterProviderInterface
21
{
22
    use SearchFilterFromMetadataTrait;
23
24
    /**
25
     * @var string
26
     */
27
    private $folder;
28
29
    /**
30
     * @var IdentifierExtractor
31
     */
32
    private $identifierExtractor;
33
34
    public function __construct(string $folder, IdentifierExtractor  $identifierExtractor)
35
    {
36
        $this->folder = $folder;
37
        $this->identifierExtractor = $identifierExtractor;
38
    }
39
40
    /**
41
     * Persist a new API resource. Should return the new API resource.
42
     *
43
     * @param mixed $resource
44
     * @param array $context
45
     * @return mixed
46
     */
47
    public function persistNew($resource, array $context = [])
48
    {
49
        $id = $this->identifierExtractor->getIdentifierValue($resource, $context);
50
        $this->store($resource, $id);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type null; however, parameter $id of W2w\Lib\Apie\Plugins\Fil...orageDataLayer::store() does only seem to accept string, 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

50
        $this->store($resource, /** @scrutinizer ignore-type */ $id);
Loading history...
51
        return $resource;
52
53
    }
54
55
    /**
56
     * Persist an existing API resource. The input resource is the modified API resource. Should return the new API
57
     * resource.
58
     *
59
     * @param mixed $resource
60
     * @param mixed $int
61
     * @param array $context
62
     * @return mixed
63
     */
64
    public function persistExisting($resource, $int, array $context = [])
65
    {
66
        $id = $this->identifierExtractor->getIdentifierValue($resource, $context);
67
        if ((string) $id !== (string) $int) {
68
            throw new InvalidIdException((string) $int);
69
        }
70
        $this->store($resource, $int);
71
        return $resource;
72
    }
73
74
    /**
75
     * Removes an existing API resource.
76
     *
77
     * @param string $resourceClass
78
     * @param string|int $id
79
     * @param array $context
80
     * @return mixed
81
     */
82
    public function remove(string $resourceClass, $id, array $context)
83
    {
84
        $file = $this->getFilename($resourceClass, $id);
85
        if (!@unlink($file)) {
86
            throw new CouldNotRemoveFileException($file);
87
        }
88
    }
89
90
    /**
91
     * Retrieves a single resource by some identifier.
92
     *
93
     * @param string $resourceClass
94
     * @param string|int $id
95
     * @param array $context
96
     * @return mixed
97
     */
98
    public function retrieve(string $resourceClass, $id, array $context)
99
    {
100
        $file = $this->getFilename($resourceClass, $id);
101
        if (!file_exists($file)) {
102
            throw new ResourceNotFoundException($id);
103
        }
104
        return unserialize(file_get_contents($file));
105
    }
106
107
    /**
108
     * Retrieves a list of resources with some pagination.
109
     *
110
     * @param string $resourceClass
111
     * @param array $context
112
     * @param SearchFilterRequest $searchFilterRequest
113
     * @return Pagerfanta
114
     */
115
    public function retrieveAll(string $resourceClass, array $context, SearchFilterRequest $searchFilterRequest): iterable
116
    {
117
        $folder = $this->getFolder($resourceClass);
118
        $iterator = Finder::create()->files()->sortByName()->depth(0)->in($folder)->getIterator();
119
        $paginator = new Pagerfanta(new FilestoragePager($this, $iterator, $resourceClass, $context));
120
        $searchFilterRequest->updatePaginator($paginator);
121
        return $paginator;
122
    }
123
124
    protected function getFolder(string $resourceClass): string
125
    {
126
        $refl = new ReflectionClass($resourceClass);
127
        $folder = $this->folder . DIRECTORY_SEPARATOR . $refl->getShortName();
128
        if (!is_dir($folder)) {
129
            if (!@mkdir($folder, 0777, true)) {
130
                throw new CouldNotMakeDirectoryException($folder);
131
            };
132
        }
133
        return $folder;
134
    }
135
136
    protected function getFilename(string $resourceClass, string $id): string
137
    {
138
        if (!preg_match('/^[a-zA-Z0-9_.-]+$/', $id)) {
139
            throw new InvalidIdException($id);
140
        }
141
        $folder = $this->getFolder($resourceClass);
142
143
        return $folder . DIRECTORY_SEPARATOR . $id;
144
145
    }
146
147
    private function store($resource, string $id) {
148
        $filename = $this->getFilename(get_class($resource), $id);
149
        if (false === file_put_contents($filename, serialize($resource))) {
150
            throw new CouldNotWriteFileException($filename);
151
        };
152
    }
153
}
154