Passed
Push — master ( cb2d88...e8a992 )
by Petr
08:25
created

ProcessDir   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Test Coverage

Coverage 85.29%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 66
dl 0
loc 173
ccs 58
cts 68
cp 0.8529
rs 10
c 1
b 0
f 0
wmc 23

13 Methods

Rating   Name   Duplication   Size   Complexity  
A filterFilesAndDirsOnly() 0 3 1
A filterDots() 0 3 1
A fullPath() 0 3 1
A copyDir() 0 9 2
A noDirectoryDelimiterSet() 0 3 1
A createDir() 0 8 2
A __construct() 0 4 1
A intoNode() 0 7 1
A deleteDir() 0 12 3
A addRootNode() 0 3 1
A moveDir() 0 16 3
A readDir() 0 25 4
A setPath() 0 6 2
1
<?php
2
3
namespace kalanis\kw_files\Processing\Volume;
4
5
6
use FilesystemIterator;
7
use kalanis\kw_files\FilesException;
8
use kalanis\kw_files\Interfaces\IFLTranslations;
9
use kalanis\kw_files\Interfaces\IProcessDirs;
10
use kalanis\kw_files\Interfaces\ITypes;
11
use kalanis\kw_files\Node;
12
use kalanis\kw_files\Processing\TPath;
13
use kalanis\kw_files\Translations;
14
use kalanis\kw_paths\Extras\TPathTransform;
15
use kalanis\kw_paths\PathsException;
16
use kalanis\kw_storage\Extras\TRemoveCycle;
17
use kalanis\kw_storage\Extras\TVolumeCopy;
18
use RecursiveDirectoryIterator;
19
use RecursiveIteratorIterator;
20
use SplFileInfo;
21
use Throwable;
22
23
24
/**
25
 * Class ProcessDir
26
 * @package kalanis\kw_files\Processing\Volume
27
 * Process dirs in basic ways
28
 */
29
class ProcessDir implements IProcessDirs
30
{
31
    use TPath;
32
    use TPathTransform;
33
    use TRemoveCycle;
34
    use TVolumeCopy;
35
36
    /** @var IFLTranslations */
37
    protected $lang = null;
38
    /** @var int */
39
    protected $sliceStartParts = 0;
40
41
    /**
42
     * @param string $path
43
     * @param IFLTranslations|null $lang
44
     * @throws PathsException
45
     */
46 10
    public function __construct(string $path = '', ?IFLTranslations $lang = null)
47
    {
48 10
        $this->lang = $lang ?? new Translations();
49 10
        $this->setPath($path);
50 10
    }
51
52
    /**
53
     * @param string $path
54
     * @throws PathsException
55
     */
56 10
    public function setPath(string $path = ''): void
57
    {
58 10
        $used = realpath($path);
59 10
        if (false !== $used) {
60 9
            $this->path = $used;
61 9
            $this->sliceStartParts = count($this->expandName($used));
62
        }
63 10
    }
64
65 1
    public function createDir(array $entry, bool $deep = false): bool
66
    {
67 1
        $path = $this->fullPath($entry);
68
        try {
69 1
            return @mkdir($path, 0777, $deep);
70
            // @codeCoverageIgnoreStart
71
        } catch (Throwable $ex) {
72
            throw new FilesException($this->lang->flCannotCreateDir($path), $ex->getCode(), $ex);
73
        }
74
        // @codeCoverageIgnoreEnd
75
    }
76
77 4
    public function readDir(array $entry, bool $loadRecursive = false, bool $wantSize = false): array
78
    {
79 4
        $path = $this->fullPath($entry);
80
        try {
81 4
            $iter = $loadRecursive
82 1
                ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path))
83 4
                : new FilesystemIterator($path, 0)
84
            ;
85 3
            return array_values(
86 3
                array_map(
87 3
                    [$this, 'intoNode'],
88 3
                    array_filter(
89 3
                        array_filter(
90 3
                            array_filter(
91 3
                                ($loadRecursive ? [] : [$this->addRootNode($path)]) + iterator_to_array($iter)
92
                            ),
93 3
                            [$this, 'filterFilesAndDirsOnly']
94
                        ),
95 3
                        [$this, 'filterDots']
96
                    )
97
                )
98
            );
99
            // @codeCoverageIgnoreStart
100 1
        } catch (Throwable $ex) {
101 1
            throw new FilesException($this->lang->flCannotReadDir($path), $ex->getCode(), $ex);
102
        }
