简体   繁体   中英

Zend Expressive - Best way to inject middleware

I am currently learning zend expressive and I can see a couple of options as to how to access middleware within routes/actions.

In the expressive skeleton application, there is a HomePageFactory where the container is injected, then the router, template engine etc are pulled from the container and a new HomePageAction class is constructed using these and returned.

For example:

class HomePageFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $router   = $container->get(RouterInterface::class);
        $template = ($container->has(TemplateRendererInterface::class))
            ? $container->get(TemplateRendererInterface::class)
            : null;

        return new HomePageAction($router, $template);
    }

I then needed a flash messenger and came across the following:

class SlimFlashMiddlewareFactory
{
    public function __invoke($container)
    {
        return function ($request, $response, $next) {
            // Start the session whenever we use this!
            session_start();

            return $next(
                $request->withAttribute('flash', new Messages()),
                $response
            );
        };
    }
}

So this is slightly different and is adding the middleware to the request via an attribute. Which can then be retrieved where its needed by something like:

$flashMessenger = $request->getAttribute('flash');

So really my question is what are the advantages/disadvantages of these two methods of getting the FlashMessenger into the action?

If I have a UserService which deals with retrieving users from a database and therefore may be needed in multiple actions/routes, would I be better off modifying the HomePageAction & Factory (and any others that need it) to accept the UserService?

ie

class HomePageFactory
    {
        public function __invoke(ContainerInterface $container)
        {
            $router   = $container->get(RouterInterface::class);
            $template = ($container->has(TemplateRendererInterface::class))
                ? $container->get(TemplateRendererInterface::class)
                : null;
            $userService = $container->get(App\UserService::class);

            return new HomePageAction($router, $template, $userService);
        }

Or would I be better to go with how the FlashMessenger works (which seems a bit easier to manage) and add it to the request via an attribute to access it that way where needed?

ie

$userService = $request->getAttribute('UserService');

I'm wondering if there are any performance issues with the latter option, although I do understand that it could be done in this way only for specific routes rather than the UserServer being application wide.

My gut feeling (after writing out this question) is that really, this is a Service and not true middleware so I should really be Modifying the HomePageAction & Factory and adding the UserService that way rather than doing what seems easier and using the attribute ala FlashMessenger. But it would be very handy if a guru could help clarify this.

Many thanks in advance.

I don't know about performance differences since I haven't tested this. But I guess the question you need to ask yourself is what does the class do? Is it needed by other middleware before or after invoking the Action class or do you need it only in the Action class or somewhere else in the application.

In your case the UserService might take care of registering or updating an user. That stuff would be injected with the ActionFactory as your gut feeling tells you. However for authentication it would be different if that is done with middleware. First you need that class in your authentication middleware which you can pass on to your authorisation middleware with the request (or maybe only pass the authenticated user object, that's what I do).

So I guess the rule of thumb is that if something is needed to change the incoming Request or outgoing Response before / after the Action, you pass it on with the Request, otherwise inject it in the Action with a Factory.

If you start passing everything around with a Request, it will be very hard to keep track of. I find it much easier to inject as much as possible into the Action itself because then I can easily see what is needed inside that class and I can test it easier.

Things like a flash messenger, session and the authenticated user I would inject in the request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM