Sammaye Sammaye - 7 months ago 50
reST (reStructuredText) Question

CaekPHP 3 make resource routes work with and without params

I have some code in my routes file:

Router::scope('/v1', function (RouteBuilder $routes) {
$routes->resources( 'Files');
});


And then a FilesController with a delete function like:

public function delete($id){
echo "here"; exit();
}


When I do:

DELETE http://192.168.1.197/v1/files/1


The response is
here
, however, if I do:

DELETE http://192.168.1.197/v1/files


The response is that it is missing the V1Controller.

What I would expect instead is for CakePHP to turn around and say "oops, you have passed the wrong number of required parameters".

Something very weird seems to be going on here and I am not quite sure what. How can I make the two do the same thing and point to the controller?

Answer Source

CakePHP operates very differently on exceptions when debug mode is enabled. When debug is true all exceptions are rendered with debug information, stack tracing and developer friendly messages.

When debug mode is false the exception is rendered as a standard HTTP response type. With handles for 400 and 500 error codes.

When the router can't find a match for a route there is no controller involved. The HTTP request never gets past the dispatching phase. It's the dispatcher that throws a 400 type exception.

In your given example the framework is throwing a MissingControllerException with the HTTP code of 404.

400 error codes are rendered via the ErrorController. CakePHP comes a with a default error controller, but if you generate a new application using the composer template, then you should have a default ErrorController in your app's controller holder.

In your templates there should be a src/Template/Error/error400.ctp file which displays the response for 400 codes. Keep in mind, that this template is not used when debug mode is enabled.

You can modify this template to find "closely" matching routes and offer them as recommendations to the user as feedback in the error message.

You can iterate all configured Routes easily like this:

    foreach (Router::routes() as $route) {
        $name = isset($route->options['_name']) ? $route->options['_name'] : $route->getName();
        $output[] = [$name, $route->template, json_encode($route->defaults)];
    }

Above taken from cakephp/src/Shell/RoutesShell.php:

Since this is technically a 404 error. There is no matching route and what you can do is try to find routes that are "close" to a match. The problem here is that you are subject to the same route matching challenges as the Router class.

The Router class uses dynamic routing techniques that take parts of the URL parameters and fills them in as names of controllers, names of actions and user defined parameters.

This can change significantly depending upon what kind of default router class you are using.

For example, you might be using the DashedRoute routing class which does the following:

/**
 * This route class will transparently inflect the controller, action and plugin
 * routing parameters, so that requesting `/my-plugin/my-controller/my-action`
 * is parsed as `['plugin' => 'MyPlugin', 'controller' => 'MyController', 'action' => 'myAction']`
 */
class DashedRoute extends Route

You might instead be using the InflectedRoute routing class which does the following:

/**
 * This route class will transparently inflect the controller and plugin routing
 * parameters, so that requesting `/my_controller` is parsed as `['controller' => 'MyController']`
 */
class InflectedRoute extends Route

Since there are cases where routing could be using dynamic routing. It's not possible to know if a URL segment is a controller, action or named parameters.

Add to the complexity that you're also using a scoped segment named /v1 it becomes even more challenging to predict what the intended route is.

You can either create custom routes to catch these edge cases and render an informative error message, or you can try to add logic to the error400.ctp to display a more informative error message.

There is also a final option. Where CakePHP allows you to write your own custom Route classes, and/or modify the middleware with your own dispatcher.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download