Filesystem   C
last analyzed

Complexity

Total Complexity 58

Size/Duplication

Total Lines 508
Duplicated Lines 24.02 %

Coupling/Cohesion

Components 2
Dependencies 12

Test Coverage

Coverage 100%

Importance

Changes 9
Bugs 1 Features 0
Metric Value
wmc 58
c 9
b 1
f 0
lcom 2
cbo 12
dl 122
loc 508
ccs 180
cts 180
cp 1
rs 6.3005

34 Methods

Rating   Name   Duplication   Size   Complexity  
A addPlugin() 0 6 1
A findPlugin() 12 12 3
A invokePlugin() 8 8 1
A __call() 12 12 2
A setConfig() 0 4 2
A getConfig() 0 8 2
A prepareConfig() 0 7 1
A __construct() 0 5 1
A getAdapter() 0 4 1
A has() 0 6 2
A write() 8 8 1
A writeStream() 14 14 2
A put() 0 11 2
A putStream() 0 16 3
A readAndDelete() 0 14 2
A update() 9 9 1
A updateStream() 13 13 2
A read() 0 11 2
A readStream() 0 11 2
A rename() 9 9 1
A copy() 9 9 1
A delete() 0 7 1
A deleteDir() 0 10 2
A createDir() 7 7 1
A listContents() 0 7 1
A getMimetype() 0 11 2
A getTimestamp() 0 11 2
A getVisibility() 11 11 2
A getSize() 10 10 3
A setVisibility() 0 6 1
A getMetadata() 0 7 1
A get() 0 14 3
A assertPresent() 0 6 2
A assertAbsent() 0 6 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Filesystem 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Filesystem, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace League\Flysystem;
4
5
use InvalidArgumentException;
6
use BadMethodCallException;
7
use League\Flysystem\Plugin\PluginNotFoundException;
8
use LogicException;
9
use League\Flysystem\Util\ContentListingFormatter;
10
11
/**
12
 * @method array getWithMetadata(string $path, array $metadata)
13
 * @method bool  forceCopy(string $path, string $newpath)
14
 * @method bool  forceRename(string $path, string $newpath)
15
 * @method array listFiles(string $path = '', boolean $recursive = false)
16
 * @method array listPaths(string $path = '', boolean $recursive = false)
17
 * @method array listWith(array $keys = [], $directory = '', $recursive = false)
18
 */
