Volume   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Test Coverage

Coverage 93.85%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 59
dl 0
loc 147
ccs 61
cts 65
cp 0.9385
rs 10
c 1
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A fillNode() 0 9 1
A getFlat() 0 3 1
A cutPathStart() 0 10 2
A toType() 0 12 4
A __construct() 0 4 1
A filterDoubleDot() 0 3 1
B process() 0 43 11
A orderUp() 0 5 1
A getRecursive() 0 3 1
A orderDown() 0 5 1
1
<?php
2
3
namespace kalanis\kw_tree\DataSources;
4
5
6
use CallbackFilterIterator;
7
use FilesystemIterator;
8
use Iterator;
9
use kalanis\kw_files\Interfaces\ITypes;
10
use kalanis\kw_paths\ArrayPath;
11
use kalanis\kw_paths\PathsException;
12
use kalanis\kw_tree\Essentials\FileNode;
13
use kalanis\kw_tree\Interfaces\ITree;
14
use RecursiveDirectoryIterator;
15
use RecursiveIteratorIterator;
16
use SplFileInfo;
17
18
19
/**
20
 * Class Volume
21
 * @package kalanis\kw_tree\DataSources
22
 * The source is local volume
23
 */
24
class Volume extends ASources
25
{
26
    protected string $systemDir = '';
27
    protected ArrayPath $libPath;
28
29 5
    public function __construct(string $systemDir)
30
    {
31 5
        $this->systemDir = $systemDir;
32 5
        $this->libPath = new ArrayPath();
33 5
    }
34
35
    /**
36
     * @throws PathsException
37
     * @return $this
38
     */
39 5
    public function process(): ITree
40
    {
41 5
        $path = realpath($this->systemDir . DIRECTORY_SEPARATOR . $this->libPath->setArray($this->startPath)->getString());
42 5
        if (false === $path) {
43 1
            return $this;
44
        }
45
46 4
        $iter = $this->recursive ? $this->getRecursive($path) : $this->getFlat($path) ;
47 4
        $iter = new CallbackFilterIterator($iter, [$this, 'filterDoubleDot']);
48 4
        if ($this->filterCallback) {
49 2
            $iter = new CallbackFilterIterator($iter, $this->filterCallback);
50
        }
51
52
        /** @var FileNode[] $nodes */
53 4
        $nodes = [];
54
        // sometimes the root node is filtered out - put it there for each situation
55 4
        $initNode = new SplFileInfo($path);
56 4
        $nodes[''] = $this->fillNode($initNode, '');
57
58 4
        foreach ($iter as $item) {
59
            /** @var SplFileInfo $item */
60 4
            $cutPath = $this->cutPathStart($path, $item->getRealPath());
61 4
            if (!is_null($cutPath)) {
62 4
                $nodes[$cutPath] = $this->fillNode($item, $cutPath);
63
            }
64
        }
65
66 4
        if (ITree::ORDER_NONE != $this->ordering) {
67 3
            uasort(
68 3
                $nodes,
69 3
                (ITree::ORDER_ASC == $this->ordering ? [$this, 'orderUp'] : [$this, 'orderDown'])
70
            );
71
        }
72
73 4
        foreach ($nodes as $node) {
74 4
            $parentPath = $this->libPath->setArray($node->getPath())->getStringDirectory();
75 4
            if (!empty($node->getPath()) && isset($nodes[$parentPath])) {
76 4
                $nodes[$parentPath]->addSubNode($node);
77
            }
78
        }
79
80 4
        $this->startNode = $nodes[''];
81 4
        return $this;
82
    }
83
84 3
    protected function getFlat(string $path): Iterator
85
    {
86 3
        return new FilesystemIterator($path);
87
    }
88
89 1
    protected function getRecursive(string $path): Iterator
90
    {
91 1
        return new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
92
    }
93
94 4
    public function filterDoubleDot(SplFileInfo $info): bool
95
    {
96 4
        return ( ITree::PARENT_DIR != $info->getFilename() ) ;
97
    }
98
99
    /**
100
     * @param FileNode $file1
101
     * @param FileNode $file2
102
     * @throws PathsException
103
     * @return int
104
     */
105 2
    public function orderUp(FileNode $file1, FileNode $file2): int
106
    {
107 2
        return strcasecmp(
108 2
            $this->libPath->setArray($file1->getPath())->getString(),
109 2
            $this->libPath->setArray($file2->getPath())->getString()
110
        );
111
    }
112
113
    /**
114
     * @param FileNode $file1
115
     * @param FileNode $file2
116
     * @throws PathsException
117
     * @return int
118
     */
119 1
    public function orderDown(FileNode $file1, FileNode $file2): int
120
    {
121 1
        return strcasecmp(
122 1
            $this->libPath->setArray($file2->getPath())->getString(),
123 1
            $this->libPath->setArray($file1->getPath())->getString()
124
        );
125
    }
126
127
    /**
128
     * @param SplFileInfo $file
129
     * @param string $path
130
     * @throws PathsException
131
     * @return FileNode
132
     */
133 4
    protected function fillNode(SplFileInfo $file, string $path): FileNode
134
    {
135 4
        $node = new FileNode();
136 4
        return $node->setData(
137 4
            $this->libPath->setString($path)->getArray(),
138 4
            $file->getSize(),
139 4
            $this->toType($file),
140 4
            $file->isReadable(),
141 4
            $file->isWritable()
142
        );
143
    }
144
145 4
    protected function cutPathStart(string $start, string $what): ?string
146
    {
147 4
        $isKnown = mb_strpos($what, $start);
148 4
        if (0 === $isKnown) {
149 4
            return mb_substr($what, mb_strlen($start) + 1);
150
        } else {
151
            // @codeCoverageIgnoreStart
152
            // false for unknown or higher number for elsewhere
153
            // this node will be kicked out of results later
154
            return null;
155
        }
156
        // @codeCoverageIgnoreEnd
157
    }
158
159 4
    protected function toType(SplFileInfo $file): string
160
    {
161 4
        switch ($file->getType()) {
162 4
            case 'dir':
163 4
                return ITypes::TYPE_DIR;
164 3
            case 'file':
165 3
                return ITypes::TYPE_FILE;
166
            // @codeCoverageIgnoreStart
167
            case 'link':
168
                return ITypes::TYPE_LINK;
169
            default:
170
                return ITypes::TYPE_UNKNOWN;
171
            // @codeCoverageIgnoreEnd
172
        }
173
    }
174
}
175