Skip to content

Issue/538 Group the stages by adapter and give the runtime stages lifecycle events - #591

Merged
armanist merged 5 commits into
quantum-php:masterfrom
armanist:issue/538-runtime-stage-events
Oct 21, 2026
Merged

armanist merged 5 commits into
quantum-php:masterfrom
armanist:issue/538-runtime-stage-events

Conversation

@armanist

@armanist armanist commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #538

What changed

  • Stage layout: the stages are grouped by the adapter that runs them. Only namespaces and imports change.

    src/App/Stages/Boot/                      LoadHelpers, LoadEnvironment, LoadAppConfig, SetupErrorHandler   (shared)
    src/App/Adapters/Web/Stages/Boot/         InitHttp, InitDebugger, LoadModules
    src/App/Adapters/Web/Stages/Runtime/      HandlePreflight, ResolveRoute, HandleRouteNotFound, PrepareRequest, DispatchRequest, SendResponse
    src/App/Adapters/Console/Stages/Boot/     InitConsole, RegisterCoreCommands, ResolveEnvironment, SetupConsoleApplication, RegisterAppCommands
    src/App/Adapters/Console/Stages/Runtime/  RunCommand
    

    src/App/Stages/Web and src/App/Stages/Console are gone, and the tests mirror the new paths.

  • Runtime events: the six web runtime stages declare web.preflight, web.route, web.not_found, web.prepare, web.dispatch and web.send, and RunCommandStage declares console.command, each with .before and .after. The pipeline dispatches them with ['context' => $context].

  • No boot events: LoadEnvironmentStage, LoadAppConfigStage, SetupErrorHandlerStage, InitHttpStage and LoadModulesStage no longer declare boot.* events, and a test fails if any boot stage declares BEFORE or AFTER.

  • Pipeline: dispatchStageEvent() no longer checks whether the event() helper is loaded; only runtime stages declare events, and they run after the helpers.

  • Changelog: the 3.1.0 "Added" line describes the runtime events instead of the boot events, and the lifecycle entry describes the stage layout.

Why

App code hooks into the running app, not into the framework's own setup: the boot events let a listener from a helper file run in the middle of the boot, before the config or the modules exist, and on a broken .env the console boot stops before most of them. The runtime stages declared no events at all, so there was nothing to listen to while a request or a command runs.

With #589 a stage event means one thing: a stage that runs fires its events, a stage that does not run fires none. So a listener never has to check isStopped():

Request Events
matched route every web.* pair, in stage order
OPTIONS web.preflight.*, web.send.*
no route web.preflight.*, web.route.*, web.not_found.*, web.send.*
a stage throws up to that stage's .before; no .after, no web.send.*

web.send.after fires after the request state is cleared. console.command.after fires only with an application that does not exit after the command; Symfony's default Application::run() exits.

Grouping the stages first means every event constant lands on its stage in its final place.

Breaking changes

None compared with 3.0.3: the boot events and the 3.1.0 stage namespaces were never released. Code that goes through AppFactory is unaffected.

Testing

  • New tests:
    • PipelineTest: the event names of the seven runtime stages, and a guard that scans the three boot stage folders for BEFORE/AFTER (it failed while the boot stages still declared them).
    • WebAppAdapterTest: the exact event order for a matched route, an OPTIONS request, a request without a route and a stage that throws; the listeners get the WebContext; the request is cleared in web.send.after.
    • ConsoleAppAdapterTest: console.command.before and .after around a command with the ConsoleContext, and only .before for an unknown command.
  • The app helper listener tests listen to web.preflight.before instead of boot.modules.before; the boot event name test and the test for skipping events while the event() helper is not loaded are removed.
  • The two move commits keep the full suite identical: the same tests and results, only the moved tests under their new class names.
  • Checked on the starter project with this branch and with master: the web requests (/, /api/posts, OPTIONS, 404 as HTML and JSON) and the console cases (valid, missing and malformed .env) give identical results. A temporary app helper listener receives boot.modules.after on master and web.preflight.before / web.send.after per request (also OPTIONS) and console.command.before for php qt list on this branch.

Summary by CodeRabbit

  • New Features

    • Added JSON expectation detection.
    • Added web and console runtime lifecycle events for monitoring and integrations.
    • Added adapter-based DeepL and Google Translate support.
    • Added an explicit application boot step for direct adapter startup.
    • Added persistent event listeners and helper-file event registration.
  • Breaking Changes

    • Replaced hook APIs with event-based APIs.
    • Updated application context and pipeline interfaces.
    • Removed the legacy loader and boot-specific event behavior.

