Easier Static Pages for CakePHP 1.2

This page is out of date. Please read the update.

Traditionally in a CakePHP application, to do static pages you have two options:

  1. Use the built-in Pages controller and either have all static pages reside in /pages/pagename or set up custom routes.
  2. Set up an empty action in a controller.

I didn't like either of those options.

With Nate Abele's help, I wrote up a custom error class that will check to see if a view exists for a missing action or missing controller/action combo. If it does, it'll render that view. This is pretty handy as it means that I can maintain a structure within the view folder that more closely matches the URL structure for the site.

The one current limitation of this right now is that it only accesses the beforeRender call on the AppController and not on a particular controller, if it exists.

Without further ado, here's the code:

class AppError extends ErrorHandler {

	function missingController($params)
	{
		$p = $this->_setupMissing($params);
		if(file_exists(VIEWS . DS . $p['controller'] . DS . $p['action'] . ".ctp"))
		{
			$this->controller->beforeRender();
			$this->controller->viewPath = $p['controller'];
			$this->controller->render($p['action'], $this->controller->layout, null);
		}else{
			$this->controller->viewPath ='errors';
			$controllerName = str_replace('Controller', '', $params['className']);
			$this->controller->set(array('controller' => $params['className'],
											'controllerName' => $controllerName,
											'title' => __('Missing Controller', true)));
			$this->controller->render('missingController');
		}
		exit();
	}

	function missingAction($params) {
		$p = $this->_setupMissing($params);

		if(file_exists(VIEWS . DS . $p['controller'] . DS . $p['action'] . ".ctp"))
		{
			$this->controller->beforeRender();
			$this->controller->viewPath = $p['controller'];
			$this->controller->render($p['action'], $this->controller->layout, null);
		}else{
			$this->controller->viewPath = 'errors';
			$this->controller->set(array('controller' => $params['className'],
											'action' => $p['action'],
											'title' => __('Missing Method in Controller', true)));
			$this->controller->render('missingAction');
		}

		exit();
	}

	function _setupMissing($params)
	{
		extract(Router::getPaths());
		extract($params, EXTR_OVERWRITE);

		$this->controller->base = $base;
		$this->controller->webroot = $webroot;
		$p = Router::getParams();
		return $p;
	}
}

This file should be saved in the root of your /app/ folder as error.php.

Published February 04, 2008
Categorized as CakePHP
Short URL: http://snook.ca/s/874

Conversation

7 Comments · RSS feed
Igor said on February 05, 2008

Jonathan, Thanks for sharing! Could you please post a small example of how it may be implemented?

Sam D said on February 05, 2008

You know it is interesting I have a similar error handler but instead of static pages it goes to a generic content controller that serves pages from the db with a path, tittle, and body content rendered with Markdown for a simple cms function.

Have to look and see if this is going to give me some new tricks, thanks as always

Jonathan Snook said on February 05, 2008

@Igor, You know, I wasn't very clear. I've updated the post to indicate that the file should be saved in your /app/ folder and named error.php. Let's say you have an About Us page for a company that should be at the url /company/about. Just create the about.ctp in the /views/company/ folder and voila, it'll just work.

@Sam: I'd love to see how you're doing it. I did something similar for a recent project

Chad said on February 05, 2008

Jonathan - this logic almost lends itself to be included in the core.... I like the idea a lot.

Sabkaraja said on February 20, 2008

Hi

Great stuff. I am working on a project where the client wants to add odd pages every now and then. What I have done is - created a pages table, with name as primary key. this allows them to add pages like events2008, free_offer etc. however they want the url to look : http://website.com/events2008 or http://website.com/free_offer.
What I did was add a route to the bottom saying:
Router::connect('/:action', array('controller' => 'pages', 'action' => 'view', ':action'));

Is there a solution for this?
thanks again

Jonathan Snook said on February 24, 2008

Sabkaraja: you could take what I have above to essentially solve that problem. When it's not found, the error handler that I have could be used to look into a pages database and read that instead.

dffc said on March 10, 2011

ddddd

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.