Summary
Refactor debugbar so it becomes a true optional integration built on top of the Event/lifecycle system.
This should remove hardcoded debugger integration from core boot/runtime flow and move framework-owned integration onto lifecycle and package event boundaries, while handling recursion and logger coupling carefully.
Why
Debugbar is currently coupled to the framework at multiple levels.
Hardcoded core integration exists through:
InitDebuggerStage in the web boot pipeline
Framework-owned runtime integration also exists in places such as:
WebAppTrait pushing hook/debug metadata into the debugger store
In addition, there are direct debugger dependencies in framework packages such as:
View
- logger message reporting through
MessageAdapter
- mailer-related reporting
If the goal is to make debugbar truly optional and lifecycle-driven, then only moving boot initialization to hooks is not enough.
At the same time, this refactor must be careful about two real risks:
- debugger listeners will themselves participate in the event system they observe, which can create self-reference and recursion problems if not handled carefully
MessageAdapter is the default logger adapter in debug mode, so blindly converting logger/debugger integration into events can create circular reporting paths
Goal
Make debugbar a true optional event-driven integration by:
- removing hardcoded core debugger wiring
- moving framework-owned debugbar integration onto lifecycle and event subscriptions
- avoiding recursive or circular integration paths
Scope
This ticket should focus on framework integration boundaries and optional integration registration.
It should:
- remove hardcoded debugbar boot/runtime wiring from core
- use external optional-integration listener registration for debugbar
- move framework-owned debugbar integration onto lifecycle hooks
- invert direct debugger dependencies where that boundary is safe and justified
- explicitly avoid recursion-prone or circular event/reporting paths
It should not force a broad event rewrite where the dependency boundary is not yet safe.
Proposed Direction
Remove hardcoded core integration
Remove InitDebuggerStage from the web boot pipeline.
Core should only define and dispatch lifecycle/event boundaries. Core should not call debugbar() directly for framework integration.
Register debugbar listeners externally
Debugbar should subscribe through the external Event/lifecycle listener registration mechanism rather than through hardcoded core wiring.
Move framework-owned integration to listeners
Framework-owned debugbar integration should move to lifecycle-driven listeners, including areas such as:
- debugger store initialization
- framework lifecycle/debug metadata collection
- other runtime/route/response integration owned by framework flow
Invert package dependencies only where safe
Direct debugger dependencies should be reduced where event emission is the better architectural boundary, but this should be done selectively.
Candidate areas include:
- view/render-related debug data
- mailer-related debug data
Treat logger/debugger coupling as a special case
MessageAdapter is the debug-mode default logger adapter today.
That means logger/debugger integration must be handled carefully to avoid circular paths such as:
- package emits log event
- debugbar listener consumes it
- listener logs again
- event loop repeats
For that reason, logger/debugger integration should either:
- remain direct in this refactor, or
- be changed only with an explicitly recursion-safe design
Enforce non-recursive debugger listeners
Debugger listeners should not rely on event-producing logging/reporting APIs while handling debugger-related events.
They should write directly to debugger storage/rendering concerns instead of routing back through logger/event producers.
Example Direction
Core lifecycle dispatch
event()->dispatch(LoadModulesStage::BEFORE, [
'context' => $context,
]);
Debugbar subscribes externally
event()->listen(LoadModulesStage::BEFORE, function (array $payload): void {
$debugger = debugbar();
if ($debugger->isEnabled()) {
$debugger->initStore();
}
});
Mailer emits an event
event()->dispatch('mailer.warning', [
'message' => $message,
'transport' => 'smtp',
]);
Debugbar listens and writes directly to its store
event()->listen('mailer.warning', function (array $payload): void {
$debugger = debugbar();
if ($debugger->isEnabled()) {
$debugger->addToStoreCell(Debugger::MAILS, 'warning', $payload['message']);
}
});
Acceptance Criteria
InitDebuggerStage is removed from hardcoded core integration
- debugbar lifecycle listeners are registered externally rather than inside core boot/runtime flow
- framework-owned debugbar integration is moved onto lifecycle/event listeners
- recursion-prone debugger listener behavior is explicitly avoided
- logger/debugger integration is either left direct or changed only through a justified recursion-safe design
- debugbar remains optional and is not hardcoded as a core framework concern
- tests are updated as needed
Notes
Relevant code:
src/App/Stages/InitDebuggerStage.php
src/App/Traits/WebAppTrait.php
src/View/View.php
src/Logger/Adapters/MessageAdapter.php
src/Logger/Factories/LoggerFactory.php
src/Mailer/Traits/MailerTrait.php
src/Mailer/Adapters/SmtpAdapter.php
src/Debugger/Debugger.php
src/Debugger/Helpers/debugger.php
Depends on:
Summary
Refactor debugbar so it becomes a true optional integration built on top of the Event/lifecycle system.
This should remove hardcoded debugger integration from core boot/runtime flow and move framework-owned integration onto lifecycle and package event boundaries, while handling recursion and logger coupling carefully.
Why
Debugbar is currently coupled to the framework at multiple levels.
Hardcoded core integration exists through:
InitDebuggerStagein the web boot pipelineFramework-owned runtime integration also exists in places such as:
WebAppTraitpushing hook/debug metadata into the debugger storeIn addition, there are direct debugger dependencies in framework packages such as:
ViewMessageAdapterIf the goal is to make debugbar truly optional and lifecycle-driven, then only moving boot initialization to hooks is not enough.
At the same time, this refactor must be careful about two real risks:
MessageAdapteris the default logger adapter in debug mode, so blindly converting logger/debugger integration into events can create circular reporting pathsGoal
Make debugbar a true optional event-driven integration by:
Scope
This ticket should focus on framework integration boundaries and optional integration registration.
It should:
It should not force a broad event rewrite where the dependency boundary is not yet safe.
Proposed Direction
Remove hardcoded core integration
Remove
InitDebuggerStagefrom the web boot pipeline.Core should only define and dispatch lifecycle/event boundaries. Core should not call
debugbar()directly for framework integration.Register debugbar listeners externally
Debugbar should subscribe through the external Event/lifecycle listener registration mechanism rather than through hardcoded core wiring.
Move framework-owned integration to listeners
Framework-owned debugbar integration should move to lifecycle-driven listeners, including areas such as:
Invert package dependencies only where safe
Direct debugger dependencies should be reduced where event emission is the better architectural boundary, but this should be done selectively.
Candidate areas include:
Treat logger/debugger coupling as a special case
MessageAdapteris the debug-mode default logger adapter today.That means logger/debugger integration must be handled carefully to avoid circular paths such as:
For that reason, logger/debugger integration should either:
Enforce non-recursive debugger listeners
Debugger listeners should not rely on event-producing logging/reporting APIs while handling debugger-related events.
They should write directly to debugger storage/rendering concerns instead of routing back through logger/event producers.
Example Direction
Core lifecycle dispatch
Debugbar subscribes externally
Mailer emits an event
Debugbar listens and writes directly to its store
Acceptance Criteria
InitDebuggerStageis removed from hardcoded core integrationNotes
Relevant code:
src/App/Stages/InitDebuggerStage.phpsrc/App/Traits/WebAppTrait.phpsrc/View/View.phpsrc/Logger/Adapters/MessageAdapter.phpsrc/Logger/Factories/LoggerFactory.phpsrc/Mailer/Traits/MailerTrait.phpsrc/Mailer/Adapters/SmtpAdapter.phpsrc/Debugger/Debugger.phpsrc/Debugger/Helpers/debugger.phpDepends on:
#536#537#538