Debugger and toolbar for Yii2 applications
Pico-inspired UI, scoped CSS, light/dark mode, and 14 inspection panels
composer require yii2-extensions/debug:^0.2 --devThe package installs php-forge/debug-core transitively. The core owns the portable snapshot and persistence model,
shared views, and frontend files; this package owns the Yii2 lifecycle, collectors, standalone actions, view rendering,
toolbar injection, and asset bundle definitions.
Enable the debug module in your application configuration (config/web.php).
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => \yii\debug\Module::class,
'allowedIPs' => ['127.0.0.1', '::1'],
];
}The toolbar appears at the bottom of every rendered page; click any panel chip to open the full debugger. The complete
frontend, including the panel stylesheet, JavaScript, fonts, icons, and toolbar Web Component, is provided by
php-forge/debug-core. This package publishes those shared assets and supplies the Yii2-specific panels and data.
Shared PHP templates are resolved through the adapter-owned @yiiDebugViews alias.
Request presents the resolved route before the response status in one toolbar group. Its detail view keeps the request identity, route, action, duration, and routing constraints visible above the canonical Input, Headers, Session, Routes, and Server tabs. The Routes tab reads the current URL manager configuration and labels that live provenance explicitly, because it can differ from the historical capture; the resolution trace itself remains capture-time data.
Server shows additional diagnostics without a second execution summary. Exact duplicates of the Request overview and inbound headers move to the collapsed Raw server variables disclosure, which preserves every captured key and value. Differences and unknown values remain visible; each group has an independent filter.
Input and Session sections use the shared disclosure: populated sections open by default, empty sections stay collapsed, and each populated section has its own filter. Session data and Flashes can be searched independently.
Routes use the same expandable ledger as the Yii3 adapter, with full-width metadata details and a filter that searches
collapsed content. Rules owned by loaded debugger modules are omitted from this inventory, including renamed and
nested modules. Their trace entries are also omitted from Request; a debugger-only resolution block is hidden. The
original captured trace remains intact for the legacy Router view. Application routes are not hidden merely because
their URL contains debug.
The built-in Router collector and panel remain registered as Request's compatibility data source, but their duplicate toolbar and sidebar entries are hidden. Applications that still need the legacy standalone Router screen can opt in explicitly while migrating custom integrations:
$config['modules']['debug']['panels']['router'] = \yii\debug\panels\RouterPanel::class;The drawer moves focus to its close control and restores the activating chip when closed. Use Escape to close it,
or resize it from the keyboard with ArrowUp, ArrowDown, Home, and End on the separator.
The History page can compare any two retained captures. The comparison shows request metric deltas and per-panel counts of added, removed, changed, and unchanged JSON paths. It never renders panel values in the overview; use the baseline and target deep links to inspect each panel through its normal redaction and presentation rules.
Register collectors explicitly through the debug module. A collector returns a typed
PHPForge\Debug\Storage\PanelSnapshot; a panel with the same stable ID hydrates and presents that payload. Existing
custom panels continue to capture normally when no matching collector is registered.
$config['modules']['debug'] = [
'class' => \yii\debug\Module::class,
'collectors' => [
\App\Debug\OrderCollector::class,
],
'panels' => [
'app.orders' => \App\Debug\OrderPanel::class,
],
];OrderCollector::id() must return app.orders. Collector instances and Yii configuration arrays with a class key
are accepted as alternatives to class names. Stored collector data without a matching panel remains available through
an escaped JSON fallback.
Every persistent capture uses the shared Debug Core policy. Its defaults redact common credentials plus
environment-style keys such as DB_PASSWORD, AWS_SECRET_ACCESS_KEY, and DATABASE_URL, while segment-aware
matching keeps unrelated keys such as DATABASE_HOST, tokenizer, and passwordless_mode visible.
Configure additional rules once on the module; they apply to request bodies and superglobals, identity attributes, queue job payloads, Inertia page props and page/location URLs, and manifest URLs:
use PHPForge\Debug\Helper\SensitiveDataRedactor;
$config['modules']['debug'] = [
'class' => \yii\debug\Module::class,
'maxBodyBytes' => 65_536,
'sensitiveKeys' => [
...SensitiveDataRedactor::DEFAULT_KEYS,
'tenant_signing_key',
],
'sensitiveKeyPrefixes' => ['internal_secret_'],
'sensitiveKeyPatterns' => [
'~(?:^|_)private_credential(?:$|_)~i',
],
];sensitiveKeys replaces the exact-key list, so include SensitiveDataRedactor::DEFAULT_KEYS when extending it.
Patterns are PCRE expressions applied to the complete original key. Leave sensitiveKeyPatterns as null to use
the segment-aware defaults with the default exact-key list, or set it to [] to disable pattern matching explicitly.
An invalid pattern or an empty prefix rejects module initialization rather than silently weakening redaction.
Debugger endpoints emit no-store, no-referrer, nosniff, noindex, and same-origin framing policies. The adapter
preserves existing host CSP directives and replaces or adds only frame-ancestors 'self' on debugger responses. Keep
the module restricted to trusted development IPs or an explicit access callback; these headers are defense in depth,
not an authentication boundary.
When upgrading from 0.1, review the 0.2 upgrade guide before deploying the package.
The debugger targets evergreen browsers with ES2022, Web Components, CSS custom properties, and native module support. Internet Explorer and other legacy browsers are not supported.
Configuration
PHP info
History
Request
Router (legacy standalone)
The same captured routing trace is shown in Request by default. This screen remains available when Router is configured explicitly for compatibility.
Inertia
Logs
Database
Profiling
Profiling combines the request-relative Timeline and sortable span details under one shared set of filters.
Timeline labels show only the short class name, such as HomeAction; hover a label to inspect its full FQCN and
method, which also remain visible in Details.
Events
Queue
Queue job
Dump
Asset bundles
User
User Roles and Permissions
User Switch User
For detailed configuration options and advanced usage.
HistoryComparison::fromSnapshots() delegates panel selection, ordering, failure precedence, capture states, and
combined structural/state counts to Debug Core's PHPForge\Debug\Comparison\PanelComparison, which reuses
PayloadDifference. Request-summary metrics remain delegated to SummaryMetricComparison. The adapter only maps
these results into its existing public models, including HistoryPanelComparison. No constructor, property, getter,
return type,
captured value, or storage format changes. Metric labels, order, units, precision, separators, signs, percentages, trends,
and panel IDs retain their exact previous behavior, including missing values, zero baselines, and unrounded float deltas.
Publish the Core revision providing SummaryMetricComparison and PanelComparison first and update consuming application
locks before installing this adapter revision. The existing ^0.1@dev constraint also admits older development revisions without the
new classes; local workspace links do not guarantee that a published installation has been updated.
Missing panels remain distinct from captured empty arrays; failure envelopes take precedence over payloads, and state-only transitions still count as one change without discarding unchanged leaves. Transitions with structural additions, removals, or changes do not increment the changed count again. Observed configured IDs retain label order; extras retain regular ascending sorting and ID labels. Unknown configured IDs do not create rows. Comparison does not apply capture-policy redaction to Logs.