feat(core): allow packages to declare global middleware in module.php#80
Conversation
Packages can now declare global HTTP middleware in module.php via the `globalMiddleware` key (flat class-strings or array with class+priority). GlobalMiddlewareResolver merges module entries with built-in defaults, sorts by priority (ascending), and deduplicates using source priority (app > modules > vendor). Built-in GLOBAL_MIDDLEWARE entries retain silent-skip behavior for backwards compatibility. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
PageCacheMiddleware (priority 10), SessionMiddleware (priority 20), and LayoutMiddleware (priority 30) are now declared via globalMiddleware in their respective module.php files instead of being hardcoded in GlobalMiddlewareResolver::DEFAULT_BUILT_INS. The DEFAULT_BUILT_INS constant and builtIns parameter are removed from GlobalMiddlewareResolver — the resolver now only works with module declarations. Package-level tests verify each middleware's priority. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…iscovery withPathAndSource() was silently dropping the globalMiddleware field, causing all module-declared global middleware to never be registered. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Replaces the priority-based scheme with module load order. Modules are
already topologically sorted by DependencyResolver (composer require +
sequence: { after, before }), so the resolver just walks them in order
and dedupes by class, with app > modules > vendor winning on position
when the same class is declared in multiple sources.
- Drops the priority field and array-form entries — globalMiddleware
is now a flat list of class-strings only.
- session declares sequence: { after: ['marko/page-cache'] } (soft).
- layout declares sequence: { after: ['marko/session'] } (soft).
- Tightens validation: non-string entries throw loudly instead of being
silently accepted.
Rationale: the project already had three ordering systems (plugin
sortOrder, observer priority, module sequence). Adding a fourth
convention with magic numbers (10/20/30) was unnecessary — module
sequence already expresses ordering declaratively and is self-
documenting ("session runs after page-cache" reads better than
"priority 20 vs 10").
Co-Authored-By: Michał Biarda <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
9ec897c to
adcea79
Compare
|
Thanks for the PR, @michalbiarda — solid premise and clean implementation. The hardcoded I pushed a refactor commit on top (force-with-lease, your three commits are preserved). The main change is dropping the Why: the project already has three ordering systems — plugins use Instead: middleware order is just module load order. Built-in ordering is now self-documenting: Other small changes:
Full suite green (5276 passing). Merging shortly — thanks again for the contribution! |
Summary
globalMiddlewarekey tomodule.php— accepts class strings or['class' => ..., 'priority' => N]entriesGlobalMiddlewareResolvernow collects, deduplicates (app > modules > vendor), and sorts by priority from module declarations onlyDEFAULT_BUILT_INSconstant andbuiltInsparameter — built-in middleware moved to their packagesPageCacheMiddleware(priority 10),SessionMiddleware(priority 20),LayoutMiddleware(priority 30) now self-register in theirmodule.phpPackageStructureTestfiles verify each middleware declaration and priorityTest plan
composer testpasses (excluding pre-existingDevDownCommandTestflake)packages/core/tests/Unit/Module/GlobalMiddlewareResolverTest.php— all 14 resolver requirements coveredpackages/session/tests/PackageStructureTest.php— SessionMiddleware at priority 20packages/page-cache/tests/PackageStructureTest.php— PageCacheMiddleware at priority 10packages/layout/tests/PackageStructureTest.php— LayoutMiddleware at priority 30Closes #79
🤖 Generated with Claude Code