103
        // @codeCoverageIgnoreEnd
104
    }
105
106 2
    protected function addRootNode(string $path): SplFileInfo
107
    {
108 2
        return new SplFileInfo($path);
109
    }
110
111 3
    public function filterFilesAndDirsOnly(SplFileInfo $file): bool
112
    {
113 3
        return in_array($file->getType(), [ITypes::TYPE_DIR, ITypes::TYPE_FILE]);
114
    }
115
116 3
    public function filterDots(SplFileInfo $file): bool
117
    {
118 3
        return '..' !== $file->getFilename();
119
    }
120
121
    /**
122
     * @param SplFileInfo $file
123
     * @throws PathsException
124
     * @return Node
125
     */
126 3
    public function intoNode(SplFileInfo $file): Node
127
    {
128 3
        $node = new Node();
129 3
        return $node->setData(
130 3
            array_slice($this->expandName($file->getRealPath()), $this->sliceStartParts),
131 3
            $file->getSize(),
132 3
            $file->getType()
133
        );
134
    }
135
136 1
    public function copyDir(array $source, array $dest): bool
137
    {
138 1
        $src = $this->fullPath($source);
139 1
        $dst = $this->fullPath($dest);
140
        try {
141 1
            return $this->xcopy($src, $dst);
142
            // @codeCoverageIgnoreStart
143
        } catch (Throwable $ex) {
144
            throw new FilesException($this->lang->flCannotCopyDir($src, $dst), $ex->getCode(), $ex);
145
        }
146
        // @codeCoverageIgnoreEnd
147
    }
148
149 1
    public function moveDir(array $source, array $dest): bool
150
    {
151 1
        $src = $this->fullPath($source);
152 1
        $dst = $this->fullPath($dest);
153
        try {
154
            // original call with doomed sub-calls chmod and chown - see
155
            // @link https://www.php.net/manual/en/function.rename.php#117590
156
            // return @rename($src, $dst);
157
158
            // to avoid that internal bug...
159 1
            $v1 = $this->copyDir($source, $dest);
160 1
            $v2 = $this->deleteDir($source, true);
161 1
            return $v1 && $v2;
162
            // @codeCoverageIgnoreStart
163
        } catch (Throwable $ex) {
164
            throw new FilesException($this->lang->flCannotMoveDir($src, $dst), $ex->getCode(), $ex);
165
        }
166
        // @codeCoverageIgnoreEnd
167
    }
168
169 1
    public function deleteDir(array $entry, bool $deep = false): bool
170
    {
171 1
        $path = $this->fullPath($entry);
172
        try {
173 1
            if ($deep) {
174 1
                return $this->removeCycle($path);
175
            } else {
176 1
                return @rmdir($path);
177
            }
178
            // @codeCoverageIgnoreStart
179
        } catch (Throwable $ex) {
180
            throw new FilesException($this->lang->flCannotRemoveDir($path), $ex->getCode(), $ex);
181
        }
182
        // @codeCoverageIgnoreEnd
183
    }
184
185
    /**
186
     * @param array<string> $path
187
     * @throws PathsException
188
     * @return string
189
     */
190 6
    protected function fullPath(array $path): string
191
    {
192 6
        return $this->getPath() . DIRECTORY_SEPARATOR . $this->compactName($path);
193
    }
194
195
    /**
196
     * @return string
197
     * @codeCoverageIgnore only when path fails
198
     */
199
    protected function noDirectoryDelimiterSet(): string
200
    {
201
        return $this->lang->flNoDirectoryDelimiterSet();
202
    }
203
}
204