The web boot stages that only the web adapter runs move to
Adapters/Web/Stages/Boot and the web runtime stages to
Adapters/Web/Stages/Runtime, with their tests. Only namespaces and
imports change.
The console boot stages move to Adapters/Console/Stages/Boot and
RunCommandStage to Adapters/Console/Stages/Runtime, with their tests.
src/App/Stages/Boot keeps only the stages both adapters run. Only
namespaces and imports change.
…vents

The six web runtime stages declare web.<stage>.before / .after and
RunCommandStage declares console.command.before / .after; the pipeline
dispatches them with the runtime context.
The boot belongs to the framework: no boot stage declares BEFORE/AFTER,
and a test guards it for every boot folder. App helper listeners hook
into the runtime events instead. The pipeline no longer checks whether
the event() helper is loaded, since runtime stages run after the helpers.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-21T11:05:37.562062Z
We couldn’t complete this review. Comment @codex review to try again.
5b652d1 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 324ea212-93cc-4959-96f1-8fc909ae4a9f
📥 Commits

Reviewing files that changed from the base of the PR and between 926909c and 5b652d1.

📒 Files selected for processing: 38
  • CHANGELOG.md
  • src/App/Adapters/Console/ConsoleAppAdapter.php
  • src/App/Adapters/Console/Stages/Boot/InitConsoleStage.php
  • src/App/Adapters/Console/Stages/Boot/RegisterAppCommandsStage.php
  • src/App/Adapters/Console/Stages/Boot/RegisterCoreCommandsStage.php
  • src/App/Adapters/Console/Stages/Boot/ResolveEnvironmentStage.php
  • src/App/Adapters/Console/Stages/Boot/SetupConsoleApplicationStage.php
  • src/App/Adapters/Console/Stages/Runtime/RunCommandStage.php
  • src/App/Adapters/Web/Stages/Boot/InitDebuggerStage.php
  • src/App/Adapters/Web/Stages/Boot/InitHttpStage.php
  • src/App/Adapters/Web/Stages/Boot/LoadModulesStage.php
  • src/App/Adapters/Web/Stages/Runtime/DispatchRequestStage.php
  • src/App/Adapters/Web/Stages/Runtime/HandlePreflightStage.php
  • src/App/Adapters/Web/Stages/Runtime/HandleRouteNotFoundStage.php
  • src/App/Adapters/Web/Stages/Runtime/PrepareRequestStage.php
  • src/App/Adapters/Web/Stages/Runtime/ResolveRouteStage.php
  • src/App/Adapters/Web/Stages/Runtime/SendResponseStage.php
  • src/App/Adapters/Web/WebAppAdapter.php
  • src/App/Pipeline.php
  • src/App/Stages/Boot/LoadAppConfigStage.php
  • src/App/Stages/Boot/LoadEnvironmentStage.php
  • src/App/Stages/Boot/SetupErrorHandlerStage.php
  • tests/Unit/App/Adapters/Console/ConsoleAppAdapterTest.php
  • tests/Unit/App/Adapters/Console/Stages/Boot/InitConsoleStageTest.php
  • tests/Unit/App/Adapters/Console/Stages/Boot/RegisterAppCommandsStageTest.php
  • tests/Unit/App/Adapters/Console/Stages/Boot/RegisterCoreCommandsStageTest.php
  • tests/Unit/App/Adapters/Console/Stages/Boot/ResolveEnvironmentStageTest.php
  • tests/Unit/App/Adapters/Console/Stages/Boot/SetupConsoleApplicationStageTest.php
  • tests/Unit/App/Adapters/Console/Stages/ConsoleStageTestCase.php
  • tests/Unit/App/Adapters/Console/Stages/Runtime/RunCommandStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/DispatchRequestStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/HandlePreflightStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/HandleRouteNotFoundStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/PrepareRequestStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/ResolveRouteStageTest.php
  • tests/Unit/App/Adapters/Web/Stages/Runtime/SendResponseStageTest.php
  • tests/Unit/App/Adapters/Web/WebAppAdapterTest.php
  • tests/Unit/App/PipelineTest.php
