ProcessDir::noDirectoryDelimiterSet()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
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\Traits\TLang;
14
use kalanis\kw_files\Traits\TSubPart;
15
use kalanis\kw_paths\ArrayPath;
16
use kalanis\kw_paths\Extras\TPathTransform;
17
use kalanis\kw_paths\PathsException;
18
use kalanis\kw_storage\Extras\TRemoveCycle;
19
use kalanis\kw_storage\Extras\TVolumeCopy;
20
use RecursiveDirectoryIterator;
21
use RecursiveIteratorIterator;
22
use SplFileInfo;
23
use Throwable;
24
25
26
/**
27
 * Class ProcessDir
28
 * @package kalanis\kw_files\Processing\Volume
29
 * Process dirs in basic ways
30
 */
31
class ProcessDir implements IProcessDirs
32
{
33
    use TLang;
34
    use TPath;
35
    use TPathTransform;
36
    use TRemoveCycle;
37
    use TSubPart;
38
    use TVolumeCopy;
39
40
    protected int $sliceStartParts = 0;
41
    protected int $sliceCustomParts = 0;
42
43
    /**
44
     * @param string $path
45
     * @param IFLTranslations|null $lang
46
     * @throws PathsException
47
     */
48 23
    public function __construct(string $path = '', ?IFLTranslations $lang = null)
49
    {
50 23
        $this->setFlLang($lang);
51 23
        $this->setPath($path);
52
    }
53
54
    /**
55
     * @param string $path
56
     * @throws PathsException
57
     */
58 23
    public function setPath(string $path = ''): void
59
    {
60 23
        $used = realpath($path);
61 23
        if (false !== $used) {
62 22
            $this->path = $used;
63 22
            $this->sliceStartParts = count($this->expandName($used));
64
        }
65
    }
66
67 4
    public function createDir(array $entry, bool $deep = false): bool
68
    {
69 4
        $path = $this->fullPath($entry);
70
        try {
71 4
            return @mkdir($path, 0777, $deep);
72
            // @codeCoverageIgnoreStart
73
        } catch (Throwable $ex) {
74
            throw new FilesException($this->getFlLang()->flCannotCreateDir($path), $ex->getCode(), $ex);
75
        }
76
        // @codeCoverageIgnoreEnd
77
    }
78
79 4
    public function readDir(array $entry, bool $loadRecursive = false, bool $wantSize = false): array
80
    {
81 4
        $path = $this->fullPath($entry);
82 4
        $this->sliceCustomParts = count($entry);
83 4
        if (!is_dir($path)) {
84 1
            throw new FilesException($this->getFlLang()->flCannotReadDir($path));
85
        }
86
87
        try {
88 3
            $iter = $loadRecursive
89 1
                ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path))
90 3
                : new FilesystemIterator($path, 0)
91 3
            ;
92 3
            return array_values(
93 3
                array_merge(
94 3
                    $this->addRootNode($path, $loadRecursive),
95 3
                    array_map(
96 3
                        [$this, 'intoNode'],
97 3
                        array_filter(
98 3
                            array_filter(
99 3
                                array_filter(
100 3
                                    iterator_to_array($iter)
101 3
                                ),
102 3
                                [$this, 'filterFilesAndDirsOnly']
103 3
                            ),
104 3
                            [$this, 'filterDots']
105 3
                        )
106 3
                    )
107 3
                )
108 3
            );
109
            // @codeCoverageIgnoreStart
110
        } catch (Throwable $ex) {
111
            throw new FilesException($this->getFlLang()->flCannotReadDir($path), $ex->getCode(), $ex);
112
        }
113
        // @codeCoverageIgnoreEnd
114
    }
115
116
    /**
117
     * @param string $path
118
     * @param bool $loadRecursive
119
     * @throws PathsException
120
     * @return Node[]
121
     */
122 3
    protected function addRootNode(string $path, bool $loadRecursive): array
123
    {
124 3
        if (PHP_VERSION_ID >= 80200) {
125
            // these versions pass root node in filesystem iterator implicitly
126
            return [];
127
        }
128 3
        if ($loadRecursive) {
129
            // recursive iterator pass root node implicitly
130 1
            return [];
131
        }
132
        // filesystem iterator in older versions skips root node
133 2
        return [$this->intoNode(new SplFileInfo($path))];
134
    }
135
136 3
    public function filterFilesAndDirsOnly(SplFileInfo $file): bool
