How to call middleware PSR-15 within event listeners in zend framework 3 (zend-mvc)?

Hi, guys!
Here https://docs.zendframework.com/zend-mvc/cookbook/middleware-in-listeners/ are docs about how to use middleware PSR-7 within event listeners. There is example of middleware with __invoke() method of middleware.

How to call middleware PSR-15 with process() method of middleware class within event listeners?

Upd:

Here https://docs.zendframework.com/zend-mvc/middleware/#writing-middleware is example of how to write middleware with process() method of middleware class, but there is nothing about how to call it in event listener. Besides, __https://github.com/http-interop/http-middleware from docs is now deprecated. Can somebody give me some modern example of using middleware PSR-15 with process() method of middleware class within event listeners?

Upd2:

zend-httphandlerrunner - Is this what I need for PSR-15 middleware within event listener? How to use that?

Upd3:

zend-stratigility __https://docs.zendframework.com/zend-stratigility/v3/middleware/#psr-15-middleware support PSR-15 middleware but how to use it within event listeners in zend framework 3 (zend-mvc)?

It’s almost exactly the same. The only differences are:

  • $done needs to be a PSR-15 request handler.
  • You call the process() method of the middleware.

So, taking the Module example from that original page:

namespace Application;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Psr7Bridge\Psr7Response;
use Zend\Psr7Bridge\Psr7ServerRequest;

class Module
{
    public function onBootstrap($e)
    {
        $app          = $e->getApplication();
        $eventManager = $app->getEventManager();
        $services     = $app->getServiceManager();

        $eventManager->attach($e::EVENT_DISPATCH, function ($e) use ($services) {
            $request  = Psr7ServerRequest::fromZend($e->getRequest());
            $response = Psr7Response::fromZend($e->getResponse());
            $done     = new class($response) implements RequestHandlerInterface {
                private $response;

                public function __construct(ResponseInterface $response)
                {
                    $this->response = $response;
                }

                public function handle(ServerRequestInterface $request) : ResponseInterface
                {
                    return $this->response;
                }
            };

            $result = $services->get(Middleware\AuthorizationMiddleware::class)
                ->process(
                    $request,
                    $done
                );

            if ($result !== $response) {
                return Psr7Response::toZend($result);
            }
        }, 2);
    }
}

In this example, I created an anonymous class as the handler, and have it return a response based off the current zend-http response. If the middleware returns that verbatim, without changes, we can assume that the middleware did not do anything to the response, and thus can continue processing the request with other listeners. Otherwise, we return the response from the middleware, after first converting it to zend-http, and short-circuit execution.

1 Like

I didn’t find RequestHandlerInterface inside zend frameworks’ components that is why I have used RequestHandlerInterface implementation from “Relay\Relay” library. And my code inside “$eventManager->attach($e::EVENT_DISPATCH …” looks like:

    $request  = Psr7ServerRequest::fromZend($e->getRequest());
    
    $queue = [];
    
    $queue[] = $services->get(Middleware\AuthorizationMiddleware::class); 
    
    $relay = new Relay($queue);
    
    $relay->handle($request);

It seems it works for me but I am not 100% sure. Should I rewrite my current code?

RequestHandlerInterface is part of PSR-15. We provide a few implementations, but for the most part, it is something your application will provide. The example I had above provides an anonymous class declaration of it, for purposes of determining whether or not the middleware returned a different response.

Relay definitely works. So does Zend\Stratigility\MiddlewarePipe. :wink:

1 Like

@matthew , I have replaced my code (with Relay part) by your code except anonymous class which I moved to the standalone class. But your code has some difference with code from documentation.

Your code:

    if ($result !== $response) {
        return Psr7Response::toZend($result);
    }

Code from documentation from this page https://docs.zendframework.com/zend-mvc/cookbook/middleware-in-listeners/ :

            if ($result) {
                return Psr7Response::toZend($result);
            }

Which part of code should I use? If I use you example I get blank page on my login page. When I remove this:

    if ($result !== $response) {
        return Psr7Response::toZend($result);
    }

my page appear as expected. I am using middleware for non-api routes for admin panel to check authorization. For api routes I am using apigility listeners.

With code from documentation:

        if($result){
            return Psr7Response::toZend($result);
        }

I also get blank page on my login page.

Please check you configuration and enable the display of exceptions:

'view_manager'       => [
    'display_not_found_reason' => true,
    'display_exceptions'       => true,
],

Compare with the configuration in the documentation of zend-view.

Yes, I have enabled these settings. Also my apach2 error file don’t show anything when blank page is showing. It’s looks like something wrong with my response when I am doing this:

return Psr7Response::toZend($result);

If i add:

return Psr7Response::toZend($result);

at the end of onDispatch(MvcEvent $e) method I have blank page on all my pages. Also within my middleware I have this code:

$response = Psr7Response::fromZend($response);

return $response;

If I remove

    if($result !== $response){
        return Psr7Response::toZend($result);
    }

all pages works as expected with my middleware.