Passed
Push — master ( 95ec1e...702df7 )
by Petr
02:32
created

Basic::removeSeparator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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