137
    {
138 3
        return in_array($file->getType(), [ITypes::TYPE_DIR, ITypes::TYPE_FILE]);
139
    }
140
141 3
    public function filterDots(SplFileInfo $file): bool
142
    {
143 3
        return '..' !== $file->getFilename();
144
    }
145
146
    /**
147
     * @param SplFileInfo $file
148
     * @throws PathsException
149
     * @return Node
150
     */
151 3
    public function intoNode(SplFileInfo $file): Node
152
    {
153 3
        $node = new Node();
154 3
        return $node->setData(
155 3
            array_slice($this->expandName($file->getRealPath()), $this->sliceStartParts + $this->sliceCustomParts),
156 3
            $file->getSize(),
157 3
            $file->getType()
158 3
        );
159
    }
160
161 5
    public function copyDir(array $source, array $dest): bool
162
    {
163 5
        $src = $this->fullPath($source);
164 5
        $dst = $this->fullPath($dest);
165 5
        if ($this->isSubPart($dest, $source)) {
166 1
            return false;
167
        }
168
169 4
        if (!file_exists($src)) {
170 1
            return false;
171
        }
172
173 3
        $dstArr = new ArrayPath();
174 3
        $dstArr->setArray($dest);
175
176 3
        if (!file_exists($this->fullPath($dstArr->getArrayDirectory()))) {
177 1
            return false;
178
        }
179
180 2
        if (file_exists($dst)) {
181 1
            return false;
182
        }
183
184
        try {
185 1
            return $this->xcopy($src, $dst);
186
            // @codeCoverageIgnoreStart
187
        } catch (Throwable $ex) {
188
            throw new FilesException($this->getFlLang()->flCannotCopyDir($src, $dst), $ex->getCode(), $ex);
189
        }
190
        // @codeCoverageIgnoreEnd
191
    }
192
193 5
    public function moveDir(array $source, array $dest): bool
194
    {
195 5
        $src = $this->fullPath($source);
196 5
        $dst = $this->fullPath($dest);
197 5
        if ($this->isSubPart($dest, $source)) {
198 1
            return false;
199
        }
200
201 4
        if (!file_exists($src)) {
202 1
            return false;
203
        }
204
205 3
        $dstArr = new ArrayPath();
206 3
        $dstArr->setArray($dest);
207
208 3
        if (!file_exists($this->fullPath($dstArr->getArrayDirectory()))) {
209 1
            return false;
210
        }
211
212 2
        if (file_exists($dst)) {
213 1
            return false;
214
        }
215
216
        try {
217
            // original call with doomed sub-calls chmod and chown - see
218
            // @link https://www.php.net/manual/en/function.rename.php#117590
219
            // return @rename($src, $dst);
220
221
            // to avoid that internal bug...
222 1
            $v1 = $this->copyDir($source, $dest);
223 1
            $v2 = $this->deleteDir($source, true);
224 1
            return $v1 && $v2;
225
            // @codeCoverageIgnoreStart
226
        } catch (Throwable $ex) {
227
            throw new FilesException($this->getFlLang()->flCannotMoveDir($src, $dst), $ex->getCode(), $ex);
228
        }
229
        // @codeCoverageIgnoreEnd
230
    }
231
232 6
    public function deleteDir(array $entry, bool $deep = false): bool
233
    {
234 6
        $path = $this->fullPath($entry);
235
        try {
236 6
            if ($deep) {
237 3
                return $this->removeCycle($path);
238
            } else {
239 6
                return @rmdir($path);
240
            }
241
            // @codeCoverageIgnoreStart
242
        } catch (Throwable $ex) {
243
            throw new FilesException($this->getFlLang()->flCannotRemoveDir($path), $ex->getCode(), $ex);
244
        }
245
        // @codeCoverageIgnoreEnd
246
    }
247
248
    /**
249
     * @param array<string> $path
250
     * @throws PathsException
251
     * @return string
252
     */
253 19
    protected function fullPath(array $path): string
254
    {
255 19
        return $this->getPath() . DIRECTORY_SEPARATOR . $this->compactName($path);
256
    }
257
258
    /**
259
     * @return string
260
     * @codeCoverageIgnore only when path fails
261
     */
262
    protected function noDirectoryDelimiterSet(): string
263
    {
264
        return $this->getFlLang()->flNoDirectoryDelimiterSet();
265
    }
266
}
267