Hi Michael, those are interesting points, my answers inline:

On Sunday 21 may 2017 10:43:57 UTC+2, Michael Mayer wrote :
>
>
> On Saturday, May 20, 2017 at 10:33:33 PM UTC+2, Matthieu Napoli wrote: 
>
>> Rasmus:
>>
>> I can see the handler-interface having 3 uses in the context of PSR-15:
>>> …
>>> 3. As type-hint for the "final" handler supported by many dispatchers.
>>
>> 3. I agree this is a bit of an ugly detail and it would be better if we 
>> could do without, but honestly this is just a detail, and it works, and 
>> it's not really a practical problem, I don't see how a PSR would matter here
>>
>
> That PSR would also allow interop of routers, controllers and final 
> handlers, and indeed solve practical problems, e.g. if you use it with your 
> pipe function:
>
> // diff in pseudo code:
> - function pipe(MiddlewareOrHandler[] stack) : Middleware {}
> + function pipe(Middleware[] stack, Handler $final) : Handler {}
> - function router(array routes) : Middleware {}
> + function router(array routes) : Handler {}
>
> Thus you do not need to fabricate handlers like the one at your 
> Router::dispatch 
> <https://github.com/stratifyphp/router/blob/779a77b6b8078fa3cb2fe86a3361c43b06df94e0/src/Router.php#L83-L85>,
>  and 
> the code of your example becomes bit more explicit:
>
> […]
>
> As you can see, there is no essential difference for the end user setup. 
> Although, we do not need to create those meaningless $next delegates: the 
> prefix and router functions return them.
>

That's an interesting solution and yes it makes sense. However it is more 
limiting than the solution where *everything is a middleware*. When you 
have middlewares and handlers you can't add a handler into a middleware 
pipe. You are forced to put it as the "last handler". This is less 
interoperable.

You cannot, for example, do this:

$application = pipe([
    ErrorHandlerMiddleware::class,

    // Resolve the controller and store it in the request
    router([
        '/' => /* controller */,
        '/article/{id}' => /* controller */,
    ]),

    Firewall::class,
    ControllerDispatcher::class, // actually invoke the controller
]); 

In the example above the controller dispatcher (or "invoker") is extracted 
from the router so that we can put middlewares in-between them, for example 
here to check permissions to access to each route.

Yes, the dispatcher could be the final handler, but my point is that the 
separation between handlers and middlewares is fuzzy, there are plenty of 
scenarios where a handler could actually be used as a middleware, so most 
handlers might actually need to implement both interfaces.

To sum up more clearly:

- MiddlewareInterface: standard for interoperability
- HandlerInterface: standard just because "this is a common signature"

IMO the middleware interface is the key for interoperability.

 

>
> And yes the router will be invoked with a $next, but IMO that's a good 
>> thing: the router can call $next if the URL doesn't match any route 
>> <https://github.com/stratifyphp/router/blob/master/src/Router.php#L58-L63>. 
>> That allows, for example, to use several routers in a single pipe (e.g. if 
>> you have modules).
>>
>
> I disagree, that's not a good thing, this means $next would be used 
> differently by different middlewares:
> For example for your HttpAuthenticationMiddleware, calling $next means: 
> *everything 
> is fine*; lets carry out the real task and if that fails I will try to 
> handle that.
> For the router you're suggesting, calling $next means: *something went 
> wrong*; lets delegate the task to someone else and if that fails I do not 
> care.
>

Nope that's not what I'm saying. Here is an example to illustrate:

$application = pipe([
    // Module
    Blog::class,

    // Routes of my application
    router([
        '/' => /* controller */,
        '/article/{id}' => /* controller */,
    ]),
]); 

The "Blog" module could be a router (or a pipe, we don't really care) that 
provides "blog" routes. Imagine also all the modules/bundles that provide 
authentication routes (login/logout, OAuth), asset routes (Glide comes to 
mind), whole application parts (e.g. SonataAdminBundle), etc. The router of 
that module simply calls $next if no route matched.

Calling next means: I delegate handling the request.

It doesn't intrinsically mean something went right (authentication) or 
wrong (404 not found).


And by the way this is a bit what Slim and IIRC Zend Expressive do: route 
>> handlers can be controllers or can be pipes, that's how you can add "route 
>> middlewares" (I hope I'm not wrong here).
>>
>
> Slim controller actions 
> <https://www.slimframework.com/docs/concepts/middleware.html#how-do-i-add-middleware>
>  are 
> not middlewares, they get an $args argument instead of a $next.
>

Slim routes are actually middleware 
pipes: https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L26 


-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to php-fig+unsubscr...@googlegroups.com.
To post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/226ea3b4-c516-4448-89e7-8bd37e0094f7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to