Skip to content

Prepare Objectiveweb Router v3.0.0 - #1

Merged
objectivebot merged 83 commits into
masterfrom
devel
Oct 1, 2026
Merged

objectivebot merged 83 commits into
masterfrom
devel

Conversation

@objectivebot

@objectivebot objectivebot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Prepare Objectiveweb Router 3.0.0 as an intentionally breaking release.

Router v3 modernizes the runtime and dependency stack, narrows and types the public API, replaces legacy controller hooks with middleware, hardens HTTP/error/template behavior, and adds the CI and release verification needed for a public release.

This release does not provide backwards compatibility with Router 2.x. See CHANGELOG.md for detailed 2.x → 3.x migration notes.

Breaking changes

  • Require PHP 8.1+.
  • Require Objectiveweb Dice ^4.1.0.
  • Router now composes Dice instead of extending Dice\\Dice.
    • Supported Router DI API: addRule() and create(string $name, array $args = []): object.
    • Dice's internal share argument and other inherited Dice methods are no longer part of the Router API.
  • Replace controller before() / beforePost() hooks with attribute-based middleware.
  • Middleware before() must return the complete controller argument array.
  • url() and redirect() are now Router instance methods.
  • Direct HTTP_HOST is no longer trusted by default for absolute URL generation; configure trusted.hosts explicitly or use '*' to retain unrestricted host behavior.
  • Controller template directories no longer implicitly include _functions.php.
  • Remove the legacy static Router::render() helper.
  • Default templates now resolve from <composer project root>/templates.
  • Controller object responses no longer enter array-only template rendering.
  • Controller HEAD actions such as head() / headFoo() are replaced by GET fallback semantics with response-body suppression.

Routing and public API

  • Add explicit PHP 8.1 parameter/return types across straightforward public APIs.
  • Keep callback parameters typed as mixed so invalid callbacks remain inside the controlled HTTP error boundary.
  • Make route(..., mixed ...$args) and controller(..., mixed ...$args) explicit.
  • Preserve regex capture ordering and controller constructor capture behavior.
  • Add PATCH().
  • Route GET/POST/PUT/PATCH/DELETE helpers through the same callback resolver and Throwable boundary.
  • Support Dice-instantiated [ClassName::class, 'method'] callbacks consistently.
  • Define Router explicitly as an immediate regex dispatcher, not a route-table dispatcher.
  • Preserve isAjax(): bool as a small public helper.

Middleware and CORS

  • Add repeatable attribute-based controller middleware.
  • Preserve repeated middleware instances at the winning scope.
  • Run before() hooks in declaration order and implemented after() hooks in reverse order.
  • Add DI-backed global request middleware through RequestMiddlewareInterface.
  • Add addRequestMiddleware() and request.middlewares configuration.
  • Add built-in CorsMiddleware.
  • Make setCors() register/replace the CORS request middleware.
  • Handle CORS preflight as a terminating HTTP 204 request-middleware flow.
  • Automatically disable credentials for wildcard Access-Control-Allow-Origin: *.

