ProcessDir::removeCycle()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 11
ccs 8
cts 8
cp 1
crap 3
rs 10
1
<?php
2
3
namespace kalanis\kw_files_mapper\Processing\Mapper;
4
5
6
use kalanis\kw_files\FilesException;
7
use kalanis\kw_files\Interfaces\IFLTranslations;
8
use kalanis\kw_files\Interfaces\IProcessDirs;
9
use kalanis\kw_files\Interfaces\IProcessNodes;
10
use kalanis\kw_files\Interfaces\ITypes;
11
use kalanis\kw_files\Node;
12
use kalanis\kw_files\Traits\TLang;
13
use kalanis\kw_files\Traits\TSubPart;
14
use kalanis\kw_files_mapper\Support\Process;
15
use kalanis\kw_files_mapper\Support\TDir;
16
use kalanis\kw_mapper\MapperException;
17
use kalanis\kw_mapper\Records\ARecord;
18
use kalanis\kw_mapper\Search\Search;
19
use kalanis\kw_paths\ArrayPath;
20
use kalanis\kw_paths\Stuff;
21
22
23
/**
24
 * Class ProcessDir
25
 * @package kalanis\kw_files_mapper\Processing\Mapper
26
 * Process dirs in basic ways
27
 */
28
class ProcessDir implements IProcessDirs
29
{
30
    use TDir;
31
    use TEntryLookup;
32
    use TLang;
33
    use TSubPart;
34
35
    protected ARecord $record;
36
37 27
    public function __construct(ARecord $record, ?Process\Translate $translate = null, ?IFLTranslations $lang = null)
38
    {
39 27
        $this->setFlLang($lang);
40 27
        $this->record = $record;
41 27
        $this->setTranslation($translate);
42 27
    }
43
44 5
    public function createDir(array $entry, bool $deep = false): bool
45
    {
46
        try {
47 5
            $parentNode = $this->getEntry([]);
48
49 4
            $maxPos = count($entry) - 1;
50 4
            foreach (array_values($entry) as $pos => $levelKey) {
51
52 4
                $all = $this->getChildrenRecords(strval($levelKey), $parentNode);
53 4
                if (!empty($all)) {
54 1
                    if ($pos == $maxPos) {
55
                        // wanted one already exists
56 1
                        return false;
57
                    }
58 1
                    $parentNode = reset($all);
59 4
                } elseif ($pos == $maxPos) {
60
                    // create wanted one
61 4
                    $parentNode = $this->createRecord(strval($levelKey), $parentNode);
62 3
                } elseif ($deep) {
63
                    // create on lower level
64 3
                    $parentNode = $this->createRecord(strval($levelKey), $parentNode);
65
                } else {
66 1
                    return false;
67
                }
68
            }
69
70 4
            return $parentNode ? $this->isDir($parentNode) : false;
71 1
        } catch (MapperException $ex) {
72 1
            throw new FilesException($this->getFlLang()->flCannotCreateDir(Stuff::arrayToPath($entry)), $ex->getCode(), $ex);
73
        }
74
    }
75
76
    /**
77
     * @param string $currentName
78
     * @param ARecord|null $parentNode
79
     * @throws MapperException
80
     * @return ARecord[]
81
     */
82 4
    protected function getChildrenRecords(string $currentName, ?ARecord $parentNode): array
83
    {
84 4
        $search = new Search($this->getLookupRecord());
85 4
        $search->exact($this->getTranslation()->getCurrentKey(), $currentName);
86 4
        if ($parentNode) {
87 4
            $search->exact(
88 4
                $this->getTranslation()->getParentKey(),
89 4
                strval($parentNode->__get($this->getTranslation()->getPrimaryKey()))
90
            );
91
        } else {
92
            // no root node?!
93
            // @codeCoverageIgnoreStart
94
            $search->null($this->getTranslation()->getParentKey());
95
        }
96
        // @codeCoverageIgnoreEnd
97 4
        return $search->getResults();
98
    }
99
100
    /**
101
     * @param string $name
102
     * @param ARecord|null $parentNode
103
     * @throws MapperException
104
     * @return ARecord
105
     */
106 4
    protected function createRecord(string $name, ?ARecord $parentNode): ARecord
107
    {
108 4
        $record = $this->getLookupRecord();
109 4
        $record->__set(
110 4
            $this->getTranslation()->getParentKey(),
111 4
            $parentNode ? strval($parentNode->__get($this->getTranslation()->getPrimaryKey())) : null
112
        );
113 4
        $record->__set(
114 4
            $this->getTranslation()->getCurrentKey(),
115
            $name
116
        );
117 4
        $record->__set(
118 4
            $this->getTranslation()->getContentKey(),
119 4
            IProcessNodes::STORAGE_NODE_KEY
120
        );
121 4
        $record->save();
122 4
        $record->load();
123
124 4
        return $record;
125
    }
126
127 6
    public function readDir(array $entry, bool $loadRecursive = false, bool $wantSize = false): array
128
    {
129 6
        $entryPath = Stuff::arrayToPath($entry);
130
        try {
131 6
            $node = $this->getEntry($entry);
132 5
            if (is_null($node)) {
133
                // no root node?!
134
                // @codeCoverageIgnoreStart
135
                throw new FilesException($this->getFlLang()->flCannotReadDir($entryPath));
136
            }
137
            // @codeCoverageIgnoreEnd
138
139 5
            if (!$this->isDir($node)) {
140 1
                throw new FilesException($this->getFlLang()->flCannotReadDir($entryPath));
141
            }
142
            /** @var array<string, Node> */
143 4
            $files = [];
144 4
            $startSub = new Node();
145 4
            $startSub->setData(
146 4
                [],
147 4
                0,
148 4
                ITypes::TYPE_DIR
149
            );
150 4
            $files[] = $startSub;
151
152 4
            return array_merge($files, $this->subNodes($node, $loadRecursive, $wantSize));
153 2
        } catch (MapperException $ex) {
154 1
            throw new FilesException($this->getFlLang()->flCannotReadDir($entryPath), $ex->getCode(), $ex);
155
        }
156
    }
157
158
    /**
159
     * @param ARecord $node
160
     * @param bool $loadRecursive
161
     * @param bool $wantSize
162
     * @param string[] $upper
163
     * @throws MapperException
164
     * @return Node[]
165
     */
166 4
    protected function subNodes(ARecord $node, bool $loadRecursive = false, bool $wantSize = false, array $upper = []): array
167
    {
168 4
        $search = new Search($this->getLookupRecord());
169 4
        $search->exact(
170 4
            $this->getTranslation()->getParentKey(),
171 4
            strval($node->__get($this->getTranslation()->getPrimaryKey()))
172
        );
173
174
        /** @var Node[] $files */
175 4
        $files = [];
176 4
        foreach ($search->getResults() as $item) {
177 4
            $path = array_merge($upper, [strval($item->__get($this->getTranslation()->getCurrentKey()))]);
178 4
            if ($this->isDir($item)) {
179 3
                $sub = new Node();
180 3
                $files[] = $sub->setData(
181 3
                    $path,
182 3
                    0,
183 3
                    ITypes::TYPE_DIR
184
                );
185 3
                if ($loadRecursive) {
186 3
                    $files = array_merge($files, $this->subNodes($item, $loadRecursive, $wantSize, $path));
187
                }
188
            } else {
189
                // normal node - file
190 4
                $sub = new Node();
191 4
                $files[] = $sub->setData(
192 4
                    $path,
193 4
                    $wantSize ? $this->getSize($item) : 0,
194 4
                    ITypes::TYPE_FILE
195
                );
196
            }
197
        }
198 4
        return $files;
199
    }
200
201 6
    public function copyDir(array $source, array $dest): bool
202
    {
203
        try {
204 6
            if ($this->isSubPart($dest, $source)) {
205 1
                return false;
206
            }
207
208 5
            $ptDst = new ArrayPath();
209 5
            $ptDst->setArray($dest);
210
211 5
            $src = $this->getEntry($source);
212 4
            if (!$src) {
213 1
                return false;
214
            }
215
216 3
            $dst = $this->getEntry($ptDst->getArrayDirectory());
217 3
            if (!$dst) {
218 1
                return false;
219
            }
220
221 2
            $tgt = $this->getEntry([$ptDst->getFileName()], $dst);
222 2
            if ($tgt) {
0 ignored issues
show
introduced by
$tgt is of type kalanis\kw_mapper\Records\ARecord, thus it always evaluated to true.
Loading history...
223 1
                return false;
224
            }
225
226 1
            $new = $this->getLookupRecord();
227 1
            $new->__set($this->getTranslation()->getCurrentKey(), $ptDst->getFileName());
228 1
            $new->__set($this->getTranslation()->getParentKey(), $dst->__get($this->getTranslation()->getPrimaryKey()));
229 1
            $new->__set($this->getTranslation()->getContentKey(), $dst->__get($this->getTranslation()->getContentKey()));
230 1
            $new->save();
231
232 1
            return $this->copyCycle($src, $new);
233
234 1
        } catch (MapperException $ex) {
235 1
            throw new FilesException($this->getFlLang()->flCannotCopyDir(
236 1
                Stuff::arrayToPath($source),
237 1
                Stuff::arrayToPath($dest)
238 1
            ), $ex->getCode(), $ex);
239
        }
240
    }
241
242 6
    public function moveDir(array $source, array $dest): bool
243
    {
244
        try {
245 6
            if ($this->isSubPart($dest, $source)) {
246 1
                return false;
247
            }
248
249 5
            $ptDst = new ArrayPath();
250 5
            $ptDst->setArray($dest);
251
252 5
            $src = $this->getEntry($source);
253 4
            if (!$src) {
254 1
                return false;
255
            }
256
257 3
            $dst = $this->getEntry($ptDst->getArrayDirectory());
258 3
            if (!$dst) {
259 1
                return false;
260
            }
261
262 2
            $tgt = $this->getEntry([$ptDst->getFileName()], $dst);
263 2
            if ($tgt) {
0 ignored issues
show
introduced by
$tgt is of type kalanis\kw_mapper\Records\ARecord, thus it always evaluated to true.
Loading history...
264 1
                return false;
265
            }
266
267 1
            $src->__set($this->getTranslation()->getCurrentKey(), $ptDst->getFileName());
268 1
            $src->__set($this->getTranslation()->getParentKey(), $dst->__get($this->getTranslation()->getPrimaryKey()));
269 1
            return $src->save();
270
271 1
        } catch (MapperException $ex) {
272 1
            throw new FilesException($this->getFlLang()->flCannotMoveDir(
273 1
                Stuff::arrayToPath($source),
274 1
                Stuff::arrayToPath($dest)
275 1
            ), $ex->getCode(), $ex);
276
        }
277
    }
278
279 7
    public function deleteDir(array $entry, bool $deep = false): bool
280
    {
281
        try {
282 7
            $start = $this->getEntry($entry);
283 6
            if (is_null($start)) {
284 1
                return false;
285
            }
286 6
            if ($deep) {
287 3
                return $this->removeCycle($start);
288 4
            } elseif ($this->isDir($start)) {
289 3
                return $this->removeDir($start);
290
            } else {
291 1
                return false;
292
            }
293 1
        } catch (MapperException $ex) {
294 1
            throw new FilesException($this->getFlLang()->flCannotRemoveDir(Stuff::arrayToPath($entry)), $ex->getCode(), $ex);
295
        }
296
    }
297
298
    /**
299
     * Copy a file, or recursively copy a folder and its contents - version for db storage
300
     * @param ARecord $source Source node
301
     * @param ARecord $dest Destination node
302
     * @throws MapperException
303
     * @return bool
304
     */
305 1
    protected function copyCycle(ARecord $source, ARecord $dest): bool
306
    {
307 1
        $stat = 0;
308
309 1
        $search = new Search($this->getLookupRecord());
310 1
        $search->exact($this->getTranslation()->getParentKey(), strval($source->__get($this->getTranslation()->getPrimaryKey())));
311 1
        $src = $search->getResults();
312
313 1
        foreach ($src as $item) {
314 1
            $newNode = $this->getLookupRecord();
315 1
            $newNode->__set($this->getTranslation()->getCurrentKey(), $item->__get($this->getTranslation()->getCurrentKey()));
316 1
            $newNode->__set($this->getTranslation()->getParentKey(), $dest->__get($this->getTranslation()->getPrimaryKey()));
317 1
            $newNode->__set($this->getTranslation()->getContentKey(), $item->__get($this->getTranslation()->getContentKey()));
318 1
            $stat += intval(!$newNode->save());
319
320 1
            if ($this->isDir($newNode)) {
321 1
                $stat += intval(!$this->copyCycle($item, $newNode));
322
            }
323
        }
324
325 1
        return !boolval($stat);
326
    }
327
328
    /**
329
     * @param ARecord $entry
330
     * @throws MapperException
331
     * @return bool
332
     */
333 3
    protected function removeCycle(ARecord $entry): bool
334
    {
335 3
        if ($this->isDir($entry)) {
336 3
            $search = new Search($this->getLookupRecord());
337 3
            $search->exact($this->getTranslation()->getParentKey(), strval($entry->__get($this->getTranslation()->getPrimaryKey())));
338 3
            $fileListing = $search->getResults();
339 3
            foreach ($fileListing as $fileRecord) {
340 3
                $this->removeCycle($fileRecord);
341
            }
342
        }
343 3
        return $entry->delete();
344
    }
345
346
    /**
347
     * @param ARecord $entry
348
     * @throws MapperException
349
     * @return bool
350
     */
351 3
    protected function removeDir(ARecord $entry): bool
352
    {
353 3
        $subs = new Search($this->getLookupRecord());
354 3
        $subs->exact($this->getTranslation()->getParentKey(), strval($entry->__get($this->getTranslation()->getPrimaryKey())));
355 3
        if (1 > $subs->getCount()) {
356 1
            return $entry->delete();
357
        } else {
358 2
            return false;
359
        }
360
    }
361
362 18
    protected function getLookupRecord(): ARecord
363
    {
364 18
        return clone $this->record;
365
    }
366
}
367