19
class Filesystem implements FilesystemInterface
20
{
21
    /**
22
     * @var array
23
     */
24
    protected $plugins = array();
25
26
    /**
27
     * Register a plugin.
28
     *
29
     * @param PluginInterface $plugin
30
     *
31
     * @return $this
32
     */
33 9
    public function addPlugin(PluginInterface $plugin)
34
    {
35 9
        $this->plugins[$plugin->getMethod()] = $plugin;
36
37 9
        return $this;
38
    }
39
40
    /**
41
     * Find a specific plugin.
42
     *
43
     * @param string $method
44
     *
45
     * @throws LogicException
46
     *
47
     * @return PluginInterface $plugin
48
     */
49 15 View Code Duplication
    protected function findPlugin($method)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
    {
51 15
        if ( ! isset($this->plugins[$method])) {
52 9
            throw new PluginNotFoundException('Plugin not found for method: ' . $method);
53
        }
54
55 9
        if ( ! method_exists($this->plugins[$method], 'handle')) {
56 3
            throw new LogicException(get_class($this->plugins[$method]) . ' does not have a handle method.');
57
        }
58
59 6
        return $this->plugins[$method];
60
    }
61
62
    /**
63
     * Invoke a plugin by method name.
64
     *
65
     * @param string $method
66
     * @param array  $arguments
67
     *
68
     * @return mixed
69
     */
70 15 View Code Duplication
    protected function invokePlugin($method, array $arguments, FilesystemInterface $filesystem)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
71
    {
72 15
        $plugin = $this->findPlugin($method);
73 6
        $plugin->setFilesystem($filesystem);
74 6
        $callback = array($plugin, 'handle');
75
76 6
        return call_user_func_array($callback, $arguments);
77
    }
78
79
    /**
80
     * Plugins pass-through.
81
     *
82
     * @param string $method
83
     * @param array  $arguments
84
     *
85
     * @throws BadMethodCallException
86
     *
87
     * @return mixed
88
     */
89 15 View Code Duplication
    public function __call($method, array $arguments)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
    {
91
        try {
92 15
            return $this->invokePlugin($method, $arguments, $this);
93 12
        } catch (PluginNotFoundException $e) {
94 9
            throw new BadMethodCallException(
95
                'Call to undefined method '
96 9
                . get_class($this)
97 9
                . '::' . $method
98 9
            );
99
        }
100
    }
101
102
103
104
    /**
105
     * @var Config
106
     */
107
    protected $config;
108
109
    /**
110
     * Set the config.
111
     *
112
     * @param Config|array|null $config
113
     */
114 228
    protected function setConfig($config)
115
    {
116 228
        $this->config = $config ? Util::ensureConfig($config) : null;
117 228
    }
118
119
    /**
120
     * Get the Config.
121
     *
122
     * @return Config config object
123
     */
124 57
    public function getConfig()
125
    {
126 57
        if ($this->config === null) {
127 57
            return $this->config = new Config;
128
        }
129
130 12
        return $this->config;
131
    }
132
133
    /**
134
     * Convert a config array to a Config object with the correct fallback.
135
     *
136
     * @param array $config
137
     *
138
     * @return Config
139
     */
140 54
    protected function prepareConfig(array $config)
141
    {
142 54
        $config = new Config($config);
143 54
        $config->setFallback($this->getConfig());
144
145 54
        return $config;
146
    }
147
148
    /**
149
     * @var AdapterInterface
150
     */
151
    protected $adapter;
152
153
    /**
154
     * Constructor.
155
     *
156
     * @param AdapterInterface $adapter
157
     * @param Config|array     $config
158
     */
159 228
    public function __construct(AdapterInterface $adapter, $config = null)
160
    {
161 228
        $this->adapter = $adapter;
162 228
        $this->setConfig($config);
163 228
    }
164
165
    /**
166
     * Get the Adapter.
167
     *
168
     * @return AdapterInterface adapter
169
     */
170 192
    public function getAdapter()
171
    {
172 192
        return $this->adapter;
173
    }
174
175
    /**
176
     * @inheritdoc
177
     */
178 159
    public function has($path)
179
    {
180 159
        $path = Util::normalizePath($path);
181
182 159
        return strlen($path) === 0 ? false : (bool) $this->getAdapter()->has($path);
183
    }
184
185
    /**
186
     * @inheritdoc
187
     */
188 12 View Code Duplication
    public function write($path, $contents, array $config = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
    {
190 12
        $path = Util::normalizePath($path);
191 12
        $this->assertAbsent($path);
192 9
        $config = $this->prepareConfig($config);
193
194 9
        return (bool) $this->getAdapter()->write($path, $contents, $config);
195
    }
196
197
    /**
198
     * @inheritdoc
199
     */
200 15 View Code Duplication
    public function writeStream($path, $resource, array $config = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
    {
202 15
        if ( ! is_resource($resource)) {
203 6
            throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.');
204
        }
205
206 9
        $path = Util::normalizePath($path);
207 9
        $this->assertAbsent($path);
208 9
        $config = $this->prepareConfig($config);
209
210 9
        Util::rewindStream($resource);
211
212 9
        return (bool) $this->getAdapter()->writeStream($path, $resource, $config);
213
    }
214
215
    /**
216
     * @inheritdoc
217
     */
218 9
    public function put($path, $contents, array $config = array())
219
    {
220 9
        $path = Util::normalizePath($path);
221 9
        $config = $this->prepareConfig($config);
222
223 9
        if ($this->has($path)) {
224 6
            return (bool) $this->getAdapter()->update($path, $contents, $config);
225
        }
226
227 6
        return (bool) $this->getAdapter()->write($path, $contents, $config);
228
    }
229
230
    /**
231
     * @inheritdoc
232
     */
233 12
    public function putStream($path, $resource, array $config = array())
234
    {
235 12
        if ( ! is_resource($resource)) {
236 3
            throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.');
237
        }
238
239 9
        $path = Util::normalizePath($path);
240 9
        $config = $this->prepareConfig($config);
241 9
        Util::rewindStream($resource);
242
243 9
        if ($this->has($path)) {
244 6
            return (bool) $this->getAdapter()->updateStream($path, $resource, $config);
245 3
        }
246
247 6
        return (bool) $this->getAdapter()->writeStream($path, $resource, $config);
248
    }
249
250
    /**
251
     * @inheritdoc
252
     */
253 6
    public function readAndDelete($path)
254
    {
255 6
        $path = Util::normalizePath($path);
256 6
        $this->assertPresent($path);
257 6
        $contents = $this->read($path);
258
259 6
        if ($contents === false) {
260 3
            return false;
261
        }
262
263 3
        $this->delete($path);
264
265 3
        return $contents;
266
    }
267
268
    /**
269
     * @inheritdoc
270
     */
271 6 View Code Duplication
    public function update($path, $contents, array $config = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
272
    {
273 6
        $path = Util::normalizePath($path);
274 6
        $config = $this->prepareConfig($config);
275
276 6
        $this->assertPresent($path);
277
278 6
        return (bool) $this->getAdapter()->update($path, $contents, $config);
279
    }
280
281
    /**
282
     * @inheritdoc
283
     */
284 15 View Code Duplication
    public function updateStream($path, $resource, array $config = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
285
    {
286 15
        if ( ! is_resource($resource)) {
287 6
            throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.');
288
        }
289
290 9
        $path = Util::normalizePath($path);
291 9
        $config = $this->prepareConfig($config);
292 9
        $this->assertPresent($path);
293 9
        Util::rewindStream($resource);
294
295 9
        return (bool) $this->getAdapter()->updateStream($path, $resource, $config);
296
    }
297
298
    /**
299
     * @inheritdoc
300
     */
301 36
    public function read($path)
302
    {
303 36
        $path = Util::normalizePath($path);
304 36
        $this->assertPresent($path);
305
306 30
        if ( ! ($object = $this->getAdapter()->read($path))) {
307 3
            return false;
308
        }
309
310 27
        return $object['contents'];
311
    }
312
313
    /**
314
     * @inheritdoc
315
     */
316 12
    public function readStream($path)
317
    {
318 12
        $path = Util::normalizePath($path);
319 12
        $this->assertPresent($path);
320
321 12
        if ( ! $object = $this->getAdapter()->readStream($path)) {
322 6
            return false;
323
        }
324
325 9
        return $object['stream'];
326
    }
327
328
    /**
329
     * @inheritdoc
330
     */
331 9 View Code Duplication
    public function rename($path, $newpath)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
332
    {
333 9
        $path = Util::normalizePath($path);
334 9
        $newpath = Util::normalizePath($newpath);
335 9
        $this->assertPresent($path);
336 9
        $this->assertAbsent($newpath);
337
338 9
        return (bool) $this->getAdapter()->rename($path, $newpath);
339
    }
340
341
    /**
342
     * @inheritdoc
343
     */
344 9 View Code Duplication
    public function copy($path, $newpath)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
345
    {
346 9
        $path = Util::normalizePath($path);
347 9
        $newpath = Util::normalizePath($newpath);
348 9
        $this->assertPresent($path);
349 9
        $this->assertAbsent($newpath);
350
351 9
        return $this->getAdapter()->copy($path, $newpath);
352
    }
353
354
    /**
355
     * @inheritdoc
356
     */
357 60
    public function delete($path)
358
    {
359 60
        $path = Util::normalizePath($path);
360 60
        $this->assertPresent($path);
361
362 57
        return $this->getAdapter()->delete($path);
363
    }
364
365
    /**
366
     * @inheritdoc
367
     */
368 63
    public function deleteDir($dirname)
369
    {
370 63
        $dirname = Util::normalizePath($dirname);
371
372 63
        if ($dirname === '') {
373 3
            throw new RootViolationException('Root directories can not be deleted.');
374
        }
375
376 60
        return (bool) $this->getAdapter()->deleteDir($dirname);
377
    }
378
379
    /**
380
     * @inheritdoc
381
     */
382 3 View Code Duplication
    public function createDir($dirname, array $config = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
383
    {
384 3
        $dirname = Util::normalizePath($dirname);
385 3
        $config = $this->prepareConfig($config);
386
387 3
        return (bool) $this->getAdapter()->createDir($dirname, $config);
388
    }
389
390
    /**
391
     * @inheritdoc
392
     */
393 12
    public function listContents($directory = '', $recursive = false)
394
    {
395 12
        $directory = Util::normalizePath($directory);
396 12
        $contents = $this->getAdapter()->listContents($directory, $recursive);
397 12
        $formatter = new ContentListingFormatter($directory, $recursive);
398 12
        return $formatter->formatListing($contents);
399
    }
400
401
    /**
402
     * @inheritdoc
403
     */
404 9
    public function getMimetype($path)
405
    {
406 9
        $path = Util::normalizePath($path);
407 9
        $this->assertPresent($path);
408
409 9
        if ( ! $object = $this->getAdapter()->getMimetype($path)) {
410 3
            return false;
411
        }
412
413 6
        return $object['mimetype'];
414
    }
415
416
    /**
417
     * @inheritdoc
418
     */
419 9
    public function getTimestamp($path)
420
    {
421 9
        $path = Util::normalizePath($path);
422 9
        $this->assertPresent($path);
423
424 9
        if ( ! $object = $this->getAdapter()->getTimestamp($path)) {
425 3
            return false;
426
        }
427
428 6
        return $object['timestamp'];
429
    }
430
431
    /**
432
     * @inheritdoc
433
     */
434 9 View Code Duplication
    public function getVisibility($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
435
    {
436 9
        $path = Util::normalizePath($path);
437 9
        $this->assertPresent($path);
438
439 9
        if (($object = $this->getAdapter()->getVisibility($path)) === false) {
440 3
            return false;
441
        }
442
443 6
        return $object['visibility'];
444
    }
445
446
    /**
447
     * @inheritdoc
448
     */
449 9 View Code Duplication
    public function getSize($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
450
    {
451 9
        $path = Util::normalizePath($path);
452
453 9
        if (($object = $this->getAdapter()->getSize($path)) === false || ! isset($object['size'])) {
454 3
            return false;
455
        }
456
457 6
        return (int) $object['size'];
458
    }
459
460
    /**
461
     * @inheritdoc
462
     */
463 6
    public function setVisibility($path, $visibility)
464
    {
465 6
        $path = Util::normalizePath($path);
466
467 6
        return (bool) $this->getAdapter()->setVisibility($path, $visibility);
468
    }
469
470
    /**
471
     * @inheritdoc
472
     */
473 51
    public function getMetadata($path)
474
    {
475 51
        $path = Util::normalizePath($path);
476 51
        $this->assertPresent($path);
477
478 51
        return $this->getAdapter()->getMetadata($path);
479
    }
480
481
    /**
482
     * @inheritdoc
483
     */
484 69
    public function get($path, Handler $handler = null)
485
    {
486 69
        $path = Util::normalizePath($path);
487
488 69
        if ( ! $handler) {
489 45
            $metadata = $this->getMetadata($path);
490 45
            $handler = $metadata['type'] === 'file' ? new File($this, $path) : new Directory($this, $path);
491 45
        }
492
493 69
        $handler->setPath($path);
494 69
        $handler->setFilesystem($this);
495
496 69
        return $handler;
497
    }
498
499
    /**
500
     * Assert a file is present.
501
     *
502
     * @param string $path path to file
503
     *
504
     * @throws FileNotFoundException
505
     */
506 126
    public function assertPresent($path)
507
    {
508 126
        if ( ! $this->has($path)) {
509 12
            throw new FileNotFoundException($path);
510
        }
511 120
    }
512
513
    /**
514
     * Assert a file is absent.
515
     *
516
     * @param string $path path to file
517
     *
518
     * @throws FileExistsException
519
     */
520 39
    public function assertAbsent($path)
521
    {
522 39
        if ($this->has($path)) {
523 3
            throw new FileExistsException($path);
524
        }
525 36
    }
526
}
527