Passed
Push — master ( 16d5db...b99896 )
by Pol
02:19
created

PhpVfs   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 340
Duplicated Lines 0 %

Test Coverage

Coverage 63.93%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 97
dl 0
loc 340
ccs 78
cts 122
cp 0.6393
rs 9.0399
c 6
b 0
f 0
wmc 42

26 Methods

Rating   Name   Duplication   Size   Complexity  
A dir_readdir() 0 3 1
A mkdir() 0 3 1
A dir_rewinddir() 0 3 1
A dir_opendir() 0 3 1
A rename() 0 35 5
A register() 0 11 1
A dir_closedir() 0 3 1
A fs() 0 7 1
A getCurrentFile() 0 7 1
A stream_close() 0 7 2
A stream_eof() 0 3 1
A stream_cast() 0 3 1
A stream_read() 0 7 2
A url_stat() 0 3 1
A setCurrentFile() 0 9 1
B stream_open() 0 41 7
A stream_write() 0 7 2
A stream_lock() 0 3 1
A stream_stat() 0 7 2
A rmdir() 0 5 1
A stream_set_option() 0 3 1
A stream_flush() 0 5 1
A stream_seek() 0 3 1
A unlink() 0 11 3
A stream_tell() 0 3 1
A unregister() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like PhpVfs often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PhpVfs, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types = 1);
4
5
namespace drupol\phpvfs;
6
7
use drupol\phpvfs\Command\Cd;
8
use drupol\phpvfs\Command\Exist;
9
use drupol\phpvfs\Command\Get;
10
use drupol\phpvfs\Filesystem\Filesystem;
11
use drupol\phpvfs\Filesystem\FilesystemInterface;
12
use drupol\phpvfs\Node\File;
13
use drupol\phpvfs\Node\FileInterface;
14
use drupol\phpvfs\Utils\Path;
15
16
/**
17
 * Class PhpVfs.
18
 */
