CakePHP 3.0
I'm getting a "Missing Route" error for a route that exists.
Here are my routes:
#my admin routes...
Router::prefix('admin', function($routes) {
$routes->connect('/', ['controller'=>'Screens', 'action'=>'index']);
$routes->connect('/screens', ['controller'=>'Screens', 'action'=>'index']);
$routes->connect('/screens/index', ['controller'=>'Screens', 'action'=>'index']);
//$routes->fallbacks('InflectedRoute');
});
Router::scope('/', function ($routes) {
$routes->connect('/login', ['controller' => 'Pages', 'action' => 'display', 'login']);
$routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
$routes->fallbacks('InflectedRoute');
});
Plugin::routes();
Basically I just added the top section (for admin routing) to the default routes that come out of the box.
When I visit /admin/screens/index I see the following error:
Notice the error message says:
Error: A route matching "array ( 'action' => 'add', 'prefix' =>
'admin', 'plugin' => NULL, 'controller' => 'Screens', '_ext' => NULL,
)" could not be found.
...which is strange because I am not trying to access the add action. The params printed below look correct.
What is going on?
Take a closer look at the stacktrace, the error dosn't occour in the dispatching process, which you seem to think, it is being triggered in your view template, where you are probably trying to create a link to the add action, and reverse-routing cannot find a matching route, hence the error.
The solution should be obvious, connect the necessary routes, being it explicit ones like
$routes->connect('/screens/add', ['controller' => 'Screens', 'action' => 'add']);
catch-all ones
$routes->connect('/screens/:action', ['controller' => 'Screens']);
or simply the fallback ones that catch everything
$routes->fallbacks('InflectedRoute');
This work for me in case of use prefix admin :-
Router::prefix('admin', function ($routes) {
// Because you are in the admin scope,
// you do not need to include the /admin prefix
// or the admin route element.
$routes->connect('/', ['controller' => 'Users', 'action' => 'index']);
$routes->extensions(['json', 'xml']);
// All routes here will be prefixed with `/admin`
$routes->connect('/admin', ['controller' => 'Order', 'action' => 'index']);
// And have the prefix => admin route element added.
$routes->fallbacks(DashedRoute::class);
});
Related
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 I have to remove exclude it, I have to create a route like this/ And so on to the other controller to access.
There is no need to specify every controller/name in the pattern, instead you can create all your specify routes first and then place the following route below them to catch all unmatched routes.
$routes->connect(':/prefix/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
And maybe another one without prefix
$routes->connect('/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
And since you mentioned that you are using 3.3.* cake version, Your routes can be written taking advatage of routes scoping
Router::prefix('website', function ($routes) {
// All routes here will be prefixed with `/prefix`
// And have the prefix => website route element added.
$routes->fallbacks(DashedRoute::class);
$routes->connect(
'/:slug',
['controller' => 'Brands', 'action' => 'index']
);
$routes->connect(
':slug/*',
['controller' => 'Products', 'action' => 'index']
});
I'm trying to load the VideoController.php when url.com/video/ is called.
Here is a piece of code from my routes.php
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/video/*', ['controller' => 'Video', 'action' => 'display']);
...
$routes->fallbacks(DashedRoute::class);
});
The result is '404 not found'
EDIT:
Inside Router::scope I have also this piece of code:
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
When I change the Pages value into Video, the VideoController is called. So how come when I change the '/' into '/video/*' it doesn't work?
Maybe it's something with the scope function parameters?
Enabling URL rewriting from the httpd.config file solved the problem.
cakephp documentation
Why iam getting a "Missing Route" error for a function that not exists.
Inside Reservations Controller I have function add with one argument:
public function add($carid = null)
{
...
}
Matching route:
Router::scope('/', function ($routes) {
Router::connect('/rentcar/:id', ['controller' => 'Reservations', 'action' => 'add'],['pass' => ['id'], 'id' => '[0-9]+']);
// rest of the routes not important
...
});
Plugin::routes();
When I visit any page I see the following error:
http://i.stack.imgur.com/ESX5I.jpg
The error message says:
Error: A route matching "array ( 'controller' => 'Reservations',
'action' => 'add', 'plugin' => NULL, '_ext' => NULL, )" could not be
found.
...which is strange because I dont have function add() without arguments, instead, I have function add($carid) with one argument.
But when i add that route, everything works fine:
Router::connect('/rentcar2', ['controller' => 'Reservations', 'action' => 'add']);
What is going on?
The problem was in commented out HTML code which contains PHP code inside, code like this one:
<!-- <li role="presentation"><?= $this->Html->link(__('New Reservation'), ['controller' => 'Reservations', 'action' => 'add']) ?></li> -->
Which contains my old function without arguments add of Reservations Controller.
I deleted any similar code and everything worked fine.
Router::scope('/:club_slug', function ($routes) {
$routes->connect('/login', ['controller' => 'Users', 'action' => 'login']);
});
So when I'm trying access http://example.com/club-name/login, I'm being redirected to http://example.com/users/login with the flash message You have to login to access this area.
Auth loginAction is [controller => 'Users', 'action' => 'login'], since the custom route that I mentioned at beginning of the question is pointing to the path that is specified at loginAction I thought the route will know that I'm talking about the same thing but is not what is happening.
Dynamic route elements are not being added/recognized automatically, you'll either have to persist them using either the persist option (applies only to that specific route):
Router::scope('/:club_slug', function ($routes) {
$routes->connect(
'/login',
['controller' => 'Users', 'action' => 'login'],
['persist' => ['club_slug']]
);
});
or URL filters (affects all routes that are using a club_slug element):
Router::addUrlFilter(function ($params, $request) {
if (isset($request->params['club_slug']) && !isset($params['club_slug'])) {
$params['club_slug'] = $request->params['club_slug'];
}
return $params;
});
or you have to pass the element to your login action manually (this would match the club_slug route regardless of the current URL):
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
'club_slug' => 'club-slug' // wherever it may have come from
]
See also
Cookbook > Routing > Creating Persistent URL Parameters
API > Cake\Routing\RouteBuilder::connect()
I have admin routing enabled. How can I set routing, to make http://website.com/admin go to posts/admin_index?
I've got this:
Router::connect('/', array('controller' => 'posts', 'action' => 'index'));
But it doesn't seem to work. I get this error (when going to http://website.com/admin):
Missing Controller
Error: Controller could not be found.
Error: Create the class Controller below in file: app/controllers/controller.php
<?php
class Controller extends AppController {
var $name = '';
}
?>
Try a route with:
Router::connect('/admin', array('controller' => 'posts', 'action' => 'index', 'admin' => true));
The default route '/' does not match the URL '/admin', admin routing enabled or not.