Rolling Your Own MVC: The Page Load Scenario

In my previous article, I announced that I would be documenting the process of developing a simple MVC framework. In this post I will go into a little more detail about each of the specific components of our MVC and will discuss the series of events which occur each time a page loads, otherwise known as the page load scenario.

We’re going to start by outlining a typical page load scenario, and then how to write code around it so we can gain more control over each part. By the end of this post we’ll have a solid understanding of the what code needs to be written, and how it all will fit together.

Before I get into any sort of detail, I think it’s important to say that there is more than one way to approach an MVC. Go ahead, ask a few seasoned developers how they would hack together a project like this and each one will give you a completely different answer. I’m going to do my best to simplify the process as much as I possibly can without damaging the stability, security, and scalability of the framework.

A 10,000 Foot View

  1. User navigates to /index.php/catalog/
  2. The front controller initializes and sets up the environment
  3. The front controller instantiates the request object.
  4. Using data in the request, the route object is instantiated.
  5. Using data in the route, the view object is instantiated.
  6. Using data in the route, the application controller object is instantiated.
  7. As the controller is being constructed, it creates instances to models and other resources it will need during execution.
  8. The front controller calls the appropriate method in the application controller.
  9. The front controller instructs the view to render. 

How URIs Work 

As the acronym would suggest, a URI identifies a resource. A typical web application may use a URI like: /viewCategory.php?id=123&output=json. This system is tried and true and always works — but it can still be improved upon. This URI could be rewritten as: /category/123.json

There are a few key things to note about this URI structure:

  • The resource context is identified by the first URI component
  • The resource identifier is identified by the second URI component (if it exists) 
  • The request method will define the method of execution upon the resource  
  • The output type will be identified by the last set of characters following a period in the URI (defaulting to HTML if none is provided) 

A Note On mod_rewrite

URI restructuring has become a common practice with most frameworks today. Apache users will use mod_rewrite, IIS users will use ISAPI Rewrite, and there are other solutions for other server platforms. When implemented properly, a well rewritten URI can prove to be a valuable site component which brings an added layer of usability and search engine optimization. But still, we can’t rely upon an external technology as a core part of the framework — it should be as “out of the box” as possible.

It’s also important to mention that the query string should not be modified by the framework in any way. This leaves it entirely up to the developer whether or not to use the query string to pass data into the application and not an assumption made by the framework. Instead of passing the information through the query string, it is advised that the extra data be passed as a path directly after the index.php in the file name; for example: /index.php/some/information

The Front Controller 

During the page load scenario, a single, central object oversees the entire execution — this is known as the front controller. The front controller loads all necessary components of the application and provides an API to access them. In this particular case, it loads the route, the request, the view, and the controller (the application controller).

If anything were to go wrong anywhere throughout the process, the front controller knows about it and handles the problem gracefully.

The Request Object 

After the front controller is loaded, the next object to be instantiated during the page load scenario is the request object. This most likely will be a singleton instance and will contain all request data (_GET, _POST, and _FILE). Additional information about the request will also be stored in the request object. This includes the request method, actual URI, and evaluated URI (which is used when creating the route object).

It’s quite obvious that most of this information is already found in PHP’s superglobals, so at first glance it may not seem like it makes sense to duplicate it here; however, it affords us the ability to filter the data as it comes in and as it goes out.

The Route Object 

The route represents the extra data from the URI mentioned above. Routes provides valuable information about a resource and how it is to be accessed. In order for a route to be instantiated properly, a request object will need to exist.

Routes are more than just path strings. They are dynamic and constantly changing. For example, imagine a scenario where no extra data is provided in the URI, but you still wish to load a default application controller. In this case, the route object would need to be injected with the default data. The only reasonable solution is to write an API for it which allows developers to add and remove path components at will. Really, routes should extend a base Path class… but we’ll worry about that later.

The View Object 

Views represent the information presented to the client who requested the data. Since clients may vary, various output formats are required. This fact alone makes the view, quite possibly, the most flexible component in our MVC. For example, when it comes to web browsers, the most common output format will be HTML. If a JavaScript application were to request the same resource, JSON should be served up. The possibilities are endless so special attention to the design of this package is critical.

Some MVC implementations suggest allowing full access to models; this one however, will not. The view will have an API allowing data to be manipulated before it is sent to the client as a response. 

