Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
132 / 132 |
|
100.00% |
10 / 10 |
CRAP | |
100.00% |
1 / 1 |
AppCollector | |
100.00% |
132 / 132 |
|
100.00% |
10 / 10 |
33 | |
100.00% |
1 / 1 |
setApp | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
setStartTime | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setEndTime | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setStartMemory | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setEndMemory | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getActivities | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
3 | |||
getContents | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
3 | |||
renderLoadedServices | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
6 | |||
getServices | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
renderAvailableServices | |
100.00% |
53 / 53 |
|
100.00% |
1 / 1 |
11 |
1 | <?php declare(strict_types=1); |
2 | /* |
3 | * This file is part of Aplus Framework MVC Library. |
4 | * |
5 | * (c) Natan Felles <natanfelles@gmail.com> |
6 | * |
7 | * For the full copyright and license information, please view the LICENSE |
8 | * file that was distributed with this source code. |
9 | */ |
10 | namespace Framework\MVC\Debug; |
11 | |
12 | use Framework\Debug\Collector; |
13 | use Framework\Debug\Debugger; |
14 | use Framework\MVC\App; |
15 | use ReflectionClass; |
16 | use ReflectionMethod; |
17 | |
18 | /** |
19 | * Class AppCollector. |
20 | * |
21 | * @package mvc |
22 | */ |
23 | class AppCollector extends Collector |
24 | { |
25 | protected App $app; |
26 | protected float $startTime; |
27 | protected float $endTime; |
28 | protected int $startMemory; |
29 | protected int $endMemory; |
30 | |
31 | public function setApp(App $app) : static |
32 | { |
33 | $this->app = $app; |
34 | if ( ! isset($this->startTime)) { |
35 | $this->setStartTime(); |
36 | } |
37 | if ( ! isset($this->startMemory)) { |
38 | $this->setStartMemory(); |
39 | } |
40 | return $this; |
41 | } |
42 | |
43 | public function setStartTime(float $microtime = null) : static |
44 | { |
45 | $this->startTime = $microtime ?? \microtime(true); |
46 | return $this; |
47 | } |
48 | |
49 | public function setEndTime(float $microtime = null) : static |
50 | { |
51 | $this->endTime = $microtime ?? \microtime(true); |
52 | return $this; |
53 | } |
54 | |
55 | public function setStartMemory(int $memoryUsage = null) : static |
56 | { |
57 | $this->startMemory = $memoryUsage ?? \memory_get_usage(); |
58 | return $this; |
59 | } |
60 | |
61 | public function setEndMemory(int $memoryUsage = null) : static |
62 | { |
63 | $this->endMemory = $memoryUsage ?? \memory_get_usage(); |
64 | return $this; |
65 | } |
66 | |
67 | public function getActivities() : array |
68 | { |
69 | $activities = []; |
70 | $activities[] = [ |
71 | 'collector' => $this->getName(), |
72 | 'class' => static::class, |
73 | 'description' => 'Runtime', |
74 | 'start' => $this->startTime, |
75 | 'end' => $this->endTime, |
76 | ]; |
77 | foreach ($this->getServices() as $service => $data) { |
78 | foreach ($data as $item) { |
79 | $activities[] = [ |
80 | 'collector' => $this->getName(), |
81 | 'class' => static::class, |
82 | 'description' => 'Load service ' . $service . ':' . $item['name'], |
83 | 'start' => $item['start'], |
84 | 'end' => $item['end'], |
85 | ]; |
86 | } |
87 | } |
88 | return $activities; |
89 | } |
90 | |
91 | public function getContents() : string |
92 | { |
93 | if ( ! isset($this->endTime)) { |
94 | $this->setEndTime(\microtime(true)); |
95 | } |
96 | if ( ! isset($this->endMemory)) { |
97 | $this->setEndMemory(\memory_get_usage()); |
98 | } |
99 | \ob_start(); ?> |
100 | <p><strong>Started at:</strong> <?= \date('r', (int) $this->startTime) ?></p> |
101 | <p><strong>Runtime:</strong> <?= \round($this->endTime - $this->startTime, 6) ?> seconds |
102 | </p> |
103 | <p> |
104 | <strong>Memory:</strong> <?= |
105 | Debugger::convertSize($this->endMemory - $this->startMemory) ?> |
106 | </p> |
107 | <h1>Services</h1> |
108 | <h2>Loaded Service Instances</h2> |
109 | <?= $this->renderLoadedServices() ?> |
110 | <h2>Available Services</h2> |
111 | <?php |
112 | echo $this->renderAvailableServices(); |
113 | return \ob_get_clean(); // @phpstan-ignore-line |
114 | } |
115 | |
116 | protected function renderLoadedServices() : string |
117 | { |
118 | $services = $this->getServices(); |
119 | $total = 0; |
120 | foreach ($services as $data) { |
121 | $total += \count($data); |
122 | } |
123 | if ($total === 0) { |
124 | return '<p>No service instance has been loaded.</p>'; |
125 | } |
126 | \ob_start(); ?> |
127 | <p>Total of <?= $total ?> service instance<?= $total !== 1 ? 's' : '' ?> loaded.</p> |
128 | <table> |
129 | <thead> |
130 | <tr> |
131 | <th>Service</th> |
132 | <th>Instances</th> |
133 | <th title="Seconds">Time to Load</th> |
134 | </tr> |
135 | </thead> |
136 | <tbody> |
137 | <?php foreach ($services as $service => $data): ?> |
138 | <?php $count = \count($data) ?> |
139 | <tr> |
140 | <td rowspan="<?= $count ?>"><?= $service ?></td> |
141 | <td><?= $data[0]['name'] ?></td> |
142 | <td><?= \round($data[0]['end'] - $data[0]['start'], 6) ?></td> |
143 | </tr> |
144 | <?php for ($i = 1; $i < $count; $i++): ?> |
145 | <tr> |
146 | <td><?= $data[$i]['name'] ?></td> |
147 | <td><?= \round($data[$i]['end'] - $data[$i]['start'], 6) ?></td> |
148 | </tr> |
149 | <?php endfor ?> |
150 | <?php endforeach ?> |
151 | </tbody> |
152 | </table> |
153 | <?php |
154 | return \ob_get_clean(); // @phpstan-ignore-line |
155 | } |
156 | |
157 | /** |
158 | * @return array<string,mixed> |
159 | */ |
160 | protected function getServices() : array |
161 | { |
162 | $result = []; |
163 | foreach ($this->getData() as $data) { |
164 | if ( ! isset($result[$data['service']])) { |
165 | $result[$data['service']] = []; |
166 | } |
167 | $result[$data['service']][] = [ |
168 | 'name' => $data['instance'], |
169 | 'start' => $data['start'], |
170 | 'end' => $data['end'], |
171 | ]; |
172 | } |
173 | return $result; // @phpstan-ignore-line |
174 | } |
175 | |
176 | protected function renderAvailableServices() : string |
177 | { |
178 | \ob_start(); |
179 | $services = []; |
180 | $class = new ReflectionClass($this->app); |
181 | $methods = $class->getMethods(ReflectionMethod::IS_STATIC); |
182 | foreach ($methods as $method) { |
183 | if ( ! $method->isPublic()) { |
184 | continue; |
185 | } |
186 | $name = $method->getName(); |
187 | if (\in_array($name, [ |
188 | 'config', |
189 | 'getService', |
190 | 'setService', |
191 | 'removeService', |
192 | 'isCli', |
193 | 'setIsCli', |
194 | 'isDebugging', |
195 | ], true)) { |
196 | continue; |
197 | } |
198 | $param = $method->getParameters()[0] ?? null; |
199 | if ( ! $param || $param->getName() !== 'instance') { |
200 | continue; |
201 | } |
202 | if ($param->getType()?->getName() !== 'string') { // @phpstan-ignore-line |
203 | continue; |
204 | } |
205 | $instances = []; |
206 | if ($param->isDefaultValueAvailable()) { |
207 | $instances[] = $param->getDefaultValue(); |
208 | } |
209 | foreach ((array) $this->app::config()->getInstances($name) as $inst => $s) { |
210 | $instances[] = $inst; |
211 | } |
212 | $instances = \array_unique($instances); |
213 | \sort($instances); |
214 | $services[$name] = [ |
215 | 'returnType' => $method->getReturnType()?->getName(), // @phpstan-ignore-line |
216 | 'instances' => $instances, |
217 | ]; |
218 | } |
219 | \ksort($services); |
220 | $countServices = \count($services); |
221 | $s = 0; ?> |
222 | <p>There are <?= $countServices ?> services available.</p> |
223 | <table> |
224 | <thead> |
225 | <tr> |
226 | <th>#</th> |
227 | <th>Service</th> |
228 | <th>Config Instances</th> |
229 | <th>Return Type</th> |
230 | </tr> |
231 | </thead> |
232 | <tbody> |
233 | <?php foreach ($services as $name => $data): ?> |
234 | <?php $count = \count($data['instances']) ?> |
235 | <tr> |
236 | <td rowspan="<?= $count ?>"><?= ++$s ?></td> |
237 | <td rowspan="<?= $count ?>"><?= $name ?></td> |
238 | <td><?= $data['instances'][0] ?></td> |
239 | <td rowspan="<?= $count ?>"><?= $data['returnType'] ?></td> |
240 | </tr> |
241 | <?php for ($i = 1; $i < $count; $i++): ?> |
242 | <tr> |
243 | <td><?= $data['instances'][$i] ?></td> |
244 | </tr> |
245 | <?php endfor ?> |
246 | <?php endforeach ?> |
247 | </tbody> |
248 | </table> |
249 | <?php |
250 | return \ob_get_clean(); // @phpstan-ignore-line |
251 | } |
252 | } |