Using CakePHP v3.3.16
I want to write a fallback route in such a way that if URL is not connected to any action then it should go to that fallback.
Created routes for SEO friendly URL like this
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
But it's also inclute all the controller actions in it so if i try to call a controller ex: cart/index it's going to website/brands/index/index
If I have to remove exclude it, I have to create a route like this/
$routes->connect('/cart',['controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
And so on to the other controller to access.
Example: I have a controller CartController action addCart
CASE 1
if I access URL my_project/cart/addCart/
It should go to cart controller action
CASE 2
if I access URL my_project/abc/xyz/
and there is no controller named abc so it should go to BrandsController action index
My Current routes.php looks like this
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['prefix'=>'website','controller' => 'Home', 'action' => 'index']);
$routes->connect('/trending-brands', ['prefix'=>'website','controller' => 'Brands', 'action' => 'trending']);
$routes->connect('/users/:action/*',['prefix'=>'website','controller' => 'Users'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart/:action/*',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(':controller', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->connect(':controller/:action/*', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('website', function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});
Plugin::routes();
Your edits totally invalidate my first answer, so I decided to just post another answer.
What you want to achieve can not be done by the router because there is no way for router to tell if the controller/action exists for a particular route. This is because the router just work with url templates and delegates the task of loading Controllers up in the request stack.
You can emulate this feature though by using a Middleware
that check if the request attribute params
is set and then validate them as appropriate and changing them to your fallback controller if the target controller doesn't exist.
Just make sure to place the RoutingMiddleware
execute before your middleware otherwise you will have no params to check because the routes wouldn't have been parsed.
Middlewares implement one method __invoke()
.
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Cake\Http\ControllerFactory;
use Cake\Routing\Exception\MissingControllerException;
class _404Middleware {
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
//$params = (array)$request->getAttribute('params', []);
try {
$factory = new ControllerFactory();
$controller = $factory->create($request, $respond);
}
catch (\Cake\Routing\Exception\MissingControllerException $e) {
// here you fallback to your controllers/action or issue app level redirect
$request = $request->withAttribute('params',['controller' =>'brands','action' => 'index']);
}
return $next($request, $response);
}
}
Then attach in your App\Application
see also attaching middlewares
$middlewareStack->add(new _404Middleware());
please remmber to clean up the code as I didn't test it under real dev't enviroment.
After thought: if your were looking to create an error page for all not found resources, then you don't need all that, instead you would just customise the error template in Template/Error/error404.ctp
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With