Passed
Pull Request — master (#77)
by Dmitriy
02:31
created

FileStorage::reindexObjects()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
ccs 0
cts 5
cp 0
crap 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Debug\Storage;
6
7
use Yiisoft\Aliases\Aliases;
8
use Yiisoft\VarDumper\VarDumper;
9
use Yiisoft\Yii\Debug\Collector\CollectorInterface;
10
use Yiisoft\Yii\Debug\Collector\IndexCollectorInterface;
11
use Yiisoft\Yii\Debug\DebuggerIdGenerator;
12
use Yiisoft\Yii\Filesystem\FilesystemInterface;
13
14
final class FileStorage implements StorageInterface
15
{
16
    /**
17
     * @var CollectorInterface[]
18
     */
19
    private array $collectors = [];
20
21
    private string $path;
22
23
    private int $historySize = 50;
24
25
    private DebuggerIdGenerator $idGenerator;
26
27
    private FilesystemInterface $filesystem;
28
29
    private Aliases $aliases;
30
31
    public function __construct(
32
        string $path,
33
        FilesystemInterface $filesystem,
34
        DebuggerIdGenerator $idGenerator,
35
        Aliases $aliases
36
    ) {
37
        $this->path = $path;
38
        $this->filesystem = $filesystem;
39
        $this->idGenerator = $idGenerator;
40
        $this->aliases = $aliases;
41
    }
42
43
    public function addCollector(CollectorInterface $collector): void
44
    {
45
        $this->collectors[get_class($collector)] = $collector;
46
    }
47
48
    public function setHistorySize(int $historySize): void
49
    {
50
        $this->historySize = $historySize;
51
    }
52
53
    public function getData(): array
54
    {
55
        $data = [];
56
        foreach ($this->collectors as $collector) {
57
            $data[get_class($collector)] = $collector->getCollected();
58
        }
59
60
        return $data;
61
    }
62
63
    public function flush(): void
64
    {
65
        $basePath = $this->path . '/' . date('Y-m-d') . '/' . $this->idGenerator->getId() . '/';
66
        try {
67
            $varDumper = VarDumper::create($this->getData());
68
            $jsonData = $varDumper->asJson();
69
            $this->filesystem->write($basePath . 'data.json', $jsonData);
70
71
            $jsonObjects = json_decode($varDumper->asJsonObjectsMap(), true);
72
            $jsonObjects = $this->reindexObjects($jsonObjects);
73
            $this->filesystem->write($basePath . 'objects.json', VarDumper::create($jsonObjects)->asJson());
74
75
            $indexData = VarDumper::create($this->collectIndexData())->asJson();
76
            $this->filesystem->write($basePath . 'index.json', $indexData);
77
78
            $this->gc();
79
        } finally {
80
            $this->collectors = [];
81
        }
82
    }
83
84
    /**
85
     * Collects summary data of current request.
86
     *
87
     * @return array
88
     */
89
    private function collectIndexData(): array
90
    {
91
        $indexData = ['id' => $this->idGenerator->getId()];
92
93
        foreach ($this->collectors as $collector) {
94
            if ($collector instanceof IndexCollectorInterface) {
95
                $indexData = \array_merge($indexData, $collector->getIndexData());
96
            }
97
        }
98
99
        return $indexData;
100
    }
101
102
    /**
103
     * Removes obsolete data files
104
     *
105
     * @throws \League\Flysystem\FilesystemException
106
     */
107
    private function gc(): void
108
    {
109
        $indexFiles = \glob($this->aliases->get($this->path) . '/**/**/index.json', GLOB_NOSORT);
110
        if (\count($indexFiles) >= $this->historySize + 1) {
0 ignored issues
show
Bug introduced by
It seems like $indexFiles can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

110
        if (\count(/** @scrutinizer ignore-type */ $indexFiles) >= $this->historySize + 1) {
Loading history...
111
            \uasort($indexFiles, fn ($a, $b) => \filemtime($b) <=> \filemtime($a));
0 ignored issues
show
Bug introduced by
It seems like $indexFiles can also be of type false; however, parameter $array of uasort() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

111
            \uasort(/** @scrutinizer ignore-type */ $indexFiles, fn ($a, $b) => \filemtime($b) <=> \filemtime($a));
Loading history...
112
            $excessFiles = \array_slice($indexFiles, $this->historySize);
113
            foreach ($excessFiles as $file) {
114
                $path1 = \dirname($file);
115
                $path2 = \dirname($file, 2);
116
                $path3 = \dirname($file, 3);
117
                $resource = substr($path1, strlen($path3));
118
                $this->filesystem->deleteDirectory($this->path . $resource);
119
120
                // Clean empty group directories
121
                $group = substr($path2, strlen($path3));
122
                $list = $this->filesystem->listContents($this->path . $group);
123
                if (empty($list->toArray())) {
124
                    $this->filesystem->deleteDirectory($this->path . $group);
125
                }
126
            }
127
        }
128
    }
129
130
    private function reindexObjects(array $objectsAsArraysCollection): array
131
    {
132
        $result = [];
133
        foreach ($objectsAsArraysCollection as $objectAsArray) {
134
            $result = array_merge($result, $objectAsArray);
135
        }
136
137
        return $result;
138
    }
139
}
140