@@ -53,10 +53,10 @@ to access route parameters and JSON body fields consistently.
5353 /** @var ServerRequestInterface $psrRequest */
5454 $decoded = Request::from(request: $psrRequest)->decode();
5555
56- $name = $decoded->body->get(key: 'name')->toString();
57- $payload = $decoded->body->toArray();
56+ $name = $decoded->body() ->get(key: 'name')->toString();
57+ $payload = $decoded->body() ->toArray();
5858
59- $id = $decoded->uri->route()->get(key: 'id')->toInteger();
59+ $id = $decoded->uri() ->route()->get(key: 'id')->toInteger();
6060 ```
6161
6262- ** Typed access with defaults** : Each value is returned as an Attribute, which provides safe conversions and default
@@ -67,24 +67,85 @@ to access route parameters and JSON body fields consistently.
6767
6868 $decoded = Request::from(request: $psrRequest)->decode();
6969
70- $id = $decoded->uri->route()->get(key: 'id')->toInteger(); # default: 0
71- $note = $decoded->body->get(key: 'note')->toString(); # default: ""
72- $tags = $decoded->body->get(key: 'tags')->toArray(); # default: []
73- $price = $decoded->body->get(key: 'price')->toFloat(); # default: 0.00
74- $active = $decoded->body->get(key: 'active')->toBoolean(); # default: false
70+ $id = $decoded->uri() ->route()->get(key: 'id')->toInteger(); # default: 0
71+ $note = $decoded->body() ->get(key: 'note')->toString(); # default: ""
72+ $tags = $decoded->body() ->get(key: 'tags')->toArray(); # default: []
73+ $price = $decoded->body() ->get(key: 'price')->toFloat(); # default: 0.00
74+ $active = $decoded->body() ->get(key: 'active')->toBoolean(); # default: false
7575 ```
7676
7777- ** Custom route attribute name** : If your framework stores route params in a different request attribute, you can
78- specify it via route().
78+ specify it via ` route() ` .
7979
8080 ``` php
8181 use TinyBlocks\Http\Request;
8282
8383 $decoded = Request::from(request: $psrRequest)->decode();
8484
85- $id = $decoded->uri->route(name: '_route_params')->get(key: 'id')->toInteger();
85+ $id = $decoded->uri() ->route(name: '_route_params')->get(key: 'id')->toInteger();
8686 ```
8787
88+ #### How route parameters are resolved
89+
90+ The library resolves route parameters from the PSR-7 ` ServerRequestInterface ` using a ** multistep fallback strategy** ,
91+ designed to work across different frameworks without importing any framework-specific code.
92+
93+ ** Resolution order** (when using the default ` route() ` or ` route(name: '...') ` ):
94+
95+ 1 . ** Specified attribute lookup** — Reads the attribute from the request using the configured name (default:
96+ ` __route__ ` ).
97+ - If the value is an ** array** , the key is looked up directly.
98+ - If the value is an ** object** , the resolver tries known accessor methods (` getArguments() ` ,
99+ ` getMatchedParams() ` , ` getParameters() ` , ` getParams() ` ) and then public properties (` arguments ` , ` params ` ,
100+ ` vars ` , ` parameters ` ).
101+ - If the value is a ** scalar** (e.g., a string), it is returned as-is.
102+
103+ 2 . ** Known attribute scan** (only when using the default ` __route__ ` name) — Scans all commonly used attribute keys
104+ across frameworks:
105+ - ` __route__ ` , ` _route_params ` , ` route ` , ` routing ` , ` routeResult ` , ` routeInfo `
106+
107+ 3 . ** Direct attribute fallback** — As a last resort, tries ` $request->getAttribute($key) ` directly, which supports
108+ frameworks like Laravel that store route params as individual request attributes.
109+
110+ 4 . ** Safe default** — If nothing is found, returns ` Attribute::from(null) ` , which provides safe conversions:
111+ ` toInteger() ` → ` 0 ` , ` toString() ` → ` "" ` , ` toFloat() ` → ` 0.00 ` , ` toBoolean() ` → ` false ` , ` toArray() ` → ` [] ` .
112+
113+ ** Supported frameworks and attribute formats:**
114+
115+ | Framework | Attribute Key | Format |
116+ | -------------------------| -----------------| -----------------------------------------------|
117+ | ** Slim 4** | ` __route__ ` | Object with ` getArguments() ` |
118+ | ** Mezzio / Expressive** | ` routeResult ` | Object with ` getMatchedParams() ` |
119+ | ** Symfony** | ` _route_params ` | ` array<string, mixed> ` |
120+ | ** Laravel** | * (direct)* | ` getAttribute('id') ` directly on the request |
121+ | ** FastRoute (generic)** | ` routeInfo ` | Array with route parameters |
122+ | ** Manual injection** | Any custom key | ` $request->withAttribute('__route__', [...]) ` |
123+
124+ #### Manually injecting route parameters
125+
126+ If your framework or middleware does not automatically populate route attributes, you can inject them manually using
127+ PSR-7's ` withAttribute() ` :
128+
129+ ``` php
130+ use TinyBlocks\Http\Request;
131+
132+ $psrRequest = $psrRequest->withAttribute('__route__', [
133+ 'id' => '42',
134+ 'email' => 'user@example.com'
135+ ]);
136+
137+ $decoded = Request::from(request: $psrRequest)->decode();
138+ $id = $decoded->uri()->route()->get(key: 'id')->toInteger(); # 42
139+
140+ $psrRequest = $psrRequest->withAttribute('my_params', ['slug' => 'hello-world']);
141+ $slug = Request::from(request: $psrRequest)
142+ ->decode()
143+ ->uri()
144+ ->route(name: 'my_params')
145+ ->get(key: 'slug')
146+ ->toString(); # "hello-world"
147+ ```
148+
88149<div id =' response ' ></div >
89150
90151### Response
@@ -184,4 +245,4 @@ Http is licensed under [MIT](LICENSE).
184245## Contributing
185246
186247Please follow the [ contributing guidelines] ( https://github.com/tiny-blocks/tiny-blocks/blob/main/CONTRIBUTING.md ) to
187- contribute to the project.
248+ contribute to the project.
0 commit comments