Although a view could stand on its own if instantiated directly, the problem arises as to which view to create. This job, will be assigned to the route as it knows all of the information it needs to create an instance of the correct view.

Controllers 

Controllers (more specifically, application controllers) are classes designated to handle requests to resources which are managed by the MVC. They also act as a liaison between models and the view. 

Traditionally, MVC applications use the first two components of the route path to identify the controller class and the method (also known as an action) to call. For example, the route /blog/view/1234 would load the Blog class, call the view method with a parameter of “1234“. There is nothing wrong with this approach, but it still could be optimized further. Ideally, all controllers would act as a REST service whereby the action could be omitted.

Controllers for REST Services

REST-friendly controllers are simple: whenever a GET request comes in, the get method is called on the controller. Likewise, if a POST, PUT, or DELETE request comes in, the post, put or delete method is called respective to the request method. According to most REST services, GET requests are used to locate data, POST request are used to create data, PUT requests are used to update data, and DELETE requests are used to destroy data.

There is one problem though: web browsers don’t support PUT or DELETE based requests. This can be overcome by using POST requests in place of PUT and DELETE, but by adding an additional field to the posted data which correctly identifies the request.

Models

Models are classes designed to represent data. Most web applications are powered by a relational database of some kind so it’s not uncommon to find that models relate to a specific database table and/or row. A lot of frameworks take that to another level and allow their model classes to implement an ActiveRecord style interface with convenience functions to find, save, and delete data that the model represents.

For this MVC, models will much more simple. If models just represent data, and nothing more, that means they can represent any kind of data and thus maximizing component reuse. If you’re worried about loosing all the convenience that ActiveRecord offers, simple inherit from the ActiveRecord class and code as you normally would.

Conclusion

So there you have it. Everything you just read sums up the core framework components for our MVC. In future posts, I will examine revisit each component in detail and provide code and unit tests. After all, you were really here for the code anyway right?

I encourage everyone to offer their feedback on any level. This is an open source project so you have as much say in it as I do.

Other Posts in this Series

This entry was posted on Monday, April 7th, 2008 at 12:29 am and is filed under Code, Design Patterns, PHP. You can leave a response, or trackback from your own site.

8 Responses to Rolling Your Own MVC: The Page Load Scenario

Jason:

On April 10th, 2008 at 8:31 am #

Hey you are on PHPDeveloper.org!

I agree with everything you said but I think that taking the REST approach for your controllers limits what you can do with a single controller and will result in having to create more controllers.

For example if I have a user controller I can create, retrieve, update, and delete my user and that is fine. What if I need to handle emailing a lost password, authentication, or other user related functions? We can add logic to handle these actions within our REST style controllers but why not handle each actions specifically?

James Morris:

On April 11th, 2008 at 6:27 am #

Good post, I will be following any more in this series so please keep them coming!

mikeg:

On April 11th, 2008 at 9:35 am #

@Jason: You’re right. Going entirely REST may not be the solution, but having the option would be quite useful. I think the best choice is to have a separate subclass for RESTful controllers. Thoughts?

@James: Thanks for the kind words. I should have the next part of this series completed this weekend.

Jason:

On April 11th, 2008 at 1:02 pm #

@mikeg: I definitely agree that in most cases RESTful controllers are exactly what you need. Perhaps implement a RESTful interface and add any additional functions needed.

I too look forward to your next post and seeing how you have implemented these ideas.

Robert:

On April 14th, 2008 at 8:17 am #

I’m in the process of developing my own framework - I’m on round two of refinements now and it looks like your articles are exactly what I need to guide round three. thanks!

PHP Weekly Reader - April 13th 2008 : phpaddiction:

On April 15th, 2008 at 2:42 am #

[…] been reading along with this series Rolling Your Own MVC: The Page Load Scenario while most developers with a firm grasp of MVC will probably not find it all that interesting I […]

Dave Marshall:

On April 16th, 2008 at 11:00 am #

Nice article, will probably work as good guide to show experienced developers the way with MVC.

Rolling Your Own MVC: The View :: Love Mike G.:

On April 28th, 2008 at 12:31 am #

[…] previous two articles, I discussed the general feature set that our framework will have and I also gave an overview of the page load scenario. In today’s episode I am going to switch gears and discuss a single component of the […]

What do you have to say?

Site Stuff

Pages

Projects

Archives

Categories