Skip to content

Commit 36cbda8

Browse files
authored
Merge pull request #29 from PHP-DI/25-request-attribute-injection
Fix #25 Inject request attributes
2 parents 9990680 + 7c12571 commit 36cbda8

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

README.md

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ By default, Slim controllers have a strict signature: `$request, $response, $arg
5454

5555
Controller parameters can be any of these things:
5656

57-
- request or response injection (parameters must be named `$request` or `$response`)
58-
- request attribute injection
59-
- service injection (by type-hint)
57+
- the request or response (parameters must be named `$request` or `$response`)
58+
- route placeholders
59+
- request attributes
60+
- services (injected by type-hint)
6061

6162
You can mix all these types of parameters together too. They will be matched by priority in the order of the list above.
6263

@@ -72,7 +73,7 @@ $app->get('/', function (ResponseInterface $response, ServerRequestInterface $re
7273

7374
As you can see, the order of the parameters doesn't matter. That allows to skip injecting the `$request` if it's not needed for example.
7475

75-
#### Request attribute injection
76+
#### Route placeholder injection
7677

7778
```php
7879
$app->get('/hello/{name}', function ($name, ResponseInterface $response) {
@@ -83,6 +84,22 @@ $app->get('/hello/{name}', function ($name, ResponseInterface $response) {
8384

8485
As you can see above, the route's URL contains a `name` placeholder. By simply adding a parameter **with the same name** to the controller, PHP-DI will directly inject it.
8586

87+
#### Request attribute injection
88+
89+
```php
90+
$app->add(function ($request, $response, $next) {
91+
$request = $request->withAttribute('name', 'Bob');
92+
return $next($request, $response);
93+
});
94+
95+
$app->get('/', function ($name, ResponseInterface $response) {
96+
$response->getBody()->write('Hello ' . $name);
97+
return $response;
98+
});
99+
```
100+
101+
As you can see above, a middleware sets a `name` attribute. By simply adding a parameter **with the same name** to the controller, PHP-DI will directly inject it.
102+
86103
#### Service injection
87104

88105
To inject services into your controllers, you can write them as classes. But if you want to write a micro-application using closures, you don't have to give up dependency injection either.

src/ControllerInvoker.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public function __invoke(
4444
// Inject the route arguments by name
4545
$parameters += $routeArguments;
4646

47+
// Inject the attributes defined on the request
48+
$parameters += $request->getAttributes();
49+
4750
return $this->invoker->call($callable, $parameters);
4851
}
4952
}

tests/RoutingTest.php

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function injects_request_and_response()
3131
/**
3232
* @test
3333
*/
34-
public function injects_request_path_parameters()
34+
public function injects_route_placeholder()
3535
{
3636
$app = new App;
3737
$app->get('/{name}', function ($name, $response) {
@@ -46,7 +46,7 @@ public function injects_request_path_parameters()
4646
/**
4747
* @test
4848
*/
49-
public function injects_optional_path_parameter()
49+
public function injects_optional_route_placeholder()
5050
{
5151
$app = new App;
5252
$app->get('/[{name}]', function ($response, $name = null) {
@@ -61,7 +61,7 @@ public function injects_optional_path_parameter()
6161
/**
6262
* @test
6363
*/
64-
public function injects_default_value_in_optional_path_parameter()
64+
public function injects_default_value_in_optional_route_placeholder()
6565
{
6666
$app = new App;
6767
$app->get('/[{name}]', function ($response, $name = 'john doe') {
@@ -73,6 +73,44 @@ public function injects_default_value_in_optional_path_parameter()
7373
$this->assertEquals('Hello john doe', (string) $response->getBody());
7474
}
7575

76+
/**
77+
* @test
78+
*/
79+
public function injects_request_attribute()
80+
{
81+
$app = new App;
82+
// Let's add a middleware that adds a request attribute
83+
$app->add(function (ServerRequestInterface $request, $response, $next) {
84+
return $next($request->withAttribute('name', 'Bob'), $response);
85+
});
86+
$app->get('/', function ($name, $response) {
87+
$response->getBody()->write('Hello ' . $name);
88+
return $response;
89+
});
90+
91+
$response = $app->callMiddlewareStack(RequestFactory::create('/'), new Response);
92+
$this->assertEquals('Hello Bob', $response->getBody()->__toString());
93+
}
94+
95+
/**
96+
* @test
97+
*/
98+
public function injects_route_placeholder_over_request_attribute()
99+
{
100+
$app = new App;
101+
$app->add(function (ServerRequestInterface $request, $response, $next) {
102+
return $next($request->withAttribute('name', 'Bob'), $response);
103+
});
104+
$app->get('/{name}', function ($name, $response) {
105+
$response->getBody()->write('Hello ' . $name);
106+
return $response;
107+
});
108+
109+
$response = $app->callMiddlewareStack(RequestFactory::create('/matt'), new Response);
110+
// The route placeholder has priority over the request attribute
111+
$this->assertEquals('Hello matt', (string) $response->getBody());
112+
}
113+
76114
/**
77115
* @test
78116
*/

0 commit comments

Comments
 (0)