diff --git a/spec/support/application/app/Config/toolbar.php b/spec/support/application/app/Config/toolbar.php
index 2122a9f8..1ee59934 100644
--- a/spec/support/application/app/Config/toolbar.php
+++ b/spec/support/application/app/Config/toolbar.php
@@ -10,10 +10,12 @@
*/
return [
- 'collectors' => [],
- 'collect_var_data' => true,
- 'max_history' => 20,
- 'view_path' => SYST_PATH . 'Debug' . DS . 'Toolbar' . DS . 'Views',
- 'max_queries' => 100,
- 'show_debugbar' => true,
+ 'collectors' => [],
+ 'collect_var_data' => true,
+ 'max_history' => 20,
+ 'view_path' => SYST_PATH . 'Debug' . DS . 'Toolbar' . DS . 'Views',
+ 'max_queries' => 100,
+ 'show_debugbar' => true,
+ 'watched_directories' => ['app'],
+ 'watched_extensions' => ['php', 'css', 'js', 'html', 'svg', 'json', 'env'],
];
diff --git a/spec/system/framework/HotReloader/DirectoryHasher.spec.php b/spec/system/framework/HotReloader/DirectoryHasher.spec.php
new file mode 100644
index 00000000..f67939c6
--- /dev/null
+++ b/spec/system/framework/HotReloader/DirectoryHasher.spec.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+use BlitzPHP\Exceptions\FrameworkException;
+use BlitzPHP\HotReloader\DirectoryHasher;
+
+use function Kahlan\expect;
+
+describe('HotReloader / DirectoryHasher', function (): void {
+ beforeAll(function (): void {
+ $this->hasher = new DirectoryHasher();
+ });
+
+ it('hashApp', function (): void {
+ $results = $this->hasher->hashApp();
+
+ expect($results)->toBeA('array');
+ expect($results)->toContainKey('app');
+ });
+
+ it('Leve une exception si on essai de hasher un dossier invalide', function (): void {
+ $path = $path = APP_PATH . 'Foo';
+
+ expect(fn() => $this->hasher->hashDirectory($path))
+ ->toThrow(FrameworkException::invalidDirectory($path));
+ });
+
+ it('Chaque dossier a un hash unique', function (): void {
+ $hash1 = $this->hasher->hashDirectory(APP_PATH);
+ $hash2 = $this->hasher->hashDirectory(SYST_PATH);
+
+ expect($hash1)->not->toBe($hash2);
+ });
+
+ it('Un meme dossier produira le meme hash', function (): void {
+ $hash1 = $this->hasher->hashDirectory(APP_PATH);
+ $hash2 = $this->hasher->hashDirectory(APP_PATH);
+
+ expect($hash1)->toBe($hash2);
+ });
+
+ it ('hash', function (): void {
+ $expected = md5(implode('', $this->hasher->hashApp()));
+
+ expect($expected)->toBe($this->hasher->hash());
+ });
+});
diff --git a/src/Debug/Toolbar.php b/src/Debug/Toolbar.php
index 64ba82c4..b422a35b 100644
--- a/src/Debug/Toolbar.php
+++ b/src/Debug/Toolbar.php
@@ -18,12 +18,12 @@
use BlitzPHP\Formatter\JsonFormatter;
use BlitzPHP\Formatter\XmlFormatter;
use BlitzPHP\Http\Request;
+use BlitzPHP\Http\Response;
use BlitzPHP\Utilities\Date;
use BlitzPHP\View\Parser;
use Exception;
use GuzzleHttp\Psr7\Utils;
use Kint\Kint;
-use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use stdClass;
@@ -66,8 +66,8 @@ public function __construct(?stdClass $config = null)
foreach ($this->config->collectors as $collector) {
if (! class_exists($collector)) {
logger()->critical(
- 'Toolbar collector does not exist (' . $collector . ').'
- . ' Please check $collectors in the app/Config/toolbar.php file.'
+ 'Le collecteur de la barre d\'outils n\'existe pas (' . $collector . ').'
+ . ' Veuillez vérifier $collectors dans le fichier app/Config/toolbar.php.'
);
continue;
@@ -80,7 +80,8 @@ public function __construct(?stdClass $config = null)
/**
* Renvoie toutes les données requises par la barre de débogage
*
- * @param float $startTime Heure de début de l'application
+ * @param float $startTime Heure de début de l'application
+ * @param Request $request
*
* @return string Données encodées en JSON
*/
@@ -88,8 +89,8 @@ public function run(float $startTime, float $totalTime, ServerRequestInterface $
{
// Éléments de données utilisés dans la vue.
$data['url'] = current_url();
- $data['method'] = strtoupper($request->getMethod());
- $data['isAJAX'] = service('request')->ajax();
+ $data['method'] = $request->getMethod();
+ $data['isAJAX'] = $request->ajax();
$data['startTime'] = $startTime;
$data['totalTime'] = $totalTime * 1000;
$data['totalMemory'] = number_format(memory_get_peak_usage() / 1024 / 1024, 3);
@@ -134,7 +135,7 @@ public function run(float $startTime, float $totalTime, ServerRequestInterface $
foreach ($_SESSION as $key => $value) {
// Remplacez les données binaires par une chaîne pour éviter l'échec de json_encode.
if (is_string($value) && preg_match('~[^\x20-\x7E\t\r\n]~', $value)) {
- $value = 'binary data';
+ $value = 'donnée binaire';
}
$data['vars']['session'][esc($key)] = is_string($value) ? esc($value) : '
';
$output .= '';
$output .= '';
$output .= '';
@@ -241,7 +242,7 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s
if ($isQuery) {
// Sortie de la chaîne de requête si requête
$output .= '';
- $output .= '' . $row['query'] . ' ';
+ $output .= '' . $row['query'] . ' ';
$output .= ' ';
} else {
// Rendre récursivement les enfants
@@ -356,13 +357,34 @@ protected function roundTo(float $number, int $increments = 5): float
return ceil($number * $increments) / $increments;
}
+ /**
+ * Traite la barre d'outils de débogage pour la requête en cours.
+ *
+ * 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.
+ *
+ * @param array $stats Un tableau contenant des statistiques de performances.
+ * @param Request $request La requête serveur en cours.
+ * @param ResponseInterface $response La réponse en cours.
+ *
+ * @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.
+ */
+ public function process(array $stats, ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+ {
+ if ($request->hasAny('blitzphp-debugbar', 'debugbar_time')) {
+ return $this->respond($request);
+ }
+
+ return $this->prepare($stats, $request, $response);
+ }
+
/**
* Préparez-vous au débogage..
*/
- public function prepare(array $stats, ?RequestInterface $request = null, ?ResponseInterface $response = null): ResponseInterface
+ public function prepare(array $stats, ?ServerRequestInterface $request = null, ?ResponseInterface $response = null): ResponseInterface
{
/** @var Request $request */
$request ??= service('request');
+ /** @var Response $response */
$response ??= service('response');
// 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
->withHeader('Debugbar-Link', site_url("?debugbar_time={$time}"));
}
- $_SESSION['_blitz_debugbar_'] = array_merge($_SESSION['_blitz_debugbar_'] ?? [], compact('time'));
-
- $debugRenderer = $this->respond();
-
- // Extract css
- preg_match('/') + 8);
+ $kintScript = ($kintScript === '0') ? '' : $kintScript;
+
+ $script = PHP_EOL
+ . ''
+ . ''
+ . ''
+ . $kintScript
+ . PHP_EOL;
+
+ if (str_contains($responseContent = (string) $response->getBody(), '')) {
+ $responseContent = preg_replace(
+ '//',
+ '' . $script,
+ $responseContent,
+ 1,
+ );
} else {
- $responseContent .= '' . trim(preg_replace('/\s+/', ' ', $debugRenderer)) . '
' . $js . '';
+ $responseContent .= $script;
}
- return $response->withBody(
- Utils::streamFor($responseContent)
- );
+ return $response->withBody(Utils::streamFor($responseContent));
}
/**
* Injectez la barre d'outils de débogage dans la réponse.
*
- * @return string
+ * @param Request $request
*
* @codeCoverageIgnore
*/
- public function respond()
+ public function respond(ServerRequestInterface $request): Response
{
+ $response = new Response();
+
if (on_test()) {
- return '';
+ return $response;
}
- $request = service('request');
-
- // Si la requête contient '?debugbar alors nous sommes
+ // Si la requête contient '?blitzphp-debugbar alors nous sommes
// renvoie simplement le script de chargement
- if ($request->getQuery('debugbar') !== null) {
- header('Content-Type: application/javascript');
+ if ($request->getQuery('blitzphp-debugbar') !== null) {
+ $response = $response->withType('application/javascript');
ob_start();
- include $this->config->view_path . 'toolbarloader.js';
+ include $this->config->view_path . DS . 'toolbarloader.js';
$output = ob_get_clean();
- return str_replace('{url}', rtrim(site_url(), '/'), $output);
+ return $response->withStringBody(str_replace('{url}', rtrim(site_url(), '/'), $output));
}
// Sinon, s'il inclut ?debugbar_time, alors
// nous devrions retourner la barre de débogage entière.
- $debugbarTime = $_SESSION['_blitz_debugbar_']['time'] ?? $request->getQuery('debugbar_time');
- if ($debugbarTime) {
+ if (null !== $debugbarTime = $request->getQuery('debugbar_time')) {
// Négociation du type de contenu pour formater la sortie
- $format = $request->negotiate('media', ['text/html', 'application/json', 'application/xml']);
- $format = explode('/', $format)[1];
+ $format = $request->negotiate('media', ['text/html', 'application/json', 'application/xml']);
+ $response = $response->withType($format);
+ $format = explode('/', $format)[1];
$filename = 'debugbar_' . $debugbarTime;
$filename = $this->debugPath . DS . $filename . '.json';
if (is_file($filename)) {
// Affiche la barre d'outils si elle existe
- return $this->format($debugbarTime, file_get_contents($filename), $format);
+ return $response->withStringBody($this->format($debugbarTime, file_get_contents($filename), $format));
}
-
- // Nom de fichier introuvable
- http_response_code(404);
-
- exit; // Quitter ici est nécessaire pour éviter de charger la page d'index
}
- return '';
+ // Nom de fichier introuvable
+ return $response->withStatus(404);
}
/**
* Formatte la sortie
*
- * @param float $debugbar_time
+ * @param mixed $debugbar_time
*/
protected function format($debugbar_time, string $data, string $format = 'html'): string
{
diff --git a/src/Debug/Toolbar/Collectors/RoutesCollector.php b/src/Debug/Toolbar/Collectors/RoutesCollector.php
index 9e483b56..c4cd23b3 100644
--- a/src/Debug/Toolbar/Collectors/RoutesCollector.php
+++ b/src/Debug/Toolbar/Collectors/RoutesCollector.php
@@ -54,6 +54,25 @@ public function __construct()
/**
* {@inheritDoc}
*
+ * @return array{
+ * matchedRoute: array
+ * }>,
+ * routes: list
+ * }
+ *
* @throws ReflectionException
*/
public function display(): array
@@ -91,8 +110,8 @@ public function display(): array
$matchedRoute = [
[
'directory' => $this->router->directory(),
- 'controller' => $this->router->controllerName(),
- 'method' => $this->router->methodName(),
+ 'controller' => is_string($controller = $this->router->controllerName()) ? $controller : 'Non défini',
+ 'method' => is_string($controller) ? $this->router->methodName() : 'Non définie',
'paramCount' => count($this->router->params()),
'truePCount' => count($params),
'params' => $params,
diff --git a/src/Debug/Toolbar/Views/_database.tpl b/src/Debug/Toolbar/Views/_database.tpl
index 0b556125..e2dbc95f 100644
--- a/src/Debug/Toolbar/Views/_database.tpl
+++ b/src/Debug/Toolbar/Views/_database.tpl
@@ -8,10 +8,20 @@
{queries}
-
+
{duration}
{! sql !}
{affected_rows}
+ {trace-file}
+
+
+
+
+ {trace}
+ {index}{file}
+ {function}
+ {/trace}
+
{/queries}
diff --git a/src/Debug/Toolbar/Views/_history.tpl b/src/Debug/Toolbar/Views/_history.tpl
index a2fee0b0..c658c0af 100644
--- a/src/Debug/Toolbar/Views/_history.tpl
+++ b/src/Debug/Toolbar/Views/_history.tpl
@@ -13,8 +13,8 @@
{files}
-
- Chargé
+
+ Chargé
{datetime}
{status}
diff --git a/src/Debug/Toolbar/Views/_routes.tpl b/src/Debug/Toolbar/Views/_routes.tpl
index f7f63e41..f5cf2266 100644
--- a/src/Debug/Toolbar/Views/_routes.tpl
+++ b/src/Debug/Toolbar/Views/_routes.tpl
@@ -9,7 +9,7 @@
-Route assortis
+Route adaptée
diff --git a/src/Debug/Toolbar/Views/toolbar-min.js b/src/Debug/Toolbar/Views/toolbar-min.js
index 1b4156e3..83116a47 100644
--- a/src/Debug/Toolbar/Views/toolbar-min.js
+++ b/src/Debug/Toolbar/Views/toolbar-min.js
@@ -1 +1 @@
-var blitzphpDebugBar={toolbarContainer:null,toolbar:null,icon:null,init:function(){this.toolbarContainer=document.getElementById("toolbarContainer"),this.toolbar=document.getElementById("debug-bar"),this.icon=document.getElementById("debug-icon"),blitzphpDebugBar.createListeners(),blitzphpDebugBar.setToolbarState(),blitzphpDebugBar.setToolbarPosition(),blitzphpDebugBar.setToolbarTheme(),blitzphpDebugBar.toggleViewsHints(),blitzphpDebugBar.routerLink(),document.getElementById("debug-bar-link").addEventListener("click",blitzphpDebugBar.toggleToolbar,!0),document.getElementById("debug-icon-link").addEventListener("click",blitzphpDebugBar.toggleToolbar,!0);var e=this.toolbar.querySelector('button[data-time="'+localStorage.getItem("debugbar-time")+'"]');blitzphpDebugBar.addClass(e.parentNode.parentNode,"current"),historyLoad=this.toolbar.getElementsByClassName("blitzphp-history-load");for(var t=0;t"+e.innerText+'':(e.style="cursor: pointer;",e.setAttribute("title",location.origin+"/"+blitzphpDebugBar.trimSlash(e.innerText)),e.addEventListener("click",(function(e){t=location.origin+"/"+blitzphpDebugBar.trimSlash(e.target.innerText),window.open(t,"_blank").location})));a=this.toolbar.querySelectorAll('td[data-debugbar-route="GET"] form');for(l=0;l0&&a.push(l[i].value);a.length>0&&(t=location.origin+"/"+o.replace(/\?/g,(function(){return a[r++]})),window.open(t,"_blank").location)}))}};
\ No newline at end of file
+var blitzphpDebugBar={toolbarContainer:null,toolbar:null,icon:null,init:function(){this.toolbarContainer=document.getElementById("toolbarContainer"),this.toolbar=document.getElementById("debug-bar"),this.icon=document.getElementById("debug-icon"),blitzphpDebugBar.createListeners(),blitzphpDebugBar.setToolbarState(),blitzphpDebugBar.setToolbarPosition(),blitzphpDebugBar.setToolbarTheme(),blitzphpDebugBar.toggleViewsHints(),blitzphpDebugBar.routerLink(),blitzphpDebugBar.setHotReloadState(),document.getElementById("debug-bar-link").addEventListener("click",blitzphpDebugBar.toggleToolbar,!0),document.getElementById("debug-icon-link").addEventListener("click",blitzphpDebugBar.toggleToolbar,!0);var e=this.toolbar.querySelector('button[data-time="'+localStorage.getItem("debugbar-time")+'"]');blitzphpDebugBar.addClass(e.parentNode.parentNode,"current"),historyLoad=this.toolbar.getElementsByClassName("blitzphp-history-load");for(var t=0;t{},e},createCookie:function(e,t,a){if(a){var r=new Date;r.setTime(r.getTime()+24*a*60*60*1e3);var i="; expires="+r.toGMTString()}else i="";document.cookie=e+"="+t+i+"; path=/; samesite=Lax"},readCookie:function(e){for(var t=e+"=",a=document.cookie.split(";"),r=0;r"+e.innerText+'':(blitzphpDebugBar.addClass(e,"debug-bar-pointer"),e.setAttribute("title",location.origin+"/"+blitzphpDebugBar.trimSlash(e.innerText)),e.addEventListener("click",(function(e){t=location.origin+"/"+blitzphpDebugBar.trimSlash(e.target.innerText),window.open(t,"_blank").location})));a=this.toolbar.querySelectorAll('td[data-debugbar-route="GET"] form');for(i=0;i0&&a.push(i[o].value);a.length>0&&(t=location.origin+"/"+l.replace(/\?/g,(function(){return a[r++]})),window.open(t,"_blank").location)}))}};
\ No newline at end of file
diff --git a/src/Debug/Toolbar/Views/toolbar.css b/src/Debug/Toolbar/Views/toolbar.css
index 92f261fe..bf68e7b3 100644
--- a/src/Debug/Toolbar/Views/toolbar.css
+++ b/src/Debug/Toolbar/Views/toolbar.css
@@ -5,10 +5,11 @@
z-index: 10000;
height: 36px;
width: 36px;
- margin: 0px;
- padding: 0px;
+ margin: 0;
+ padding: 0;
clear: both;
text-align: center;
+ cursor: pointer;
}
#debug-icon a svg {
margin: 8px;
@@ -23,6 +24,10 @@
display: none;
}
+ #debug-bar .debug-bar-vars {
+ cursor: pointer;
+ }
+
#debug-bar {
bottom: 0;
left: 0;
@@ -39,12 +44,15 @@
display: flex;
font-weight: normal;
margin: 0 0 0 auto;
+ padding: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}
#debug-bar h1 svg {
width: 16px;
margin-right: 5px;
}
#debug-bar h2 {
+ font-weight: bold;
font-size: 16px;
margin: 0;
padding: 5px 0 10px 0;
@@ -87,6 +95,7 @@
line-height: normal;
margin: 5px 10px 15px 10px;
width: calc(100% - 10px);
+ overflow-y: auto;
}
#debug-bar table strong {
font-weight: 500;
@@ -148,19 +157,21 @@
bottom: auto;
top: 36px;
}
- #debug-bar #toolbar-position a,
- #debug-bar #toolbar-theme a {
+ #debug-bar #toolbar-position,
+ #debug-bar #toolbar-theme {
padding: 0 6px;
display: inline-flex;
vertical-align: top;
+ cursor: pointer;
}
- #debug-bar #toolbar-position a:hover,
- #debug-bar #toolbar-theme a:hover {
+ #debug-bar #toolbar-position:hover,
+ #debug-bar #toolbar-theme:hover {
text-decoration: none;
}
#debug-bar #debug-bar-link {
display: flex;
padding: 6px;
+ cursor: pointer;
}
#debug-bar .blitzphp-label {
display: inline-flex;
@@ -196,6 +207,8 @@
white-space: nowrap;
}
#debug-bar .tab {
+ height: fit-content;
+ text-align: left;
bottom: 35px;
display: none;
left: 0;
@@ -208,6 +221,8 @@
z-index: 9999;
}
#debug-bar .timeline {
+ position: static;
+ display: table;
margin-left: 0;
width: 100%;
}
@@ -280,6 +295,9 @@
padding-left: 1em;
text-align: right;
}
+ #debug-bar > .debug-bar-dblock {
+ display: block;
+ }
.debug-view.show-view {
border: 1px solid;
@@ -307,6 +325,25 @@
display: none !important;
}
}
+ @media screen and (max-width: 768px) {
+ #debug-bar table {
+ display: block;
+ font-size: 12px;
+ margin: 5px 5px 10px 5px;
+ }
+ #debug-bar table td,
+ #debug-bar table th {
+ padding: 4px 6px;
+ }
+ #debug-bar .timeline {
+ display: block;
+ white-space: nowrap;
+ font-size: 12px;
+ }
+ #debug-bar .toolbar {
+ overflow-x: auto;
+ }
+ }
#debug-icon {
background-color: #FFFFFF;
box-shadow: 0 0 4px #DFDFDF;
@@ -524,9 +561,6 @@
#debug-bar .timeline .timer {
background-color: #c2bb44;
}
- #debug-bar .timeline .timeline-parent-open td {
- color: #252525;
- }
.debug-view.show-view {
border-color: #c2bb44;
}
@@ -639,9 +673,6 @@
#toolbarContainer.dark #debug-bar .timeline .timer {
background-color: #c2bb44;
}
- #toolbarContainer.dark #debug-bar .timeline .timeline-parent-open td {
- color: #252525;
- }
#toolbarContainer.dark .debug-view.show-view {
border-color: #c2bb44;
}
@@ -802,4 +833,47 @@
.debug-bar-noverflow {
overflow: hidden;
}
-
\ No newline at end of file
+
+ .debug-bar-dtableRow {
+ display: table-row;
+ }
+
+ .debug-bar-dinlineBlock {
+ display: inline-block;
+ }
+
+ .debug-bar-pointer {
+ cursor: pointer;
+ }
+
+ .debug-bar-mleft4 {
+ margin-left: 4px;
+ }
+
+ .debug-bar-level-0 {
+ --level: 0;
+ }
+
+ .debug-bar-level-1 {
+ --level: 1;
+ }
+
+ .debug-bar-level-2 {
+ --level: 2;
+ }
+
+ .debug-bar-level-3 {
+ --level: 3;
+ }
+
+ .debug-bar-level-4 {
+ --level: 4;
+ }
+
+ .debug-bar-level-5 {
+ --level: 5;
+ }
+
+ .debug-bar-level-6 {
+ --level: 6;
+ }
\ No newline at end of file
diff --git a/src/Debug/Toolbar/Views/toolbar.js b/src/Debug/Toolbar/Views/toolbar.js
new file mode 100644
index 00000000..6f1d4f44
--- /dev/null
+++ b/src/Debug/Toolbar/Views/toolbar.js
@@ -0,0 +1,824 @@
+/*
+ * Fonctionnalité de la barre d'outils de débogage BlitzPHP.
+ */
+
+var blitzphpDebugBar = {
+ toolbarContainer: null,
+ toolbar: null,
+ icon: null,
+
+ init: function () {
+ this.toolbarContainer = document.getElementById("toolbarContainer");
+ this.toolbar = document.getElementById("debug-bar");
+ this.icon = document.getElementById("debug-icon");
+
+ blitzphpDebugBar.createListeners();
+ blitzphpDebugBar.setToolbarState();
+ blitzphpDebugBar.setToolbarPosition();
+ blitzphpDebugBar.setToolbarTheme();
+ blitzphpDebugBar.toggleViewsHints();
+ blitzphpDebugBar.routerLink();
+ blitzphpDebugBar.setHotReloadState();
+
+ document
+ .getElementById("debug-bar-link")
+ .addEventListener("click", blitzphpDebugBar.toggleToolbar, true);
+ document
+ .getElementById("debug-icon-link")
+ .addEventListener("click", blitzphpDebugBar.toggleToolbar, true);
+
+ // Permet de mettre en évidence la ligne d'historique de la requete en cours
+ var btn = this.toolbar.querySelector(
+ 'button[data-time="' + localStorage.getItem("debugbar-time") + '"]'
+ );
+ blitzphpDebugBar.addClass(btn.parentNode.parentNode, "current");
+
+ historyLoad = this.toolbar.getElementsByClassName("blitzphp-history-load");
+
+ for (var i = 0; i < historyLoad.length; i++) {
+ historyLoad[i].addEventListener(
+ "click",
+ function () {
+ loadDoc(this.getAttribute("data-time"));
+ },
+ true
+ );
+ }
+
+ // Afficher l'onglet actif au chargement de la page
+ var tab = blitzphpDebugBar.readCookie("debug-bar-tab");
+ if (document.getElementById(tab)) {
+ var el = document.getElementById(tab);
+ blitzphpDebugBar.switchClass(el, "debug-bar-ndisplay", "debug-bar-dblock");
+ blitzphpDebugBar.addClass(el, "active");
+ tab = document.querySelector("[data-tab=" + tab + "]");
+ if (tab) {
+ blitzphpDebugBar.addClass(tab.parentNode, "active");
+ }
+ }
+ },
+
+ createListeners: function () {
+ var buttons = [].slice.call(
+ this.toolbar.querySelectorAll(".blitzphp-label a")
+ );
+
+ for (var i = 0; i < buttons.length; i++) {
+ buttons[i].addEventListener("click", blitzphpDebugBar.showTab, true);
+ }
+
+ // Connecter une bascule générique via les attributs de données `data-toggle="foo"`
+ var links = this.toolbar.querySelectorAll("[data-toggle]");
+ for (var i = 0; i < links.length; i++) {
+ let toggleData = links[i].getAttribute("data-toggle");
+ if (toggleData === "datatable") {
+
+ let datatable = links[i].getAttribute("data-table");
+ links[i].addEventListener("click", function() {
+ blitzphpDebugBar.toggleDataTable(datatable)
+ }, true);
+
+ } else if (toggleData === "childrows") {
+
+ let child = links[i].getAttribute("data-child");
+ links[i].addEventListener("click", function() {
+ blitzphpDebugBar.toggleChildRows(child)
+ }, true);
+
+ } else {
+ links[i].addEventListener("click", blitzphpDebugBar.toggleRows, true);
+ }
+ }
+ },
+
+ showTab: function () {
+ // Obtenir l'onglet cible, le cas échéant
+ var tab = document.getElementById(this.getAttribute("data-tab"));
+
+ // Si l'étiquette n'a pas de tabulation, arrêtez-vous ici
+ if (! tab) {
+ return;
+ }
+
+ // Supprimer le cookie de la barre de débogage
+ blitzphpDebugBar.createCookie("debug-bar-tab", "", -1);
+
+ // Vérifiez notre état actuel.
+ var state = tab.classList.contains("debug-bar-dblock");
+
+ // Masquer tous les onglets
+ var tabs = document.querySelectorAll("#debug-bar .tab");
+
+ for (var i = 0; i < tabs.length; i++) {
+ blitzphpDebugBar.switchClass(tabs[i], "debug-bar-dblock", "debug-bar-ndisplay");
+ }
+
+ // Marquer toutes les étiquettes comme inactives
+ var labels = document.querySelectorAll("#debug-bar .blitzphp-label");
+
+ for (var i = 0; i < labels.length; i++) {
+ blitzphpDebugBar.removeClass(labels[i], "active");
+ }
+
+ // Afficher/masquer l'onglet sélectionné
+ if (! state) {
+ blitzphpDebugBar.switchClass(tab, "debug-bar-ndisplay", "debug-bar-dblock");
+ blitzphpDebugBar.addClass(this.parentNode, "active");
+ // Créer un cookie de débogage-barre-onglet à l'état persistant
+ blitzphpDebugBar.createCookie(
+ "debug-bar-tab",
+ this.getAttribute("data-tab"),
+ 365
+ );
+ }
+ },
+
+ addClass: function (el, className) {
+ if (el.classList) {
+ el.classList.add(className);
+ } else {
+ el.className += " " + className;
+ }
+ },
+
+ removeClass: function (el, className) {
+ if (el.classList) {
+ el.classList.remove(className);
+ } else {
+ el.className = el.className.replace(
+ new RegExp(
+ "(^|\\b)" + className.split(" ").join("|") + "(\\b|$)",
+ "gi"
+ ),
+ " "
+ );
+ }
+ },
+
+ switchClass : function(el, classFrom, classTo) {
+ blitzphpDebugBar.removeClass(el, classFrom);
+ blitzphpDebugBar.addClass(el, classTo);
+ },
+
+ /**
+ * Basculer l'affichage d'un autre objet en fonction de la valeur de basculement des données de cet objet
+ *
+ * @param event
+ */
+ toggleRows: function (event) {
+ if (event.target) {
+ let row = event.target.closest("tr");
+ let target = document.getElementById(
+ row.getAttribute("data-toggle")
+ );
+
+ if (target.classList.contains("debug-bar-ndisplay")) {
+ blitzphpDebugBar.switchClass(target, "debug-bar-ndisplay", "debug-bar-dtableRow");
+ } else {
+ blitzphpDebugBar.switchClass(target, "debug-bar-dtableRow", "debug-bar-ndisplay");
+ }
+ }
+ },
+
+ /**
+ * Basculer l'affichage d'un tableau de données
+ *
+ * @param obj
+ */
+ toggleDataTable: function (obj) {
+ if (typeof obj == "string") {
+ obj = document.getElementById(obj + "_table");
+ }
+
+ if (obj) {
+ if (obj.classList.contains("debug-bar-ndisplay")) {
+ blitzphpDebugBar.switchClass(obj, "debug-bar-ndisplay", "debug-bar-dblock");
+ } else {
+ blitzphpDebugBar.switchClass(obj, "debug-bar-dblock", "debug-bar-ndisplay");
+ }
+ }
+ },
+
+ /**
+ * Activer/désactiver l'affichage des éléments enfants de la chronologie
+ *
+ * @param obj
+ */
+ toggleChildRows: function (obj) {
+ if (typeof obj == "string") {
+ par = document.getElementById(obj + "_parent");
+ obj = document.getElementById(obj + "_children");
+ }
+
+ if (par && obj) {
+
+ if (obj.classList.contains("debug-bar-ndisplay")) {
+ blitzphpDebugBar.removeClass(obj, "debug-bar-ndisplay");
+ } else {
+ blitzphpDebugBar.addClass(obj, "debug-bar-ndisplay");
+ }
+
+ par.classList.toggle("timeline-parent-open");
+ }
+ },
+
+ //--------------------------------------------------------------------
+
+ /**
+ * Basculer la barre d'outils de pleine à icône et de l'icône à pleine (aggrandir/reduire)
+ */
+ toggleToolbar: function () {
+ var open = ! blitzphpDebugBar.toolbar.classList.contains("debug-bar-ndisplay");
+
+ if (open) {
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.icon, "debug-bar-ndisplay", "debug-bar-dinlineBlock");
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.toolbar, "debug-bar-dinlineBlock", "debug-bar-ndisplay");
+ } else {
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.icon, "debug-bar-dinlineBlock", "debug-bar-ndisplay");
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.toolbar, "debug-bar-ndisplay", "debug-bar-dinlineBlock");
+ }
+
+ // Remember it for other page loads on this site
+ blitzphpDebugBar.createCookie("debug-bar-state", "", -1);
+ blitzphpDebugBar.createCookie(
+ "debug-bar-state",
+ open == true ? "minimized" : "open",
+ 365
+ );
+ },
+
+ /**
+ * Définit l'état initial de la barre d'outils (ouverte ou réduite) lorsque la page est chargée
+ * pour la première fois pour lui permettre de mémoriser l'état entre les actualisations.
+ */
+ setToolbarState: function () {
+ var open = blitzphpDebugBar.readCookie("debug-bar-state");
+
+ if (open != "open") {
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.icon, "debug-bar-ndisplay", "debug-bar-dinlineBlock");
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.toolbar, "debug-bar-dinlineBlock", "debug-bar-ndisplay");
+ } else {
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.icon, "debug-bar-dinlineBlock", "debug-bar-ndisplay");
+ blitzphpDebugBar.switchClass(blitzphpDebugBar.toolbar, "debug-bar-ndisplay", "debug-bar-dinlineBlock");
+ }
+ },
+
+ toggleViewsHints: function () {
+ // Évitez les astuces de basculement sur les demandes d'historique qui ne sont pas les initiales
+ if (
+ localStorage.getItem("debugbar-time") !=
+ localStorage.getItem("debugbar-time-new")
+ ) {
+ var a = document.querySelector('a[data-tab="blitzphp-views"]');
+ a.href = "#";
+ return;
+ }
+
+ var nodeList = []; // [ Element, NewElement( 1 )/OldElement( 0 ) ]
+ var sortedComments = [];
+ var comments = [];
+
+ var getComments = function () {
+ var nodes = [];
+ var result = [];
+ var xpathResults = document.evaluate(
+ "//comment()[starts-with(., ' DEBUG-VIEW')]",
+ document,
+ null,
+ XPathResult.ANY_TYPE,
+ null
+ );
+ var nextNode = xpathResults.iterateNext();
+ while (nextNode) {
+ nodes.push(nextNode);
+ nextNode = xpathResults.iterateNext();
+ }
+
+ // trier les commentaires par balises d'ouverture et de fermeture
+ for (var i = 0; i < nodes.length; ++i) {
+ // obtenir le chemin du fichier + le nom à utiliser comme clé
+ var path = nodes[i].nodeValue.substring(
+ 18,
+ nodes[i].nodeValue.length - 1
+ );
+
+ if (nodes[i].nodeValue[12] === "S") {
+ // vérification simple pour démarrer le commentaire
+ // créer une nouvelle entrée
+ result[path] = [nodes[i], null];
+ } else if (result[path]) {
+ // ajouter à l'entrée existante
+ result[path][1] = nodes[i];
+ }
+ }
+
+ return result;
+ };
+
+ // trouver le nœud qui a TargetNode comme parentNode
+ var getParentNode = function (node, targetNode) {
+ if (node.parentNode === null) {
+ return null;
+ }
+
+ if (node.parentNode !== targetNode) {
+ return getParentNode(node.parentNode, targetNode);
+ }
+
+ return node;
+ };
+
+ // définir les éléments invalides et externes (également invalides)
+ const INVALID_ELEMENTS = ["NOSCRIPT", "SCRIPT", "STYLE"];
+ const OUTER_ELEMENTS = ["HTML", "BODY", "HEAD"];
+
+ var getValidElementInner = function (node, reverse) {
+ // gérer les balises invalides
+ if (OUTER_ELEMENTS.indexOf(node.nodeName) !== -1) {
+ for (var i = 0; i < document.body.children.length; ++i) {
+ var index = reverse
+ ? document.body.children.length - (i + 1)
+ : i;
+ var element = document.body.children[index];
+
+ // ignorer les balises invalides
+ if (INVALID_ELEMENTS.indexOf(element.nodeName) !== -1) {
+ continue;
+ }
+
+ return [element, reverse];
+ }
+
+ return null;
+ }
+
+ // passer à l'élément valide suivant
+ while (
+ node !== null &&
+ INVALID_ELEMENTS.indexOf(node.nodeName) !== -1
+ ) {
+ node = reverse
+ ? node.previousElementSibling
+ : node.nextElementSibling;
+ }
+
+ // renvoyer un element non-tableau (null) si nous n'avons pas trouvé quelque chose
+ if (node === null) {
+ return null;
+ }
+
+ return [node, reverse];
+ };
+
+ // Obtenir l'élément valide suivant (pour ajouter des divs en toute sécurité)
+ // @return [élément, élément ignoré] ou null si nous n'avons pas trouvé d'emplacement valide
+ var getValidElement = function (nodeElement) {
+ if (nodeElement) {
+ if (nodeElement.nextElementSibling !== null) {
+ return (
+ getValidElementInner(
+ nodeElement.nextElementSibling,
+ false
+ ) ||
+ getValidElementInner(
+ nodeElement.previousElementSibling,
+ true
+ )
+ );
+ }
+ if (nodeElement.previousElementSibling !== null) {
+ return getValidElementInner(
+ nodeElement.previousElementSibling,
+ true
+ );
+ }
+ }
+
+ // quelque chose s'est mal passé ! -> l'élément n'est pas dans le DOM
+ return null;
+ };
+
+ function showHints() {
+ // Vous aviez AJAX ? Réinitialiser les blocs de vue
+ sortedComments = getComments();
+
+ for (var key in sortedComments) {
+ var startElement = getValidElement(sortedComments[key][0]);
+ var endElement = getValidElement(sortedComments[key][1]);
+
+ // ignorer si nous ne pouvons pas obtenir un élément valide
+ if (startElement === null || endElement === null) {
+ continue;
+ }
+
+ // trouver l'élément qui a le même parent que l'élément de départ
+ var jointParent = getParentNode(
+ endElement[0],
+ startElement[0].parentNode
+ );
+ if (jointParent === null) {
+ // trouver l'élément qui a le même parent que l'élément final
+ jointParent = getParentNode(
+ startElement[0],
+ endElement[0].parentNode
+ );
+ if (jointParent === null) {
+ // les deux tentatives ont échoué
+ continue;
+ } else {
+ startElement[0] = jointParent;
+ }
+ } else {
+ endElement[0] = jointParent;
+ }
+
+ var debugDiv = document.createElement("div"); // titulaire
+ var debugPath = document.createElement("div"); // chemein
+ var childArray = startElement[0].parentNode.childNodes; // tableau des enfants cibles
+ var parent = startElement[0].parentNode;
+ var start, end;
+
+ // configuration du container
+ debugDiv.classList.add("debug-view");
+ debugDiv.classList.add("show-view");
+ debugPath.classList.add("debug-view-path");
+ debugPath.innerText = key;
+ debugDiv.appendChild(debugPath);
+
+ // calculer la distance entre eux
+ // debut
+ for (var i = 0; i < childArray.length; ++i) {
+ // vérifier le commentaire (début et fin) -> s'il est antérieur à un élément de départ valide
+ if (
+ childArray[i] === sortedComments[key][1] ||
+ childArray[i] === sortedComments[key][0] ||
+ childArray[i] === startElement[0]
+ ) {
+ start = i;
+ if (childArray[i] === sortedComments[key][0]) {
+ start++; // augmenter pour ignorer le commentaire de départ
+ }
+ break;
+ }
+ }
+ // ajuster si nous voulons ignorer l'élément de départ
+ if (startElement[1]) {
+ start++;
+ }
+
+ // fin
+ for (var i = start; i < childArray.length; ++i) {
+ if (childArray[i] === endElement[0]) {
+ end = i;
+ // ne pas interrompre pour vérifier le commentaire de fin après l'élément valide de fin
+ } else if (childArray[i] === sortedComments[key][1]) {
+ // si nous trouvons le commentaire final, nous pouvons casser
+ end = i;
+ break;
+ }
+ }
+
+ // déplacer des éléments
+ var number = end - start;
+ if (endElement[1]) {
+ number++;
+ }
+ for (var i = 0; i < number; ++i) {
+ if (INVALID_ELEMENTS.indexOf(childArray[start]) !== -1) {
+ // ignorer les enfants invalides qui peuvent causer des problèmes s'ils sont déplacés
+ start++;
+ continue;
+ }
+ debugDiv.appendChild(childArray[start]);
+ }
+
+ // ajouter le conteneur au DOM
+ nodeList.push(parent.insertBefore(debugDiv, childArray[start]));
+ }
+
+ blitzphpDebugBar.createCookie("debug-view", "show", 365);
+ blitzphpDebugBar.addClass(btn, "active");
+ }
+
+ function hideHints() {
+ for (var i = 0; i < nodeList.length; ++i) {
+ var index;
+
+ // trouver l'index
+ for (
+ var j = 0;
+ j < nodeList[i].parentNode.childNodes.length;
+ ++j
+ ) {
+ if (nodeList[i].parentNode.childNodes[j] === nodeList[i]) {
+ index = j;
+ break;
+ }
+ }
+
+ // déplacer l'enfant vers l'arrière
+ while (nodeList[i].childNodes.length !== 1) {
+ nodeList[i].parentNode.insertBefore(
+ nodeList[i].childNodes[1],
+ nodeList[i].parentNode.childNodes[index].nextSibling
+ );
+ index++;
+ }
+
+ nodeList[i].parentNode.removeChild(nodeList[i]);
+ }
+ nodeList.length = 0;
+
+ blitzphpDebugBar.createCookie("debug-view", "", -1);
+ blitzphpDebugBar.removeClass(btn, "active");
+ }
+
+ var btn = document.querySelector("[data-tab=blitzphp-views]");
+
+ // Si le collecteur de vues est inactif, il s'arrête ici
+ if (! btn) {
+ return;
+ }
+
+ btn.parentNode.onclick = function () {
+ if (blitzphpDebugBar.readCookie("debug-view")) {
+ hideHints();
+ } else {
+ showHints();
+ }
+ };
+
+ // Déterminer l'état des indices lors du chargement de la page
+ if (blitzphpDebugBar.readCookie("debug-view")) {
+ showHints();
+ }
+ },
+
+ setToolbarPosition: function () {
+ var btnPosition = this.toolbar.querySelector("#toolbar-position");
+
+ if (blitzphpDebugBar.readCookie("debug-bar-position") === "top") {
+ blitzphpDebugBar.addClass(blitzphpDebugBar.icon, "fixed-top");
+ blitzphpDebugBar.addClass(blitzphpDebugBar.toolbar, "fixed-top");
+ }
+
+ btnPosition.addEventListener(
+ "click",
+ function () {
+ var position = blitzphpDebugBar.readCookie("debug-bar-position");
+
+ blitzphpDebugBar.createCookie("debug-bar-position", "", -1);
+
+ if (! position || position === "bottom") {
+ blitzphpDebugBar.createCookie("debug-bar-position", "top", 365);
+ blitzphpDebugBar.addClass(blitzphpDebugBar.icon, "fixed-top");
+ blitzphpDebugBar.addClass(blitzphpDebugBar.toolbar, "fixed-top");
+ } else {
+ blitzphpDebugBar.createCookie(
+ "debug-bar-position",
+ "bottom",
+ 365
+ );
+ blitzphpDebugBar.removeClass(blitzphpDebugBar.icon, "fixed-top");
+ blitzphpDebugBar.removeClass(blitzphpDebugBar.toolbar, "fixed-top");
+ }
+ },
+ true
+ );
+ },
+
+ setToolbarTheme: function () {
+ var btnTheme = this.toolbar.querySelector("#toolbar-theme");
+ var isDarkMode = window.matchMedia(
+ "(prefers-color-scheme: dark)"
+ ).matches;
+ var isLightMode = window.matchMedia(
+ "(prefers-color-scheme: light)"
+ ).matches;
+
+ // Si un cookie est défini avec une valeur, nous forçons le schéma de couleurs
+ if (blitzphpDebugBar.readCookie("debug-bar-theme") === "dark") {
+ blitzphpDebugBar.removeClass(blitzphpDebugBar.toolbarContainer, "light");
+ blitzphpDebugBar.addClass(blitzphpDebugBar.toolbarContainer, "dark");
+ } else if (blitzphpDebugBar.readCookie("debug-bar-theme") === "light") {
+ blitzphpDebugBar.removeClass(blitzphpDebugBar.toolbarContainer, "dark");
+ blitzphpDebugBar.addClass(blitzphpDebugBar.toolbarContainer, "light");
+ }
+
+ btnTheme.addEventListener(
+ "click",
+ function () {
+ var theme = blitzphpDebugBar.readCookie("debug-bar-theme");
+
+ if (
+ ! theme &&
+ window.matchMedia("(prefers-color-scheme: dark)").matches
+ ) {
+ // S'il n'y a pas de cookie et que « prefers-color-scheme » est défini sur « dark »,
+ // cela signifie que l'utilisateur souhaite passer en mode clair.
+ blitzphpDebugBar.createCookie("debug-bar-theme", "light", 365);
+ blitzphpDebugBar.removeClass(blitzphpDebugBar.toolbarContainer, "dark");
+ blitzphpDebugBar.addClass(blitzphpDebugBar.toolbarContainer, "light");
+ } else {
+ if (theme === "dark") {
+ blitzphpDebugBar.createCookie(
+ "debug-bar-theme",
+ "light",
+ 365
+ );
+ blitzphpDebugBar.removeClass(
+ blitzphpDebugBar.toolbarContainer,
+ "dark"
+ );
+ blitzphpDebugBar.addClass(
+ blitzphpDebugBar.toolbarContainer,
+ "light"
+ );
+ } else {
+ // Dans tous les autres cas : s'il n'y a pas de cookie, ou si le cookie est réglé sur
+ // « light », ou si le « prefers-color-scheme » est « light »...
+ blitzphpDebugBar.createCookie("debug-bar-theme", "dark", 365);
+ blitzphpDebugBar.removeClass(
+ blitzphpDebugBar.toolbarContainer,
+ "light"
+ );
+ blitzphpDebugBar.addClass(
+ blitzphpDebugBar.toolbarContainer,
+ "dark"
+ );
+ }
+ }
+ },
+ true
+ );
+ },
+
+ setHotReloadState: function () {
+ var btn = document.getElementById("debug-hot-reload").parentNode;
+ var btnImg = btn.getElementsByTagName("img")[0];
+ var eventSource;
+
+ // Si le collecteur de rechargement à chaud est inactif, il s'arrête ici
+ if (! btn) {
+ return;
+ }
+
+ btn.onclick = function () {
+ if (blitzphpDebugBar.readCookie("debug-hot-reload")) {
+ blitzphpDebugBar.createCookie("debug-hot-reload", "", -1);
+ blitzphpDebugBar.removeClass(btn, "active");
+ blitzphpDebugBar.removeClass(btnImg, "rotate");
+
+ // Fermez la connexion EventSource si elle existe
+ if (typeof eventSource !== "undefined") {
+ eventSource.close();
+ eventSource = void 0; // Indéfinir la variable
+ }
+ } else {
+ blitzphpDebugBar.createCookie("debug-hot-reload", "show", 365);
+ blitzphpDebugBar.addClass(btn, "active");
+ blitzphpDebugBar.addClass(btnImg, "rotate");
+
+ eventSource = blitzphpDebugBar.hotReloadConnect();
+ }
+ };
+
+ // Déterminer l'état de rechargement à chaud lors du chargement de la page
+ if (blitzphpDebugBar.readCookie("debug-hot-reload")) {
+ blitzphpDebugBar.addClass(btn, "active");
+ blitzphpDebugBar.addClass(btnImg, "rotate");
+ eventSource = blitzphpDebugBar.hotReloadConnect();
+ }
+ },
+
+ hotReloadConnect: function () {
+ const eventSource = new EventSource(blitzSiteURL + "/__hot-reload");
+
+ eventSource.addEventListener("reload", function (e) {
+ console.log("reload", e);
+ window.location.reload();
+ });
+
+ eventSource.onerror = (err) => {
+ console.error("EventSource failed:", err);
+ };
+
+ return eventSource;
+ },
+
+ /**
+ * Aide à la création d'un cookie.
+ *
+ * @param name
+ * @param value
+ * @param days
+ */
+ createCookie: function (name, value, days) {
+ if (days) {
+ var date = new Date();
+
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
+
+ var expires = "; expires=" + date.toGMTString();
+ } else {
+ var expires = "";
+ }
+
+ document.cookie =
+ name + "=" + value + expires + "; path=/; samesite=Lax";
+ },
+
+ readCookie: function (name) {
+ var nameEQ = name + "=";
+ var ca = document.cookie.split(";");
+
+ for (var i = 0; i < ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) == " ") {
+ c = c.substring(1, c.length);
+ }
+ if (c.indexOf(nameEQ) == 0) {
+ return c.substring(nameEQ.length, c.length);
+ }
+ }
+ return null;
+ },
+
+ trimSlash: function (text) {
+ return text.replace(/^\/|\/$/g, "");
+ },
+
+ routerLink: function () {
+ var row, _location;
+ var rowGet = this.toolbar.querySelectorAll(
+ 'td[data-debugbar-route="GET"]'
+ );
+ var patt = /\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)/;
+
+ for (var i = 0; i < rowGet.length; i++) {
+ row = rowGet[i];
+ if (!/\/\(.+?\)/.test(rowGet[i].innerText)) {
+ blitzphpDebugBar.addClass(row, "debug-bar-pointer");
+ row.setAttribute(
+ "title",
+ location.origin + "/" + blitzphpDebugBar.trimSlash(row.innerText)
+ );
+ row.addEventListener("click", function (ev) {
+ _location =
+ location.origin +
+ "/" +
+ blitzphpDebugBar.trimSlash(ev.target.innerText);
+ var redirectWindow = window.open(_location, "_blank");
+ redirectWindow.location;
+ });
+ } else {
+ row.innerHTML =
+ "" +
+ row.innerText +
+ "
" +
+ '";
+ }
+ }
+
+ rowGet = this.toolbar.querySelectorAll(
+ 'td[data-debugbar-route="GET"] form'
+ );
+ for (var i = 0; i < rowGet.length; i++) {
+ row = rowGet[i];
+
+ row.addEventListener("submit", function (event) {
+ event.preventDefault();
+ var inputArray = [],
+ t = 0;
+ var input = event.target.querySelectorAll("input[type=text]");
+ var tpl = event.target.getAttribute("data-debugbar-route-tpl");
+
+ for (var n = 0; n < input.length; n++) {
+ if (input[n].value.length > 0) {
+ inputArray.push(input[n].value);
+ }
+ }
+
+ if (inputArray.length > 0) {
+ _location =
+ location.origin +
+ "/" +
+ tpl.replace(/\?/g, function () {
+ return inputArray[t++];
+ });
+
+ var redirectWindow = window.open(_location, "_blank");
+ redirectWindow.location;
+ }
+ });
+ }
+ },
+};
diff --git a/src/Debug/Toolbar/Views/toolbar.tpl.php b/src/Debug/Toolbar/Views/toolbar.tpl.php
index daee1d4d..890b18e1 100644
--- a/src/Debug/Toolbar/Views/toolbar.tpl.php
+++ b/src/Debug/Toolbar/Views/toolbar.tpl.php
@@ -19,11 +19,10 @@
*/
?>
-
-
+
-
-
+
@@ -120,7 +124,7 @@
$items) : ?>
-
+
= $heading ?>
@@ -144,7 +148,7 @@
-
+
Données utilisateur de session
@@ -170,7 +174,7 @@
Requête ( = $vars['request'] ?> )
-
+
$_GET
@@ -187,7 +191,7 @@
-
+
$_POST
@@ -204,7 +208,7 @@
-
+
Headers
@@ -221,7 +225,7 @@
-
+
Cookies
@@ -237,12 +241,12 @@
- Reponse
+ Réponse
( = $vars['response']['statusCode'] . ' - ' . $vars['response']['reason'] ?> )
-
+
Headers
@@ -266,5 +270,4 @@
= $parser->setData($config)->render('_config.tpl') ?>
-
-
+
diff --git a/src/Debug/Toolbar/Views/toolbarloader.js b/src/Debug/Toolbar/Views/toolbarloader.js
index 7e591435..6f0083fa 100644
--- a/src/Debug/Toolbar/Views/toolbarloader.js
+++ b/src/Debug/Toolbar/Views/toolbarloader.js
@@ -25,19 +25,19 @@ function loadDoc(time) {
let dynamicStyle = document.getElementById('debugbar_dynamic_style');
let dynamicScript = document.getElementById('debugbar_dynamic_script');
- // get the first style block, copy contents to dynamic_style, then remove here
+ // récupérez le premier bloc de style, copiez le contenu dans dynamic_style, puis supprimez-le ici
let start = responseText.indexOf('>', responseText.indexOf('', start);
dynamicStyle.innerHTML += responseText.substr(start, end - start);
@@ -45,11 +45,11 @@ function loadDoc(time) {
toolbar.innerHTML = responseText;
- if (typeof ciDebugBar === 'object') {
- ciDebugBar.init();
+ if (typeof blitzphpDebugBar === 'object') {
+ blitzphpDebugBar.init();
}
} else if (this.readyState === 4 && this.status === 404) {
- console.log('CodeIgniter DebugBar: File "WRITEPATH/debugbar/debugbar_' + time + '" not found.');
+ console.log('BlitzPHP DebugBar: File "STORAGE_PATH/debugbar/debugbar_' + time + '" not found.');
}
};
@@ -71,11 +71,14 @@ function newXHR() {
let debugbarTime = realXHR.getResponseHeader('Debugbar-Time');
if (debugbarTime) {
- let h2 = document.querySelector('#ci-history > h2');
+ let h2 = document.querySelector('#blitzphp-history > h2');
if (h2) {
- h2.innerHTML = 'History You have new debug data. Update ';
- document.querySelector('a[data-tab="ci-history"] > span > .badge').className += ' active';
+ h2.innerHTML = 'Historique Vous avez de nouvelles données de débogage. Mettre à jour ';
+ document.querySelector('a[data-tab="blitzphp-history"] > span > .badge').className += ' active';
+ document.getElementById('blitzphp-history-update').addEventListener('click', function () {
+ loadDoc(debugbarTime);
+ }, false)
}
}
}
diff --git a/src/Exceptions/FrameworkException.php b/src/Exceptions/FrameworkException.php
index f01337a5..570cd99c 100644
--- a/src/Exceptions/FrameworkException.php
+++ b/src/Exceptions/FrameworkException.php
@@ -28,6 +28,11 @@ public static function enabledZlibOutputCompression()
return new static(lang('Core.enabledZlibOutputCompression'));
}
+ public static function invalidDirectory(string $path)
+ {
+ return new static(lang('Core.invalidDirectory', [$path]));
+ }
+
public static function invalidFile(string $path)
{
return new static(lang('Core.invalidFile', [$path]));
diff --git a/src/HotReloader/DirectoryHasher.php b/src/HotReloader/DirectoryHasher.php
new file mode 100644
index 00000000..6f590c45
--- /dev/null
+++ b/src/HotReloader/DirectoryHasher.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace BlitzPHP\HotReloader;
+
+use BlitzPHP\Exceptions\FrameworkException;
+use FilesystemIterator;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+
+/**
+ * @internal
+ *
+ * @credit CodeIgniter 4.6 - CodeIgniter\HotReloader\DirectoryHasher
+ */
+final class DirectoryHasher
+{
+ /**
+ * Génère une valeur MD5 de tous les répertoires surveillés par le rechargeur à chaud,
+ * comme défini dans le fichier app/Config/toolbar.php.
+ *
+ * Il s'agit de l'empreinte actuelle de l'application.
+ */
+ public function hash(): string
+ {
+ return md5(implode('', $this->hashApp()));
+ }
+
+ /**
+ * Génère un tableau de hachages md5 pour tous les répertoires surveillés par le Hot Reloader,
+ * comme défini dans app/Config/toolbar.php.
+ */
+ public function hashApp(): array
+ {
+ $hashes = [];
+
+ $watchedDirectories = config('toolbar.watched_directories', []);
+
+ foreach ($watchedDirectories as $directory) {
+ if (is_dir(ROOTPATH . $directory)) {
+ $hashes[$directory] = $this->hashDirectory(ROOTPATH . $directory);
+ }
+ }
+
+ return array_unique(array_filter($hashes));
+ }
+
+ /**
+ * Génère un hachage MD5 d'un répertoire donné et de tous ses fichiers * qui correspondent aux extensions surveillées
+ * définies dans app/Config/toolbar.php.
+ */
+ public function hashDirectory(string $path): string
+ {
+ if (! is_dir($path)) {
+ throw FrameworkException::invalidDirectory($path);
+ }
+
+ $directory = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
+ $filter = new IteratorFilter($directory);
+ $iterator = new RecursiveIteratorIterator($filter);
+
+ $hashes = [];
+
+ foreach ($iterator as $file) {
+ if ($file->isFile()) {
+ $hashes[] = md5_file($file->getRealPath());
+ }
+ }
+
+ return md5(implode('', $hashes));
+ }
+}
diff --git a/src/HotReloader/HotReloader.php b/src/HotReloader/HotReloader.php
new file mode 100644
index 00000000..779daf50
--- /dev/null
+++ b/src/HotReloader/HotReloader.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace BlitzPHP\HotReloader;
+
+/**
+ * @internal
+ *
+ * @credit CodeIgniter 4.6 - CodeIgniter\HotReloader\HotReloader
+ */
+final class HotReloader
+{
+ public function run(): void
+ {
+ if (session_status() === PHP_SESSION_ACTIVE) {
+ session_write_close();
+ }
+
+ ini_set('zlib.output_compression', 'Off');
+
+ header('Cache-Control: no-store');
+ header('Content-Type: text/event-stream');
+ header('Access-Control-Allow-Methods: GET');
+
+ ob_end_clean();
+ set_time_limit(0);
+
+ $hasher = new DirectoryHasher();
+ $appHash = $hasher->hash();
+
+ while (true) {
+ if (connection_status() !== CONNECTION_NORMAL || connection_aborted() === 1) {
+ break;
+ }
+
+ $currentHash = $hasher->hash();
+
+ // Si le hachage a changé, demandez au navigateur de se recharger.
+ if ($currentHash !== $appHash) {
+ $appHash = $currentHash;
+
+ $this->sendEvent('reload', ['time' => date('Y-m-d H:i:s')]);
+ break;
+ }
+
+ if (mt_rand(1, 10) > 8) {
+ $this->sendEvent('ping', ['time' => date('Y-m-d H:i:s')]);
+ }
+
+ sleep(1);
+ }
+ }
+
+ /**
+ * Envoyer un événement au navigateur.
+ */
+ private function sendEvent(string $event, array $data): void
+ {
+ echo "event: {$event}\n";
+ echo 'data: ' . json_encode($data) . "\n\n";
+
+ ob_flush();
+ flush();
+ }
+}
diff --git a/src/HotReloader/IteratorFilter.php b/src/HotReloader/IteratorFilter.php
new file mode 100644
index 00000000..8291501a
--- /dev/null
+++ b/src/HotReloader/IteratorFilter.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace BlitzPHP\HotReloader;
+
+use RecursiveFilterIterator;
+use RecursiveIterator;
+
+/**
+ * @internal
+ *
+ * @psalm-suppress MissingTemplateParam
+ *
+ * @credit CodeIgniter 4.6 - CodeIgniter\HotReloader\IteratorFilter
+ */
+final class IteratorFilter extends RecursiveFilterIterator implements RecursiveIterator
+{
+ private array $watchedExtensions = [];
+
+ public function __construct(RecursiveIterator $iterator)
+ {
+ parent::__construct($iterator);
+
+ $this->watchedExtensions = config('toolbar.watched_extensions', []);
+ }
+
+ /**
+ * Appliquer des filtres aux fichiers dans l'itérateur.
+ */
+ public function accept(): bool
+ {
+ if (! $this->current()->isFile()) {
+ return true;
+ }
+
+ $filename = $this->current()->getFilename();
+
+ // Ignorer les fichiers et répertoires cachés.
+ if ($filename[0] === '.') {
+ return false;
+ }
+
+ // Ne consommez que les fichiers qui vous intéressent.
+ $ext = trim(strtolower($this->current()->getExtension()), '. ');
+
+ return in_array($ext, $this->watchedExtensions, true);
+ }
+}
diff --git a/src/Http/ServerRequest.php b/src/Http/ServerRequest.php
index dd491c0e..8c2bb2a7 100644
--- a/src/Http/ServerRequest.php
+++ b/src/Http/ServerRequest.php
@@ -242,10 +242,6 @@ protected function _setConfig(array $config): void
$uri = new Uri(Psr7ServerRequest::getUriFromGlobals()->__toString());
}
- if (isset($config['environment']['REQUEST_URI'])) {
- $uri = $uri->withPath($config['environment']['REQUEST_URI']);
- }
-
if (in_array($uri->getHost(), ['localhost', '127.0.0.1'], true)) {
$uri = $uri->withHost(parse_url(config('app.base_url'), PHP_URL_HOST));
}
diff --git a/src/Router/Dispatcher.php b/src/Router/Dispatcher.php
index a54ea6cf..28e39f41 100644
--- a/src/Router/Dispatcher.php
+++ b/src/Router/Dispatcher.php
@@ -365,7 +365,7 @@ protected function dispatchRoutes(?RouteCollectionInterface $routes = null): arr
}
// $routes est defini dans app/Config/routes.php
- $this->router = single_service('router', $routes, $this->request);
+ $this->router = service('router', $routes, $this->request);
$this->outputBufferingStart();
@@ -576,7 +576,7 @@ public function storePreviousURL($uri)
protected function sendResponse()
{
if (! $this->isAjaxRequest()) {
- $this->response = service('toolbar')->prepare(
+ $this->response = service('toolbar')->process(
$this->getPerformanceStats(),
$this->request,
$this->response
@@ -685,6 +685,12 @@ private function spoofRequestMethod(): callable
};
}
+ /**
+ * Démarre l'application en configurant la requete et la réponse,
+ * en exécutant le contrôleur et en gérant les exceptions de validation.
+ *
+ * Cette méthode renvoie un objet callable qui sert de middleware pour le cycle requête-réponse de l'application.
+ */
private function bootApp(): callable
{
return function (ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface {
diff --git a/src/Translations/en/Core.php b/src/Translations/en/Core.php
index f5812490..c0801278 100644
--- a/src/Translations/en/Core.php
+++ b/src/Translations/en/Core.php
@@ -13,6 +13,7 @@
return [
'copyError' => 'An error was encountered while attempting to replace the file ({0}). Please make sure your file directory is writable.',
'enabledZlibOutputCompression' => 'Your zlib.output_compression ini directive is turned on. This will not work well with output buffers.',
+ 'invalidDirectory' => 'Directory does not exist: "{0}"',
'invalidFile' => 'Invalid file: {0}',
'invalidPhpVersion' => 'Your PHP version must be {0} or higher to run CodeIgniter. Current version: {1}',
'missingExtension' => 'The framework needs the following extension(s) installed and loaded: {0}.',