I have a cakephp plugin that creates image thumbnails.
Currently, thumbnails are "served" by an action of a controller that returns a file as response (here).
This is the route:
Router::plugin(THUMBER, ['path' => '/thumb'], function (RouteBuilder $routes) {
$routes->get('/:basename', ['controller' => 'Thumbs', 'action' => 'thumb'], 'thumb')
->setPatterns(['basename' => '[\w\d=]+'])
->setPass(['basename']);
});
So the url are these (the thumbnail basename is encoded):
/thumb/ZDc1NTYyMGY1N2VmMzRiNTQyZjE0NTY2Mjk0YWQ2NTFfNGIyYTBkMjVhMTdjZTdjN2E4MjVjY2M1YWU1ODNhMzcuZ2lm
Now I'm trying to replace the controller with a middleware.
This is quite simple, because basically it would work like the AssetMiddleware
and the __invoke()
method is almost like the old action method:
class ThumbnailMiddleware
{
use ThumbsPathTrait;
public function __invoke($request, $response, $next)
{
if ($request->getParam('_name') !== 'thumb' || !$request->getParam('basename')) {
return $next($request, $response);
}
$file = $this->getPath(base64_decode($request->getParam('basename')));
if (!is_readable($file)) {
throw new ThumbNotFoundException(__d('thumber', 'File `{0}` doesn\'t exist', $file));
}
$response = $response->withModified(filemtime($file));
if ($response->checkNotModified($request)) {
return $response;
}
return $response->withFile($file)->withType(mime_content_type($file));
}
}
This works very well.
The problem is that it now works because this middleware takes the controller's route and "intercepts" the request, "resolving" it without going through the controller (see the first three lines of the __invoke()
method).
Now I would like to rewrite that route and untie it from the controller, which I should totally eliminate from the plugin.
Obviously it works well like this (the second parameter is null
):
$routes->get('/:basename', null, 'thumb')
->setPatterns(['basename' => '[\w\d=]+'])
->setPass(['basename']);
Or I could just call the RouteBuilder::fallback()
method and analyze the url of the request (as it happens for the AssetMiddleware
).
But I was wondering if there is a way to link a route only to a middleware and explicitly for a middleware. Or, if not, what is the best method. I know that I can apply "middleware to specific routing scopes" (cookbook), so I'm wondering if this is definitely the correct formula:
Router::plugin(THUMBER, ['path' => '/thumb'], function (RouteBuilder $routes) {
$routes->registerMiddleware('thumbnail', new ThumbnailMiddleware);
$routes->applyMiddleware('thumbnail');
$routes->get('/:basename', null, 'thumb')
->setPatterns(['basename' => '[\w\d=]+'])
->setPass(['basename']);
});