Home / Blog / Is Your MVC MIA When it Comes to 404s?

Is Your MVC MIA When it Comes to 404s?

Dealing with missing pages in Web applications.

For those of you who know me, you know that I don't like the term MVC in Web applications and Web frameworks. MVC doesn't really work for stateless HTTP, but that's another story. Sometimes it looks like anybody who uses a template system and a database layer in the same app is suddenly "MVC".

But this post is not about the overuse or misuse of any particular terms. This post is about the consistency of frameworks. Consistency is key to a low learning curve. If all parts of a framework behave the same way, then a developer is less likely to be surprised by behaviors in the framework. Also, I feel that they are less likely to rely on a manual every couple of minutes to look up method names, directory names, etc.

Yesterday, my brother asked me how he could capture 404 errors in Cognifty, as he was building an app that relied on dealing with random URL patterns. He said he tried to use htaccess files and mod_rewrite, but that wouldn't cut it. Given the fact that most, if not all, MVC frameworks use a front-controller pattern, there is never a missing file error (404) at the Apache level. Apache is always finding the index.php file that kicks off the MVC application.

Usually, a request into a PHP framework is something like this

example.com/some/thing

... which gets re-written by mod_rewrite into

example.com/index.php/some/thing

The index.php uses the remaining "/some/thing" as instructions for which bit of logic to run. Failing to find the requested code can be akin to not finding a regular page in the traditional Web world, which would result in a 404 error. But, shouldn't we expect a bit more from an advanced Web framework nowadays?

After talking for a bit, we decided that handing off the request to a standard service (or controller) was the best way to handle this type of "error". He started searching to see if other frameworks had a consistent, or at least documented, way of dealing with missing controllers. Some of the frameworks (ZF in particular) treat the missing controller as an error. Whether or not this situation is actually an error depends on your point of view.

If your application is designed to act upon any inbound URL, regardless of whether or not it matches any particular controller file, then treating this condition as an error has its downsides. Triggering an error condition disrupts the regular flow of code, requiring that the end-developer do some more tracing or searching to figure out how to handle this error. Also, the error might trigger a path of execution in the framework that doesn't have all the benefits of a traditional MVC request... events, pre- and post- method handlers, logging, tracking, permissions, templating....

If your application is not designed to handle any random inbound URL, well you might be inclined to treat this sort of condition as a regular error. And that's fine, but treating it as an error only disrupts the flow of code and puts a burden on the programmer to switch mental modes and deal with the error in a new "silo" of thinking.

In Cognifty, when the request runner cannot find a module or service (controller in other systems) that matches the incoming request, it simply adds a new, standard service to the execution stack. That service can do any error handling or reporting that it chooses, but it has the exact same feel as all the other business logic in the system. So, if you choose not to modify it there are no downsides, it will behave just like traditional error handling. But, if you do choose to modify the default behavior, you can do it just like any other business logic in the system; no need to catch errors, or listen for error signals.

This level of consistency reminds me of how Cognifty (and LogiCreate before it) handled 301 and 302 redirects. In most PHP systems you see something like this.

  header('Location: some/thing/else');
  exit();

I've always felt that this is horrible. The execution dies right then and there, no clean up can happen by the system if you exit the code in 10 different places in your app. It also makes it hard to profile and refactor.

The LogiCreate/Cognifty way of performing a redirect is to simply change your presentation handler. Displaying the location header is treated the same way as displaying an HTML template:

  $this->presenter = 'redirect';
  $t['url'] = 'some/thing/else';
  return;

Earth-shattering? No. Different from the rest? Definitely.

These micro-revelations about how easy code should be are always what keep me from truly enjoying coding in other frameworks. I'll do it for money if the job requires it, but I can't seem to devote any free time to anything but Cognifty.

Anyone have any insight into how their favorite framework handles 404s?



Comments on "Is Your MVC MIA When it Comes to 404s?"

Anonymous
Relating to your original comment about MVC, I can't see how it's anything but? You have a model, a view and a controller. If that's not MVC, what is it?
 
Anonymous
My philosophy is that a web application always needs to handle every URL and input that's thrown at it. All URLs should be handled equally - by outputting a formatted HTTP response. The only difference between an expected URL that we explicitly know how to handle and one we do not is that the output for that should include a 404 header.

It's only when *that's* missing, then we have an error.
 
Anonymous
Sorry, i do not get the point ... But using 301 Moved Permanently, is a big danger. What should uncle google think?
Return 4xx/5xx, add some alternbative content, based on the path youre into, or handle the 404 by a standard 404 document of the webserver, BUT NOT use 302 or stuff like that. Period ;)
 
Anonymous
I think you picked the wrong target for your criticism - Zend Framework is very flexible when handling errors. Sure, by default it throws an error, but you can easily set up an error controller that has the benefits of a MVC request you described:
http://framework.zend.com/manual/en/zend.controller.html#zend.controller.quickstart.go.errorhandler
 
mgkimsal
Not 100%, but I think some of the ZF criticism stems from this:

http://www.nabble.com/Problem-with-Zend_Controller_Plugin_ActionStack-td17560561.html

which seemed to indicate that something treated as an 'error' gets resolved differently than just something 'not found'. Because of the 'error' state triggered in the example, things were run in a different order, things were dispatched differently, etc.
 
Mark Kimsal
Just to clarify:

The redirect example is totally separate from the 404 handling techniques.

I put the redirect handler there just to show another example of how things can be handled very consistently, whether it's missing controllers (execute a filenotfound controller), or regular page redirects (tell the templating engine that you want to redirect instead of show html).
 
Anonymous
I come from the Solar framework camp. In Solar, the front controller decides which page controller to instantiate for the request. You can set the default page controller, which will be used if none was was requested. If even the default could not be found, the front controller simply returns a few lines of HTML to describe a 404, also a 404 status is along with the response. The situation when the front controller can't find the default page controller, however is a mistake by the developer and will never happen if you've configured your app correctly. You can always extend the default front controller and write your own _notFound() method if you really want that.

Once the request is handled to the page controller class, you can at any point set the response status to 404 and serve content from a template of your own choosing as the error page content.

Ps. From what I can tell about your wise words about consistency, you'd be very satisfied with Solar.
 
Anonymous
You can find Solar at:

http://solarphp.com/
 
Mark Kimsal
@anonymous solr

"The situation when the front controller can't find the default page controller, however is a mistake by the developer and will never happen if you've configured your app correctly. You can always extend the default front controller and write your own _notFound() method if you really want that."

You say that if a developer writes their app "correctly", then the missing controller will never happen. What is incorrect to one person is correct to another. This is the heart of the entire discussion.

I cannot restrict people from typing in ANY URL they want into their browser. So, you'd better be able to handle anything that anybody throws at you.

The other point is that you may not WANT to restrict what people type into the browser.

http://example.com/MyFavoritePerson/

That type of URL could easily initiate a search, or load up an account page for a user, or do any number of things. Yes, this could all be handled with "routers", but routers assume that your urls follow a pattern. If you specifically do not want any pattern to your URLs, then you're left with catching "errors".

When pattern-less URL structure is designed into a developer's application it is neither incorrect nor an exceptional state or error.
 
Rhibree
> No config found for: config://template/site/name No, but yours is.
 
Devyn
reposting - earlier link was wrong.
 

 

Add a comment