Taking Advantage of the Pages Controller

By Joel Stein (joelstein)
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!

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 57

CakePHP Team Comments Author Comments
 

Comment

1 little improvements

Instead of putting it in /app you could better put it in /app/controllers/ (afaik only app_model.php and app_controller.php should be put in /app)

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();
  } 
?>
Posted Sep 25, 2006 by Dieter Plaetinck
 

Comment

2 Good points

Dieter, good points. I made the change regarding the /app/controller directory... slight oversight!

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)

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.
Posted Sep 25, 2006 by Joel Stein
 

Comment

3 Route placement

Just for reference, you should place the /* route LAST in your routes file or it will override all of the other routes.
Posted Oct 22, 2006 by Luke Sheridan
 

Comment

4 Spaces in the title

To change MyCoolPage to My cool page

$title = Inflector::humanize(Inflector::underscore($title));
Posted Nov 5, 2006 by David Lloyd
 

Question

5 overriding index()

how do you keep it from overriding an index() method for a controller?

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

Posted Dec 31, 1969 by reversefolds
 

Comment

6 Nice Work

I know it sounds kind of lame, but I'm new to cake so this actually helped for what I had in mind. I needed to process my logic in my controller before rendering my page. Thanks a bunch!!!
Posted Dec 31, 1969 by Anthony White
 

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..
Posted Apr 16, 2007 by Gerhard Sletten
 

Comment

8 Ummmm....

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.

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.
Posted May 2, 2007 by Nate
 

Comment

9 Nice

This maked my day. finaly I have nice looking url's
Posted Dec 19, 2007 by Christher Lenander