SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 51
  1. #1
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    MVC Router Implementations

    I would just like to gather some opinions if I may on everyone's thoughts surrounding the Router of an MVC implementation.

    I have to admit, being the control freak I am, I've found a lot of the implementations I've looked at to be very 'hackish'.

    • For example
      • Hard coded controller paths and directories
      • Assumption of URL structure (/controller/action/)
      • Required extension of base controller object to determine request validity.
      • Predefined routes

    I'm sure most are going to point me in the way of the Zend Framework, but even that messes around appending controller methods (indexAction)to prevent the calling of controller internals.

    Surely this irks others, no?

    In all my applications, I can code merrily away happy in the knowledge I have free reign in how components 'slot' together, but once it comes to wiring them up to user requests - I fall into the seemingly inevitable trance-like state of staring at the IDE and pondering for a better solution.

    It's quite a nemesis of mine.

    The router process has always niggled away at me, and I've never been entirely happy with it. I'm no OOP guru, nor profess to be, but when I'm unhappy with something its usually a good sign it's wrong.

    How do you approach it, do you sacrifice OOP principles for the sake of brevity?

    Cheers people.
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  2. #2
    SitePoint Enthusiast
    Join Date
    Aug 2005
    Location
    Germany
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm not sure if I will hit your nail on the head, as I am a beginner with all this. But maybe you will find something useful in my way of doing things

    I personally never liked the way of using URL structures (/controller/action/). While this gives nice URLs I chose to go with the GET method and add parameters as needed. One of my parameters is - guess - controller and determines in the frontcontroller which controller should be loaded.

    PHP Code:
            $controllerRequest $this->requestMapper->getParameter('controller');
            
    $class ucfirst($controllerRequest).'Controller';

            if (
    class_exists($class))  {
                
    $controller = new $class($this->page$this->registry);
                
    $this->page $controller->dispatch(); 
    The loaded controllers then know (hard coded) which view to open (depending on the action: POST for insert/update data, GET for viewing things).

    The views are still somewhat messy, but they deal with templating and loading the models from the database - nothing unusual but I haven't still found a good path for me to trod.

    Concerning paths: I use autoload to load my classes. I only define my paths there and I am ok with this. My directory structure is somewhat messy, but works. My lib-directory holds all kinds of classes, value objects and interfaces in a more or less defined structure. The only place where this does not work is template files and language translations (to a certain level). I have template pages, modules, sidebars, widgets and what else and I still did not find a good way to go without using paths directly. Finding translations works well with the Iso Codes and the name of the template.

    I rely somewhat on a strict naming convention though to always find the appropriate parts/classes. When there is a ProjectController, there is likely a ProjectView and a ProjectTemplate, but this might be overriden through a parameter.
    To be a bit more concrete, my MapController has a MapView which then decides on the map parameter in the get request which map to display. But I found that keeping a good naming structure gives advantages in terms of flexibility in the view/controller.

    PHP Code:
    //
    $this->mapName $this->requestMapper->getParameter('map');
    // Map model with specific info for map display (javascript driven)
    require SITE_PATH.'/model/'.$this->mapName.'Model.php';
    // Language
    require SITE_PATH.'/languages/'.$this->currentLanguage.'/'.$this->mapName.'/'.$this->mapName.'.php';
    // Template
    $map = new Template(SITE_PATH.'/templates/'.$this->mapName.'.php'); 
    But this is my first shot in the MVC game so I just might have gotten some concepts wrong

  3. #3
    SitePoint Member
    Join Date
    Mar 2008
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I prefer the Horde/Routes package: dev.horde.org/routes/

  4. #4
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    I've seen as many implementations of this as there are developers here. To be honest, if your design is flowchartable and works for you, then use it.

    However, here's my formula:

    Entry point is RequestController. In it's constructor I run a filter chain. Each one filters one of the superglobals. EX:

    foreach ($_REQUEST as $key => $val)
    {
    $_REQUEST[$key] = trim(strip_tags($val));
    }

    At this point all incoming data is relatively clean. In the execute function I set a default for $_REQUEST['cmd'] if not set. Then simply instantiate the command and execute. Controller is done.

    In the command abstract, I setup my security context object, which restores a user from session or cookie, and checks the users access permissions for the called command (see my post in the form one level up for get_called_class implementation prior to 5.3). Command processes any posted information and the usual stuff, and determines which view to display. Of course I think you know the rest from here on out.

    It pretty much maps out like this.

    Controller -> Command -> View

    Models, Validators and Connectors (db layers) are used exclusively in commands. Cache objects read info in from xml files, such as options.xml, roles.xml, locale.xml, skin.xml and so on.

    I was probably ZERO help here, but maybe not.

  5. #5
    SitePoint Evangelist
    Join Date
    Jun 2003
    Location
    Melbourne, Australia
    Posts
    440
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I really like <a href="konstrukt.dk">Konstukt's</a> use of hierarchical controllers ("components" in v2, I think, which I've yet to look at in any detail). Each "segment" of a pretty URL is handled by a different controller. The controller contains a 'map' associative array which tells it which controller class to instantiate and dispatch the 'next' segment to.
    Zealotry is contingent upon 100 posts and addiction 200?

  6. #6
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Each "segment" of a pretty URL is handled by a different controller.
    Nightmarish. What about optional language part, which is mostly located as first part? Router should be single component.

  7. #7
    SitePoint Addict webaddictz's Avatar
    Join Date
    Feb 2006
    Location
    Netherlands
    Posts
    295
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    Each "segment" of a pretty URL is handled by a different controller.
    Nightmarish. What about optional language part, which is mostly located as first part? Router should be single component.
    Actually, it's really very practical: having a controller responsible for each segment in the URL makes a lot of sense, once you've gotten accustomed to it, at least, that's how I feel. On the question how this handles languages in the URL, you might just wonder if it should be in the URL path or as a query parameter.
    Yes, I blog, too.

  8. #8
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    As I said above, there's a million different ways you could do it. I think a lot depends on how your raw urls are used, outside of the "pretty" guise. I got confused really early on myself until I set aside the pretty url thing and developed my application using real url. It was easier to visualize. Once I was done, I added the pretty url mappings.

    Take the following two urls

    /en-US/Documents/Help
    index.php?mod=Documents&item=Help&lang=en-US

    Well I don't know about you, but the latter seems more intuitive. Load DocumentsHelpCommand, then let whatever view you wind up with ( DocumentNotFoundView() or DocumentHelpView() ) handle language loading.

    Jus as a caveat, in my applications, I have no use for language or skin before the view anyway, so it works.

  9. #9
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I prefer former. But sometimes I think about third way:
    /lang=en-US/module=Documents/action=Help
    /lang.en-US/module.Documents/action.Help

    The parsing would be much quicker.

  10. #10
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    To the OP, have you sat down and mapped out your app in terms of what items you have to display, and what actions can be taken on them? This alone helped me decide on a system. It turned out with mine, I'd never having anything more than two levels deep plus an item id occasionally (/item/action[/id]). For example /articles/modify/23 or /articles/view/23 (you could use a doc name instead of id, I was just lazy). This is why I simply have controller -> command -> view. However, if your structures allows for deeper level, such as /documents/support/product/model/installing then yes, you may indeed need more level of mapping. I for one, would not be inclined to name a class DocumentsSupportProductModelInstallingCommand. =/

    EDIT:

    You're parsing these urls? Aren't you using url rewrite?

  11. #11
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    Each "segment" of a pretty URL is handled by a different controller.
    Nightmarish. What about optional language part, which is mostly located as first part? Router should be single component.
    I don't understand why you consider it nightmarish. If you feel that there's to many controllers, one controller could handle more than one segment, but the default approach is that each segment has one component.

  12. #12
    Theoretical Physics Student bronze trophy Jake Arkinstall's Avatar
    Join Date
    May 2006
    Location
    Lancaster University, UK
    Posts
    7,062
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    I actually use a switch/case system.

    This is because my article URLS would look like:
    Site.com/MainCategory/SecondaryCategory/SubCategory/Article/PageNumber

    Each step involves dynamic names, so this is the best way in this scenario.
    Jake Arkinstall
    "Sometimes you don't need to reinvent the wheel;
    Sometimes its enough to make that wheel more rounded"-Molona

  13. #13
    SitePoint Enthusiast
    Join Date
    Jan 2009
    Posts
    81
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    i built my MVC router after looking at how some of the bigger frameworks do theirs, and some random tutorials/articles. i ended up with one that assumes a url of module/controller/action. modules are folders, and optional. for example, if you just did controller/action, it would assume an 'index' module (which all projects have per my design). it does instantiate the controller to test that the action exists, but i don't see a problem with that. i consider myself a big control freak too, but really, this has suited my needs pretty well so far. although i did have to do a bit of hacking to get myblog.com/category/tech/page/2 to work. 'category' is my action, and 'tech', 'page', and '2' are all params sent to the 'category' action. not the way i would choose to do it, but i'm not about to rewrite the router now

  14. #14
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    default approach is that each segment has one component.
    So you propose to have three controllers for this route?
    Code:
    /controller/action/id ( articles/delete/123 )
    It makes no sense for me. Maybe I missed something.

    Serenarules:
    Yes, I use parsing, because rules are too complex for htaccess (or I cannot write such a rule in it ...) and almost all parts are optional with defaults.

  15. #15
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It makes perfect sense if you have urls like this:
    /articles/ <- List of all articles
    /articles/tech/ <- List of tech articles
    /articles/tech/singleton-is-evil <- A specific article

  16. #16
    Theoretical Physics Student bronze trophy Jake Arkinstall's Avatar
    Join Date
    May 2006
    Location
    Lancaster University, UK
    Posts
    7,062
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    But then if each category had subcategories which had subcategories etc etc etc, it would be impossible to do through a simple RewriteRule or two.

    For example:
    Articles/PHP/Databases/PDO/Prepared_Statements/Introduction/

    You would need to pass that to a PHP controller, and verify each topic or article depending on their parent ID etc.
    Jake Arkinstall
    "Sometimes you don't need to reinvent the wheel;
    Sometimes its enough to make that wheel more rounded"-Molona

  17. #17
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    It makes perfect sense if you have urls like this:
    /articles/ <- List of all articles
    /articles/tech/ <- List of tech articles
    /articles/tech/singleton-is-evil <- A specific article
    Unless there is some greater point to be made, that is nothing to do with MVC though, you are merely a way of describing paths to unique URIs.

    /articles/ <- List of all articles
    /articles/hacks/ <- List of journo articles
    /articles/hacks/singleton-is-evil <- Alex Singleton attacks politicos

    Ditto arkinstalls remark.
    For example:
    Articles/PHP/Databases/PDO/Prepared_Statements/Introduction/
    Isn't that mixing up public URI and site navigation with MVC routing?

  18. #18
    Spirit Coder allspiritseve's Avatar
    Join Date
    Dec 2002
    Location
    Ann Arbor, MI (USA)
    Posts
    648
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Cups View Post
    Unless there is some greater point to be made, that is nothing to do with MVC though, you are merely a way of describing paths to unique URIs.
    I think the "greater point to be made" is whether to distribute routing among your controllers, or have centralized routing in the front controller. If you have a lot of nested content, as wysiwyg's example showed, then nested controllers that each handle their own segment of the URI is more flexible than trying to describe all of that up front. Mastodont's counter-example, on the other hand, is not nested content and can be handled with a single level of controllers. The difference as I see it:

    Centralized routing:
    Front Controller -> Router -> Controller

    Distributed routing:
    Front Controller -> ArticlesController -> ArticleCategoryController -> ArticleController

  19. #19
    SitePoint Zealot
    Join Date
    Jun 2004
    Location
    Netherlands
    Posts
    172
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by allspiritseve View Post
    I think the "greater point to be made" is whether to distribute routing among your controllers, or have centralized routing in the front controller. If you have a lot of nested content, as wysiwyg's example showed, then nested controllers that each handle their own segment of the URI is more flexible than trying to describe all of that up front. Mastodont's counter-example, on the other hand, is not nested content and can be handled with a single level of controllers. The difference as I see it:

    Centralized routing:
    Front Controller -> Router -> Controller

    Distributed routing:
    Front Controller -> ArticlesController -> ArticleCategoryController -> ArticleController
    I would say a centralized place for all urls would be more logical. Look at how the zend farmework handles routes. URLs consisting of many segments go to a single (module) controller/action set, possibly including the extra parameters you set for that route.

    So say you have an url like
    site.com/find/room/in/washington/in/2009/03/29
    could map to:
    Module: rooms
    Controller: roomfinder
    Action: find
    Extra parameters: year, 2009, month 03, day 29, place, washington

  20. #20
    Spirit Coder allspiritseve's Avatar
    Join Date
    Dec 2002
    Location
    Ann Arbor, MI (USA)
    Posts
    648
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by matthijsA View Post
    I would say a centralized place for all urls would be more logical.
    Why? Websites are hierarchical in nature (or should be, it's more useable), doesn't it make more sense to construct them using a hierarchy of controllers?

    Quote Originally Posted by matthijsA View Post
    Look at how the zend farmework handles routes. URLs consisting of many segments go to a single (module) controller/action set, possibly including the extra parameters you set for that route.
    That means that the longer the URL, the more parameters you pass that one controller. If you're listing items, and the extra parameters just narrow down the list, that's pretty simple to do. However, when behavior starts to change depending on what parameters are passed, that controller gets more and more complex.

    For your example, I'd probably split that into at least two controllers: one for searching for rooms, and one for displaying rooms. These require different views and each may need different parameters. Splitting separate behaviors off into child controllers means the code is simpler and thus more readable and more maintainable.

    Having a hierarchy of controllers also opens up opportunities for code reuse. A parent controller could be setting a datasource for a child controller, which means you could have the same child controller work for many parent controllers. I'm sure there are a lot more benefits than this, but wysiwyg or kyberfabrikken would probably be able to explain them better than I could.

  21. #21
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by allspiritseve View Post
    two controllers: one for searching for rooms, and one for displaying rooms. These require different views
    A view for search controller? Why, if there is DISPLAY controller?

  22. #22
    SitePoint Zealot
    Join Date
    Jun 2004
    Location
    Netherlands
    Posts
    172
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by allspiritseve
    Having a hierarchy of controllers also opens up opportunities for code reuse. A parent controller could be setting a datasource for a child controller, which means you could have the same child controller work for many parent controllers. I'm sure there are a lot more benefits than this, but wysiwyg or kyberfabrikken would probably be able to explain them better than I could.
    Well I think it's an architectural choice, depending on the framework you use. kyberfabrikken's konstrukt is specifically build around the idea of a hierarchy of controllers. In zend framework that wouldn't work, because every call to a controller is an expensive one.

    The fact is that in the end it's always one controller and one action that are responsible for the response. So the question is, do you get to that controller/action set in one go or through several steps? In that last case controller A gets the first part of the URL. Can I handle it? No, forward to next controller. That one checks if it has to handle it as well. No? Forward again. Etc etc.

    On one side it seems simple to use, but at the same time I wonder what happens if you want to restructure your whole URL scheme. If you have the scheme in a central place, it's easy to change. If it's decentralized, you have to change every part of it.

    And second, I also think that the whole part of a centralized route handling and controllers who can handle "bigger chunks of urls", is that you need less code. I mean, if you need a controller for each segment of an URL, you might as well go back to creating static folders and html pages on your server.

  23. #23
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you have a lot of urls in your website/application, having only one place for all that logic means that all that logic has to run every time. If you base the routing logic on steps (first segment is "articles", load that component and let that component worry about further mapping), only the mapping logic that is actually needed is run. That also makes it easy to move large parts of your application around (move /articles/tech/* to /articles/geek/*).

    Quote Originally Posted by matthijsA View Post
    you might as well go back to creating static folders and html pages on your server.
    That's kind of what Konstrukt is trying to emulate, since it's actually a quite logical and elegant solution. Konstrukt adds some niceities to it, like being able to access the parent component. I think the real strength of Konstrukt is that a component is a resource, and not just a method on a controller class.

  24. #24
    SitePoint Addict webaddictz's Avatar
    Join Date
    Feb 2006
    Location
    Netherlands
    Posts
    295
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by matthijsA View Post
    On one side it seems simple to use, but at the same time I wonder what happens if you want to restructure your whole URL scheme. If you have the scheme in a central place, it's easy to change. If it's decentralized, you have to change every part of it.
    I can imagine that you have second thoughts and the argument of change is a good one. Then again, a URL is just a unique name for a resource, so I have problems imagining a situation where I would want to change the URL's. But, I think you are right: having the URL routing in a centralized place would make it easier to change. I don't really care though, as I wouldn't change the URL's much.

    Quote Originally Posted by matthijsA View Post
    And second, I also think that the whole part of a centralized route handling and controllers who can handle "bigger chunks of urls", is that you need less code. I mean, if you need a controller for each segment of an URL, you might as well go back to creating static folders and html pages on your server.
    Not quite true. When using a monolithic controller which can display a list, a single entry and a form to edit that single entry, you'll have to write the code that does those things in both approaches. There is a difference in the number of classes: when using composite controllers, you'll have more classes, but they simply are smaller because they only do one thing and do that one thing well. Also, subsequent controllers can make calls to the methods provided by their "parent" context, which means both controllers can use the same method, without a hassle. That's a benefit and will lead to less and better code in general.
    Yes, I blog, too.

  25. #25
    SitePoint Evangelist
    Join Date
    Jun 2003
    Location
    Melbourne, Australia
    Posts
    440
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    So you propose to have three controllers for this route?
    Code:
    /controller/action/id ( articles/delete/123 )
    There are those (kyberfabrikken--konstukt's author--among them, I think) who would say that one should not delete a resource from a GET request (which is what your example seems to be doing). There might be better examples, though.
    Zealotry is contingent upon 100 posts and addiction 200?


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •