Middleware with id *** could not be found in container

Hello

I try to add Middleware in my tested module, for get and check request token, but I have this error

Additional information:
Laminas\Mvc\Middleware\InvalidMiddlewareException

File:

    /var/www/html/local/laminas/vendor/laminas/laminas-mvc-middleware/src/InvalidMiddlewareException.php:58

Message:

    Middleware with id User\Middleware\AuthenticationMiddleware could not be found in container

Stack trace:

    #0 /var/www/html/local/laminas/vendor/laminas/laminas-mvc-middleware/src/HandlerFromPipeSpecFactory.php(98): Laminas\Mvc\Middleware\InvalidMiddlewareException::fromMissingInContainer()
    #1 /var/www/html/local/laminas/vendor/laminas/laminas-mvc-middleware/src/HandlerFromPipeSpecFactory.php(33): Laminas\Mvc\Middleware\HandlerFromPipeSpecFactory->middlewareFromContainer()
    #2 /var/www/html/local/laminas/vendor/laminas/laminas-mvc-middleware/src/MiddlewareListener.php(59): Laminas\Mvc\Middleware\HandlerFromPipeSpecFactory->createFromMiddlewareParam()
    #3 /var/www/html/local/laminas/vendor/laminas/laminas-eventmanager/src/EventManager.php(319): Laminas\Mvc\Middleware\MiddlewareListener->onDispatch()
    #4 /var/www/html/local/laminas/vendor/laminas/laminas-eventmanager/src/EventManager.php(179): Laminas\EventManager\EventManager->triggerListeners()
    #5 /var/www/html/local/laminas/vendor/laminas/laminas-mvc/src/Application.php(325): Laminas\EventManager\EventManager->triggerEventUntil()
    #6 /var/www/html/local/laminas/public/index.php(42): Laminas\Mvc\Application->run()
    #7 {main}

my router is :

    'router' => [
        'routes' => [
            'test' => [
                'type' => Literal::class,
                'options' => [
                    'route' => '/test',
                    'defaults' => [
                        'controller' => PipeSpec::class,
                        'middleware' => AuthenticationMiddleware::class,
                    ],
                ],
           ],
       ],

Middleware class :

<?php

namespace User\Middleware;

use Fig\Http\Message\StatusCodeInterface;
use Laminas\Router\RouteMatch;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use User\Repository\AccountRepositoryInterface;

class AuthenticationMiddleware implements MiddlewareInterface
{
    /** @var AccountRepositoryInterface */
    public $accountRepository;

    /** @var ResponseFactoryInterface */
    public $responseFactory;

    public function __construct(AccountRepositoryInterface $accountRepository, ResponseFactoryInterface $responseFactory)
    {
        $this->accountRepository = $accountRepository;
        $this->responseFactory = $responseFactory;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        /** @var RouteMatch $routeMatch */
        $routeMatch = $request->getAttribute(RouteMatch::class);
        $userId    = $routeMatch->getParam('id');
        $account      = $this->accountRepository->getAccount(['id' => $userId]);

        // if no album was found, we short-circuit the pipe and return a 404 error:
        if ($account === null) {
            return $this->responseFactory->createResponse(
                StatusCodeInterface::STATUS_NOT_FOUND,
                sprintf('Album with ID %s not found!', $userId)
            );
        }

        // ...otherwise we populate the request with the album and call the RequestHandler
        $request = $request->withAttribute('account', $account);
        return $handler->handle($request);
    }
}

and handler class

<?php

namespace User\Handler;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthenticationHandler implements RequestHandlerInterface
{
    /** @var ResponseFactoryInterface */
    public $responseFactory;

    /** @var StreamFactoryInterface */
    public $streamFactory;

    public function __construct(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory)
    {
        $this->responseFactory = $responseFactory;
        $this->streamFactory   = $streamFactory;
    }

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
       // /** @var  $album */
        $account = $request->getAttribute('account');

        $body = $this->streamFactory->createStream('The name of the user is: ' . $account->getName());
        return $this->responseFactory->createResponse()->withBody($body);
    }
}

Can you please check it and tell me what is the problem? or perhaps I miss someting

It looks like your middleware is not registered.

Extend the module configuration:

module/User/config/module.config.php

