Conversation
📝 WalkthroughWalkthroughAdds URL rewrite processing before route matching, strict duplicate-route detection with named-route tracking, router state APIs ( Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Router
participant RouteStore
participant Dispatcher
Client->>Router: HTTP request (URL)
Router->>Router: rewriteUrl(original URL)
Router->>RouteStore: find matching route for rewritten URL
alt route found
Router->>Dispatcher: dispatch(controller/action)
Dispatcher->>Client: response
else route not found
Router->>Client: 404 response
end
sequenceDiagram
participant Dev
participant Router
participant RouteStore
participant Exception
Dev->>Router: addRoute(method, path, handler, name?)
Router->>RouteStore: checkDuplicateRoute(method+path)
Router->>RouteStore: checkDuplicateName(name)
alt conflict detected and strict mode
Router->>Exception: throw DuplicateRouteException(details)
else no conflict or strict mode disabled
Router->>RouteStore: register route and name
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In @README.md:
- Around line 360-365: The README code block showing the duplicate route error
(the block starting with "Duplicate route name detected: 'users'") is missing a
language identifier; update the triple-backtick fence to include a language
specifier (e.g., change ``` to ```text) so the block becomes ```text and ensure
all similar error-code fences in the README follow the same convention for
consistency and linting compliance.
- Around line 266-273: The fenced code block showing the numbered workflow steps
is missing a language identifier; update the opening fence from ``` to ```text
(or ```plaintext) so the block becomes ```text and thus satisfies the linter and
renders correctly (the block containing "1. Client requests:
http://example.com/" through "6. Browser still shows: http://example.com/").
- Around line 341-346: The README code block showing the duplicate route error
should include a language identifier for consistency; change the opening fence
from ``` to ```text so the block reads ```text followed by the message
"Duplicate route detected: GET /users ..." (which references
App\Controllers\UserController@index and App\Controllers\UserController@list)
and keep the closing ```; also scan for any other similar plaintext error blocks
and add the same `text` specifier.
In @src/Routing/Exceptions/DuplicateRouteException.php:
- Around line 57-72: DuplicateRouteException::buildMessage() incorrectly prints
the second route's method/path for both entries; add properties $firstMethod and
$firstPath to the DuplicateRouteException class, assign them when the exception
is constructed (where $firstDefinition is set) from the original route, and then
update buildMessage() to use $this->firstMethod and $this->firstPath for the
"First:" line while keeping $this->routeMethod and $this->routePath for the
"Second:" line so the error shows each route's actual method and path.
In @src/Routing/Router.php:
- Around line 270-281: When detecting a duplicate route name in Router::add (the
block using $name, $this->_registeredNames and throwing
Exceptions\DuplicateRouteException), instead of passing the new route's $method
and $path, extract the original route signature from
$this->_registeredRoutes[$this->_registeredNames[$name]] and parse out its
method and path, then pass those original method/path values into the
DuplicateRouteException so the message reflects the first-registered route; also
update the DuplicateRouteException constructor (and any call sites) to accept
and store the originalMethod and originalPath parameters along with the existing
data and use them in its error message formatting.
🧹 Nitpick comments (1)
src/Routing/Router.php (1)
298-308: Consider enhancing controller info extraction for closures.The current implementation returns "unknown controller" for closures and other callable types. For better debugging, consider extracting additional information:
Optional enhancement
protected function extractControllerInfo( RouteMap $route ): string { $payload = $route->Payload; if( is_array( $payload ) && isset( $payload['Controller'] ) ) { return $payload['Controller']; } + if( $payload instanceof \Closure ) + { + $reflection = new \ReflectionFunction( $payload ); + return sprintf( 'Closure at %s:%d', $reflection->getFileName(), $reflection->getStartLine() ); + } + + if( is_callable( $payload ) ) + { + return 'callable'; + } + return 'unknown controller'; }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
README.mdsrc/Routing/Exceptions/DuplicateRouteException.phpsrc/Routing/Router.phptests/unit/RouteTest.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/RouteTest.php (1)
src/Routing/Router.php (2)
Router(45-779)clearRoutes(103-113)
🪛 markdownlint-cli2 (0.18.1)
README.md
179-179: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
254-254: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
266-266: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
266-266: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
280-280: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
292-292: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
331-331: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
341-341: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
341-341: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
350-350: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
360-360: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
360-360: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
371-371: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
384-384: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
399-399: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (9)
tests/unit/RouteTest.php (1)
16-21: LGTM! Good test isolation practice.The tearDown method properly clears routes between tests, which is essential now that strict duplicate route detection is enabled by default. This prevents test pollution and ensures each test starts with a clean router state.
README.md (1)
360-365: Documentation shows error format that differs from implementation.The documented error message shows different HTTP methods and paths for the first and second routes (
GET /usersvsPOST /users/create), but the currentDuplicateRouteExceptionimplementation displays the same method and path for both entries. See my comment onDuplicateRouteException.phpfor details on the bug.src/Routing/Exceptions/DuplicateRouteException.php (2)
74-84: LGTM for method+path duplicate messages.This branch correctly handles duplicates where the method and path are identical—displaying the same values for both is accurate in this case.
91-134: LGTM! Clean accessor methods.The getter methods are well-documented and follow standard patterns.
src/Routing/Router.php (5)
56-66: LGTM! Well-documented tracking properties.The new properties for duplicate detection and URL rewrites are clearly documented with their purpose and structure.
89-113: LGTM! Clean implementation of strict mode and route clearing.Both methods work correctly. Note that
clearRoutes()intentionally preserves_filterRegistrysince filters are registered separately from routes—this is appropriate behavior.
150-174: LGTM! Robust URL rewrite handling.The implementation correctly handles edge cases:
- Root "/" is preserved (not stripped to empty string)
- Both
/pathand/path/variants are checked- Debug logging aids troubleshooting
317-356: LGTM! Consistent HTTP method propagation.All route registration methods correctly pass their respective HTTP method strings to
addRoute(), enabling proper duplicate detection per method+path combination.
650-651: LGTM! Correct integration point for URL rewrites.Rewrites are applied after input validation and before route matching, which aligns with the documented workflow. The original URL from
$argv['route']is still used in the 404 warning log, which is appropriate for debugging.
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @src/Routing/RouteMap.php:
- Around line 218-228: The setName method can throw DuplicateRouteException if
called twice with the same name because it re-registers unconditionally; update
setName (method setName) to first check if $this->Name is already set and equals
$name and in that case simply return $this without calling
$this->_router->registerRouteName; otherwise proceed to register the new name
(and optionally, if you support renaming, call a router method to unregister the
old name before registering the new one), ensuring you still reference
$this->_router, $this->_method, $this->Path and $this->Name appropriately.
In @src/Routing/Router.php:
- Around line 225-253: The route name is registered via RouteMap::setName before
checkDuplicateRoute runs, so if checkDuplicateRoute throws the name remains in
the router's _registeredNames; to fix, perform the path+method duplicate check
(this->checkDuplicateRoute($route, $method)) before calling
$route->setName($name) when _strictMode is enabled, or alternately wrap setName
in a try/catch and unregister the name on exception; update addRoute accordingly
(function addRoute, RouteMap::setName, checkDuplicateRoute, _strictMode, and any
_registeredNames cleanup) so a thrown duplicate-path error never leaves a stale
registered name.
🧹 Nitpick comments (1)
src/Routing/Router.php (1)
332-348: Consider enhancing controller extraction for better error messages.Since
Payloadis typically set after route creation,extractControllerInfo()will likely return "unknown controller" for the conflicting route. For more informative error messages, consider extracting the callable information directly from$route->Function.♻️ Optional enhancement
protected function extractControllerInfo( RouteMap $route ): string { $payload = $route->Payload; if( is_array( $payload ) && isset( $payload['Controller'] ) ) { return $payload['Controller']; } + // Try to get info from the callable + $function = $route->Function; + if( is_array( $function ) && count( $function ) === 2 ) + { + $class = is_object( $function[0] ) ? get_class( $function[0] ) : $function[0]; + return $class . '@' . $function[1]; + } + return 'unknown controller'; }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/Routing/RouteMap.phpsrc/Routing/Router.phptests/unit/RouterTest.php
🧰 Additional context used
🧬 Code graph analysis (2)
src/Routing/RouteMap.php (1)
src/Routing/Router.php (2)
Router(45-823)registerRouteName(269-298)
src/Routing/Router.php (3)
src/Routing/RouteMap.php (2)
RouteMap(40-333)getPath(104-107)src/Routing/Exceptions/DuplicateRouteException.php (1)
DuplicateRouteException(15-163)src/Routing/Request.php (1)
getPath(50-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (16)
src/Routing/RouteMap.php (2)
49-53: LGTM! Router context properties for duplicate detection.The nullable private properties appropriately store the router reference and HTTP method needed for registering route names during duplicate detection.
88-99: LGTM! Clean fluent API for setting router context.The method correctly stores the router reference and method, enabling RouteMap to register names with the router for duplicate detection. Since this is called internally by
Router::addRoute()with controlled method strings, additional validation is unnecessary.tests/unit/RouterTest.php (5)
647-656: LGTM! Good test coverage for duplicate path detection.The test correctly validates that registering two routes with identical method and path throws
DuplicateRouteException.
658-670: LGTM! Validates fluent API name conflict detection.Test correctly verifies that duplicate route names via the fluent
setName()API throw an exception with the route name in the message.
672-682: LGTM! Tests name parameter API for duplicates.Correctly validates that passing duplicate names via the route method's
$nameparameter also triggers the exception.
684-696: LGTM! Important edge case for cross-method name conflicts.Correctly validates that route names must be unique across all HTTP methods, not just within the same method.
698-714: LGTM! Good coverage for strict mode disabled behavior.The test correctly validates that when strict mode is disabled, duplicate routes and names are silently allowed without throwing exceptions.
src/Routing/Router.php (9)
56-66: LGTM! Well-structured tracking properties.Good design choices: strict mode defaults to
truefor safety, and the data structures clearly separate route path tracking from name tracking.
79-92: LGTM! Clean strict mode setter.The method and its documentation clearly explain the behavior difference between strict and non-strict modes.
94-113: LGTM! Comprehensive state reset for testing.The method correctly resets all route-related state. The
_filterRegistry(registered Filter instances) is intentionally preserved, as filters are typically registered once at application bootstrap, separate from route configuration.
115-138: LGTM! Well-documented URL rewrite configuration.The method and docblock clearly explain the use case and provide helpful examples.
140-174: LGTM! Clean URL rewrite implementation.The method correctly handles trailing slash normalization and falls back gracefully when no rewrite rule matches. The "exact matches only" limitation is clearly documented.
255-298: LGTM! Robust name registration with detailed error reporting.The method correctly handles both strict and non-strict modes, and provides useful debugging information in the exception when a duplicate name is detected.
300-330: LGTM! Clean duplicate route detection.The method correctly checks for existing method+path combinations and registers the new route only after validation passes.
350-400: LGTM! Clean API extension for route naming.The HTTP method helpers consistently accept an optional
$nameparameter while maintaining backward compatibility. The explicit method strings ('GET', 'POST', etc.) correctly match the expected format for signature creation.
694-696: LGTM! Clean integration of URL rewrites.The rewrite is correctly applied after extracting the URI and before route matching, making it transparent to downstream routing logic.
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In @src/Routing/RouteMap.php:
- Around line 212-241: setName() currently unregisters the old route name before
calling registerRouteName(), which can leave the router missing the old name if
registerRouteName() throws; change the logic to attempt registering the new name
first (call _router->registerRouteName($name, $this->_method, $this->Path,
$this)) and only if that succeeds unregister the old name (or, alternatively,
wrap the registration in a try/catch and on failure re-register the old name),
then update $this->Name and return; ensure this applies only when _router and
_method are set and keep the early-return when $this->Name === $name.
In @src/Routing/Router.php:
- Around line 94-113: clearRoutes() currently claims to clear filters but does
not reset $_filterRegistry; update the method to also clear the filter registry
by resetting $this->_filterRegistry = [] (or, if intended, modify the docblock
to state it only clears the active filter list $_filter and routing state).
Locate the clearRoutes method and either add the reset for $_filterRegistry
alongside $_filter, or change the docblock text to remove/clarify the statement
about clearing filters so it matches the actual fields cleared.
- Around line 79-92: setStrictMode currently just flips _strictMode, but
existing routes added while strict was false can create undetected duplicates;
update setStrictMode so that when $strict is true it rebuilds or re-checks
duplicate tracking for existing routes (iterate $this->_routes and re-populate /
re-validate whatever index you use, e.g. _routeIndex) and call
checkDuplicateRoute or throw DuplicateRouteException for any duplicates found;
reference setStrictMode, addRoute, checkDuplicateRoute, _strictMode, _routes,
_routeIndex and DuplicateRouteException when implementing this fix.
- Around line 140-174: The debug call in rewriteUrl() logs the raw incoming $url
which can include query strings or sensitive tokens; update rewriteUrl to log
only the path portion (strip the query string and fragment using parse_url or by
truncating at '?'/#) or log the normalized path from $normalizedUrl instead of
the full $url, and change the Log::debug messages (in the branches referencing
$this->_urlRewrites[$normalizedUrl] and $this->_urlRewrites[$url]) to output
only the sanitized path or a redacted placeholder so query params and tokens are
not emitted.
- Around line 257-365: The registries must be updated consistently while
retaining “first match wins” and only throwing in strict mode: update
checkDuplicateRoute(RouteMap $route, string $method) to always register the
signature in $_registeredRoutes (i.e. set $_registeredRoutes[$signature] =
extractControllerInfo($route)) but only throw Exceptions\DuplicateRouteException
when $_strictMode is true (use existing isset check but gate the throw on
$_strictMode); change registerRouteName(string $name, ...) so that in non-strict
mode it does not overwrite an existing $_registeredNames[$name] (leave the first
registered "{$method}:{$path}" intact), and in strict mode keep the current
duplicate-detection/throw behavior; ensure both methods use the same signature
format ("{$method}:{$path}") and reference extractControllerInfo($route) when
registering.
- Around line 215-255: addRoute currently only populates $_registeredRoutes when
$_strictMode is true and leaves an entry if setName() throws, causing stale
signatures; change addRoute so it always registers the route signature (call or
replicate checkDuplicateRoute logic to add the method:path to $_registeredRoutes
regardless of $_strictMode) before attempting setName(), then wrap setName() in
a try/catch and remove/unregister that exact signature from $_registeredRoutes
if setName() throws so you don't leave stale entries; reference addRoute,
checkDuplicateRoute, setName, $_registeredRoutes, $_strictMode and ensure
rollback/unregister happens on name failure.
🧹 Nitpick comments (3)
src/Routing/RouteMap.php (1)
88-99: Consider normalizing/validating$methodinsetRouterContext()(defensive).
If a caller ever passesgetvsGET, you’ll end up with inconsistentmethod:pathsignatures.src/Routing/Router.php (2)
115-138:setUrlRewrites()looks good; consider normalizing rules on set (optional).
If you normalize keys/values once here (leading slash, trailing slash),rewriteUrl()can stay simpler and behavior becomes easier to reason about.
710-712: Good: rewrites are applied before matching; consider logging original + rewritten for debugging (optional).
Right now later logs/warnings use the original route in some places, which can be confusing when a rewrite is active.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Routing/RouteMap.phpsrc/Routing/Router.php
🧰 Additional context used
🧬 Code graph analysis (2)
src/Routing/RouteMap.php (1)
src/Routing/Router.php (3)
Router(45-839)unregisterRouteName(311-314)registerRouteName(271-300)
src/Routing/Router.php (2)
src/Routing/RouteMap.php (3)
RouteMap(40-346)setRouterContext(94-99)getPath(104-107)src/Routing/Exceptions/DuplicateRouteException.php (1)
DuplicateRouteException(15-163)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (3)
src/Routing/RouteMap.php (1)
49-54: Good: route-scoped router context is private and nullable.
No concerns with introducingRouteMap::$_router/RouteMap::$_methodfor name registration.src/Routing/Router.php (2)
56-67: Good: explicit registries for duplicates and rewrites.
The state buckets ($_registeredRoutes,$_registeredNames,$_urlRewrites,$_strictMode) are a clean basis for the new behavior.
366-416: Good: optional?string $namestays BC-friendly on method helpers.
Parameter is appended and defaults tonull, so existing call sites remain valid.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/Routing/Router.php (2)
935-963: Consider validating parameter substitution.The
generateUrl()method doesn't verify that all route parameters (:param) were substituted. If a required parameter is missing from the$parametersarray, the generated URL will contain the literal:paramplaceholder.This may be intentional for flexibility, but consider either:
- Logging a warning when unsubstituted parameters remain
- Throwing an exception for missing required parameters
♻️ Optional: Add validation for complete substitution
public function generateUrl( string $name, array $parameters = [], bool $absolute = false ): ?string { $route = $this->getRouteByName( $name ); if( !$route ) { return null; } $path = $route->getPath(); // Replace route parameters with actual values foreach( $parameters as $key => $value ) { $path = str_replace( ':' . $key, $value, $path ); } + // Warn if unsubstituted parameters remain + if( preg_match( '/:(\w+)/', $path, $matches ) ) + { + Log::warning( "generateUrl: Missing parameter '{$matches[1]}' for route '{$name}'" ); + } + // If absolute URL requested, prepend base URL
907-925: Consider using the name registry for O(1) lookup.
getRouteByName()iterates through all routes for O(n) lookup. Since$_registeredNamesalready maps names to signatures, you could use it for direct lookup, then fetch the route from the appropriate method array.This is a minor optimization and the current implementation is fine for typical route counts.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Routing/RouteMap.phpsrc/Routing/Router.php
🧰 Additional context used
🧬 Code graph analysis (2)
src/Routing/RouteMap.php (1)
src/Routing/Router.php (3)
Router(45-998)registerRouteName(421-449)unregisterRouteName(460-463)
src/Routing/Router.php (2)
src/Routing/RouteMap.php (3)
RouteMap(40-349)setRouterContext(94-99)setName(218-244)src/Routing/Exceptions/DuplicateRouteException.php (1)
DuplicateRouteException(15-163)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (17)
src/Routing/RouteMap.php (3)
49-53: LGTM!The nullable properties for router context are appropriately typed and provide a clean mechanism for context propagation without breaking existing RouteMap usage.
88-99: LGTM!Clean fluent interface method for setting router context. The implementation correctly stores both router reference and HTTP method for subsequent name registration operations.
218-244: Well-structured rollback-safe name registration.The implementation correctly registers the new name before unregistering the old one, ensuring atomicity—if registration fails due to a duplicate, the old name remains intact. The early return optimization for unchanged names is a good touch.
One edge case to consider: if
setName()is called on a RouteMap beforesetRouterContext()is set, the name will be stored locally but not registered with the router for duplicate detection. IfsetRouterContext()is later called, the existing name won't be retroactively registered. This appears acceptable given the intended usage flow inRouter::addRoute(), but verify this doesn't cause issues if RouteMap is used standalone.src/Routing/Router.php (14)
56-66: LGTM!The new properties are well-typed and documented. Defaulting
$_strictModetotrueis a safe choice that encourages explicit route definitions.
79-102: LGTM!Good defensive design: validating existing routes when enabling strict mode ensures that enabling strict mode doesn't leave the router in an inconsistent state if duplicates already exist.
113-188: LGTM!The rollback mechanism is well-implemented—saving registry state before validation and restoring on failure ensures atomicity. The iteration through all HTTP method arrays provides comprehensive duplicate detection.
199-210: LGTM!Complete reset of route-related state. Note that
$_strictModeand$_ipResolverare intentionally preserved, which makes sense as they're configuration/dependency settings rather than route state.
232-235: LGTM!Clean setter with good documentation. The simple assignment is appropriate here.
247-274: LGTM!The method correctly handles trailing slash normalization while preserving the ability to define rewrites for both forms. Returning the original URL when no rewrite matches preserves existing behavior.
285-313: Good security practice.Sanitizing URLs before logging prevents accidental exposure of sensitive query parameters (tokens, API keys, etc.). The implementation correctly handles all combinations of query strings and fragments.
364-401: LGTM!The rollback mechanism in the try-catch ensures consistency: if
setName()throws aDuplicateRouteException, the route signature added bycheckDuplicateRoute()is properly removed before re-throwing. This prevents orphaned registry entries.
421-449: LGTM!The method correctly implements first-match-wins semantics in non-strict mode and throws descriptive exceptions in strict mode. The
explode( ':', $originalSignature, 2 )correctly handles route paths that contain colons.
460-463: LGTM!Simple and safe—
unset()on a non-existent key is a no-op in PHP, so no additional checks are needed.
477-505: LGTM!The first-match-wins semantics are correctly implemented: in non-strict mode, only the first occurrence is registered in the tracking registry, which aligns with the runtime routing behavior where routes are matched in registration order.
513-523: LGTM!Simple extraction method with a sensible fallback for error message generation.
533-575: LGTM!Consistent API extension across all HTTP method helpers. The optional
$nameparameter maintains backward compatibility while enabling named route registration.
869-871: LGTM!Clean integration of URL rewriting before route matching. The comment clearly documents the purpose.
Note
Introduces internal URL rewrite support and strict duplicate-route detection with runtime toggles and clearer error reporting.
DuplicateRouteExceptionand router registries to detect duplicate method+path and name conflicts; strict mode enabled by default withsetStrictMode(false)to relaxsetUrlRewrites, transparentrewriteUrlinrun,clearRoutes, name registration viaregisterRouteName/unregisterRouteName;get/post/put/deleteaccept optionalnameRouteMapgains router context and validatedsetNameto participate in name-dup checksconfig/routing.yamlprecedence, add URL rewrite docs, examples, and duplicate detection guidance; remove hybrid YAML+attributes sectionWritten by Cursor Bugbot for commit fdd3815. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.