Easier Static Pages for CakePHP 1.2 Update

So it seems that the old code I had didn't work in debug mode, although on the current CakePHP 1.2 RC2, I'm not even sure it works at all. However, I decided to take some time to revisit the code. Last time, I simply hacked up the missingAction and missingController calls and it felt kludgy. It looked kludgy.

This time I took a closer look at how the dispatch was being handled. Daniel Hofstetter made mentioned how using the error handler seemed inappropriate since it's for handling errors. Unfortunately, the Dispatcher looks for a missing action or controller and if it can't find them, it sends it off to the AppError class well before anything else. As a result, it seems that overriding the AppError is really the approach that I want to take. I think you'll see, though, that the new code is more straightforward.

It uses the constructor to capture what kind of error is being called. If it's a missingAction or missingController then I look for the missing file. If the file doesn't exist, the flow continues on to the parent error class and the missingAction and missingController calls happen as they normally would. The old code actually handled both scenarios creating bulky code.

If the page exists then the AppController is instantiated and the view is rendered. The only problem currently is that CakePHP doesn't seem to load the custom AppController, if it exists. I've filed a ticket but I'm not entirely sure if this is by design, so this may not ultimately get resolved.

Without further ado, here's my AppError:

class AppError extends ErrorHandler {

	function __construct($method, $messages) {

		$params = Router::getParams();

		if (($method == 'missingController' || $method == 'missingAction') 
           && file_exists(VIEWS . DS . $params['controller'] . DS . $params['action'] . ".ctp")) {
			$this->controller =& new AppController();
			$this->controller->_set(Router::getPaths());
			$this->controller->params = $params;
			$this->controller->constructClasses();
			$this->controller->viewPath = $params['controller'];
			$this->controller->render($params['action']);
			e($this->controller->output);
			exit;
		}

		parent::__construct($method, $messages);
		exit();
	}

}
Published July 04, 2008
Categorized as CakePHP
Short URL: https://snook.ca/s/899

Conversation

8 Comments · RSS feed
Jason said on July 05, 2008

Thank you, this code works great with the debug now, and is much easier to understand. I can confirm that it also works with cake 1.2 rc2. Your code worked fine in cake 1.2 beta, but when I added in my own code for checking a pages database I had some problems. It was a known bug where sessions were not getting initiallized again or something. Anyway, that seems to have been fixed in later versions of cake.

Jonathan Snook said on July 05, 2008

I'm happy to hear it works!

One quick note, that ticket I filed was invalid. It works on the latest version from svn. My dev copy must've been slightly older. So there should be no issues adding in functionality from AppController.

avto said on July 11, 2008

Thank you!
very very nice!

Matti putkonen said on August 09, 2008

Awesome work Jonathan, I hope they add this type of functionality to core in the future.

Do you see any problems with setting all of these view to be stored in one view directory, like 'static', if they are not related to a controller in any way ?

jamie scott said on September 28, 2008

Thanks for this code. Any idea how I can make routing work with a .html suffix and still get the url caught by your error system?

Mark said on January 11, 2009

Jonathan,

"...there should be no issues adding in functionality from AppController"

Have you figured out how to get missing controllers to load components (specifically, the Auth component)? Or rather, have it use the AppController as usual?

Jonathan Snook said on January 11, 2009

Mark: assuming things haven't regressed since I posted this, if you've specified the Auth component in AppController, it should be used.

Mark said on January 11, 2009

I guess things have regressed then (using 1.2 stable now). As a quick test, I added an echo to the beforeFilter in AppController. It's displayed on all pages where the controller is specified, but not when there's a missing controller.

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