19
class PhpVfs implements StreamWrapperInterface
20
{
21
    /**
22
     * The scheme.
23
     */
24
    protected const SCHEME = 'phpvfs';
25
26
    /**
27
     * The stream context.
28
     *
29
     * @var array
30
     */
31
    public $context;
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function dir_closedir(): bool // phpcs:ignore
37
    {
38
        throw new \Exception('Not implemented yet.');
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    public function dir_opendir(string $path, int $options): bool // phpcs:ignore
45
    {
46
        throw new \Exception('Not implemented yet.');
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function dir_readdir(): string // phpcs:ignore
53
    {
54
        throw new \Exception('Not implemented yet.');
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function dir_rewinddir(): bool // phpcs:ignore
61
    {
62
        throw new \Exception('Not implemented yet.');
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 5
    public static function fs(): FilesystemInterface
69
    {
70 5
        $options = \stream_context_get_options(
71 5
            \stream_context_get_default()
72
        );
73
74 5
        return $options[static::SCHEME]['filesystem'];
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function mkdir(string $path, int $mode, int $options): bool
81
    {
82
        throw new \Exception('Not implemented yet.');
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 5
    public static function register(Filesystem $filesystem, array $options = [])
89
    {
90
        $options = [
91 5
            static::SCHEME => [
92 5
                'filesystem' => $filesystem,
93
                'currentFile' => null,
94 5
            ] + $options,
95
        ];
96
97 5
        \stream_context_set_default($options);
98 5
        \stream_wrapper_register(self::SCHEME, __CLASS__);
99 5
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 1
    public function rename(string $from, string $to): bool
105
    {
106 1
        if (!Exist::exec($this::fs(), $from)) {
107
            throw new \Exception('Source resource does not exist.');
108
        }
109
110 1
        $from = Get::exec($this::fs(), $from);
111
112 1
        if (Exist::exec($this::fs(), $to)) {
113 1
            throw new \Exception('Destination already exist.');
114
        }
115
116 1
        $toPath = Path::fromString($to);
117
118 1
        $this::fs()
119 1
            ->getCwd()
120 1
            ->mkdir($toPath->dirname());
121
122 1
        if (null !== $parent = $from->getParent()) {
123 1
            $parent->delete($from);
124
        }
125
126 1
        Cd::exec($this::fs(), $toPath->dirname());
127
128 1
        $from->setAttribute('id', $toPath->basename());
129
130 1
        if ($from instanceof FileInterface) {
131 1
            $from->setPosition(0);
132
        }
133
134 1
        $this::fs()
135 1
            ->getCwd()
136 1
            ->add($from);
137
138 1
        return true;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function rmdir(string $path, int $options): bool
145
    {
146
        $this::fs()
147
            ->getCwd()
148
            ->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...
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function stream_cast(int $cast_as) // phpcs:ignore
155
    {
156
        throw new \Exception('Not implemented yet.');
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 5
    public function stream_close(): void // phpcs:ignore
163
    {
164 5
        if (null !== $file = $this->getCurrentFile()) {
165 5
            $file->setPosition(0);
166
        }
167
168 5
        $this->setCurrentFile(null);
169 5
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 1
    public function stream_eof(): bool // phpcs:ignore
175
    {
176 1
        return true;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182 5
    public function stream_flush(): bool // phpcs:ignore
183
    {
184 5
        \clearstatcache();
185
186 5
        return true;
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192
    public function stream_lock($operation): bool // phpcs:ignore
193
    {
194
        throw new \Exception('Not implemented yet.');
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200 5
    public function stream_open(string $resource, string $mode, int $options, ?string &$openedPath): bool // phpcs:ignore
201
    {
202 5
        $mode = \str_split(\str_replace('b', '', $mode));
203
204 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...
205 5
        $readMode = \in_array('r', $mode, true);
206 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...
207 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...
208
209 5
        $resourcePath = Path::fromString($resource);
210
211 5
        if (!Exist::exec($this::fs(), $resource)) {
212
            if ($readMode || !Exist::exec($this::fs(), $resourcePath->dirname())) {
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
            $file = File::create($resource);
221
222
            $this->setCurrentFile($file);
223
            $this::fs()
224
                ->getCwd()
225
                ->add($file->root());
226
        }
227
228 5
        if (null === $file = $this::fs()->get($resource)) {
229
            return false;
230
        }
231
232 5
        if (!($file instanceof FileInterface)) {
233
            return false;
234
        }
235
236 5
        $file->setPosition(0);
237
238 5
        $this->setCurrentFile($file);
239
240 5
        return true;
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246
    public function stream_read(int $bytes) // phpcs:ignore
247
    {
248
        if (null !== $file = $this->getCurrentFile()) {
249
            return $file->read($bytes);
250
        }
251
252
        return false;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool // phpcs:ignore
259
    {
260
        throw new \Exception('Not implemented yet.');
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function stream_set_option(int $option, int $arg1, int $arg2): bool // phpcs:ignore
267
    {
268
        throw new \Exception('Not implemented yet.');
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274 1
    public function stream_stat(): array // phpcs:ignore
275
    {
276 1
        if (null === $file = $this->getCurrentFile()) {
277 1
            return [];
278
        }
279
280 1
        return (array) $file->getAttributes();
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function stream_tell(): int // phpcs:ignore
287
    {
288
        throw new \Exception('Not implemented yet.');
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294 5
    public function stream_write(string $data): int // phpcs:ignore
295
    {
296 5
        if (null !== $file = $this->getCurrentFile()) {
297 5
            return $file->write($data);
298
        }
299
300
        return 0;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 1
    public function unlink(string $path): bool
307
    {
308 1
        if (true === Exist::exec($this::fs(), $path)) {
309 1
            $file = Get::exec($this::fs(), $path);
310
311 1
            if (null !== $parent = $file->getParent()) {
312 1
                $parent->delete($file);
313
            }
314
        }
315
316 1
        return true;
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322 5
    public static function unregister()
323
    {
324 5
        \stream_wrapper_unregister(self::SCHEME);
325 5
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330
    public function url_stat(string $path, int $flags): array // phpcs:ignore
331
    {
332
        throw new \Exception('Not implemented yet.');
333
    }
334
335
    /**
336
     * @return null|FileInterface
337
     */
338 5
    protected function getCurrentFile(): ?FileInterface
339
    {
340 5
        $options = \stream_context_get_options(
341 5
            \stream_context_get_default()
342
        );
343
344 5
        return $options[static::SCHEME]['currentFile'];
345
    }
346
347
    /**
348
     * @param null|FileInterface $file
349
     */
350 5
    protected function setCurrentFile(?FileInterface $file)
351
    {
352 5
        $options = \stream_context_get_options(
353 5
            \stream_context_get_default()
354
        );
355
356 5
        $options[static::SCHEME]['currentFile'] = $file;
357
358 5
        \stream_context_set_default($options);
359 5
    }
360
}
361