benomite
benomite

Reputation: 868

Zend Expressive nested application

I'm trying to use zend expressive nested application, so I'm following this blog post : https://framework.zend.com/blog/2017-03-15-nested-middleware-in-expressive.html

The problem seems to be in the Middleware factory:

class CreateBookMiddlewareFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $nested = new Application(
          $container->get(RouterInterface::class),
          $container
        );

        $nested->pipe(AuthenticationMiddleware::class);
        $nested->pipe(ContentValidationMiddleware::class);
        $nested->pipe(BodyParamsMiddleware::class);
        $nested->pipe(BookValidationMiddleware::class);
        $nested->pipe(CreateBookMiddleware::class);

        return $nested;
    }
}

I don't get how CreateBookMiddleware could be added to the pipe here as we are in its Factory. So piping it will call the factory, create a new nested application, which will call the factory, which will create another nested application...

( ! ) Fatal error: Maximum function nesting level of '256' reached, aborting! in /var/www/project/vendor/zendframework/zend-stratigility/src/Next.php on line
   158

Is there something I'm not getting right from this blog post?

Upvotes: 0

Views: 312

Answers (2)

user2408230
user2408230

Reputation:

You named the factory CreateBookMiddlewareFactory. And then inside __invoke you have $nested->pipe(CreateBookMiddleware::class);. It depends on your config, but usually CreateBookMiddlewareFactory would be the factory for CreateBookMiddleware. So it's stuck in a loop because it keeps creating itself.

As you have the exact same code as in the blogpost, I'm guessing it's an error in that blog post. I think it should have been like in the last delegator factory example: without the last $nested->pipe(CreateBookMiddleware::class);.

I've notified the author of the blog post.

Edit: The blog post is updated with this fix:

namespace Acme\Api;

use Acme\AuthenticationMiddleware;
use Acme\ContentNegotiationMiddleware;
use Psr\Container\ContainerInterface;
use Zend\Expressive\Application;
use Zend\Expressive\Helper\BodyParams\BodyParamsMiddleware;
use Zend\Expressive\Router\RouterInterface;

class CreateBookMiddlewareFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $nested = new Application(
          $container->get(RouterInterface::class),
          $container
        );

        $nested->pipe(AuthenticationMiddleware::class);
        $nested->pipe(ContentValidationMiddleware::class);
        $nested->pipe(BodyParamsMiddleware::class);
        $nested->pipe(BookValidationMiddleware::class);

        // If dependencies are needed, pull them from the container and pass
        // them to the constructor:
        $nested->pipe(new CreateBookMiddleware());

        return $nested;
    }
}

Upvotes: 2

benomite
benomite

Reputation: 868

I accepted @xtreamwayz answer for the clarification. But here's how I made it work:

class CreateBookMiddlewareFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $nested = new Application(
          $container->get(RouterInterface::class),
          $container
        );

        $nested->pipe($container->get(AuthenticationMiddleware::class));
        $nested->pipe($container->get(ContentValidationMiddleware::class));
        $nested->pipe($container->get(BodyParamsMiddleware::class));
        $nested->pipe($container->get(BookValidationMiddleware::class));
        // instanciate the new class, so it will not call the factory again
        $nested->pipe(new CreateBookMiddleware());

        return $nested;
    }
}

Upvotes: 0

Related Questions