Router::connect('(?!' . $admin . '|' . $prefix . '|login|contact)(.*)', array('controller' => 'wild_pages', 'action' => 'view', 'plugin' => 'wildflower'), array('$2'));If you notice this route will basically connect everything that is not admin, prefix, login, or contact with the generic Wildflower view controller.
Advantage:
The advantage of having a connect string like the one above is so that we can have dynamic content directly after the URL in the site. Normally the dynamic content would point to something like /pages/name-of-the-article, so the link would look like:
http://localhost/pages/name-of-the-articleHowever with the route above, everything that is not defined will point to the pages controller, allowing you to skip the /pages/ in the URL. For example, the url above can now be written:
http://localhost/name-of-the-articleThis makes it nicer when dealing with dynamic content...
The Problem:
Since Wildflower is a plugin, it is an addition to my normal application. Let's say my normal application has 2 controllers: foo_controller and bar_controller.
Normally in CakePHP, the routes for foo and bar would be automagic. This means that by default if I point my browser to http://localhost/foo/index it will automatically load the controllers/foo_controller.php, and look for the function index() definition. Otherwise it will throw an error.
With the route above, my "foo" controller will not load unless I specifically define a "foo" route to point to the foo controller before the Wildflower route:
Router::connect('/foo/*', array('controller'=>'foo', 'action'=>'index');Well I don't want to have to define 1 or more routes for every controller I build in my application. I want the automagic to still work.
Router::connect('(?!' . $admin . '|' . $prefix . '|login|contact)(.*)', array('controller' => 'wild_pages', 'action' => 'view', 'plugin' => 'wildflower'), array('$2'));
Solution:
There is a solution for this problem. It is a bit tricky, but Cake PHP is flexable enough to handle it. The solution is to grab only a list of the pages that you want available for the routing, and only assign those routes. This will remove the "catch-all" route from above and allow us to create the normal automagic routes for my application.
But how do you get a list of the pages from the database when the routes have no access to the databse when they're called?
The answer is the object method: requestAction(). requestAction can be called anywhere in the system and it can call any current route. The results of the requestAction call is an array of returned results. Since the router extends object, it has access to call it, and therefore can gain access to dynamic data.
Here's an example:
// Set a temporary routeThe next step is simply to add function get_root_pages() in your pages controller. It would simply find all the active pages with a parent == 0.
Router::connect('/pages/get_root_pages', array('controller' => 'wild_pages', 'action' => 'get_root_pages', 'plugin' => 'wildflower'));
// Now request that temporary route.
$root_pages = Router::requestAction('/pages/get_root_pages');
// Loop through the root pages and manually define the pages.
foreach($root_pages as $i => $page) {
Router::connect('/' . $page['WildPage']['slug'], array('controller' => 'wild_pages', 'action' => 'view', 'plugin' => 'wildflower'));
}
The disadvantage of this method is that the Cake system is called 2 times for every request, however this can be alieviated with Caching. If you store the results of root_pages in the /tmp folder, you can build a caching system that will check to see if the file is outdated, and only load the requestAction() on such an occasion. Of course then you would store the file again.
Summary:
With this solution, you will not only have root level slugs (i.e. http://localhost/this-is-my-page) but also you will not need to modify routes every time you add a new controller to your system. The only disadvantage would be if a slug is called the same thing as your controller. In that case you simply decide ahead of time which has the priority, and the route will hit the first one that is decalred.
Links:
Learn more about Wildflower CMS.