An alternative approach for organizing your controllers

Published on July 04, 2006 and tagged with cakephp  ideas

The recommended way to organize your controllers in a CakePHP application is to group functions related to one model in a controller, like UsersController, ProjectsController, and so on. So you get urls like /users/edit/1 and /projects/show/1. That works fine, but there is a little issue. If you compare the urls with the natural language, such urls are not that easy to read. We can translate them to: “From the users edit the one with id 1″ or “From the projects show the one with id 1″. But that is not the way we usually speak. We say “Edit user 1″ or “Show project 1″. So it would be nice to have similar urls: /edit/user/1 and /show/project/1.

A possible solution is to group similar actions in a single controller. There would be an EditController with user() and project() functions for editing the respective models, and a ShowController with the same functions for showing the models. With some imagination you will see that this approach is similar to the command pattern.

What do you think about such an approach? Is it just a crazy idea on a hot summer day?

13 comments baked

  • poncho July 04, 2006 at 16:18

    You have a good point there, I’ve often wondered about alternative URI formatting. For instance, I’d much rather have “/users/{username}/edit” than “/users/edit/{username}”.

    For small-scale projects I would recommend just using routes to achive your goal though.

    $Route->connect(‘edit/user’, array(‘controller’ => ‘users’, ‘action’ => ‘edit’));

    Cheers;
    Poncho

  • Mladen Mihajlovic July 04, 2006 at 16:34

    I must admit that I’ve used routes to do just that in a couple of instances. Thing is I like having all the actions for one entity in it’s own controller.

  • drypek July 04, 2006 at 16:43

    i think you should use ROUTE’s to customize your URL’s

  • nate July 04, 2006 at 17:19

    Actually, any one of those scenarios is possible to do with routes.

  • KesheR July 04, 2006 at 19:45

    Mmmmm I like the way it is, I don’t need it :)

  • Brandon Pearce July 04, 2006 at 21:07

    One other issue is that if all you’re doing is updating a single table, then you really don’t need a separate edit() function for each model. Kind of like scaffolding, I have a save() function in app_controller that I use to save all my models unless there is something special I need to do. With this new suggestion, I would need to create an extra function to save every model even if it uses the same code as another model. (True I could just call the other function, but it’s still extra code).

    Fun to think about, though. Thanks for the idea.

  • Felix Geisendörfer July 05, 2006 at 09:22

    I sometimes feel like messing with the url’s as well, in fact right now I’m working on a UrlAlias Model that’ll be released soon.

    Most of the times I feel the most flexible approach is to modify the $from_url variable in the routes.php. So in this case you would explode the $from_url on ‘/’, check if a controller with the name second item of the resulting array exists, and if this controller has an action named like the first item of the array. If that’s the case you simply switch those two arguments in your $from_url, and voilá you got yourself a new url convention.

    I think using something like an EditController would be a rather confusing setup, but well, it might offers some other advantages like better refactoring of edit related code, who knows.

    Just my ideas ; )

  • uzyn July 05, 2006 at 16:54

    Very interesting idea.

    But wouldn’t that means breaking the MVC model? I admit I did think about the same issues as well, but usually I would simply use routing for that.

    But interesting idea anyway. Gives a different perspective to the whole MVC.

  • cakebaker July 06, 2006 at 18:05

    @all: thanks for your comments and ideas. I will keep experimenting :)

  • olegs July 08, 2006 at 19:56

    For more complex cases:

    Edit item 34 in category 12 :

    /categories/12/edit/item/34 ?

    edit category 12:

    /categories/edit/12 ????

  • cakebaker July 11, 2006 at 10:36

    @olegs: I am not sure what you mean with your comment. According to my statements in this post the urls would look like:

    /edit/item/34/category/12

    and

    /edit/category/12

  • Roger Lancefield January 29, 2007 at 13:38

    In my view, if you are changing the structure or organization of your application for valid architectural/design philosophy reasons, that’s one thing, but to do so just to achieve prettier URLs is allowing the tail to wag the dog. That is, by all means adopt the command pattern if it’s useful, but not to prettify URLs! To do so would be altering the inherent design philosophy of your application for the most trivial reasons. An application’s design should aim to achieve modularity, clarity, coherence, maintainability, performance, etc. etc. but not to churn out easy to read URLs. That’s why the gods gave us mod_rewrite isn’t it? :)

    Another point, it’s worth bearing in mind that not all natural languages use the SVO (subject-verb-object) syntax that English uses. E.g. for speakers of Japanese, Tibetan, Turkish and Navajo, /users/edit should look just fine. More good reasons why URL structure should ‘float free’ from application design methinks.

    Anyway, great CakePHP blog. Cheers!

  • cakebaker January 30, 2007 at 11:09

    @Roger: Thanks for your comment.

    Yes, you are right, it is a bad idea to design an application only for providing nice urls. But if you think this idea further, you will end up with a “perfect” system, at least in theory. Each controller would have just one method which handles the respective action for all models. And as the framework would provide the actions for crud operations, you would have to write much less code…

    But back to reality. Yes, you are right, something like /edit/user/1 wouldn’t be natural for all languages.

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License