💤 Files with no reviewable changes: 3
  • src/App/Stages/Boot/LoadAppConfigStage.php
  • src/App/Stages/Boot/SetupErrorHandlerStage.php
  • src/App/Stages/Boot/LoadEnvironmentStage.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The pull request moves web and console stages into adapter-specific namespaces. Runtime stages declare lifecycle events, while boot stages no longer declare events. The pipeline dispatches declared stage events without checking whether the event helper is loaded.

Changes: Runtime lifecycle events and adapter stage layout

Layer / File(s) Summary
Adapter stage layout and event declarations
src/App/Adapters/Console/Stages/..., src/App/Adapters/Web/Stages/..., src/App/Stages/Boot/*
Web and console stages move into adapter-specific namespaces. Web and console runtime stages declare BEFORE and AFTER event names. The listed boot stages no longer declare these constants.
Pipeline and adapter wiring
src/App/Pipeline.php, src/App/Adapters/Console/ConsoleAppAdapter.php, src/App/Adapters/Web/WebAppAdapter.php
The adapters import stages from their adapter-specific namespaces. The pipeline dispatches an event when a stage declares its event constant, without checking whether the event helper exists.
Runtime event tests and changelog
tests/Unit/App/Adapters/..., tests/Unit/App/PipelineTest.php, CHANGELOG.md
Tests cover runtime event names, ordering, context payloads, and selected request and exception paths. The changelog describes runtime events and app-helper registration timing.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant WebAppAdapter
  participant Pipeline
  participant DispatchRequestStage
  participant EventHelper as event()
  participant AppListener
  WebAppAdapter->>Pipeline: run stage with WebContext
  Pipeline->>EventHelper: dispatch before event with context
  EventHelper-->>AppListener: deliver before event
  Pipeline->>DispatchRequestStage: process WebContext
  DispatchRequestStage-->>Pipeline: return after processing
  Pipeline->>EventHelper: dispatch after event with context
  EventHelper-->>AppListener: deliver after event
Loading

Possibly related issues

  • quantum-php/framework#589 — The pull request changes pipeline stage-event dispatch and adds tests for runtime event behavior around successful execution and exceptions.
Merge Risk: ⚪ Minimal · up to 5b652

No confirmed issue blocks merging, subject to the normal checks.

Pre-merge checks: Passed 3 · Failed 1 · Inconclusive 1

Failed Failed checks: 1 warning · 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 11.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 34 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check Inconclusive The supplied PR evidence supports the coding changes for #538. The current paths group the adapter stages and tests. The old Web and Console stage paths are absent. Runtime stages declare the specifie… Provide reviewable results for composer test, composer cs:check, composer phpstan, and composer rector:check, or equivalent CI evidence. Provide a readable merge-base diff if verification of the complete change set is required.
Passed Passed checks: 3 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the primary changes: grouping stages by adapter and adding lifecycle events to runtime stages.
Out of Scope Changes check Passed The supplied change summary ties the source, test, pipeline, and changelog changes to #538. The moved stages and tests support the grouping objective. The runtime event tests support the lifecycle obj…
Full details: Out of Scope Changes check

Explanation

The supplied change summary ties the source, test, pipeline, and changelog changes to #538. The moved stages and tests support the grouping objective. The runtime event tests support the lifecycle objective. No change demonstrates Debugbar integration, deferred response tasks, or a native non-exiting Quantum console.

Full details: Docstring Coverage

Explanation

Docstring coverage is 11.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 34 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Full details: Linked Issues check

Explanation

The supplied PR evidence supports the coding changes for #538. The current paths group the adapter stages and tests. The old Web and Console stage paths are absent. Runtime stages declare the specified events. The pipeline sends the context payload. Boot stages no longer declare events. The changelog documents the event names and lifecycle rules. The tests cover ordering, stop and failure behavior, payloads, request clearing, and console behavior. The evidence does not show results for composer cs:check, composer phpstan, or composer rector:check. The merge-base diff is unavailable, so these requirements cannot be verified.

Resolution

Provide reviewable results for composer test, composer cs:check, composer phpstan, and composer rector:check, or equivalent CI evidence. Provide a readable merge-base diff if verification of the complete change set is required.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@armanist
armanist merged commit 34385ef into quantum-php:master Oct 21, 2026
5 of 6 checks passed
@armanist
armanist deleted the issue/538-runtime-stage-events branch October 21, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Group the stages by adapter and give the runtime stages lifecycle events

3 participants