Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit e260d12

Browse files
committed
Merge branch 'feature/456' into develop
Close #460 Close #456 Finishes out Expressive 2.0 documentation tasks
2 parents c83fe64 + a6d2430 commit e260d12

File tree

12 files changed

+949
-18
lines changed

12 files changed

+949
-18
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Delegator Factories
2+
3+
- Since 2.0.
4+
5+
Starting with the 2.0 version of the Expressive skeleton, we now support the
6+
concept of _delegator factories_, which allow decoration of services created by
7+
your dependency injection container, across all dependency injection containers
8+
supported by Expressive.
9+
10+
_Delegator factories_ accept the following arguments:
11+
12+
- The container itself;
13+
- The name of the service whose creation is being decrorated;
14+
- A callback that will produce the service being decorated.
15+
16+
As an example, let's say we have a `UserRepository` class that composes some sort of
17+
event manager. We might want to attach listeners to that event manager, but not
18+
wish to alter the basic creation logic for the repository itself. As such, we
19+
might write a _delegator factory_ as follows:
20+
21+
```php
22+
namespace Acme;
23+
24+
use Psr\Container\ContainerInterface;
25+
use Psr\Log\LoggerInterface;
26+
27+
class UserRepositoryListenerDelegatorFactory
28+
{
29+
/**
30+
* @param ContainerInterface $container
31+
* @param string $name
32+
* @param callable $callback
33+
* @return UserRepository
34+
*/
35+
public function __invoke(ContainerInterface $container, $name, callable $callback)
36+
{
37+
$listener = new LoggerListener($container->get(LoggerInterface::class));
38+
$repository = $callback();
39+
$repository->getEventManager()->attach($listener);
40+
return $repository;
41+
}
42+
}
43+
```
44+
45+
To notify the container about this delegator factory, we would add the following
46+
configuration to our application:
47+
48+
```php
49+
'dependencies' => [
50+
'delegators' => [
51+
Acme\UserRepository::class => [
52+
Acme\UserRepositoryListenerDelegatorFactory::class,
53+
],
54+
],
55+
],
56+
```
57+
58+
Note that you specify delegator factories using the service name being decorated
59+
as the key, with an _array_ of delegator factories as a value. **You may attach
60+
multiple delegator factories to any given service**, which can be a very
61+
powerful feature.
62+
63+
At the time of writing, this feature works for each of the Aura.Di, Pimple, and
64+
zend-servicemanager container implementations. Delegator factories have been
65+
supported with Pimple and zend-servicemanager since the 1.X series.

doc/book/features/error-handling.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,93 @@ return [
137137
> `config/autoload/*.local.php` file with the above configuration whenever you
138138
> want to enable whoops.
139139
140+
## Listening for errors
141+
142+
When errors occur, you may want to _listen_ for them in order to provide
143+
features such as logging. `Zend\Stratigility\Middleware\ErrorHandler` provides
144+
the ability to do so via its `attachListener()` method.
145+
146+
This method accepts a callable with the following signature:
147+
148+
```php
149+
function (
150+
Throwable|Exception $error,
151+
ServerRequestInterface $request,
152+
ResponseInterface $response
153+
) : void
154+
```
155+
156+
The response provided is the response returned by your error response generator,
157+
allowing the listener the ability to introspect the generated response as well.
158+
159+
As an example, you could create a logging listener as follows:
160+
161+
```php
162+
namespace Acme;
163+
164+
use Exception;
165+
use Psr\Log\LoggerInterface;
166+
use Psr\Http\Message\ResponseInterface;
167+
use Psr\Http\Message\ServerRequestInterface;
168+
use Throwable;
169+
170+
class LoggingErrorListener
171+
{
172+
/**
173+
* Log format for messages:
174+
*
175+
* STATUS [METHOD] path: message
176+
*/
177+
const LOG_FORMAT = '%d [%s] %s: %s';
178+
179+
private $logger;
180+
181+
public function __construct(LoggerInterface $logger)
182+
{
183+
$this->logger = $logger;
184+
}
185+
186+
public function __invoke($error, ServerRequestInterface $request, ResponseInterface $response)
187+
{
188+
$this->logger->error(sprintf(
189+
self::LOG_FORMAT,
190+
$response->getStatusCode(),
191+
$request->getMethod(),
192+
(string) $request->getUri(),
193+
$error->getMessage()
194+
));
195+
}
196+
}
197+
```
198+
199+
You could then use a [delegator factory](container/delegator-factories.md) to
200+
create your logger listener and attach it to your error handler:
201+
202+
```php
203+
namespace Acme;
204+
205+
use Psr\Container\ContainerInterface;
206+
use Psr\Log\LoggerInterface;
207+
use Zend\Stratigility\Middleware\ErrorHandler;
208+
209+
class LoggerErrorListenerDelegatorFactory
210+
{
211+
/**
212+
* @param ContainerInterface $container
213+
* @param string $name
214+
* @param callable $callback
215+
* @return ErrorHandler
216+
*/
217+
public function __invoke(ContainerInterface $container, $name, callable $callback)
218+
{
219+
$listener = new LoggerErrorListener($container->get(LoggerInterface::class));
220+
$errorHandler = $callback();
221+
$errorHandler->attachListener($listener);
222+
return $errorHandler;
223+
}
224+
}
225+
```
226+
140227
## Handling more specific error types
141228

142229
You could also write more specific error handlers. As an example, you might want

doc/book/features/helpers/url-helper.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ Each method will raise an exception if:
6464
represents a matching failure.
6565
- The given `$routeName` is not defined in the router.
6666

67+
> ### Signature changes
68+
>
69+
> The signature listed above is current as of version 3.0.0 of
70+
> zendframework/zend-expressive-helpers. Prior to that version, the helper only
71+
> accepted the route name and route parameters.
72+
6773
## Creating an instance
6874

6975
In order to use the helper, you will need to instantiate it with the current

doc/book/features/router/interface.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ Implementors should also read the following sections detailing the `Route` and
7676
`RouteResult` classes, to ensure that their implementations interoperate
7777
correctly.
7878

79+
> ### generateUri() signature change in 2.0
80+
>
81+
> Prior to zendframework/zend-expressive-router 2.0.0, the signature of
82+
> `generateUri()` was:
83+
>
84+
> ```php
85+
> public function generateUri(
86+
> string $name,
87+
> array $substitutions = []
88+
> ) : string
89+
> ```
90+
>
91+
> If you are targeting that version, you may still provide the `$options`
92+
> argument, but it will not be invoked.
93+
7994
## Routes
8095
8196
Routes are defined via `Zend\Expressive\Router\Route`, and aggregate the

doc/book/features/template/twig.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,8 @@ return [
127127
],
128128
];
129129
```
130+
131+
When specifying the `twig.extensions` values, always use fully qualified class
132+
names or actual extension instances to ensure compatibility with any version of
133+
Twig used. Version 2 of Twig _requires_ that a fully qualified class name is
134+
used, and not a short-name alias.

doc/book/features/template/zend-view.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ for doing so:
9292
In each case, the zend-view implementation will do a depth-first, recursive
9393
render in order to provide content within the selected layout.
9494

95+
- Since 1.3: You may also pass a boolean `false` value to either
96+
`addDefaultParam()` or via the template variables for the `layout` key; doing
97+
so will disable the layout.
98+
9599
### Layout name passed to constructor
96100

97101
```php

0 commit comments

Comments
 (0)