Skip to content

Commit 09af8d8

Browse files
authored
Merge pull request #65 from blitz-php/devs
chore: refactorisation de la debug bar
2 parents cd0e5a2 + 000925b commit 09af8d8

19 files changed

Lines changed: 1348 additions & 126 deletions

File tree

spec/support/application/app/Config/toolbar.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
*/
1111

1212
return [
13-
'collectors' => [],
14-
'collect_var_data' => true,
15-
'max_history' => 20,
16-
'view_path' => SYST_PATH . 'Debug' . DS . 'Toolbar' . DS . 'Views',
17-
'max_queries' => 100,
18-
'show_debugbar' => true,
13+
'collectors' => [],
14+
'collect_var_data' => true,
15+
'max_history' => 20,
16+
'view_path' => SYST_PATH . 'Debug' . DS . 'Toolbar' . DS . 'Views',
17+
'max_queries' => 100,
18+
'show_debugbar' => true,
19+
'watched_directories' => ['app'],
20+
'watched_extensions' => ['php', 'css', 'js', 'html', 'svg', 'json', 'env'],
1921
];
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Blitz PHP framework.
5+
*
6+
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
use BlitzPHP\Exceptions\FrameworkException;
13+
use BlitzPHP\HotReloader\DirectoryHasher;
14+
15+
use function Kahlan\expect;
16+
17+
describe('HotReloader / DirectoryHasher', function (): void {
18+
beforeAll(function (): void {
19+
$this->hasher = new DirectoryHasher();
20+
});
21+
22+
it('hashApp', function (): void {
23+
$results = $this->hasher->hashApp();
24+
25+
expect($results)->toBeA('array');
26+
expect($results)->toContainKey('app');
27+
});
28+
29+
it('Leve une exception si on essai de hasher un dossier invalide', function (): void {
30+
$path = $path = APP_PATH . 'Foo';
31+
32+
expect(fn() => $this->hasher->hashDirectory($path))
33+
->toThrow(FrameworkException::invalidDirectory($path));
34+
});
35+
36+
it('Chaque dossier a un hash unique', function (): void {
37+
$hash1 = $this->hasher->hashDirectory(APP_PATH);
38+
$hash2 = $this->hasher->hashDirectory(SYST_PATH);
39+
40+
expect($hash1)->not->toBe($hash2);
41+
});
42+
43+
it('Un meme dossier produira le meme hash', function (): void {
44+
$hash1 = $this->hasher->hashDirectory(APP_PATH);
45+
$hash2 = $this->hasher->hashDirectory(APP_PATH);
46+
47+
expect($hash1)->toBe($hash2);
48+
});
49+
50+
it ('hash', function (): void {
51+
$expected = md5(implode('', $this->hasher->hashApp()));
52+
53+
expect($expected)->toBe($this->hasher->hash());
54+
});
55+
});

