diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2cdf248ea..64cd47585 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,56 +1,60 @@ - + - - $this->_composerPaths - $this->_pluginPaths + + _composerPaths]]> + _pluginPaths]]> - + bindings - + self::$_timers - + $pos - + $result - + array - + new $className($config) - + string|null - + new $class($this, $config) - + genericInstances - + + new HtmlFormatter() new HtmlFormatter() - + + dump dump + new HtmlFormatter() + new HtmlFormatter() diff --git a/src/Controller/PanelsController.php b/src/Controller/PanelsController.php index 18c14542f..5b5817785 100644 --- a/src/Controller/PanelsController.php +++ b/src/Controller/PanelsController.php @@ -83,7 +83,7 @@ public function index(?string $requestId = null): void public function view(?string $id = null): void { $this->set('sort', $this->request->getCookie('debugKit_sort')); - $panel = $this->Panels->get($id, ['contain' => ['Requests']]); + $panel = $this->Panels->get($id, ...['contain' => ['Requests']]); $this->set('panel', $panel); // @codingStandardsIgnoreStart diff --git a/src/Model/Table/PanelsTable.php b/src/Model/Table/PanelsTable.php index 1326c4e24..4cfc7b460 100644 --- a/src/Model/Table/PanelsTable.php +++ b/src/Model/Table/PanelsTable.php @@ -22,7 +22,7 @@ * each request. * * @property \DebugKit\Model\Table\RequestsTable&\Cake\ORM\Association\BelongsTo $Requests - * @method \DebugKit\Model\Entity\Panel get($primaryKey, $options = []) + * @method \DebugKit\Model\Entity\Panel get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, ...$args) * @method \DebugKit\Model\Entity\Panel newEntity($data = null, array $options = []) * @method \DebugKit\Model\Entity\Panel[] newEntities(array $data, array $options = []) * @method \DebugKit\Model\Entity\Panel|false save(\Cake\Datasource\EntityInterface $entity, $options = []) diff --git a/src/Model/Table/RequestsTable.php b/src/Model/Table/RequestsTable.php index 2c09a3dcd..9b31f10ff 100644 --- a/src/Model/Table/RequestsTable.php +++ b/src/Model/Table/RequestsTable.php @@ -25,7 +25,7 @@ * The requests table tracks basic information about each request. * * @property \DebugKit\Model\Table\PanelsTable $Panels - * @method \DebugKit\Model\Entity\Request get($primaryKey, $options = []) + * @method \DebugKit\Model\Entity\Request get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, ...$args) * @method \DebugKit\Model\Entity\Request newEntity($data = null, array $options = []) * @method \DebugKit\Model\Entity\Request[] newEntities(array $data, array $options = []) * @method \DebugKit\Model\Entity\Request save(\Cake\Datasource\EntityInterface $entity, $options = []) diff --git a/src/Panel/IncludePanel.php b/src/Panel/IncludePanel.php index 3bb989468..a0d52a7cb 100644 --- a/src/Panel/IncludePanel.php +++ b/src/Panel/IncludePanel.php @@ -14,6 +14,7 @@ */ namespace DebugKit\Panel; +use Cake\Error\Debugger; use Cake\Event\EventInterface; use Cake\Utility\Hash; use DebugKit\DebugInclude; @@ -85,6 +86,10 @@ protected function _prepare(): array ksort($plugin); } + foreach ($return as $k => $v) { + $return[$k] = Debugger::exportVarAsNodes($v); + } + return $return; } diff --git a/src/Panel/RequestPanel.php b/src/Panel/RequestPanel.php index 1cafcdc8e..815b16f0f 100644 --- a/src/Panel/RequestPanel.php +++ b/src/Panel/RequestPanel.php @@ -14,6 +14,7 @@ */ namespace DebugKit\Panel; +use Cake\Error\Debugger; use Cake\Event\EventInterface; use DebugKit\DebugPanel; use Exception; @@ -42,17 +43,21 @@ public function shutdown(EventInterface $event): void } catch (Exception $e) { $value = "Could not serialize `{$attr}`. It failed with {$e->getMessage()}"; } - $attributes[$attr] = $value; + $attributes[$attr] = Debugger::exportVarAsNodes($value); } $this->_data = [ 'attributes' => $attributes, - 'query' => $request->getQueryParams(), - 'data' => $request->getData(), - 'cookie' => $request->getCookieParams(), - 'get' => $_GET, + 'query' => Debugger::exportVarAsNodes($request->getQueryParams()), + 'data' => Debugger::exportVarAsNodes($request->getData()), + 'cookie' => Debugger::exportVarAsNodes($request->getCookieParams()), + 'get' => Debugger::exportVarAsNodes($_GET), 'matchedRoute' => $request->getParam('_matchedRoute'), - 'headers' => ['response' => headers_sent($file, $line), 'file' => $file, 'line' => $line], + 'headers' => [ + 'response' => headers_sent($file, $line), + 'file' => $file, + 'line' => $line, + ], ]; } } diff --git a/src/Panel/SessionPanel.php b/src/Panel/SessionPanel.php index 0c0ec30a5..7c7560c20 100644 --- a/src/Panel/SessionPanel.php +++ b/src/Panel/SessionPanel.php @@ -14,6 +14,7 @@ */ namespace DebugKit\Panel; +use Cake\Error\Debugger; use Cake\Event\EventInterface; use DebugKit\DebugPanel; @@ -33,7 +34,8 @@ public function shutdown(EventInterface $event): void /** @var \Cake\Http\ServerRequest|null $request */ $request = $event->getSubject()->getRequest(); if ($request) { - $this->_data = ['content' => $request->getSession()->read()]; + $content = Debugger::exportVarAsNodes($request->getSession()->read()); + $this->_data = compact('content'); } } } diff --git a/src/Panel/VariablesPanel.php b/src/Panel/VariablesPanel.php index 4efe3d798..aacba7fdc 100644 --- a/src/Panel/VariablesPanel.php +++ b/src/Panel/VariablesPanel.php @@ -97,11 +97,11 @@ public function shutdown(EventInterface $event): void foreach ($vars as $k => $v) { // Get the validation errors for Entity if ($v instanceof EntityInterface) { - $errors[$k] = $this->_getErrors($v); + $errors[$k] = Debugger::exportVarAsNodes($this->_getErrors($v), $varsMaxDepth); } elseif ($v instanceof Form) { $formErrors = $v->getErrors(); if ($formErrors) { - $errors[$k] = $formErrors; + $errors[$k] = Debugger::exportVarAsNodes($formErrors, $varsMaxDepth); } } $content[$k] = Debugger::exportVarAsNodes($v, $varsMaxDepth); diff --git a/src/View/Helper/ToolbarHelper.php b/src/View/Helper/ToolbarHelper.php index df829bd8c..3fb992b37 100644 --- a/src/View/Helper/ToolbarHelper.php +++ b/src/View/Helper/ToolbarHelper.php @@ -18,8 +18,8 @@ use Cake\Error\Debug\ArrayItemNode; use Cake\Error\Debug\ArrayNode; use Cake\Error\Debug\HtmlFormatter; +use Cake\Error\Debug\NodeInterface; use Cake\Error\Debug\ScalarNode; -use Cake\Error\Debugger; use Cake\View\Helper; /** @@ -66,7 +66,6 @@ public function setSort(bool $sort): void */ public function dumpNodes(array $nodes): string { - /** @psalm-suppress InternalMethod */ $formatter = new HtmlFormatter(); if ($this->sort) { ksort($nodes); @@ -78,41 +77,25 @@ public function dumpNodes(array $nodes): string $root = new ArrayNode($items); return implode([ - '
', + '
', $formatter->dump($root), '
', ]); } /** - * Dump the value in $value into an interactive HTML output. + * Dump an error node * - * @param mixed $value The value to output. + * @param \Cake\Error\Debug\NodeInterface $node A error node containing dumped variables. * @return string Formatted HTML - * @deprecated 4.4.0 */ - public function dump(mixed $value): string + public function dumpNode(NodeInterface $node): string { - $debugger = Debugger::getInstance(); - $exportFormatter = $debugger->getConfig('exportFormatter'); - $restore = false; - if ($exportFormatter !== HtmlFormatter::class) { - $restore = true; - $debugger->setConfig('exportFormatter', HtmlFormatter::class); - } - - if ($this->sort && is_array($value)) { - ksort($value); - } - - $contents = Debugger::exportVar($value, 25); - if ($restore) { - $debugger->setConfig('exportFormatter', $exportFormatter); - } + $formatter = new HtmlFormatter(); return implode([ - '
', - $contents, + '
', + $formatter->dump($node), '
', ]); } diff --git a/templates/element/include_panel.php b/templates/element/include_panel.php index 95fdd5626..8f5cc6772 100644 --- a/templates/element/include_panel.php +++ b/templates/element/include_panel.php @@ -14,12 +14,12 @@ /** * @var \DebugKit\View\AjaxView $this - * @var array $paths - * @var array $app - * @var array $cake - * @var array $plugins - * @var array $vendor - * @var array $other + * @var array<\Cake\Error\Debug\NodeInterface> $paths + * @var array<\Cake\Error\Debug\NodeInterface> $app + * @var array<\Cake\Error\Debug\NodeInterface> $cake + * @var array<\Cake\Error\Debug\NodeInterface> $plugins + * @var array<\Cake\Error\Debug\NodeInterface> $vendor + * @var array<\Cake\Error\Debug\NodeInterface> $other */ // Backwards compat for old DebugKit data. @@ -29,8 +29,8 @@ ?>

Include Paths

- Toolbar->dump($paths) ?> + Toolbar->dumpNodes(compact('paths')) ?>

Included Files

- Toolbar->dump(compact('app', 'cake', 'plugins', 'vendor', 'other')) ?> + Toolbar->dumpNodes(compact('app', 'cake', 'plugins', 'vendor', 'other')) ?>
diff --git a/templates/element/request_panel.php b/templates/element/request_panel.php index 907720572..6f113d154 100644 --- a/templates/element/request_panel.php +++ b/templates/element/request_panel.php @@ -20,11 +20,14 @@ * @var \DebugKit\View\AjaxView $this * @var array $headers * @var array $attributes - * @var array $data - * @var array $query - * @var array $cookie + * @var \Cake\Error\Debug\NodeInterface $data + * @var \Cake\Error\Debug\NodeInterface $query + * @var \Cake\Error\Debug\NodeInterface $cookie * @var string $matchedRoute */ + +use Cake\Error\Debugger; + ?>
@@ -43,7 +46,7 @@ if (empty($attributes)) : echo '

No attributes data.

'; else : - echo $this->Toolbar->dump($attributes); + echo $this->Toolbar->dumpNodes($attributes); endif; ?> @@ -52,7 +55,7 @@ if (empty($data)) : echo '

No post data.

'; else : - echo $this->Toolbar->dump($data); + echo $this->Toolbar->dumpNode($data); endif; ?> @@ -61,19 +64,19 @@ if (empty($query)) : echo '

No querystring data.

'; else : - echo $this->Toolbar->dump($query); + echo $this->Toolbar->dumpNode($query); endif; ?>

Cookie

- Toolbar->dump($cookie) ?> + Toolbar->dumpNode($cookie) ?>

No Cookie data.

Matched Route

-

Toolbar->dump(['template' => $matchedRoute]) ?>

+

Toolbar->dumpNode(Debugger::exportVarAsNodes(['template' => $matchedRoute])) ?>

diff --git a/templates/element/session_panel.php b/templates/element/session_panel.php index ee5be637b..d7d13f383 100644 --- a/templates/element/session_panel.php +++ b/templates/element/session_panel.php @@ -14,9 +14,9 @@ /** * @var \DebugKit\View\AjaxView $this - * @var array $content + * @var \Cake\Error\Debug\NodeInterface $content */ ?>
- Toolbar->dump($content) ?> + Toolbar->dumpNode($content) ?>
diff --git a/templates/element/variables_panel.php b/templates/element/variables_panel.php index af1249d88..57c508be0 100644 --- a/templates/element/variables_panel.php +++ b/templates/element/variables_panel.php @@ -16,7 +16,6 @@ * @var string $error * @var bool|null $sort * @var array $variables - * @var array $content * @var array $errors */ ?> @@ -34,22 +33,6 @@ printf('

%s

', $msg); } - // Backwards compatibility for old debug kit data. - if (!empty($content)) :?> -
- -
- Toolbar->setSort($sort); - echo $this->Toolbar->dump($content); - endif; - // New node based data. if (!empty($variables)) :?>
@@ -68,7 +51,7 @@ class="js-debugkit-sort-variables" if (!empty($errors)) : echo '

Validation errors

'; - echo $this->Toolbar->dump($errors); + echo $this->Toolbar->dumpNodes($errors); endif; ?>
diff --git a/tests/TestCase/FixtureFactoryTrait.php b/tests/TestCase/FixtureFactoryTrait.php index 8bf73e5ea..4aeaa9cb7 100644 --- a/tests/TestCase/FixtureFactoryTrait.php +++ b/tests/TestCase/FixtureFactoryTrait.php @@ -15,6 +15,8 @@ */ namespace DebugKit\Test\TestCase; +use Cake\Error\Debugger; + trait FixtureFactoryTrait { protected function makeRequest() @@ -33,20 +35,22 @@ protected function makePanel($request, $name = 'DebugKit.Request', $title = 'Req if ($content === null) { $content = [ 'attributes' => [ - 'params' => [ - 'plugin' => null, - 'controller' => 'Tasks', - 'action' => 'add', - '_ext' => null, - 'pass' => [], - ], + Debugger::exportVarAsNodes([ + 'params' => [ + 'plugin' => null, + 'controller' => 'Tasks', + 'action' => 'add', + '_ext' => null, + 'pass' => [], + ], + ]), ], - 'query' => [], - 'data' => [], - 'get' => [], - 'cookie' => [ + 'query' => Debugger::exportVarAsNodes([]), + 'data' => Debugger::exportVarAsNodes([]), + 'get' => Debugger::exportVarAsNodes([]), + 'cookie' => Debugger::exportVarAsNodes([ 'toolbarDisplay' => 'show', - ], + ]), ]; } $panels = $this->getTableLocator()->get('DebugKit.Panels'); diff --git a/tests/TestCase/Panel/IncludePanelTest.php b/tests/TestCase/Panel/IncludePanelTest.php index 462fc13fa..aa0668732 100644 --- a/tests/TestCase/Panel/IncludePanelTest.php +++ b/tests/TestCase/Panel/IncludePanelTest.php @@ -51,13 +51,8 @@ public function testShutdown() $data = $this->panel->data(); $this->assertArrayHasKey('cake', $data); $this->assertArrayHasKey('app', $data); - $this->assertArrayHasKey('plugins', $data); - $this->assertArrayHasKey('DebugKit', $data['plugins']); - $this->assertArrayHasKey('other', $data['plugins']['DebugKit']); - $this->assertArrayHasKey('vendor', $data); - $this->assertArrayHasKey('other', $data); } @@ -69,6 +64,6 @@ public function testShutdown() public function testSummary() { $total = $this->panel->summary(); - $this->assertGreaterThan(50, $total); + $this->assertEquals(5, $total); } } diff --git a/tests/TestCase/Panel/RequestPanelTest.php b/tests/TestCase/Panel/RequestPanelTest.php index 8d40e0d37..2a680bbd5 100644 --- a/tests/TestCase/Panel/RequestPanelTest.php +++ b/tests/TestCase/Panel/RequestPanelTest.php @@ -64,7 +64,7 @@ public function testShutdownSkipAttributes() $data = $this->panel->data(); $this->assertArrayHasKey('attributes', $data); - $this->assertEquals('string', $data['attributes']['ok']); - $this->assertStringContainsString('Could not serialize `closure`', $data['attributes']['closure']); + $this->assertEquals('string', $data['attributes']['ok']->getType()); + $this->assertStringContainsString('Could not serialize `closure`', $data['attributes']['closure']->getValue()); } } diff --git a/tests/TestCase/Panel/SessionPanelTest.php b/tests/TestCase/Panel/SessionPanelTest.php new file mode 100644 index 000000000..4970de027 --- /dev/null +++ b/tests/TestCase/Panel/SessionPanelTest.php @@ -0,0 +1,69 @@ +panel = new SessionPanel(); + } + + /** + * Test that shutdown will skip unserializable attributes. + * + * @return void + */ + public function testShutdownSkipAttributes() + { + $session = new Session(); + $session->write('test', 123); + $request = new ServerRequest([ + 'session' => $session, + ]); + + $controller = new Controller($request); + $event = new Event('Controller.shutdown', $controller); + $this->panel->shutdown($event); + + $data = $this->panel->data(); + $this->assertArrayHasKey('content', $data); + /** @var \Cake\Error\Debug\ArrayItemNode $content */ + $content = $data['content']->getChildren()[0]; + $this->assertEquals('test', $content->getKey()->getValue()); + $this->assertEquals('123', $content->getValue()->getValue()); + } +} diff --git a/tests/TestCase/Panel/VariablesPanelTest.php b/tests/TestCase/Panel/VariablesPanelTest.php index 20dfde33b..d163a037f 100644 --- a/tests/TestCase/Panel/VariablesPanelTest.php +++ b/tests/TestCase/Panel/VariablesPanelTest.php @@ -96,6 +96,7 @@ public function testShutdown() 'string' => 'yes', 'array' => ['some' => 'key'], 'notSerializableForm' => new TestForm(), + 'emptyEntity' => $requests->newEmptyEntity(), ]; $controller->viewBuilder()->setVars($vars); $event = new Event('Controller.shutdown', $controller); diff --git a/tests/TestCase/View/Helper/ToolbarHelperTest.php b/tests/TestCase/View/Helper/ToolbarHelperTest.php index 1ec8e56fb..3f86bf0fc 100644 --- a/tests/TestCase/View/Helper/ToolbarHelperTest.php +++ b/tests/TestCase/View/Helper/ToolbarHelperTest.php @@ -15,14 +15,14 @@ */ namespace DebugKit\Test\TestCase\View\Helper; -use Cake\Error\Debug\TextFormatter; use Cake\Error\Debugger; use Cake\Http\ServerRequest as Request; use Cake\Routing\Router; use Cake\TestSuite\TestCase; use Cake\View\View; use DebugKit\View\Helper\ToolbarHelper; -use SimpleXmlElement; +use DOMDocument; +use DOMXPath; /** * Class ToolbarHelperTestCase @@ -75,46 +75,28 @@ public function testDumpNodesSorted() return Debugger::exportVarAsNodes($v); }, $data); $result = $this->Toolbar->dumpNodes($nodes); - $xml = new SimpleXmlElement($result); - $elements = $xml->xpath($path); - $this->assertSame(["'z'", "'a'", "'m'"], array_map('strval', $elements)); + $doc = new DOMDocument(); + $doc->loadHTML($result); + $elements = new DOMXPath($doc); + + $result = []; + foreach ($elements->query($path) as $elem) { + $result[] = $elem->nodeValue; + } + $expected = ["'z'", "'a'", "'m'"]; + $this->assertSame($expected, $result); $this->Toolbar->setSort(true); $result = $this->Toolbar->dumpNodes($nodes); - $xml = new SimpleXmlElement($result); - $elements = $xml->xpath($path); - $this->assertSame(["'a'", "'m'", "'z'"], array_map('strval', $elements)); - } - - public function testDumpCoerceHtml() - { - $restore = Debugger::configInstance('exportFormatter'); - Debugger::configInstance('exportFormatter', TextFormatter::class); - $result = $this->Toolbar->dump(false); - $this->assertMatchesRegularExpression('/<\w/', $result, 'Contains HTML tags.'); - $this->assertSame( - TextFormatter::class, - Debugger::configInstance('exportFormatter'), - 'Should restore setting' - ); - - // Restore back to original value. - Debugger::configInstance('exportFormatter', $restore); - } + $doc = new DOMDocument(); + $doc->loadHTML($result); + $elements = new DOMXPath($doc); - public function testDumpSorted() - { - $path = '//*[@class="cake-debug-array-item"]/*[@class="cake-debug-string"]'; - $data = ['z' => 1, 'a' => 99, 'm' => 123]; - $result = $this->Toolbar->dump($data); - $xml = new SimpleXmlElement($result); - $elements = $xml->xpath($path); - $this->assertSame(["'z'", "'a'", "'m'"], array_map('strval', $elements)); - - $this->Toolbar->setSort(true); - $result = $this->Toolbar->dump($data); - $xml = new SimpleXmlElement($result); - $elements = $xml->xpath($path); - $this->assertSame(["'a'", "'m'", "'z'"], array_map('strval', $elements)); + $result = []; + foreach ($elements->query($path) as $elem) { + $result[] = $elem->nodeValue; + } + $expected = ["'a'", "'m'", "'z'"]; + $this->assertSame($expected, $result); } }