ForcedRename   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 8
dl 0
loc 120
ccs 34
cts 34
cp 1
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getMethod() 0 4 1
A handle() 0 17 3
A isValidRename() 0 20 5
A compareTypes() 0 32 5
1
<?php
2
3
namespace Twistor\Flysystem\Plugin;
4
5
use League\Flysystem\FileNotFoundException;
6
use League\Flysystem\Util;
7
use Twistor\Flysystem\Exception\DirectoryExistsException;
8
use Twistor\Flysystem\Exception\DirectoryNotEmptyException;
9
use Twistor\Flysystem\Exception\NotADirectoryException;
10
11
class ForcedRename extends AbstractPlugin
12
{
13
    /**
14
     * @inheritdoc
15
     */
16 210
    public function getMethod()
17
    {
18 210
        return 'forcedRename';
19
    }
20
21
    /**
22
     * Renames a file.
23
     *
24
     * @param string $path    path to file
25
     * @param string $newpath new path
26
     *
27
     * @return bool
28
     *
29
     * @throws \League\Flysystem\FileNotFoundException
30
     * @throws \Twistor\Flysystem\Exception\DirectoryExistsException
31
     * @throws \Twistor\Flysystem\Exception\DirectoryNotEmptyException
32
     * @throws \Twistor\Flysystem\Exception\NotADirectoryException
33
     */
34 39
    public function handle($path, $newpath)
35
    {
36 39
        $path = Util::normalizePath($path);
37 39
        $newpath = Util::normalizePath($newpath);
38
39
        // Ignore useless renames.
40 39
        if ($path === $newpath) {
41 6
            return true;
42
        }
43
44 39
        if ( ! $this->isValidRename($path, $newpath)) {
45
            // Returns false if a Flysystem call fails.
46 3
            return false;
47
        }
48
49 6
        return (bool) $this->filesystem->getAdapter()->rename($path, $newpath);
50
    }
51
52
    /**
53
     * Checks that a rename is valid.
54
     *
55
     * @param string $source
56
     * @param string $dest
57
     *
58
     * @return bool
59
     *
60
     * @throws \League\Flysystem\FileNotFoundException
61
     * @throws \Twistor\Flysystem\Exception\DirectoryExistsException
62
     * @throws \Twistor\Flysystem\Exception\DirectoryNotEmptyException
63
     * @throws \Twistor\Flysystem\Exception\NotADirectoryException
64
     */
65 39
    protected function isValidRename($source, $dest)
66
    {
67 39
        $adapter = $this->filesystem->getAdapter();
68
69 39
        if ( ! $adapter->has($source)) {
70 6
            throw new FileNotFoundException($source);
71
        }
72
73 33
        $subdir = Util::dirname($dest);
74
75 33
        if (strlen($subdir) && ! $adapter->has($subdir)) {
76 6
            throw new FileNotFoundException($source);
77
        }
78
79 27
        if ( ! $adapter->has($dest)) {
80 6
            return true;
81
        }
82
83 27
        return $this->compareTypes($source, $dest);
84
    }
85
86
    /**
87
     * Compares the file/dir for the source and dest.
88
     *
89
     * @param string $source
90
     * @param string $dest
91
     *
92
     * @return bool
93
     *
94
     * @throws \Twistor\Flysystem\Exception\DirectoryExistsException
95
     * @throws \Twistor\Flysystem\Exception\DirectoryNotEmptyException
96
     * @throws \Twistor\Flysystem\Exception\NotADirectoryException
97
     */
98 27
    protected function compareTypes($source, $dest)
99
    {
100 27
        $adapter = $this->filesystem->getAdapter();
101
102 27
        $source_type = $adapter->getMetadata($source)['type'];
103 27
        $dest_type = $adapter->getMetadata($dest)['type'];
104
105
        // These three checks are done in order of cost to minimize Flysystem
106
        // calls.
107
108
        // Don't allow overwriting different types.
109 27
        if ($source_type !== $dest_type) {
110 12
            if ($dest_type === 'dir') {
111 6
                throw new DirectoryExistsException();
112
            }
113
114 6
            throw new NotADirectoryException();
115
        }
116
117
        // Allow overwriting destination file.
118 15
        if ($source_type === 'file') {
119 9
            return $adapter->delete($dest);
120
        }
121
122
        // Allow overwriting destination directory if not empty.
123 12
        $contents = $this->filesystem->listContents($dest);
124 12
        if ( ! empty($contents)) {
125 6
            throw new DirectoryNotEmptyException();
126
        }
127
128 6
        return $adapter->deleteDir($dest);
129
    }
130
}
131