src/Debug/Toolbar.php

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
use BlitzPHP\Formatter\JsonFormatter;
1919
use BlitzPHP\Formatter\XmlFormatter;
2020
use BlitzPHP\Http\Request;
21+
use BlitzPHP\Http\Response;
2122
use BlitzPHP\Utilities\Date;
2223
use BlitzPHP\View\Parser;
2324
use Exception;
2425
use GuzzleHttp\Psr7\Utils;
2526
use Kint\Kint;
26-
use Psr\Http\Message\RequestInterface;
2727
use Psr\Http\Message\ResponseInterface;
2828
use Psr\Http\Message\ServerRequestInterface;
2929
use stdClass;
@@ -66,8 +66,8 @@ public function __construct(?stdClass $config = null)
6666
foreach ($this->config->collectors as $collector) {
6767
if (! class_exists($collector)) {
6868
logger()->critical(
69-
'Toolbar collector does not exist (' . $collector . ').'
70-
. ' Please check $collectors in the app/Config/toolbar.php file.'
69+
'Le collecteur de la barre d\'outils n\'existe pas (' . $collector . ').'
70+
. ' Veuillez vérifier $collectors dans le fichier app/Config/toolbar.php.'
7171
);
7272

7373
continue;
@@ -80,16 +80,17 @@ public function __construct(?stdClass $config = null)
8080
/**
8181
* Renvoie toutes les données requises par la barre de débogage
8282
*
83-
* @param float $startTime Heure de début de l'application
83+
* @param float $startTime Heure de début de l'application
84+
* @param Request $request
8485
*
8586
* @return string Données encodées en JSON
8687
*/
8788
public function run(float $startTime, float $totalTime, ServerRequestInterface $request, ResponseInterface $response): string
8889
{
8990
// Éléments de données utilisés dans la vue.
9091
$data['url'] = current_url();
91-
$data['method'] = strtoupper($request->getMethod());
92-
$data['isAJAX'] = service('request')->ajax();
92+
$data['method'] = $request->getMethod();
93+
$data['isAJAX'] = $request->ajax();
9394
$data['startTime'] = $startTime;
9495
$data['totalTime'] = $totalTime * 1000;
9596
$data['totalMemory'] = number_format(memory_get_peak_usage() / 1024 / 1024, 3);
@@ -134,7 +135,7 @@ public function run(float $startTime, float $totalTime, ServerRequestInterface $
134135
foreach ($_SESSION as $key => $value) {
135136
// Remplacez les données binaires par une chaîne pour éviter l'échec de json_encode.
136137
if (is_string($value) && preg_match('~[^\x20-\x7E\t\r\n]~', $value)) {
137-
$value = 'binary data';
138+
$value = 'donnée binaire';
138139
}
139140

140141
$data['vars']['session'][esc($key)] = is_string($value) ? esc($value) : '<pre>' . esc(print_r($value, true)) . '</pre>';
@@ -160,7 +161,7 @@ public function run(float $startTime, float $totalTime, ServerRequestInterface $
160161
$data['vars']['cookies'][esc($name)] = esc($value);
161162
}
162163

163-
$data['vars']['request'] = (service('request')->is('ssl') ? 'HTTPS' : 'HTTP') . '/' . $request->getProtocolVersion();
164+
$data['vars']['request'] = ($request->is('ssl') ? 'HTTPS' : 'HTTP') . '/' . $request->getProtocolVersion();
164165

165166
$data['vars']['response'] = [
166167
'statusCode' => $response->getStatusCode(),
@@ -210,12 +211,12 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s
210211
$open = $row['name'] === 'Controller';
211212

212213
if ($hasChildren || $isQuery) {
213-
$output .= '<tr class="timeline-parent' . ($open ? ' timeline-parent-open' : '') . '" id="timeline-' . $styleCount . '_parent" onclick="blitzphpDebugBar.toggleChildRows(\'timeline-' . $styleCount . '\');">';
214+
$output .= '<tr class="timeline-parent' . ($open ? ' timeline-parent-open' : '') . '" id="timeline-' . $styleCount . '_parent" data-toggle="childrows" data-child="timeline-' . $styleCount . '">';
214215
} else {
215216
$output .= '<tr>';
216217
}
217218

218-
$output .= '<td class="' . ($isChild ? 'debug-bar-width30' : '') . '" style="--level: ' . $level . ';">' . ($hasChildren || $isQuery ? '<nav></nav>' : '') . $row['name'] . '</td>';
219+
$output .= '<td class="' . ($isChild ? 'debug-bar-width30' : '') . ' debug-bar-level-' . $level . '" >' . ($hasChildren || $isQuery ? '<nav></nav>' : '') . $row['name'] . '</td>';
219220
$output .= '<td class="' . ($isChild ? 'debug-bar-width10' : '') . '">' . $row['component'] . '</td>';
220221
$output .= '<td class="' . ($isChild ? 'debug-bar-width10 ' : '') . 'debug-bar-alignRight">' . number_format($row['duration'] * 1000, 2) . ' ms</td>';
221222
$output .= "<td class='debug-bar-noverflow' colspan='{$segmentCount}'>";
@@ -233,15 +234,15 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s
233234

234235
// Ajouter des enfants le cas échéant
235236
if ($hasChildren || $isQuery) {
236-
$output .= '<tr class="child-row" id="timeline-' . ($styleCount - 1) . '_children" style="' . ($open ? '' : 'display: none;') . '">';
237+
$output .= '<tr class="child-row ' . ($open ? '' : ' debug-bar-ndisplay') . '" id="timeline-' . ($styleCount - 1) . '_children" >';
237238
$output .= '<td colspan="' . ($segmentCount + 3) . '" class="child-container">';
238239
$output .= '<table class="timeline">';
239240
$output .= '<tbody>';
240241

241242
if ($isQuery) {
242243
// Sortie de la chaîne de requête si requête
243244
$output .= '<tr>';
244-
$output .= '<td class="query-container" style="--level: ' . ($level + 1) . ';">' . $row['query'] . '</td>';
245+
$output .= '<td class="query-container debug-bar-level-' . ($level + 1) . '" >' . $row['query'] . '</td>';
245246
$output .= '</tr>';
246247
} else {
247248
// Rendre récursivement les enfants
@@ -356,13 +357,34 @@ protected function roundTo(float $number, int $increments = 5): float
356357
return ceil($number * $increments) / $increments;
357358
}
358359

360+
/**
361+
* Traite la barre d'outils de débogage pour la requête en cours.
362+
*
363+
* Cette méthode détermine s'il faut afficher la barre d'outils de débogage ou la préparer pour une utilisation ultérieure.
364+
*
365+
* @param array $stats Un tableau contenant des statistiques de performances.
366+
* @param Request $request La requête serveur en cours.
367+
* @param ResponseInterface $response La réponse en cours.
368+
*
369+
* @return ResponseInterface La réponse traitée, avec la barre d'outils de débogage injectée ou préparée pour une utilisation ultérieure.
370+
*/
371+
public function process(array $stats, ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
372+
{
373+
if ($request->hasAny('blitzphp-debugbar', 'debugbar_time')) {
374+
return $this->respond($request);
375+
}
376+
377+
return $this->prepare($stats, $request, $response);
378+
}
379+
359380
/**
360381
* Préparez-vous au débogage..
361382
*/
362-
public function prepare(array $stats, ?RequestInterface $request = null, ?ResponseInterface $response = null): ResponseInterface
383+
public function prepare(array $stats, ?ServerRequestInterface $request = null, ?ResponseInterface $response = null): ResponseInterface
363384
{
364385
/** @var Request $request */
365386
$request ??= service('request');
387+
/** @var Response $response */
366388
$response ??= service('response');
367389

368390
// Si on est en CLI ou en prod, pas la peine de continuer car la debugbar n'est pas utilisable dans ces environnements
@@ -402,95 +424,88 @@ public function prepare(array $stats, ?RequestInterface $request = null, ?Respon
402424
->withHeader('Debugbar-Link', site_url("?debugbar_time={$time}"));
403425
}
404426

405-
$_SESSION['_blitz_debugbar_'] = array_merge($_SESSION['_blitz_debugbar_'] ?? [], compact('time'));
406-
407-
$debugRenderer = $this->respond();
408-
409-
// Extract css
410-
preg_match('/<style (?:.+)>(.+)<\/style>/', $debugRenderer, $matches);
411-
$style = $matches[0] ?? '';
412-
$debugRenderer = str_replace($style, '', $debugRenderer);
413-
414-
// Extract js
415-
preg_match('/<script (?:.+)>(.+)<\/script>/', $debugRenderer, $matches);
416-
$js = $matches[0] ?? '';
417-
$debugRenderer = str_replace($js, '', $debugRenderer);
418-
419-
$responseContent = $response->getBody()->getContents();
420-
421-
if (str_contains($responseContent, '<head>')) {
422-
$responseContent = preg_replace('/<head>/', '<head>' . $style, $responseContent, 1);
423-
} else {
424-
$responseContent .= $style;
425-
}
426-
427-
if (str_contains($responseContent, '</body>')) {
428-
$responseContent = preg_replace('/<\/body>/', '<div id="toolbarContainer">' . trim(preg_replace('/\s+/', ' ', $debugRenderer)) . '</div>' . $js . '<script>blitzphpDebugBar.init();</script></body>', $responseContent, 1);
427+
$oldKintMode = Kint::$mode_default;
428+
Kint::$mode_default = Kint::MODE_RICH;
429+
$kintScript = @Kint::dump('');
430+
Kint::$mode_default = $oldKintMode;
431+
$kintScript = substr($kintScript, 0, strpos($kintScript, '</style>') + 8);
432+
$kintScript = ($kintScript === '0') ? '' : $kintScript;
433+
434+
$script = PHP_EOL
435+
. '<script id="debugbar_loader" '
436+
. 'data-time="' . $time . '" '
437+
. 'src="' . site_url() . '?blitzphp-debugbar"></script>'
438+
. '<script id="debugbar_dynamic_script"></script>'
439+
. '<style id="debugbar_dynamic_style"></style>'
440+
. $kintScript
441+
. PHP_EOL;
442+
443+
if (str_contains($responseContent = (string) $response->getBody(), '<head>')) {
444+
$responseContent = preg_replace(
445+
'/<head>/',
446+
'<head>' . $script,
447+
$responseContent,
448+
1,
449+
);
429450
} else {
430-
$responseContent .= '<div id="toolbarContainer">' . trim(preg_replace('/\s+/', ' ', $debugRenderer)) . '</div>' . $js . '<script>blitzphpDebugBar.init();</script>';
451+
$responseContent .= $script;
431452
}
432453

433-
return $response->withBody(
434-
Utils::streamFor($responseContent)
435-
);
454+
return $response->withBody(Utils::streamFor($responseContent));
436455
}
437456

438457
/**
439458
* Injectez la barre d'outils de débogage dans la réponse.
440459
*
441-
* @return string
460+
* @param Request $request
442461
*
443462
* @codeCoverageIgnore
444463
*/
445-
public function respond()
464+
public function respond(ServerRequestInterface $request): Response
446465
{
466+
$response = new Response();
467+
447468
if (on_test()) {
448-
return '';
469+
return $response;
449470
}
450471

451-
$request = service('request');
452-
453-
// Si la requête contient '?debugbar alors nous sommes
472+
// Si la requête contient '?blitzphp-debugbar alors nous sommes
454473
// renvoie simplement le script de chargement
455-
if ($request->getQuery('debugbar') !== null) {
456-
header('Content-Type: application/javascript');
474+
if ($request->getQuery('blitzphp-debugbar') !== null) {
475+
$response = $response->withType('application/javascript');
457476

458477
ob_start();
459-
include $this->config->view_path . 'toolbarloader.js';
478+
include $this->config->view_path . DS . 'toolbarloader.js';
460479
$output = ob_get_clean();
461480

462-
return str_replace('{url}', rtrim(site_url(), '/'), $output);
481+
return $response->withStringBody(str_replace('{url}', rtrim(site_url(), '/'), $output));
463482
}
464483

465484
// Sinon, s'il inclut ?debugbar_time, alors
466485
// nous devrions retourner la barre de débogage entière.
467-
$debugbarTime = $_SESSION['_blitz_debugbar_']['time'] ?? $request->getQuery('debugbar_time');
468-
if ($debugbarTime) {
486+
if (null !== $debugbarTime = $request->getQuery('debugbar_time')) {
469487
// Négociation du type de contenu pour formater la sortie
470-
$format = $request->negotiate('media', ['text/html', 'application/json', 'application/xml']);
471-
$format = explode('/', $format)[1];
488+
$format = $request->negotiate('media', ['text/html', 'application/json', 'application/xml']);
489+
$response = $response->withType($format);
490+
$format = explode('/', $format)[1];
472491

473492
$filename = 'debugbar_' . $debugbarTime;
474493
$filename = $this->debugPath . DS . $filename . '.json';
475494

476495
if (is_file($filename)) {
477496
// Affiche la barre d'outils si elle existe
478-
return $this->format($debugbarTime, file_get_contents($filename), $format);
497+
return $response->withStringBody($this->format($debugbarTime, file_get_contents($filename), $format));
479498
}
480-
481-
// Nom de fichier introuvable
482-
http_response_code(404);
483-
484-
exit; // Quitter ici est nécessaire pour éviter de charger la page d'index
485499
}
486500

487-
return '';
501+
// Nom de fichier introuvable
502+
return $response->withStatus(404);
488503
}
489504

490505
/**
491506
* Formatte la sortie
492507
*
493-
* @param float $debugbar_time
508+
* @param mixed $debugbar_time
494509
*/
495510
protected function format($debugbar_time, string $data, string $format = 'html'): string
496511
{

src/Debug/Toolbar/Collectors/RoutesCollector.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ public function __construct()
5454
/**
5555
* {@inheritDoc}
5656
*
57+
* @return array{
58+
* matchedRoute: array<array{
59+
* directory: string,
60+
* controller: string,
61+
* method: string,
62+
* paramCount: int,
63+
* truePCount: int,
64+
* params: list<array{
65+
* name: string,
66+
* value: mixed
67+
* }>
68+
* }>,
69+
* routes: list<array{
70+
* method: string,
71+
* route: string,
72+
* handler: string
73+
* }>
74+
* }
75+
*
5776
* @throws ReflectionException
5877
*/
5978
public function display(): array
@@ -91,8 +110,8 @@ public function display(): array
91110
$matchedRoute = [
92111
[
93112
'directory' => $this->router->directory(),
94-
'controller' => $this->router->controllerName(),
95-
'method' => $this->router->methodName(),
113+
'controller' => is_string($controller = $this->router->controllerName()) ? $controller : 'Non défini',
114+
'method' => is_string($controller) ? $this->router->methodName() : 'Non définie',
96115
'paramCount' => count($this->router->params()),
97116
'truePCount' => count($params),
98117
'params' => $params,

0 commit comments

Comments
 (0)