Passed
Push — master ( 79545d...728467 )
by Petr
02:28
created

Basic::isNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
1
<?php
2
3
namespace kalanis\kw_files\Processing\Storage\Dirs;
4
5
6
use kalanis\kw_files\FilesException;
7
use kalanis\kw_files\Interfaces\IFLTranslations;
8
use kalanis\kw_files\Interfaces\IProcessNodes;
9
use kalanis\kw_files\Interfaces\ITypes;
10
use kalanis\kw_files\Node;
11
use kalanis\kw_paths\ArrayPath;
12
use kalanis\kw_storage\Interfaces\IStorage;
13
use kalanis\kw_storage\StorageException;
14
15
16
/**
17
 * Class Basic
18
 * @package kalanis\kw_files\Processing\Storage\Dirs
19
 * Process dirs via lookup
20
 */
21
class Basic extends ADirs
22
{
23
    /** @var IStorage */
24
    protected $storage = null;
25
26 33
    public function __construct(IStorage $storage, ?IFLTranslations $lang = null)
27
    {
28 33
        $this->storage = $storage;
29 33
        $this->setLang($lang);
30 33
    }
31
32 10
    public function createDir(array $entry, bool $deep = false): bool
33
    {
34 10
        $full = array_merge([''], $entry);
35 10
        $entryPath = $this->compactName($full, $this->getStorageSeparator());
36
        try {
37 10
            if ($this->storage->exists($entryPath)) {
38 2
                return false;
39
            }
40 9
            $total = count($full);
41 9
            for ($i = 1; $i < $total; $i++) {
42 9
                $subNodeName = $this->compactName(array_slice($full, 0, $i), $this->getStorageSeparator());
43 9
                $exists = $this->storage->exists($subNodeName);
44 9
                if ($exists) {
45 5
                    if (!$this->isNode($subNodeName)) {
46
                        // current node is file/data
47 5
                        return false;
48
                    }
49
                } else {
50 8
                    if ($deep) {
51
                        // create deep tree
52 8
                        $this->storage->write($subNodeName, IProcessNodes::STORAGE_NODE_KEY);
53
                    } else {
54
                        // cannot create in shallow tree
55 1
                        return false;
56
                    }
57
                }
58
            }
59 9
            return $this->storage->write($entryPath, IProcessNodes::STORAGE_NODE_KEY);
60 1
        } catch (StorageException $ex) {
61 1
            throw new FilesException($this->getLang()->flCannotCreateDir($entryPath), $ex->getCode(), $ex);
62
        }
63
    }
64
65 7
    public function readDir(array $entry, bool $loadRecursive = false, bool $wantSize = false): array
66
    {
67 7
        $entryPath = $this->removeSeparator($this->compactName(array_filter($entry), $this->getStorageSeparator()));
68 7
        $entryPath = empty($entryPath) ? '' : $this->getStorageSeparator() . $entryPath;
69
        try {
70 7
            if (!$this->isNode($entryPath)) {
71 1
                throw new FilesException($this->getLang()->flCannotReadDir($entryPath));
72
            }
73
            /** @var array<string, Node> */
74 5
            $files = [];
75 5
            $sepLen = mb_strlen($this->getStorageSeparator());
76 5
            foreach ($this->storage->lookup($entryPath) as $item) {
77 5
                $usePath = mb_substr($item, $sepLen);
78 5
                if (!$loadRecursive && (false !== mb_strpos($usePath, $this->getStorageSeparator()))) {
79
                    // pass sub when not need
80 3
                    continue;
81
                }
82
83 5
                $sub = new Node();
84 5
                $currentPath = $this->removeSeparator($this->compactName(array_merge(
85 5
                    $entry,
86 5
                    $this->expandName($usePath, $this->getStorageSeparator())
87 5
                ), $this->getStorageSeparator()));
88 5
                if (empty($item)) {
89 5
                    $sub->setData(
90 5
                        [],
91 5
                        0,
92 5
                        ITypes::TYPE_DIR
93
                    );
94 5
                } elseif ($this->isNode($this->getStorageSeparator() . $currentPath)) {
95 4
                    $sub->setData(
96 4
                        $this->expandName($usePath),
97 4
                        0,
98 4
                        ITypes::TYPE_DIR
99
                    );
100
                } else {
101
                    // normal node - file
102 4
                    $sub->setData(
103 4
                        $this->expandName($usePath),
104 4
                        $wantSize ? $this->getSize($this->getStorageSeparator() . $currentPath) : 0,
105 4
                        ITypes::TYPE_FILE
106
                    );
107
                }
108 5
                $files[] = $sub;
109
            }
110 5
            return $files;
111 2
        } catch (StorageException $ex) {
112 1
            throw new FilesException($this->getLang()->flCannotReadDir($entryPath), $ex->getCode(), $ex);
113
        }
114
    }
115
116 7
    protected function removeSeparator(string $path): string
117
    {
118 7
        $sepLen = mb_strlen($this->getStorageSeparator());
119 7
        $first = mb_substr($path, 0, $sepLen);
120 7
        return $this->getStorageSeparator() == $first ? mb_substr($path, $sepLen) : $path;
121
    }
122
123 6
    public function copyDir(array $source, array $dest): bool
124
    {
125 6
        $src = $this->getStorageSeparator() . $this->compactName($source, $this->getStorageSeparator());
126 6
        $dst = $this->getStorageSeparator() . $this->compactName($dest, $this->getStorageSeparator());
127
        try {
128 6
            if ($this->isSubPart($dest, $source)) {
129 1
                return false;
130
            }
131
132 5
            if (!$this->isNode($src)) {
133 1
                return false;
134
            }
135 3
            if ($this->storage->exists($dst)) {
136 1
                return false;
137
            }
138 2
            $dstArr = new ArrayPath();
139 2
            $dstArr->setArray($dest);
140 2
            $tgt = $this->compactName($dstArr->getArrayDirectory(), $this->getStorageSeparator());
141 2
            if (!empty($tgt) && !$this->storage->exists($this->getStorageSeparator() . $tgt)) {
142 1
                return false;
143
            }
144
145 1
            $paths = $this->storage->lookup($src);
146 1
            $this->storage->write($dst, IProcessNodes::STORAGE_NODE_KEY);
147 1
            foreach ($paths as $path) {
148 1
                if (empty($path)) {
149
                    // skip current
150 1
                    continue;
151
                }
152 1
                $this->storage->write($dst . $path, $this->storage->read($src . $path));
153
            }
154 1
            return true;
155 1
        } catch (StorageException $ex) {
156 1
            throw new FilesException($this->getLang()->flCannotCopyDir($src, $dst), $ex->getCode(), $ex);
157
        }
158
    }
159
160 6
    public function moveDir(array $source, array $dest): bool
161
    {
162 6
        $src = $this->getStorageSeparator() . $this->compactName($source, $this->getStorageSeparator());
163 6
        $dst = $this->getStorageSeparator() . $this->compactName($dest, $this->getStorageSeparator());
164
        try {
165 6
            if ($this->isSubPart($dest, $source)) {
166 1
                return false;
167
            }
168
169 5
            if (!$this->isNode($src)) {
170 1
                return false;
171
            }
172 3
            if ($this->storage->exists($dst)) {
173 1
                return false;
174
            }
175 2
            $dstArr = new ArrayPath();
176 2
            $dstArr->setArray($dest);
177 2
            $tgt = $this->compactName($dstArr->getArrayDirectory(), $this->getStorageSeparator());
178 2
            if (!empty($tgt) && !$this->storage->exists($this->getStorageSeparator() . $tgt)) {
179 1
                return false;
180
            }
181
182 1
            $paths = $this->storage->lookup($src);
183 1
            $this->storage->write($dst, IProcessNodes::STORAGE_NODE_KEY);
184 1
            foreach ($paths as $path) {
185 1
                if (empty($path)) {
186
                    // skip current
187 1
                    continue;
188
                }
189 1
                $this->storage->write($dst . $path, $this->storage->read($src . $path));
190 1
                $this->storage->remove($src . $path);
191
            }
192 1
            return $this->storage->remove($src);
193 1
        } catch (StorageException $ex) {
194 1
            throw new FilesException($this->getLang()->flCannotMoveDir($src, $dst), $ex->getCode(), $ex);
195
        }
196
    }
197
198 8
    public function deleteDir(array $entry, bool $deep = false): bool
199
    {
200 8
        $path = $this->getStorageSeparator() . $this->compactName($entry, $this->getStorageSeparator());
201
        try {
202 8
            if (!$this->storage->exists($path)) {
203 1
                return false;
204
            }
205 7
            if (!$this->isNode($path)) {
206 1
                return false;
207
            }
208 6
            $paths = $this->storage->lookup($path);
209 6
            foreach ($paths as $item) {
210 6
                if ('' != $item) {
211
                    // found something
212 4
                    if (!$deep) {
213 2
                        return false;
214
                    }
215 3
                    $this->storage->remove($path . $item);
216
                }
217
            }
218 5
            return $this->storage->remove($path);
219 1
        } catch (StorageException $ex) {
220 1
            throw new FilesException($this->getLang()->flCannotRemoveDir($path), $ex->getCode(), $ex);
221
        }
222
    }
223
224
    /**
225
     * @param string $entry
226
     * @throws StorageException
227
     * @return bool
228
     */
229 23
    protected function isNode(string $entry): bool
230
    {
231 23
        return $this->storage->exists($entry) ? (IProcessNodes::STORAGE_NODE_KEY === $this->storage->read($entry)) : false;
232
    }
233
234
    /**
235
     * @param string $file
236
     * @throws FilesException
237
     * @throws StorageException
238
     * @return int
239
     */
240 1
    protected function getSize(string $file): int
241
    {
242 1
        $content = $this->storage->read($file);
243 1
        if (is_resource($content)) {
244
            // a bit workaround
245 1
            $tempStream = fopen("php://temp", "w+b");
246 1
            if (false === $tempStream) {
247
                // @codeCoverageIgnoreStart
248
                throw new FilesException($this->getLang()->flCannotLoadFile($file));
249
            }
250
            // @codeCoverageIgnoreEnd
251 1
            rewind($content);
252 1
            $size = stream_copy_to_stream($content, $tempStream, -1, 0);
253 1
            if (false === $size) {
254
                // @codeCoverageIgnoreStart
255
                throw new FilesException($this->getLang()->flCannotGetSize($file));
256
            }
257
            // @codeCoverageIgnoreEnd
258 1
            return intval($size);
259
        } else {
260 1
            return mb_strlen(strval($content));
261
        }
262
    }
263
264
    /**
265
     * @return string
266
     * @codeCoverageIgnore only when path fails
267
     */
268
    protected function noDirectoryDelimiterSet(): string
269
    {
270
        return $this->getLang()->flNoDirectoryDelimiterSet();
271
    }
272
}
273