HTTP and response handling

  • Route normal responses, registered serializers, and exceptions through the common respond() pipeline.
  • Restore late-static respond() dispatch for Router subclasses.
  • Negotiate Accept media ranges with q-values, wildcards, and q=0 exclusions.
  • Return 406 when no supported representation is acceptable.
  • Emit explicit HTML/JSON content types and Vary: Accept only when multiple representations are available.
  • Encode string values as valid JSON scalars when JSON is requested.
  • Parse request bodies according to Content-Type.
  • Support application/json and structured application/*+json media types.
  • Return 400 for malformed JSON and 415 for unsupported/missing media types on class-typed JSON bodies.
  • Make HEAD use GET representation semantics while suppressing the body.
  • Suppress bodies and representation negotiation for 1xx, 204, 205, and 304 responses.

Error boundary and disclosure

  • Catch all PHP Throwable failures at the route boundary, including dependency-injection and callback-resolution failures.
  • Preserve valid HTTP status codes from 400 through 599; normalize invalid/missing codes to 500.
  • Negotiate default Throwable responses as HTML or JSON.
  • Redact unregistered 5xx exception details by default while logging the original Throwable.
  • Add per-Router debug => true to expose development error details.
  • Preserve detailed 4xx responses and explicitly registered exception serializers.
  • Escape exception content in HTML responses.

Templates and URL generation

  • Harden template rendering with typed paths/returns, EXTR_SKIP, protected layout contents, and exact output-buffer restoration after failures.
  • Add Template::url(), backed by the owning Router.
  • Add trusted.proxies support for exact IPv4/IPv6 addresses and CIDR ranges.
  • Accept forwarded proto/host/port metadata only from trusted peers.
  • Reject forwarded chains and malformed forwarded host values.
  • Add trusted.hosts validation for direct HTTP_HOST usage.
  • Cover relative/subdirectory URLs, url('0'), IPv6 hosts/ports, proxy behavior, and redirects.

Documentation and migration

  • Rewrite README examples for the v3 API.
  • Add controller and middleware documentation.
  • Remove legacy Dice includes and obsolete controller-hook examples.
  • Document HEAD fallback behavior, trusted hosts/proxies, request middleware, CORS, templates, serializers, response negotiation, and the immediate-regex routing model.
  • Add CHANGELOG.md with detailed 2.x → 3.x migration guidance.
  • Add MIT LICENSE.

Dependencies and CI

  • Remove Travis CI.
  • Add GitHub Actions CI for PHP 8.1, 8.2, 8.3, 8.4, and 8.5.
  • Add a PHP 8.1 lowest-compatible-dependencies job using composer update --prefer-lowest --prefer-stable.
  • Run composer validate --strict.
  • Run PHPUnit with --fail-on-deprecation --display-deprecations.
  • Support PHPUnit 10–12.
  • Update JMS Serializer development compatibility to ^3.32.
  • Use the published Objectiveweb Dice package rather than a temporary VCS override.
  • Add a release-verification workflow for pushes to master and manual dispatch, including:
    • PHP 8.1–8.5 tests;
    • strict Composer validation;
    • production composer install --no-dev verification.

Test coverage

The v3 suite now covers, among other areas:

  • raw route captures and explicit route arguments;
  • controller regex captures and constructor arguments;
  • immediate route ordering and no-match behavior;
  • GET/POST/PUT/PATCH/DELETE/OPTIONS/custom controller actions;
  • controller and request middleware ordering/DI;
  • CORS simple and preflight requests;
  • content negotiation and custom serializer output;
  • malformed/unsupported request bodies;
  • safe 4xx/5xx handling and debug disclosure;
  • real emitted HTTP status/headers/body using PHP's built-in server;
  • HEAD and bodyless HTTP statuses;
  • relative/absolute redirects;
  • template rendering and output-buffer cleanup;
  • trusted host/proxy URL generation;
  • public API signatures and removed internals.

Current verification

Current devel HEAD is green on:

  • PHP 8.1
  • PHP 8.2
  • PHP 8.3
  • PHP 8.4
  • PHP 8.5
  • PHP 8.1 with lowest compatible dependencies
  • composer validate --strict
  • deprecation-clean test execution

Deferred follow-up

Objectiveweb Auth compatibility with the Router v3 middleware contract will be handled separately after this release.

Remaining release checklist

  • Finalize the v3.0.0 changelog date.
  • Merge PR Prepare Objectiveweb Router v3.0.0 #1 to master and verify the automatically triggered Release verification workflow passes, including the production --no-dev install.
  • Tag v3.0.0 manually after the master release verification passes.
  • Verify a clean composer require objectiveweb/router:^3.0 install and confirm Packagist sees the v3 tag.

GuilhermeBarile and others added 30 commits September 9, 2025 21:49
While initializing Attributes with Dice, linting got broken since the Attribute misses the arguments that will be injected by DI.

This changes syntax to calling #[Middleware(class, ...args)] instead of referencing the Attribute directly.
 - Instantiate from Router
 - Set template.root and default middlewares in Router
@objectivebot
objectivebot merged commit 6f2d70e into master Oct 1, 2026
6 checks passed
@GuilhermeBarile
GuilhermeBarile deleted the devel branch October 1, 2026 00:00
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.

2 participants