return [
    // …
    'service_manager' => [[
        'factories'  => [
            User\Middleware\AuthenticationMiddleware::class => Laminas\ServiceManager\Factory\InvokableFactory::class,
        ],
    ],
    // …
];

Thank you so much, I registered the middleware and this problem was solved, now I need to improve my middleware to get a true result.

Perhaps is good if we can add a register section in the MVC-middleware doc. when I finish this part I try update doc and send pull request

thank you very much

That would be great. Thanks in advance! :+1:t3:

Hello again
I finally finish Middleware and check it, My use-case was to get a JWT token from UTL (as a query string) and check user

But if I understand true, in MVC I could not write global Middleware and run it before each request for the normal controller

If I want use Middleware, I should write Handler ( as a single action controller ). But can I use one Middleware for some of my Handler, for example, I want to create profile-view, profile-edit, logout, submit-post, and … actions ( All of them should be handlers) and get user token and check validation and after that run handler.

It’s true? and the best way for this use-case? or it better I write service for it and run it on controller or actions? or another way?

My final code is :

    'service_manager' => [
        'aliases'   => [
            Repository\AccountRepositoryInterface::class => Repository\AccountRepository::class,
            Service\ServiceInterface::class              => Service\AccountService::class,
        ],
        'factories' => [
            AuthenticationServiceInterface::class      => Factory\AuthenticationServiceFactory::class,
            Repository\AccountRepository::class        => Factory\AccountRepositoryFactory::class,
            Service\AccountService::class              => Factory\AccountServiceFactory::class,
            Middleware\AuthenticationMiddleware::class => Factory\AuthenticationMiddlewareFactory::class,
        ],
    ],

'router' => [
        'routes' => [
            'test2' => [
                'type'    => Literal::class,
                'options' => [
                    'route'    => '/test2',
                    'defaults' => [
                        'controller' => PipeSpec::class,
                        'middleware' => Middleware\AuthenticationMiddleware::class,
                    ],
                ],
            ],
            ...
        ],
    ],

AuthenticationMiddleware

<?php

namespace User\Middleware;

use Fig\Http\Message\StatusCodeInterface;
use Laminas\Diactoros\StreamFactory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use User\Handler\AuthenticationHandler;
use User\Repository\AccountRepositoryInterface;
use User\Service\AuthService;

class AuthenticationMiddleware implements MiddlewareInterface
{
    /** @var AccountRepositoryInterface */
    public $accountRepository;

    /** @var ResponseFactoryInterface */
    public $responseFactory;

    /** @var AuthService */
    protected $authService;

    /** @var AuthenticationHandler */
    protected $handler;

    /** @var StreamFactoryInterface */
    public $streamFactory;

    public function __construct(AccountRepositoryInterface $accountRepository, ResponseFactoryInterface $responseFactory)
    {
        $this->accountRepository = $accountRepository;
        $this->responseFactory   = $responseFactory;
        $this->streamFactory     = new StreamFactory();
        $this->authService       = new AuthService();
        $this->handler           = new AuthenticationHandler($this->responseFactory, $this->streamFactory);
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $params = $request->getQueryParams();

        if (!isset($params['token']) || empty($params['token'])) {
            die('to token !');
        }

        $token = $this->authService->parseToken($params['token']);

        if (empty($token)) {
            die('to token !');
        }

        $account = $this->accountRepository->getAccount(['id' => $token->uid]);

        if (empty($account)) {
            die('no user !');
        }

        if ($account === null) {
            return $this->responseFactory->createResponse(
                StatusCodeInterface::STATUS_NOT_FOUND,
                sprintf('Album with ID %s not found!', $token->uid)
            );
        }

        $request = $request->withAttribute('account', $account);
        return $this->handler->handle($request);
    }
}

AuthenticationHandler ( or another handler for example logout or update profile )

<?php

namespace User\Handler;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthenticationHandler implements RequestHandlerInterface
{
    /** @var ResponseFactoryInterface */
    public $responseFactory;

    /** @var StreamFactoryInterface */
    public $streamFactory;

    public function __construct(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory)
    {
        $this->responseFactory = $responseFactory;
        $this->streamFactory   = $streamFactory;
    }

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $account = $request->getAttribute('account');

        $body = $this->streamFactory->createStream('The name of the user is: ' . $account->getName());
        return $this->responseFactory->createResponse()->withBody($body);
    }
}

Questions:

  1. I use Laminas\Diactoros\StreamFactory in middleware and as Psr StreamFactoryInterface in the handler, it true?

Please create a new thread for this question. This will also help others to find the question and the answers.
Thanks in advance! :+1:t3:

The same here: please create a separate thread for this question. Thanks!

Thanks, Ok I will create it tonight

Best