Taking Advantage of the Pages Controller
Looking for a few tips on how to make the Pages Controller your new friend? Out-of-the-box it automatically maps incoming requests to their views, sets the page title, and even handles sub-pages well. But wait, there's more!
Looking for a few tips on how to make the Pages Controller your new friend? Out-of-the-box it maps incoming requests to their views, sets the page title, and even handles sub-pages well. But wait, there's more!
Of course, we could manipulate the pages controller in it's default location (/cake/libs/controller/pages_controller.php), but then we would probably forget the next time we update Cake to its latest version. Instead, let's copy it into our /app/controllers directory. Now we can change it all we want, and it will always be with us.
Sure, it's nice that our about page maps to /pages/about and our contact page to /pages/contact. But what if we have to get rid of the /pages/ business? Assuming that pages is our default, catch-all, controller, this should work:
Download code
Now we're "cooking with gas" and we have our beloved /about and /contact urls without having to map every single page in the router. What's next? What if we need some custom controller action before our contact page? All we have to do is add one line to the display() function.
Works like magic! Now, if you have a contact() function in your controller, it will first process any logic you have before calling the view.
Got any more snazzy ways to jazz up the Pages Controller?
Initial Installation
Of course, we could manipulate the pages controller in it's default location (/cake/libs/controller/pages_controller.php), but then we would probably forget the next time we update Cake to its latest version. Instead, let's copy it into our /app/controllers directory. Now we can change it all we want, and it will always be with us.
Ultra Clean URLs
Sure, it's nice that our about page maps to /pages/about and our contact page to /pages/contact. But what if we have to get rid of the /pages/ business? Assuming that pages is our default, catch-all, controller, this should work:
Download code
$Route->connect('/*', array('controller' => 'pages', 'action' => 'display'));
Give Control to the Controller
Now we're "cooking with gas" and we have our beloved /about and /contact urls without having to map every single page in the router. What's next? What if we need some custom controller action before our contact page? All we have to do is add one line to the display() function.
Controller Class:
Download code
<?php
function display() {
...
// add this snippet before the last line
if (method_exists($this, $page)) {
$this->$page();
}
// here's the last line
$this->render(join('/', $path));
}
?>
Works like magic! Now, if you have a contact() function in your controller, it will first process any logic you have before calling the view.
Got any more snazzy ways to jazz up the Pages Controller?
Comments
Comment
1 little improvements
Personally i choose to just call a loadContent function that performs a switch($page) instruction to do logic for a page if needed.
Your trick is very neat, but you run the risk of having a page called the same of one of your avaiable (other) functions. (app/pages/display for example)
That's why maybe you could add a prefix like this:
PHP Snippet:
<?php$function = 'pages_'.$page;
if (method_exists($this, $function)) {
$this->$function();
}
?>
Comment
2 Good points
Isn't that already a possibility in Cake? For instance, if I have an Articles controller, and I go to /articles/redirect/some_encoded_url, won't that call the redirect() function of the Controller? Your fix works well for the Pages controller, but there should be a way that protected, internal functions aren't callable through the url in all controllers.
Comment
3 Route placement
Comment
4 Spaces in the title
$title = Inflector::humanize(Inflector::underscore($title));
Question
5 overriding index()
I'd like my content pages (about/faq/contact) to use the pages controller,
but for functional pages, I have a controller with an index method
example.com/users should load the index() in users_controller instead of having to create a users.thtml in the pages dir
Comment
6 Nice Work
Comment
7 If you have admin routing you should do the following..
$Route->connect ('(?!admin|items|images)(.*)', array('controller'=>'pages', 'action'=>'display'));
Else the wildcard will knock out your admin routing..
Comment
8 Ummmm....
Well, have you ever actually tried that? Here, I'll spoil the surprise and tell you what actually happens: it doesn't work. Access to native Controller object methods is disabled at the Dispatcher level.
Comment
9 Nice