I added CakeDC-Users plugin in app/plugins.
Now for http://example.com/ , if i click the home/index link, it wrongly redirects to http://example.com/users/posts/index , but it should be http://example.com/posts/index .
Why is the plugin 'users' always added before the respective controller?
If i delete the CakeDC-Users plugin from app/Plugin and delete that line CakePlugin::loadAll(); from bootstrap.php then i get normal link/route
routes.php:
Router::connect('/', array('controller' => 'posts', 'action' => 'index'));
How can i fix that problem addin CakeDC-Users plugin
That is the way how plugins are accessed. You can define your custom route this way
Router::connect('/posts', array('controller' => 'posts', 'plugin' => 'users'));
This will be done in app/Config/routes.php
if it is for link issues you will have to explicitly specify
echo $this->Html->link('link', array(
'controller' => '',
'action' => '',
'plugin' => false)
);
But i would prefer custom routing.
For more info, you can always sneak into the CookBook
Related
A bit of an obscure question, I think. I've successfully set up the language prefix for all of my routing rules to handle localization. Everything works great when a user requests controllers which exist in the application (e.g., /users/view/4). In my AppController I have the application successfully redirect any requests which are missing a language prefix to a URL that has one (e.g., /eng/users/view/4).
The problem arises when a user requests an invalid controller. In this case, after redirecting the user, the application throws a MissingControllerException (which it should) but the controller it reports as invalid is the language prefix itself (e.g., "EngController"), not the controller that comes after this in the request URI.
This indicates that in an error state, the Cake application is no longer aware of any language prefix routing. This suggests I need to add another routing rule to routes.php which will target only invalid requests and ensure that a language prefix is expected and accounted for in any requests which are handled by CakeErrorController (which is the core controller that takes over for these types of exceptions).
But I've scoured the docs and I have no idea how to craft such a route. Thanks for your help!
Here is my routes.php file:
<?php
$lang_settings = ['language' => '[a-z]{3}'];
// ElStats homepage vs tenant homepage
if(!TENANT) {
Router::connect('/', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
Router::connect('/:language', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
} else {
Router::connect('/', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
Router::connect('/:language', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
}
/**
* ...and connect the rest of 'Pages' controller's urls.
*/
Router::connect('/:language/pages/*', ['controller' => 'pages', 'action' => 'display'], $lang_settings);
Router::connect('/:language/contests/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/contests/:action/*', ['controller'=>'contests'], $lang_settings);
Router::connect('/:language/contests/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/candidates/search/*', ['controller' => 'candidates', 'action' => 'index'], $lang_settings);
Router::connect('/:language/candidates/:action/*', ['controller'=>'candidates'], $lang_settings);
Router::connect('/:language/candidates/*', ['controller' => 'candidates', 'action' => 'index'], $lang_settings);
// If just /search, then default to /contests/search
Router::connect('/:language/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
/**
* Full-controller alias routing
*/
// ballot_questions => contests
Router::connect('/:language/ballot_questions/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/ballot_questions/:action/*', ['controller'=>'contests'], $lang_settings);
Router::connect('/:language/ballot_questions/*', ['controller'=>'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/admin/ballot_questions/:action/*', ['controller'=>'contests','admin' => true], $lang_settings);
Router::connect('/:language/admin/ballot_questions/*', ['controller'=>'contests', 'action' => 'index', 'admin' => true], $lang_settings);
// Admin Routing
Router::connect('/:language/admin', [ 'controller'=> 'pages', 'action'=> 'index','admin' => true], $lang_settings);
Router::connect('/:language/admin/:controller/:action/*',['admin' => true], $lang_settings);
Router::connect('/:language/admin/:controller/*',['admin' => true], $lang_settings);
Router::connect('/:language/:controller/:action/*',[], $lang_settings);
require CAKE . 'Config' . DS . 'routes.php';
Edit: Update your router to use negative lookahead with the languages your application supports.
Here's an example regex:
^(?!(spa|eng|swe)){1}.*
Any route that doesn't start with spa, eng or swe, you'd redirect that to the controller and action of your choice.
In your router
Router::connect(
'/:language/candidates/search/*',
array('controller' => 'errorController', 'action' => 'index'),
array('language' => '^(?!(spa|eng|swe)).*')
);
You'll need this route pattern for every section, since the number of url parameters vary.
You can test regex with various online Regex tools. Here's that pattern with some test data to validate that it works.
Original post:
You may be overthinking this.
Your question is on how to add a route for a MissingController, something that only occurs when you're developing (in debug mode). In production this turns into 404.
Since showing a developer what is missing is what any proper framework should do (CakePHP included), you should not set out to write your own ExceptionHandler for these cases to try shoehorning some bizarre solution.
Instead, you should look at handling that 404, since, as said, once in production, that error message will default to a 404 error message.
Here's how the same (missing) route looks:
In Development mode:
In Production mode:
Handling a 404
If you want to display a 404, this question explains on how to customize this error page.
If you want to redirect somewhere when a 404 happens, you can do something like this (from this question):
To catch and handle 404 errors, you need to extend the ErrorHandler
class and override the error404 method. To do that, create the file
app/app_error.php with the following code:
class AppError extends ErrorHandler {
function error404($params) {
// redirect to homepage (or any page you like)
$this->controller->redirect('/');
}
}
Couple of side notes
To make it easier for yourself down the line, consider changing your routing schemes to include the language as a request parameter instead. Otherwise search engines (if your site should be indexes), will crawl your language pages, and that's not always what you want.
That means you'll have routes like this:
candidates/list?lang=eng
That way you can easier manage handling invalid language codes by doing i.e:
// In a controller
$languageCode = $this->request->params['lang'];
if (!in_array($language, ['eng', 'spa', 'swe'])) {
// Set a variable to view to display a wrong error code, or redirect to a default language.
}
Hope any of this made sense.
I am trying to make changes on a CakePHP cms site. I found "main_menu.cpt" file where is the main menu located. Following the existing menus I added my own:
<li>
<a href="<?=$html->url('/'.$lang.'/orders');?>"<?=($page=='orders')?'class="active" ':''?>>
<?__('orders')?>
</a>
</li>
which is pointing to file orders.php but when I click on the link I get this message:
Not Found
Error: The requested address '/en/orders' was not found on this server.
Where I must upload the file orders.php?
I know it sounds stupid, but this cms is totally new for me and even the directory structure doesn't help me :) Hope you will do it !
Thanks in advance
edit ################
<?php
Router::connect('/', array('controller' => 'dpages', 'action' => 'home', 'lang'=>'bg'));
Router::connect('/:lang/', array('controller' => 'dpages', 'action' => 'home'), array( 'lang' => 'bg|en'));
Router::connect('/:lang/pages/:action/*', array('controller' => 'dpages'), array( 'lang' => 'bg|en'));
Router::connect('/:lang/:controller/:action/*', array('action' => 'index'), array( 'lang' => 'bg|en'));
Router::connect('/pages/:action/*', array('controller' => 'dpages'));
Router::connect('/dpages/*', array('controller' => 'dpages', 'action' => 'view'));
Router::connect('/admin', array('admin'=>1, 'controller' => 'dpages', 'action' => 'home'));
Router::connect('/tests', array('controller' => 'tests', 'action' => 'index'));
?>
CakePHP is a framework.
You may need an OrdersController that has a view file for each method.
Check to see how the other pages are build (what files you have in the Controllers folder).
If you just want to add a content page, for orders, you can put it inside the View/Pages folder, and call it orders.ctp.
You can access it on site.com/pages/orders
Add the following line in Config/routes.php (among the other Router::connect lines)
Router::connect('/:lang/orders', array('controller' => 'dpages', 'action' => 'orders'), array( 'lang' => 'bg|en'));
Go to Controller/DPagesController.php and add:
public function orders() {
// can be blank for now
}
Go to views/dpages folder and create orders.ctp and put the static form in there.
Then try the link again.
CakePHP is not designed for you to add additional php files like that, nor should it be. Therefore I highly recommend that you rewrite whatever you have in your orders.php file to be use the CakePHP framework.
However, you can add orders.php into your app/Vendor folder, then include it in a controller's action (example: include_once(APP . 'Vendor/orders.php'); ). Then, you should be able to access it via http://yourwebsite.com/controller/action where controller is the name of the controller you chose to put the include in, and action is the name of the action you chose to put the include in.
So I started making the admin panel of our site as a plugin. And I'm able to redirect every request like domain.com/admin or domain.com/admin/users or domain.com/admin/pages/edit/5 - to the appropriate controller and action from the admin plugin.
Like this one:
Router::connect('/admin', array('plugin' => 'admin', 'controller' => 'index', 'action' => 'index'));
Router::connect('/admin/users/list', array('plugin' => 'admin', 'controller' => 'users', 'action' => 'list'));
But this means I will have to write separate route for almost each URL ??? or actually - for each action ... So - is there a way to set it globally? ...
For example:
Router::connect('/admin/users/*', array('plugin' => 'admin', 'controller' => 'users'));
Or even better:
Router::connect('/admin/*', array('plugin' => 'admin'));
Cause the last two examples didn't work at all ...
EDIT: the CakePHP version is the latest at the moment - 2.4.1.
Normally you shouldn't have to create such routes for plugins, the basic mapping works out of the box, ie in case your plugin is named admin, then /admin/users/list will automatically map to plugin admin, controller users, action list.
An exception is your /admin route, by default this would look for index on AdminController. So for mapping to index on IndexController you'll need a custom route like the one in your question:
Router::connect('/admin', array('plugin' => 'admin', 'controller' => 'index', 'action' => 'index'));
Apart from this it should work as is in case you don't have any other preceding rules that will override the default behaviour, something like Router::connect('/*', ...) for example. In case there are such rules and you cannot change them, then this is how you could connect the basic routes of your plugin:
Router::connect('/admin/:controller/:action/*', array('plugin' => 'admin'));
Router::connect('/admin/:controller/*', array('plugin' => 'admin', 'action' => 'index'));
Router::connect('/admin/*', array('plugin' => 'admin', 'controller' => 'index', 'action' => 'index'));
Note that this needs to be placed before the other routes that override the default behaviour!
See also http://book.cakephp.org/2.0/en/development/routing.html
On a side note, list as an action name will probably not work, this should throw a parser error as list is a reserved keyword. So you in case this isn't just an example you'll need an extra route for that if you want to use /list as the action name in the URL.
I have set up two routes, one is the default and the other is one to enable the admin section which has controllers in a sub-directory of the controller directory. These are how they look like:
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'Home',
'action' => 'index',
));
// Admin routes
Route::set('admin', 'admin(/<controller>(/<action>(/<id>)))')
->defaults(array(
'directory' => 'Admin',
'controller' => 'Main',
'action' => 'index',
));
When I navigate to /admin/ or /admin/main I get a 404 error and I can't get it to work. I've also named the classes in the admin sub-directory as Controller_Admin_Main so that should work, right?
Please provide examples to how this should be done correctly. Thank you very much! :)
The problem got fixed by switching the position of the admin route to above the default route in the code. I guess kohana matched the first expression and tried to show a view according to the default route.
I have an application that is essentially working until I tried to implement an Auth module for logins and registrations.
My application directory structure is basically:
application
-- classes
-- controller
-- admin
(admin area)
-- block
(blocks to display within pages)
-- page
(default pages)
By default I want to have URL's such as http://www.testsite.com/test which would access the Controller_Page_Test class. Or to explicitly call admin or block pages http://www.testsite.com/admin/test which would access the Controller_Admin_Test class. To further complicate matters it also needs to handle optional actions and id's.
I said at the top that this is basically working correctly - until I've tried to add in the Auth module. The Auth module calls http://www.testsite.com/user/login but instead of accessing the module's path via the default, it looks in the page directory.
To overcome this I placed a higher level route but now this has become my default page handler. Explicit calls still get through.
My routes currently look like this:
Route::set('user', '(<controller>(/<action>(/<id>)))', array('controller' => 'user|admin_user'))
->defaults(array(
'controller' => 'user',
'action' => 'index',
'id' => NULL,
));
Route::set('with_dir', '<directory>/<controller>(/<action>(/<id>))', array('directory' => 'block|admin'))
->defaults(array(
'directory' => 'page',
'controller' => 'home',
'action' => 'index',
));
Route::set('just_id', '<controller>(/<id>)', array('id' => '\d+'))
->defaults(array(
'directory' => 'page',
'controller' => 'home',
'action' => 'index',
));
Route::set('auto_dir', '<controller>(/<action>(/<id>))', array('id' => '\d+'))
->defaults(array(
'directory' => 'page',
'controller' => 'home',
'action' => 'index',
));
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'prototype',
'action' => 'index',
));
Can this be cleaned up any better? And how do I get this module to only kick in when I need it to?
Yes, it can be cleaned better. Kohana developers encourage people using this framework to add as much routes as needed. You can even specify them for each action which will enable you to change URLs in the future (eg. instead of /user/login you may wish to have /signin), if you use proper methods to generate links etc. (eg. Route::url() helper).
Now, saying that, here is the other way to specify the user route:
Route::set('user', '<controller>(/<action>(/<id>))', array('controller' => '(user|admin_user)'))
->defaults(array(
'controller' => 'user',
'action' => 'index',
));
Which will match only the requests, where the first part of the URI is given and is equal either to user or admin_user. Previously the controller part was optional, thus was also matching calls to / URI.