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

Basic   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Test Coverage

Coverage 96.75%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 122
dl 0
loc 229
ccs 119
cts 123
cp 0.9675
rs 8.72
c 1
b 0
f 0
wmc 46

10 Methods

Rating   Name   Duplication   Size   Complexity  
A copyDir() 0 23 6
A isNode() 0 3 2
A getSize() 0 21 4
A __construct() 0 4 1
A moveDir() 0 24 6
B deleteDir() 0 23 7
A noDirectoryDelimiterSet() 0 3 1
A removeSeparator() 0 5 2
B createDir() 0 29 7
B readDir() 0 48 10

How to fix   Complexity   

Complex Class

Complex classes like Basic often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Basic, and based on these observations, apply Extract Interface, too.

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