Completed
Push — master ( 23d46a...ee003d )
by Pol
03:02
created

PhpVfs::stream_write()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 4
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
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 6
    public static function fs(): FilesystemInterface
66
    {
67 6
        $options = \stream_context_get_options(
68 6
            \stream_context_get_default()
69
        );
70
71 6
        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 6
    public static function register(Filesystem $filesystem, array $options = [])
86
    {
87
        $options = [
88 6
            static::SCHEME => [
89 6
                'filesystem' => $filesystem,
90
                'currentFile' => null,
91 6
            ] + $options,
92
        ];
93
94 6
        \stream_context_set_default($options);
95 6
        \stream_wrapper_register(self::SCHEME, __CLASS__);
96 6
    }
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
        $directory
128 1
            ->add($from);
129
130 1
        return true;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 1
    public function rmdir(string $path, int $options): bool
137
    {
138 1
        $cwd = $this::fs()
139 1
            ->getCwd()
140 1
            ->rmdir($path);
141
142 1
        $this::fs()
143 1
            ->setCwd($cwd);
144
145 1
        return true;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function stream_cast(int $cast_as) // phpcs:ignore
152
    {
153
        throw new \Exception('Not implemented yet.');
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159 5
    public function stream_close(): void // phpcs:ignore
160
    {
161 5
        if (null !== $file = $this->getCurrentFile()) {
162 5
            $file->setPosition(0);
163
        }
164
165 5
        $this->setCurrentFile(null);
166 5
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171 1
    public function stream_eof(): bool // phpcs:ignore
172
    {
173 1
        return true;
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179 5
    public function stream_flush(): bool // phpcs:ignore
180
    {
181 5
        \clearstatcache();
182
183 5
        return true;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function stream_lock($operation): bool // phpcs:ignore
190
    {
191
        throw new \Exception('Not implemented yet.');
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 5
    public function stream_open(string $resource, string $mode, int $options, ?string &$openedPath): bool // phpcs:ignore
198
    {
199 5
        $modeSplit = \str_split(\str_replace('b', '', $mode));
200
201 5
        $appendMode = \in_array('a', $modeSplit, true);
202 5
        $readMode = \in_array('r', $modeSplit, true);
203 5
        $writeMode = \in_array('w', $modeSplit, true);
204 5
        $extended = \in_array('+', $modeSplit, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $extended is dead and can be removed.
Loading history...
205
206 5
        $resourcePath = Path::fromString($resource);
207
208 5
        $resourceExist = $this::fs()->getCwd()->exist($resource);
209 5
        $resourceDirnameExist = $this::fs()->getCwd()->exist($resourcePath->dirname());
0 ignored issues
show
Unused Code introduced by
The assignment to $resourceDirnameExist is dead and can be removed.
Loading history...
210
211 5
        if (false === $resourceExist) {
212
            if (true === $readMode) {
213
                if ($options & STREAM_REPORT_ERRORS) {
214
                    \trigger_error(\sprintf('%s: failed to open stream.', $resourcePath), E_USER_WARNING);
215
                }
216
217
                return false;
218
            }
219
220
            $this::fs()
221
                ->getCwd()
222
                ->add(File::create($resource)->root());
223
        }
224
225 5
        $file = $this::fs()->getCwd()->get($resource);
226
227 5
        if (!($file instanceof FileInterface)) {
228
            if ($options & STREAM_REPORT_ERRORS) {
229
                \trigger_error(\sprintf('fopen(%s): failed to open stream: Not a file.', $resource), E_USER_WARNING);
230
            }
231
232
            return false;
233
        }
234
235 5
        $fileHandler = new Handler\File($file, $mode, 0);
236
237 5
        if (true === $appendMode) {
238
            $fileHandler->seekToEnd();
239 5
        } elseif (true === $writeMode) {
240 5
            $fileHandler->truncate();
241 5
            \clearstatcache();
242
        }
243
244 5
        $this->setCurrentFile($fileHandler);
245
246 5
        $openedPath = $file->getPath()->__toString();
247
248 5
        return true;
249
    }
250
251
    /**
252
     * {@inheritdoc}
253
     */
254
    public function stream_read(int $bytes) // phpcs:ignore
255
    {
256
        if ((null === $file = $this->getCurrentFile()) || (false === $file->isReadable())) {
257
            return false;
258
        }
259
260
        return $file->read($bytes);
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool // phpcs:ignore
267
    {
268
        throw new \Exception('Not implemented yet.');
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274
    public function stream_set_option(int $option, int $arg1, int $arg2): bool // phpcs:ignore
275
    {
276
        throw new \Exception('Not implemented yet.');
277
    }
278
279
    /**
280
     * {@inheritdoc}
281
     */
282 1
    public function stream_stat(): array // phpcs:ignore
283
    {
284 1
        if (null === $file = $this->getCurrentFile()) {
285 1
            return [];
286
        }
287
288 1
        return (array) $file->getFile()->getAttributes();
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function stream_tell(): int // phpcs:ignore
295
    {
296
        throw new \Exception('Not implemented yet.');
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302 5
    public function stream_write(string $data): int // phpcs:ignore
303
    {
304 5
        if ((null === $file = $this->getCurrentFile()) || (false === $file->isWritable())) {
305 1
            return 0;
306
        }
307
308 5
        return $file->write($data);
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314 1
    public function unlink(string $path): bool
315
    {
316 1
        if (true === $this::fs()->getCwd()->exist($path)) {
317 1
            $file = $this::fs()->getCwd()->get($path);
318
319 1
            if (null !== $parent = $file->getParent()) {
320 1
                $parent->delete($file);
321
            }
322
        }
323
324 1
        return true;
325
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330 6
    public static function unregister()
331
    {
332 6
        \stream_wrapper_unregister(self::SCHEME);
333 6
    }
334
335
    /**
336
     * {@inheritdoc}
337
     */
338
    public function url_stat(string $path, int $flags): array // phpcs:ignore
339
    {
340
        throw new \Exception('Not implemented yet.');
341
    }
342
343
    /**
344
     * @return null|\drupol\phpvfs\Handler\File
345
     */
346 5
    protected function getCurrentFile(): ?Handler\File
347
    {
348 5
        $options = \stream_context_get_options(
349 5
            \stream_context_get_default()
350
        );
351
352 5
        return $options[static::SCHEME]['currentFile'];
353
    }
354
355
    /**
356
     * @param null|\drupol\phpvfs\Handler\File $file
357
     */
358 5
    protected function setCurrentFile(?Handler\File $file)
359
    {
360 5
        $options = \stream_context_get_options(
361 5
            \stream_context_get_default()
362
        );
363
364 5
        $options[static::SCHEME]['currentFile'] = $file;
365
366 5
        \stream_context_set_default($options);
367 5
    }
368
}
369