Garden Preview Part III: Anatomy of a Request

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

mod_rewrite was an afterthought in Vanilla 1. As a result, I’ve always felt that the mod_rewrite mappings were sloppy and really just didn’t make much sense. In Garden, the way pages are accessed is completely different, and definitely deserves explaining. Let’s start by looking at a typical url request in Garden without mod_rewrite enabled:

http://localhost/garden/default.php/garden/settings/configure

Let’s look closer at each part of the request:

http://localhost/garden/default.php: On my development server, I’ve created a folder called garden, and placed all of the garden files I discussed in last week’s preview in it. As you can see, the default.php file that handles all requests is sitting within that folder’s root.

/garden: The next part of the url is the application that is being requested. In this case, we are requesting the “garden” application within the garden framework’s application folder.

/settings: The next part of the url is the controller that is being requested within the garden application. In this example, we are requesting a controller called “Settings”.

/configure: the final part of the url in this example is the method within the “Settings” controller that we are calling. In this example, we are calling $SettingsController->Configure();.

If you were to map this request to the filesystem, it would be like this:

Request

I could take the same request and add information to the end, like this:

http://localhost/garden/default.php/garden/settings/configure/arg1/arg2/argn

And it would take any other parameters after the controller’s configure method as if they are arguments being passed into that method. In other words, the above request would be essentially the same as calling that method like so:

$SettingsController->Configure('arg1', 'arg2', 'argn');

This can get pretty handy when doing things like paging through records, or specifying which user to load in a page. For example, to edit a user, the url would be:

http://localhost/garden/default.php/garden/user/edit/mark

Which would map to:

$UserController->Edit('mark');

Analyzing the Request
All requests are handled through the Dispatcher class. The dispatcher class looks at the request (everything after default.php) and tries to figure out the best way to handle it. As far as the dispatcher is concerned, in a perfect world the request would always include the application name, the controller name, and the method name. But in reality you might not always want all three items in your url. For example, you might want your application invisible to the user – so that, for example, a request to vanilla’s discussion list goes to

http://yourwebsite.com/default.php/discussions/all

… instead of …

http://yourwebsite.com/default.php/vanilla/discussions/all

Furthermore, you might want your controller’s method hidden as well. So you could end up with something like:

http://yourwebsite.com/default.php/discussions

The dispatcher can handle all of these and a lot more. First of all, when no method is defined in the request, the dispatcher assumes that you are calling the “index” method of the controller. So, a request to:

http://yourwebsite.com/default.php/vanilla/discussions

… is the same as calling …

$DiscussionsController->Index();

Furthermore, when the dispatcher gets a request that doesn’t include the application name, it starts to look through all of the enabled applications for the requested controller name. As soon as it finds one, it records it’s mapping in the cache folder and calls it appropriately. There is the possibility that two different applications could have the same controller name, and in that case, it would return the first application’s controller that it found.

Probably the nicest thing about this method of handling requests is that a 6-line .htaccess file:

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ default.php/$1 [QSA,L]
</IfModule>

… allows you to remove the default.php from the url and makes all requests look like this:

http://yourdomain.com/application/controller/method

Or, in it’s simplest form:

http://yourdomain.com/controller

Next
In the next garden preview, I’ll be getting into how controllers work, how views are found and rendered, and how master views can let you customize layouts between applications and themes.

