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.