class TestMiddleware {
public function __construct($param) {}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) {
return $next($request, $response);
}
}
In Expressive 2:
$app->pipe(TestMiddleware::class);
It’s OK!
In Expressive 3:
$app->pipe(TestMiddleware::class);
Actual results
Throw message:
Service "TestMiddleware" did not to resolve to a Psr\Http\Server\MiddlewareInterface instance; resolved to "TestMiddleware"
Expected results
Support __invoke($request, $response, $next) .
Or support $app->pipe(doublePassMiddleware(TestMiddleware::class));
This is not terribly difficult; handle it in the factory for that middleware, and/or create a factory for it, and/or create a delegator factory for it.
Probably the easiest route is to create a single delegator factory for such middleware, and then map it to any services you have that currently produce double-pass middleware. It would likely look something like the following:
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use function Zend\Stratigility\doublePassMiddleware;
class DoublePassMiddlewareDelegator
{
public function __invoke(Container $container, string $serviceName, callable $callback)
{
return doublePassMiddleware(
$callback(),
($container->get(ResponseInterface::class))()
);
}
}
You would then attach it to the service within your configuration:
The nice bit about this approach is you can re-use it for any service that normally returns double-pass middleware — and you’ll easily be able to grep through your configuration to identify double-pass middleware in order to determine dependencies you may want to re-think or replace.
We want to encourage people to migrate to PSR-15 middleware, as it is a standard. If we make it difficult to use double-pass middleware, the hope is this will put pressure on middleware package authors to update.
I will create a library , and extend Zend\Expressive\MiddlewareContainer for compatible with callable middleware. I think this is minimal change for my project migration to v3.
This is full code:
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Expressive\Exception;
use Zend\Stratigility\Middleware\DoublePassMiddlewareDecorator;
use Zend\Stratigility\Middleware\RequestHandlerMiddleware;
class MiddlewareContainer extends \Zend\Expressive\MiddlewareContainer
{
protected $container;
protected $responsePrototype;
public function __construct(ContainerInterface $container, ResponseInterface $responsePrototype = null)
{
parent::__construct($container);
$this->container = $container;
$this->responsePrototype = $responsePrototype;
}
public function get($service) : MiddlewareInterface
{
if (! $this->has($service)) {
throw Exception\MissingDependencyException::forMiddlewareService($service);
}
$middleware = $this->container->has($service)
? $this->container->get($service)
: new $service();
if ($middleware instanceof RequestHandlerInterface) {
$middleware = new RequestHandlerMiddleware($middleware);
}
if (is_callable($middleware)) {
$middleware = new DoublePassMiddlewareDecorator($middleware, $this->responsePrototype);
}
if (! $middleware instanceof MiddlewareInterface) {
throw Exception\InvalidMiddlewareException::forMiddlewareService($service, $middleware);
}
return $middleware;
}
}