Passed
Push — master ( d467ff...321125 )
by Petr
08:04
created

Basic   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Test Coverage

Coverage 98.35%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 122
c 1
b 0
f 0
dl 0
loc 221
ccs 119
cts 121
cp 0.9835
rs 8.8
wmc 45

9 Methods

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