27 Responses to “Garden Preview Part III: Anatomy of a Request”

  1. MySchizoBuddy

    so far so good :)
    one question, if i want to add a user in vanilla, i will be calling the garden app to do it? i’m assuming vanilla (all other apps) has its own user stuff that calls the generic garden user classes.

  2. Mark

    There is a User Model that you would use to create a new user. All models, though application-specific, can be referenced by other applications just by importing it wherever you need it.

  3. Adrian

    Can you have folders of controllers within the controller folder?

    Or does it just do one level?

  4. Mark

    Currently it is just one level. Allowing folders within the controllers folder isn’t difficult to do – but what’s the point when none of the controllers should have the same name, anyway?

  5. Adrian

    You’re right it is not too complex, just merely interested if you had implemented or considered it.

    I have written a MVC framework myself recently and implemented the feature just so that you could create collections of controllers. For example a collection of all the admin console controllers. So they url would then be:

    http://localhost/vanilla/admin/controller/method/action/

    As opposed to trying to write one admin controller that tried to do too much.

  6. MySchizoBuddy

    agree with mark why would you want controllers inside controllers, makes no sense.

    ok so the controller naming convention is ClassnameController and Classname.php
    So /settings/ in the url will map to SettingsController class, and the file name will be settings.php.

    please don’t hide the method name else i don’t know if it is calling method name “all” but hidden or there is no method and its calling the “index” method.

  7. MySchizoBuddy

    so we are not going to use namespace feature in php 5.3, that can help differentiate controllers from different apps having the same name

  8. MySchizoBuddy

    ok just read adrians comment about controller collection.
    so it will be
    http://localhost/application/collection/controller/method

    method and action are the same thing right, ROR calls methods as actions

  9. MySchizoBuddy

    you can have one controller AdminController and a folder inside the controller folder called admin. the Contents of this folder are not assessable from the url. The AdminController will act as a dispatcher and call the controllers in the admin folder.

    this way you can get your collection and mark won’t have to do anything.

  10. Mark

    @MySchizoBuddy – In my examples above, I called the instantiated object $XXXController just for clarity that the object was, in fact, a controller. The reality of the naming conventions in Garden is that the Controller filename is the same as the classname.

    That’s not a final rule by any means – we could call the class definition whatever we wanted. I just figured that there was little point in adding the “Controller” suffix.

    Furthermore, the dispatcher is pretty smart about parsing the url. A request to /garden/controller/something will examine the controller to see if there is a “something” method before assuming that it should call $Controller->Index(‘something’);.

    Regardless, it’s just an option I wanted to have. 99% of the time the method will appear in the url.

    About ROR Action vs Method. I just called it a method because that’s exactly what it is on the controller object.

  11. MySchizoBuddy

    how do you differentiate between settings model and settings controller.

    $bar = new foo();

    now is foo a controller, model or normal class?

  12. Adrian

    MySchizoBuddy
    you can have one controller AdminController and a folder inside the controller folder called admin. the Contents of this folder are not assessable from the url. The AdminController will act as a dispatcher and call the controllers in the admin folder.

    this way you can get your collection and mark won’t have to do anything.

    Hmmmm I guess that solution would work, but then there would need to be a new form of dispatcher written and added to the controller, which is probably replicating a lot of the already existing dispatcher class.

    The whole reason that I mention the idea of collections of controllers is because I wrote a simple MVC framework that quickly became used in a number of complex projects that have admin consoles and also two different front ends to the applications. If I had all the controllers in one folder, it would quickly have become confusing.

    Although with the existence of seperate applications I can imagine that this will become less of a concern.

  13. Mark

    @MySchizoBuddy – Models have the “Model” suffix. So, here’s a user controller:

    class User extends Controller {}

    And here’s a user model:

    class UserModel extends Model {}

    Also, I’d have loved to use the namespaces that php5.3 is supposed to have, but I couldn’t find a windows binary for anything past 5.2 to use for development. I also wasn’t sure when 5.3 is going to be released, so I didn’t know if it would be out in time for *my* release. For the time-being I’ve got placeholders in my code for the namespace declarations. When they are 100% available, I’ll definitely be adding them.

    @Adrian – it’s definitely an interesting idea. I know that I’ve run into that same issue of making a single controller take on too much workload. Open-ended controllers like a “Settings” controller can quickly take on too much; after all, what type of settings should a “settings” controller handle? App settings? User Settings? Role Settings? etc…

    Anyway, I’ll keep that in mind as I finish up Garden and Vanilla and may add something like that before the release.

  14. MySchizoBuddy

    this is how codeigniter does subfolders in controllers
    http://codeigniter.com/user_guide/general/controllers.html#subfolders

  15. Adrian

    I never knew CI did that.

    all this talk of subfolders has got me testing my routing code now! currently testing it with 3 levels of nested folders. totally pointless but there you go.

    have you stress tested garden yet Mark? how do you think it would hold up to heavy load? could it survive a digging on modest hardware?

  16. Mark

    I’ve done stress testing, and it performed well. But that was a while ago. I’m going to finish Garden and most of Vanilla before I go through stress testing again. I’ve found that typically the bottlenecks are commonly used functions and they’re easily fixable.

  17. Jeff

    I’m curious if you have a router built into Garden?

    Can we map our URLs to different routes?

    An example would be mapping the login method (action) of the Users controller:
    By default: http://www.domain.com/application/users/login
    Map to: http://www.domain.com/application/login or even http://www.domain.com/login

  18. Mark

    Yes, I do. I was going to write about it in this post, but I ran out of time :)

  19. Jeff

    Glad to hear about that! Hopefully we can see those features in a future post?

    Also, one quick note on the naming conventions for models vs. controllers.

    Typically with MVC frameworks, the controller class name would be UsersController and the model would be Users. It is just a convention I have noticed, but I thought I would mention it.

    Awesome work, I can’t wait to see more!

  20. MySchizoBuddy

    i don’t think there is any hard and fast rule for mvc. usually the model name is the plural of the table name

    Database table: “people”
    Model class: “Person”, found at /app/models/person.php
    Controller class: “PeopleController”, found at /app/controllers/people_controller.php
    View template, found at /app/views/people/index.ctp

    so as a none native speaker of english language. I’m suppose to know the plural of people is person, not peoples and that some words don’t have plurals

    any convention will do.

  21. Mark

    @MySchizoBuddy – Yeah, I noticed the pluralism and I didn’t like it either.

  22. Mark O’Sullivan - Blog » Blog Archive » Garden Preview Part V: Data

    [...] here to read the Garden Preview Part I Click here to read the Garden Preview Part II Click here to read the Garden Preview Part III Click here to read the Garden Preview Part [...]

  23. Mark O’Sullivan - Blog » Blog Archive » Garden Preview Part VI: Models & Forms

    [...] here to read the Garden Preview Part I Click here to read the Garden Preview Part II Click here to read the Garden Preview Part III Click here to read the Garden Preview Part IV Click here to read the Garden Preview Part [...]

  24. Mark O’Sullivan - Blog » Blog Archive » Garden Preview Part IX: Roles & Permissions

    [...] here to read the Garden Preview Part I Click here to read the Garden Preview Part II Click here to read the Garden Preview Part III Click here to read the Garden Preview Part IV Click here to read the Garden Preview Part V Click [...]

  25. Mark O’Sullivan - Blog » Blog Archive » Garden Preview Part II: FileSystem

    [...] Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models & [...]

  26. Mark O’Sullivan - Blog » Blog Archive » Garden Preview Part IV: Views

    [...] Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models & [...]

  27. Mark O’Sullivan - Blog » Blog Archive » Garden Preview XV: Modules

    [...] Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models & [...]

Leave a Reply