Passed
Push — master ( 696cbf...968eef )
by Melech
05:53 queued 01:56
created

InMemoryFilesystem::timestamp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Filesystem;
15
16
use Valkyrja\Exception\RuntimeException;
17
use Valkyrja\Filesystem\Contract\Filesystem as Contract;
18
use Valkyrja\Filesystem\Data\InMemoryFile;
19
use Valkyrja\Filesystem\Data\InMemoryMetadata;
20
use Valkyrja\Filesystem\Enum\Visibility;
21
use Valkyrja\Filesystem\Exception\UnableToReadContentsException;
22
23
use function fread;
24
use function str_starts_with;
25
use function time;
26
27
/**
28
 * Class InMemoryFilesystem.
29
 *
30
 * @author Melech Mizrachi
31
 */
32
class InMemoryFilesystem implements Contract
33
{
34
    /**
35
     * @var array<string, InMemoryFile>
36
     */
37
    protected array $files = [];
38
39
    public function __construct(
40
        InMemoryFile ...$files
41
    ) {
42
        foreach ($files as $file) {
43
            $this->files[$file->name] = $file;
44
        }
45
    }
46
47
    /**
48
     * @inheritDoc
49
     */
50
    public function exists(string $path): bool
51
    {
52
        return isset($this->files[$path]);
53
    }
54
55
    /**
56
     * @inheritDoc
57
     */
58
    public function read(string $path): string
59
    {
60
        return $this->files[$path]->contents
61
            ?? throw new UnableToReadContentsException("Error reading file contents for $path");
62
    }
63
64
    /**
65
     * @inheritDoc
66
     */
67
    public function write(string $path, string $contents): bool
68
    {
69
        $this->files[$path] = new InMemoryFile($path, $contents, timestamp: time());
70
71
        return true;
72
    }
73
74
    /**
75
     * @inheritDoc
76
     *
77
     * @param resource $resource The resource
78
     */
79
    public function writeStream(string $path, $resource): bool
80
    {
81
        $pathContents = fread($resource, 4096);
82
83
        if ($pathContents === false) {
84
            throw new RuntimeException('Failed to read provided resource');
85
        }
86
87
        $this->files[$path] = new InMemoryFile($path, $pathContents, timestamp: time());
88
89
        return true;
90
    }
91
92
    /**
93
     * @inheritDoc
94
     */
95
    public function update(string $path, string $contents): bool
96
    {
97
        return $this->write($path, $contents);
98
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103
    public function updateStream(string $path, $resource): bool
104
    {
105
        return $this->writeStream($path, $resource);
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    public function put(string $path, string $contents): bool
112
    {
113
        return $this->write($path, $contents);
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public function putStream(string $path, $resource): bool
120
    {
121
        return $this->writeStream($path, $resource);
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function rename(string $path, string $newPath): bool
128
    {
129
        if ($this->exists($newPath) || ! $this->exists($path)) {
130
            return false;
131
        }
132
133
        $this->files[$newPath] = $this->files[$path];
134
135
        $this->delete($path);
136
137
        return true;
138
    }
139
140
    /**
141
     * @inheritDoc
142
     */
143
    public function copy(string $path, string $newPath): bool
144
    {
145
        if ($this->exists($newPath) || ! $this->exists($path)) {
146
            return false;
147
        }
148
149
        $this->files[$newPath] = $this->files[$path];
150
151
        return true;
152
    }
153
154
    /**
155
     * @inheritDoc
156
     */
157
    public function delete(string $path): bool
158
    {
159
        unset($this->files[$path]);
160
161
        return true;
162
    }
163
164
    /**
165
     * @inheritDoc
166
     */
167
    public function metadata(string $path): array|null
168
    {
169
        return $this->getMetadataInternal($path)?->toArray();
170
    }
171
172
    /**
173
     * @inheritDoc
174
     */
175
    public function mimetype(string $path): string|null
176
    {
177
        return $this->getMetadataInternal($path)->mimetype ?? null;
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    public function size(string $path): int|null
184
    {
185
        return $this->getMetadataInternal($path)->size ?? null;
186
    }
187
188
    /**
189
     * @inheritDoc
190
     */
191
    public function timestamp(string $path): int|null
192
    {
193
        return $this->files[$path]->timestamp ?? null;
194
    }
195
196
    /**
197
     * @inheritDoc
198
     */
199
    public function visibility(string $path): string|null
200
    {
201
        return $this->getMetadataInternal($path)->visibility ?? null;
202
    }
203
204
    /**
205
     * @inheritDoc
206
     */
207
    public function setVisibility(string $path, Visibility $visibility): bool
208
    {
209
        if (! $this->exists($path)) {
210
            return false;
211
        }
212
213
        $this->files[$path]->metadata->visibility = $visibility->value;
214
215
        return true;
216
    }
217
218
    /**
219
     * @inheritDoc
220
     */
221
    public function setVisibilityPublic(string $path): bool
222
    {
223
        return $this->setVisibility($path, Visibility::PUBLIC);
224
    }
225
226
    /**
227
     * @inheritDoc
228
     */
229
    public function setVisibilityPrivate(string $path): bool
230
    {
231
        return $this->setVisibility($path, Visibility::PRIVATE);
232
    }
233
234
    /**
235
     * @inheritDoc
236
     */
237
    public function createDir(string $path): bool
238
    {
239
        $this->files[$path] = new InMemoryFile($path, timestamp: time());
240
241
        return true;
242
    }
243
244
    /**
245
     * @inheritDoc
246
     */
247
    public function deleteDir(string $path): bool
248
    {
249
        foreach ($this->files as $filePath => $file) {
250
            if (str_starts_with($filePath, $path)) {
251
                unset($this->files[$filePath]);
252
            }
253
        }
254
255
        return true;
256
    }
257
258
    /**
259
     * @inheritDoc
260
     */
261
    public function listContents(string|null $directory = null, bool $recursive = false): array
262
    {
263
        $directory ??= '';
264
265
        $contents = [];
266
267
        foreach ($this->files as $filePath => $file) {
268
            if (str_starts_with($filePath, $directory)) {
269
                $contents[] = [
270
                    'path'     => $filePath,
271
                    'contents' => $file->contents,
272
                ];
273
            }
274
        }
275
276
        return $contents;
277
    }
278
279
    protected function getMetadataInternal(string $path): InMemoryMetadata|null
280
    {
281
        return $this->files[$path]->metadata ?? null;
282
    }
283
}
284