Completed
Push — master ( 20e2c2...b48497 )
by Pol
02:23
created

PhpVfs::stream_read()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 0
cts 4
cp 0
crap 6
rs 10
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace drupol\phpvfs;
6
7
use drupol\phpvfs\Filesystem\Filesystem;
8
use drupol\phpvfs\Filesystem\FilesystemInterface;
9
use drupol\phpvfs\Node\File;
10
use drupol\phpvfs\Node\FileInterface;
11
use drupol\phpvfs\Utils\Path;
12
13
/**
14
 * Class PhpVfs.
15
 */
16
class PhpVfs implements StreamWrapperInterface
17
{
18
    /**
19
     * The scheme.
20
     */
21
    protected const SCHEME = 'phpvfs';
22
23
    /**
24
     * The stream context.
25
     *
26
     * @var array
27
     */
28
    public $context;
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function dir_closedir(): bool // phpcs:ignore
34
    {
35
        throw new \Exception('Not implemented yet.');
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    public function dir_opendir(string $path, int $options): bool // phpcs:ignore
42
    {
43
        throw new \Exception('Not implemented yet.');
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function dir_readdir(): string // phpcs:ignore
50
    {
51
        throw new \Exception('Not implemented yet.');
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function dir_rewinddir(): bool // phpcs:ignore
58
    {
59
        throw new \Exception('Not implemented yet.');
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65 5
    public static function fs(): FilesystemInterface
66
    {
67 5
        $options = \stream_context_get_options(
68 5
            \stream_context_get_default()
69
        );
70
71 5
        return $options[static::SCHEME]['filesystem'];
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function mkdir(string $path, int $mode, int $options): bool
78
    {
79
        throw new \Exception('Not implemented yet.');
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85 5
    public static function register(Filesystem $filesystem, array $options = [])
86
    {
87
        $options = [
88 5
            static::SCHEME => [
89 5
                'filesystem' => $filesystem,
90
                'currentFile' => null,
91 5
            ] + $options,
92
        ];
93
94 5
        \stream_context_set_default($options);
95 5
        \stream_wrapper_register(self::SCHEME, __CLASS__);
96 5
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 1
    public function rename(string $from, string $to): bool
102
    {
103 1
        if (!$this::fs()->getCwd()->exist($from)) {
104
            throw new \Exception('Source resource does not exist.');
105
        }
106
107 1
        $from = $this::fs()->getCwd()->get($from);
108
109 1
        if ($this::fs()->getCwd()->exist($to)) {
110 1
            throw new \Exception('Destination already exist.');
111
        }
112
113 1
        $toPath = Path::fromString($to);
114
115 1
        $this::fs()
116 1
            ->getCwd()
117 1
            ->mkdir($toPath->dirname());
118
119 1
        if (null !== $parent = $from->getParent()) {
120 1
            $parent->delete($from);
121
        }
122
123 1
        $directory = $this::fs()->getCwd()->cd($toPath->dirname());
124
125 1
        $from->setAttribute('id', $toPath->basename());
126
127 1
        if ($from instanceof FileInterface) {
128 1
            $from->setPosition(0);
129
        }
130
131
        $directory
132 1
            ->add($from);
133
134 1
        return true;
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function rmdir(string $path, int $options): bool
141
    {
142
        $this::fs()
143
            ->getCwd()
144
            ->rmdir($path);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function stream_cast(int $cast_as) // phpcs:ignore
151
    {
152
        throw new \Exception('Not implemented yet.');
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158 5
    public function stream_close(): void // phpcs:ignore
159
    {
160 5
        if (null !== $file = $this->getCurrentFile()) {
161 5
            $file->setPosition(0);
162
        }
163
164 5
        $this->setCurrentFile(null);
165 5
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 1
    public function stream_eof(): bool // phpcs:ignore
171
    {
172 1
        return true;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178 5
    public function stream_flush(): bool // phpcs:ignore
179
    {
180 5
        \clearstatcache();
181
182 5
        return true;
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188
    public function stream_lock($operation): bool // phpcs:ignore
189
    {
190
        throw new \Exception('Not implemented yet.');
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 5
    public function stream_open(string $resource, string $mode, int $options, ?string &$openedPath): bool // phpcs:ignore
197
    {
198 5
        $mode = \str_split(\str_replace('b', '', $mode));
199
200 5
        $appendMode = \in_array('a', $mode, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $appendMode is dead and can be removed.
Loading history...
201 5
        $readMode = \in_array('r', $mode, true);
202 5
        $writeMode = \in_array('w', $mode, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $writeMode is dead and can be removed.
Loading history...
203 5
        $extended = \in_array('+', $mode, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $extended is dead and can be removed.
Loading history...
204
205 5
        $resourcePath = Path::fromString($resource);
206
207 5
        if (!$this::fs()->getCwd()->exist($resource)) {
208
            if ($readMode || !$this::fs()->getCwd()->exist($resourcePath->dirname())) {
209
                if ($options & STREAM_REPORT_ERRORS) {
210
                    \trigger_error(\sprintf('%s: failed to open stream.', $resourcePath), E_USER_WARNING);
211
                }
212
213
                return false;
214
            }
215
216
            $file = File::create($resource);
217
218
            $this->setCurrentFile($file);
219
            $this::fs()
220
                ->getCwd()
221
                ->add($file->root());
222
        }
223
224 5
        $file = $this::fs()->getCwd()->get($resource);
225
226 5
        if (!($file instanceof FileInterface)) {
227
            return false;
228
        }
229
230 5
        $file->setPosition(0);
231
232 5
        $this->setCurrentFile($file);
233
234 5
        return true;
235
    }
236
237
    /**
238
     * {@inheritdoc}
239
     */
240
    public function stream_read(int $bytes) // phpcs:ignore
241
    {
242
        if (null !== $file = $this->getCurrentFile()) {
243
            return $file->read($bytes);
244
        }
245
246
        return false;
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool // phpcs:ignore
253
    {
254
        throw new \Exception('Not implemented yet.');
255
    }
256
257
    /**
258
     * {@inheritdoc}
259
     */
260
    public function stream_set_option(int $option, int $arg1, int $arg2): bool // phpcs:ignore
261
    {
262
        throw new \Exception('Not implemented yet.');
263
    }
264
265
    /**
266
     * {@inheritdoc}
267
     */
268 1
    public function stream_stat(): array // phpcs:ignore
269
    {
270 1
        if (null === $file = $this->getCurrentFile()) {
271 1
            return [];
272
        }
273
274 1
        return (array) $file->getAttributes();
275
    }
276
277
    /**
278
     * {@inheritdoc}
279
     */
280
    public function stream_tell(): int // phpcs:ignore
281
    {
282
        throw new \Exception('Not implemented yet.');
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288 5
    public function stream_write(string $data): int // phpcs:ignore
289
    {
290 5
        if (null !== $file = $this->getCurrentFile()) {
291 5
            return $file->write($data);
292
        }
293
294
        return 0;
295
    }
296
297
    /**
298
     * {@inheritdoc}
299
     */
300 1
    public function unlink(string $path): bool
301
    {
302 1
        if (true === $this::fs()->getCwd()->exist($path)) {
303 1
            $file = $this::fs()->getCwd()->get($path);
304
305 1
            if (null !== $parent = $file->getParent()) {
306 1
                $parent->delete($file);
307
            }
308
        }
309
310 1
        return true;
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316 5
    public static function unregister()
317
    {
318 5
        \stream_wrapper_unregister(self::SCHEME);
319 5
    }
320
321
    /**
322
     * {@inheritdoc}
323
     */
324
    public function url_stat(string $path, int $flags): array // phpcs:ignore
325
    {
326
        throw new \Exception('Not implemented yet.');
327
    }
328
329
    /**
330
     * @return null|FileInterface
331
     */
332 5
    protected function getCurrentFile(): ?FileInterface
333
    {
334 5
        $options = \stream_context_get_options(
335 5
            \stream_context_get_default()
336
        );
337
338 5
        return $options[static::SCHEME]['currentFile'];
339
    }
340
341
    /**
342
     * @param null|FileInterface $file
343
     */
344 5
    protected function setCurrentFile(?FileInterface $file)
345
    {
346 5
        $options = \stream_context_get_options(
347 5
            \stream_context_get_default()
348
        );
349
350 5
        $options[static::SCHEME]['currentFile'] = $file;
351
352 5
        \stream_context_set_default($options);
353 5
    }
354
}
355