For clarification: I'm still undecided about the usefulness of the two 
modifier interfaces (described in this thread as "$request = $foo
->modify($request);" and "$response = $foo->modify($response);"). I've 
added them to the hms proposal 
<https://github.com/http-message-strategies-interop/fig-standards/blob/http-message-strategies/proposed/http-message-strategies/http-message-strategies-meta.md>
 to 
make them discussable and to explore their pros and cons. As Rasmus 
suggested, they will be removed within the next few days because the 
ActionInterface/HandlerInterface can stand on its on.

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:

$application = pipe([
    ErrorHandlerMiddleware::class,
    ForceHttpsMiddleware::class,
], prefix([
    '/api/' => pipe([
        HttpAuthenticationMiddleware::class,
    ], router([
        '/api/articles' => /* controller */,
        '/api/articles/{id}' => /* controller */,
    ])),
    
    '/' => pipe([
        MaintenanceModeMiddleware::class,
        SessionMiddleware::class,
        DebugBarMiddleware::class,
    ], router([
        '/' => /* controller */,
        '/article/{id}' => /* controller */,
    ])),
])); 

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.

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.

Thus, using $next to signal "404 Not Found" is bad for many reasons:
1. 404 is one error of many, e.g. what about routing related errors like 
"405 Method Not Allowed" and "415 Unsupported Media Type"?
2. What kind of *final handler* do I need to dispatch middlewares? For 
router middlewares I probably want a *NotFoundHandler*, but for a 
controller action I probably want a handler which returns a plain response 
object.
3. Because of 2., you need some conventions, i.e. framework specific 
conventions(!), which means it would neither be possible to reuse your 
'/api/' middleware stack across multiple frameworks nor and more 
importantly your RouteMiddleware itself.
 

> 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.
Zend Expressive and Zend Stratigility:

$app->pipe('/', function (ServerRequestInterface $request, DelegateInterface 
$delegate) {
    return $delegate->process($request);
});

$app->pipe('/', function (ServerRequestInterface $request, DelegateInterface 
$delegate) {
    $response = new Response();
    $response->getBody()->write('Wtf?');
    return $response;
});

Zend Expressive is based on Stratigility and returns a 404 for '/'. 
Interestingly, Zend Stratigility itself returns a 200 (content: 'Wtf?') – 
yes, exactly the same code snippet can be used in both frameworks.
IMO, these setups are hard to debug, and to me, it is another reason why I 
dislike routers/controllers which call $next: I can never be sure what 
$next will return (without further knowledge about the framework).

-- 
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/9fb17b11-95da-4b42-9737-e4464b5c090f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to