SitePoint Sponsor

User Tag List

Page 1 of 5 12345 LastLast
Results 1 to 25 of 120

Hybrid View

  1. #1
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    To hopefully clear up some MVC confusion

    Important: ironically as it is, this thread was meant to sort out some confusion, but it turns out that I was one of the people who was confused. I can see now that I have mixed up the PageController and FrontController patterns. What I posted initially as PageController classes in this example, are what Martin Fowler in his Patterns of Enterprise Application Architecture (PoEAA) book refers to as Commands. I only recently bought this book and based on that decided to change this example. Everything named *PageController is now named *Command. The example is still valid, but the names are now compatible with Fowler's definition of the patterns.

    There has been a lot of interest in the MVC pattern lately and as a result of that a lot of confusion. People extending controllers from views, models acting as controllers: you name it and it gets mixed up around here

    That's why I would like to present a very simple example application that is structured using MVC and related patterns such as the FrontController. This approach is working for me and I have built a number of apps with it (can't release the source of those unfortunately).

    Some aspects of this example have been simplified, such as exactly how a form should be validated, as this is beyond the scope of the MVC pattern and only adds to the confusion. I also left out some implementations of the View classes, because they are also beyond the scope of the example. Nonetheless, I believe that the example demonstrates the different responsibilities of the objects involved here.

    I'd be happy to hear you guys' comments on it of course, just hopefully not questions as "Why aren't you using a DAO?" because those have nothing to do with MVC.

    Here goes:

    PHP Code:
    /**
    * The FrontController's job is to look at the incoming HTTP request
    * to see what task the user of the application wants to perform.
    * It will then create an object, which purpose is to handle that
    * specific task: a Command
    *
    * For this example application, people can do the following tasks:
    *    - add a user account to the system => handled by the UserAddCommand
    * - edit a user account => handled by the UserEditCommand
    * - view a list of users => handled by the UserListCommand
    **/
    class FrontController
    {
        function 
    run()
        {
            switch (
    $_GET['page'])
            {
                case 
    'add':
                    
    $command = new UserAddCommand;
                    break;

                case 
    'edit':
                    
    $command = new UserEditCommand;
                    break;

                case 
    'list':
                    
    $command = new UserListCommand;
                    break;
            }

            
    $command->execute();
            
    $view $command->getView();
            
    $view->render();
        }
    }

    /**
    * This Command is responsible for the task of
    * adding a user, and all the events that can occur while the user
    * executes that task (submission of a form in this case)
    *
    **/
    class UserAddCommand extends BaseCommand
    {
        function 
    execute()
        {
            if (!
    $formHasBeenSubmitted)
            {
                
    $this->view = new UserAddView;
                return;
            }

            if (
    $formIsValid)
            {
                
    $user = new User;
                
    $user->username $_POST['username'];
                
    $user->password $_POST['password'];
                
    $user->email $_POST['email'];

                
    $user->save(); // could be $userDAO->save($user) or whatever

                
    $this->view = new UserHasBeenAddedView;
            }
            else
            {
                
    // Redisplay the form
                
    $this->view = new UserAddView($_POST$formErrorMessages);
            }
        }
    }

    class 
    UserEditCommand extends BaseCommand
    {
        function 
    execute()
        {
            if (
    $userIsNotFoundInDatabase)
            {
                
    $this->view = new UserNotFoundView;
                return;
            }

            if (!
    $formHasBeenSubmitted)
            {
                
    $this->view = new UserAddView;
                return;
            }

            if (
    $formIsValid)
            {
                
    $user;
                
    $user->username $_POST['username'];
                
    $user->password $_POST['password'];
                
    $user->email $_POST['email'];

                
    $user->save(); // could be $userDAO->save($user) or whatever

                
    $this->view = new UserHasBeenEditedView;
            }
            else
            {
                
    // Redisplay the form
                
    $this->view = new UserEditView($_POST$formErrorMessages);
            }
        }
    }

    class 
    UserListCommand extends BaseCommand
    {
        function 
    execute()
        {
            
    $users getUsersFromDatabaseSomehow();

            
    $this->view = new UserListView($users);
        }
    }

    class 
    UserAddView
    {
        function 
    render()
        {
            
    // Print a html form here
        
    }
    }

    class 
    UserHasBeenAddedView
    {
        function 
    render()
        {
            echo 
    'The user account has been created succesfully.
            Click here to return to the main page'
    ;
        }
    }

    class 
    UserEditView
    {
        function 
    UserEditView($userObject)
        {
            
    $this->userObject $userObject;
        }

        function 
    render()
        {
            
    // Print a html form here and fill up the form fields
            // with data from the $userObject
        
    }
    }

    class 
    UserListView
    {
        function 
    UserListView($users)
        {
            
    $this->users $users;
        }

        function 
    render()
        {
            foreach (
    $this->users as $user)
            {
                echo ...;
            }
        }

    Last edited by Captain Proton; Aug 27, 2004 at 10:09.

  2. #2
    SitePoint Zealot
    Join Date
    Jun 2004
    Location
    Bogota
    Posts
    101
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
    class UserEditView
     
    {
         function 
    UserEditView($userObject)
         {
             
    $this->userObject $userObject;
         }
         
         function 
    render()
         {    
             
    // Print a html form here and fill up the form fields
             // with data from the $userObject
         
    }
     } 
    Is userObject from your Model Layer? I would prefer to send this info in a dataset... or at least using a hash. Would'nt you?
    If I have wings, why am I walking?

  3. #3
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Switch/cases can quickly get very large. Dynamically invoking PCs can be a good option.

    Following class also uses a CommandReader which parses a custom url format.

    PHP Code:
           class FrontController
           
    {
               function 
    FrontController(&$command_reader)
               {
                   
    $this->command_reader =& $command_reader;
               }
               
               function 
    execute()
               {
                   
    $this->module   =  $this->command_reader->getModule(); 
                   
    $this->command  =  $this->command_reader->getCommand();
              
    $params         $this->command_reader->getParams();
              
    $class         $this->_selectPC();
              
    $command        =& new $class($this->module
                                              
    $this->command
                                              
    $params
                                                  
    );
                   
                   
    $command->execute();
               }
           
               
    /*
                   Command dictionary check.
                   return (string) - a class name
               */
               
    function _selectPC() 
               {
             if(@include(
    'modules/' $this->module '/rc/' $this->command '.php'))
                   {
                   return 
    ucfirst($this->command) . 'PageController';
           
                   } else {
                   
                  include(
    'modules/invalid_requests/rc/invalid_command.php');
                       return 
    'InvalidCommandPageController';
                   }
               }
           
           } 
    PS: sorry I can't seem to get this indented properly.

  4. #4
    No. Phil.Roberts's Avatar
    Join Date
    May 2001
    Location
    Nottingham, UK
    Posts
    1,142
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Is userObject from your Model Layer?
    It's the constant niggling questions like that that deter me from ever going near MVC. Any kind of coding structure that causes this much confusion over so many minor details must be going wrong somewhere.
    THE INSTRUCTIONS BELOW ARE OLD AND MAY BE INACCURATE.
    THIS INSTALL METHOD IS NOT RECOMMENDED, IT MAY RUN
    OVER YOUR DOG. <-- MediaWiki installation guide

  5. #5
    SitePoint Member
    Join Date
    Jul 2004
    Location
    Winnipeg, MB
    Posts
    18
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, Captain Proton. This code example is exactly what I have been looking for. I've been reading and studying so much about MVC and PHP the last couple of weeks that I couldn't keep anything straight. This helps a lot!

    My only question is about the base PageController and what should be in it? An example skeleton or psuedo-code of what should/could be in a base PageController is something that I have, as yet, been unable to find. Any directions would be greatly apprciated.

    Peer

  6. #6
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pallan
    My only question is about the base PageController and what should be in it?
    Anything common to all the PCs - starting a session & authentication for example.

  7. #7
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Captain Proton,

    Thanks for the post. I have a few questions about your specific implementation. Why do you invoke Page Controllers from your Front Controller? Doesn't that defeat the purpose of having a Page Controller in the first place? If Page Controllers are used, the Web server should act as the Front Controller. Instead, I would have a set of Command (or Action) classes (e.g. ViewNewsCommand, AddNewsCommand, UpdateNewsCommand, DeleteNewsCommand, etc.) and leave the Page Controllers out all together unless you are trying to reuse the Page Controller functionality somewhere else. These two patterns can certainly live together, but I have never seen one invoke the other or vice-versa.

    For a Front Controller implementation, usually we will have URL's of the following form:

    Code:
    http://www.sample.com/index.php?command=ViewNews
    or

    Code:
    http://www.sample.com/index.php/command/ViewNews
    The Front Controller gets the 'ViewNews' from the URL and creates a ViewNewsCommand which it invokes. If news is available, the ViewNewsCommand chooses the NewsView, otherwise the ViewNewsCommand chooses NoNewsView.

    The Page Controller version, although extremely similar, uses the Web server as the Front Controller and would have a URL like this:

    Code:
    http://www.sample.com/viewnews.php
    Inside viewnews.php, we would create a ViewNewsController object which would have virtually identical functionality to the ViewNewsCommand object. I prefer this method primarily because PHP recreates its environment upon every request. If I was using Java Servlets, I would most likely go for the Front Controller instead.

    Obviously, a particular application could use both of these patterns, but I do not see them interacting because of their distinct differences.

    Thanks,

    JT
    Last edited by seratonin; Jul 29, 2004 at 11:33.

  8. #8
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Is userObject from your Model Layer? I would prefer to send this info in a dataset... or at least using a hash. Would'nt you?
    Yep, $userObject comes from my model layer. When you say you'd like to send it as a hash, do you mean an array like array('username' => ..., 'password' => ..., etc) or an array like array('user' => $userObject)? If you mean the first, then, well, I guess it's a matter of personal preference. You could pass the View an array instead of an object, the important thing is that it's some model data.

    Switch/cases can quickly get very large. Dynamically invoking PCs can be a good option.
    Completely agree. The switch statement was merely an example. For the app I'm developing now I use something like what you describe. But then again, the example was simply to illustrate what a FrontController should do. The actual implementaion of how that is done is up to the developer's creativity (or the framework writer ).

    It's the constant niggling questions like that that deter me from ever going near MVC. Any kind of coding structure that causes this much confusion over so many minor details must be going wrong somewhere.
    That's because MVC does not say anything about this question: it leaves it up to you, the developer, to decide this to your best ability. MVC doesn't care about that, because that is not what the pattern is for.

    My only question is about the base PageController and what should be in it? An example skeleton or psuedo-code of what should/could be in a base PageController is something that I have, as yet, been unable to find. Any directions would be greatly apprciated.
    Here's something that would fit in with the example code:

    PHP Code:
    class PageController
    {
        var 
    $view;
        
        function 
    execute();
        
        function 
    getView()
        {
            return 
    $this->view;
        }

    Anything common to all the PCs - starting a session & authentication for example.
    How common are those things to all Page Controllers? For the public section of a website, you don't need to authenticate users, right? I personally prefer to implement sessions & authentication through the use of InterceptingFilters. The FrontController can set these up. But you can achieve the same thing by having multiple PageController base classes: one for pages that do need authentication, one for those that don't need authentication, one for those that need authentication and sessions, one for those that only need sessions... see why a chain of intercepting filters might be more flexible?

    Why do you invoke Page Controllers from your Front Controller? Doesn't that defeat the purpose of having a Page Controller in the first place? If Page Controllers are used, the Web server should act as the Front Controller. Instead, I would have a set of Command (or Action) classes (e.g. ViewNewsCommand, AddNewsCommand, UpdateNewsCommand, DeleteNewsCommand, etc.) and leave the Page Controllers out all together unless you are trying to reuse the Page Controller functionality somewhere else. These two patterns can certainly live together, but I have never seen one invoke the other or vice-versa.
    You are essentially right. My FrontController is not one in the strict sense of how Martin Fowler describes it. What Fowler proposes is that a FrontController invokes commands on the model of the application and contains the logic for choosing a view. Fowler's FrontController is essentially a mix of the potentially large switch statements of my FrontController plus the logic for choosing a view that you find inside each PageController.

    A ViewNewsCommand is not the type of command that the FrontController would invoke, that is not a domain model command. Domain model commands are independent of the presentation layer on top of it. They are things like CalculateInterestRatesCommand and MakeSSLPaymentCommand.

    The code that you probably have in 'ViewNewsCommand' is probably something like this: create a DAO, find a News object by id and create a View object to display that news. When you follow Fowler's FrontController pattern, this code would be implemented inside the FrontController itself with the help of something like a GetNewsCommand. Now this may not seem like a big difference, but trust me, it is. GetNewsCommand is independent of the kind of presentation layer involved (it only loads a News object from the DB, no view choosing whatsoever), while ViewNewsCommand is not: it knows what View object it must create to display the news.

    The Page Controller version, although extremely similar, uses the Web server as the Front Controller and would have a URL like this:
    Alright, you could use the web server as the front controller (which isn't a true front controller either, by the Martin Fowler pattern). But you loose all the advantages that a FrontController in combination with PageControllers can give you:

    - the ability to (dynamically) run Object Oriented!InterceptingFilters before passing on the request to a PageController instead of messing with auto_prepend_files and auto_append_files
    - you can change the URL naming scheme of your website from something like index.php?page=whatever to /site/whatever by making a change in the FrontController instead of messing around with mod_rewrite for all page controllers
    - have a central entry point for all the requests to your application. This is important to make the code readable and understanable, a clear structure of the 'flow of a request': from the FrontController possibly through the InterceptingFilters to a PageController. This instead of having to wade through if/else statements in auto_prepended files and to be unsure if control needs to be passed back to the actual requested page, redirected somewhere else, etc.

    Notice how a combination of a FrontController and PageControllers is the Object Oriented equivalent of the procedural and messy combination of a web server, auto_prepend and auto_append files and possibly mod_rewrite? Since we are talking about a Design Pattern here, Object Oriented, I'd say that it makes sense

  9. #9
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Front Commands (those commands invoked by a Front Controller) and Domain Commands (those invoked by an Application Controller) are not the same thing. ViewNewsCommand is a valid command as it is the representation of a user's request to view the news. This is presentation layer stuff not domain layer stuff. I think we are simply looking at the problem from two different perspectives. I am looking at it from the user's perspective. What does the user want to do? View the news? Update a news item? Well, IMHO, these are "Commands" which a front controller would invoke. They may ultimately lead to updating the state of the model or invoking one or operations on the model or they may simply request the state of the model as with "ViewNewsCommand". On the other hand, I think you are looking at it more from the application perspective. What does the application have to do (in resonse to a user request)? Get the news items? It is a subtle yet important difference in our perspectives. Which way is "correct"? I cannot say. To some people, your way may make a lot more sense than mine.

    JT

  10. #10
    SitePoint Member
    Join Date
    Jul 2004
    Location
    Winnipeg, MB
    Posts
    18
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    How common are those things to all Page Controllers? For the public section of a website, you don't need to authenticate users, right? I personally prefer to implement sessions & authentication through the use of InterceptingFilters. The FrontController can set these up. But you can achieve the same thing by having multiple PageController base classes: one for pages that do need authentication, one for those that don't need authentication, one for those that need authentication and sessions, one for those that only need sessions... see why a chain of intercepting filters might be more flexible?
    Jeepers Creepers, now I am really going to get some therapy. Each post keeps me changing my opinion on what I should do. Personally, I preferred not to use Front Controllers (I think Harry's article about them started me down that path), but this last post is has a excellent argument for them.

    As a result, I would like to know more about Intercepting Filters. I have seen lots of posts talking about using them, but no information about them. Anyone got any references that you could direct me to?

    Peer

  11. #11
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    Alright, you could use the web server as the front controller (which isn't a true front controller either, by the Martin Fowler pattern). But you loose all the advantages that a FrontController in combination with PageControllers can give you:

    - the ability to (dynamically) run Object Oriented!InterceptingFilters before passing on the request to a PageController instead of messing with auto_prepend_files and auto_append_files

    - you can change the URL naming scheme of your website from something like index.php?page=whatever to /site/whatever by making a change in the FrontController instead of messing around with mod_rewrite for all page controllers

    - have a central entry point for all the requests to your application. This is important to make the code readable and understanable, a clear structure of the 'flow of a request': from the FrontController possibly through the InterceptingFilters to a PageController. This instead of having to wade through if/else statements in auto_prepended files and to be unsure if control needs to be passed back to the actual requested page, redirected somewhere else, etc.

    Notice how a combination of a FrontController and PageControllers is the Object Oriented equivalent of the procedural and messy combination of a web server, auto_prepend and auto_append files and possibly mod_rewrite? Since we are talking about a Design Pattern here, Object Oriented, I'd say that it makes sense
    After re-reading the PoEAA chapter on Web Presentation Patterns, I am convinced that there is NOTHING you can do with this combination of Front Controller and Page Controller that you cannot do with Front Controller alone. Also, Front Controller and Intercepting Filters are a natural fit:

    http://www.corej2eepatterns.com/Patt...tingFilter.htm

    <snip/>

    JT
    Last edited by Mittineague; Dec 17, 2010 at 23:59. Reason: pre-new-sticky cleanup

  12. #12
    SitePoint Zealot
    Join Date
    Jun 2004
    Location
    Bogota
    Posts
    101
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    Yep, $userObject comes from my model layer. When you say you'd like to send it as a hash, do you mean an array like array('username' => ..., 'password' => ..., etc) or an array like array('user' => $userObject)? If you mean the first, then, well, I guess it's a matter of personal preference. You could pass the View an array instead of an object, the important thing is that it's some model data.
    Yes, an array like array('username' => ..., 'password' => ..., etc).

    The thing is that I am not confortable letting the presentation layer to run business logic. For example, if I send the whole UserObject to the view I might be allowing someone else to run methods from the user object IN the view. A work that I would prefer to do in the controller.

    If I find myself provided with a UserObject (from the Model layer) in my presentation logic, I am aware that I've been provided with this object to get the Domain data I want to display ... just that. But still the object lies there with a lot of methods that you won't use, or at least you should not, BUT you cant enforce it.

    The point I am getting at is that sending this Domian Object to the View might lead to tightly coupling both layers, which kinda defeats the purpose of the pattern. IMO, using some kind of Data Transfer Object will clear the View from the responsability of executing any Domain Logic. The view just needs the data to be displayed.

    One more thing, using a Data Transfer Object will help you do tests on your View objects since you can fill the DTO with some dummy data, giving the layer a certain kind of independency for testing, if the other ones are not ready.

    Cheers,
    Andres
    If I have wings, why am I walking?

  13. #13
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by otnemem
    ...
    The point I am getting at is that sending this Domian Object to the View might lead to tightly coupling both layers, which kinda defeats the purpose of the pattern. IMO, using some kind of Data Transfer Object will clear the View from the responsability of executing any Domain Logic. The view just needs the data to be displayed.
    ...
    Fowler talks about using a helper:
    PHP Code:
    class User {
        var 
    $id;
        var 
    $name;
        function 
    getId() {
            return 
    $this->id;
        } 
        function 
    getName() {
            return 
    $this->name;
        } 
        
    // All of your setters aswell.
        // This would contain all of you domain logic functions aswell

    // Helpers only have functions relating to the view
    class UserHelper {
        private 
    $user;
        function 
    UserHelper(User $user) {
            
    $this->user $user;
        } 
        function 
    getName() {
            return 
    $this->user->getName();
        } 
        function 
    getId() {
            return 
    $this->user->getId();
        } 


    $user getUserFromDatabaseSomehow();
    // Carry out domainLogic
    $this->view = new UserEditView(new UserHelper($user)); 
    Of course before you use a domain object like User you probably should have some sort of domain logic, otherwise a dataset/resultset would work the same.

  14. #14
    SitePoint Member
    Join Date
    Jul 2004
    Location
    Winnipeg, MB
    Posts
    18
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Earlier in the thread Captain Proton posted this

    Quote Originally Posted by Captain Proton
    How common are those things to all Page Controllers? For the public section of a website, you don't need to authenticate users, right? I personally prefer to implement sessions & authentication through the use of InterceptingFilters. The FrontController can set these up. But you can achieve the same thing by having multiple PageController base classes: one for pages that do need authentication, one for those that don't need authentication, one for those that need authentication and sessions, one for those that only need sessions... see why a chain of intercepting filters might be more flexible?
    Thanks to the latest example that have been provided I really see what it meant. However, I do have another question, where does one setup which filters should be run? In the quote above, different scenarios are laid out where different filters would need to run depending on the page/section requirements. How are you configuring what should be in the FilterChain?

    The example InterceptingFilter has already paid off dividends in the progress of my project, thank you very much.

    Peer

  15. #15
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @pallan: Have a look at the stickied thread Advanced PHP Resources by Harry, there is some useful link for intercepting filters there.

  16. #16
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just to confuse you further, it is possible to put just about all of the FrontController code (eg intercepting filters) into a base PageController class.

    The webserver-duplicating role has to stay in the FC, of course. A slim FC like this isn't completely pointless. There's a minor convenience with relative paths (the current working directory is always the same, ie wherever you installed index.php). Similarly, cookies are always set in root which might save you having to merge validation rules for root cookies with any additional cookies which might be set in whatever directory the current PageController is in. Neither makes a particularly strong case for a FrontController - but then a FC shouldn't create any real penalty either.

  17. #17
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff
    Just to confuse you further, it is possible to put just about all of the FrontController code (eg intercepting filters) into a base PageController class.

    The webserver-duplicating role has to stay in the FC, of course. A slim FC like this isn't completely pointless. There's a minor convenience with relative paths (the current working directory is always the same, ie wherever you installed index.php). Similarly, cookies are always set in root which might save you having to merge validation rules for root cookies with any additional cookies which might be set in whatever directory the current PageController is in. Neither makes a particularly strong case for a FrontController - but then a FC shouldn't create any real penalty either.
    Yes, it should be theoretically possible to put intercepting filter code into a base PageController class, however, it seems to be much easier to do this and to chain actions when you are using a FrontController setup. Hence, why they recommend it. I haven't tried implementing a PageController with intercepting filter, I've always just gone to a front controller in that case. Might be interesting to try out...

    JT

  18. #18
    SitePoint Member
    Join Date
    Jul 2004
    Location
    Winnipeg, MB
    Posts
    18
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is all starting to make more sense to me. Thanks everyone. Naturally, I do have another question

    When using a Front Controller would you recommend only using the one page access point (eg .index.php)? Or would it make any sense to have a FrontController for each section of your site (eg. UserFrontController, NewsFrontController, etc)? I ask because I can see the switch statement getting rather large in a single access point for a big site and this would seem to break it up into logical units.

    Peer

  19. #19
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pallan
    This is all starting to make more sense to me. Thanks everyone. Naturally, I do have another question

    When using a Front Controller would you recommend only using the one page access point (eg .index.php)? Or would it make any sense to have a FrontController for each section of your site (eg. UserFrontController, NewsFrontController, etc)? I ask because I can see the switch statement getting rather large in a single access point for a big site and this would seem to break it up into logical units.

    Peer
    It depends. I've seen it both ways. I believe that the intention of the PoEAA Front Controller pattern is to have one single entry point into the application. However, the seminal paper on MVC for Smalltalk describes mutliple controllers which manage related operations. I guess it is up to the developer in terms of how they want to partition their application.

    JT

  20. #20
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Seratonin, alright, but then I don't even see the difference between your Commands and my PageControllers, except the name of course.

    does the user want to do? View the news? Update a news item? Well, IMHO, these are "Commands" which a front controller would invoke
    .. and ..
    however, it seems to be much easier to do this and to chain actions when you are using a FrontController setup.
    I assume chain actions are a chain of Commands? If so, if you use Commands for things like session tracking you might ask yourself this question "Does a user want to do session management or is he/she really not interested in that?" Because, like you said, Commands are "what a user wants to do".

    Fowler talks about using a helper ...
    He may talk about a View Helper, but your User Helper is not a View Helper. A View Helper is a class that contains logic that is really business logic but it's business logic that is only required by a small number of Views, and implementing it into the business objects themselves would make them bloated, that is why they are in a separate class.

    When using a Front Controller would you recommend only using the one page access point (eg .index.php)? Or would it make any sense to have a FrontController for each section of your site (eg. UserFrontController, NewsFrontController, etc)?
    This depends on what you prefer. Like we've said before, if the switch statement grows too large, you can start using external files to determine which PageController must be loaded for which URL. But there is no reason why you can't have multiple FrontControllers with switch statements in them.

    Just a note though, it is possible to have multiple index.php files that all initiate the same FrontController class.

  21. #21
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    He may talk about a View Helper, but your User Helper is not a View Helper. A View Helper is a class that contains logic that is really business logic but it's business logic that is only required by a small number of Views, and implementing it into the business objects themselves would make them bloated, that is why they are in a separate class.
    I dont know the term "View Helper" but I wouldnt put business logic in a class that specificly relates to the view. I dont see why a business object shouldnt have bussiness logic. Putting business logic in a view object is not a good answer IMO. View objects should only have presentation logic if any.

    Whether or not you should use a Helper like below in php is a different discussion, I was only offering a solution for otnemem.

    To exactly quote his example from PoEAA pg 355-357:
    PHP Code:
    class Artist {
      private 
    $name;
      private 
    $albums = array();
      public function 
    getName() {
        return 
    $this->name;
      }
      public function 
    getAlbums() {
        return 
    $this->albums;
      }
    }
    class 
    ArtistHelper {
      private 
    $artist;
      public function 
    ArtistHelper(Artist $artist) {
        
    $this->artist $artist;
      }
      public function 
    getName() {
        return 
    $this->artist->getName();
      }
      public function 
    getAlbums() {
        return 
    $this->artist->getAlbums();
      }
      public function 
    getAlblumList() {
        
    $result '<ul>';
        foreach(
    $this->getAlbumns() as $album) {
          
    $result '<li>' $album->getTitle() . '</li>';
        }
        return 
    $result '</ul>';
      }
    }
    $artist Artist::findNamed($request->getParameter('name'));
    if (
    $artist == null) {
        
    // foward to Missing artist error
    } else {
        
    // Below is a jsp/servlet thing.
        // but is passing the artist to the
        // view via a helper
        
    $request->setAttribute('helper', new ArtistHelper($artist));


  22. #22
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    .. and .. I assume chain actions are a chain of Commands? If so, if you use Commands for things like session tracking you might ask yourself this question "Does a user want to do session management or is he/she really not interested in that?" Because, like you said, Commands are "what a user wants to do".
    By chaining I meant more like a pipe and filter or intercepting filter (poor choice of wording) type architecture. Which would be something that happens internally when the Front Controller is carrying out a request. Although, you could definitely chain together two use cases. If you have a use case like Update News and you want to immediately forward control to View News upon success, I could see something like that happening. I am using use cases/features to help me partition my application. If View News is a use case what has to happen behind the scenes to provide that functionality is a completely different story. It may include authentication, authorization, logging, but that is all behind the scenes. What the user sees and cares about is viewing the news. So there is what the user observes is happening and what is happening internally.

    JT

  23. #23
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    Seratonin, alright, but then I don't even see the difference between your Commands and my PageControllers, except the name of course.
    Captain Proton,

    I applaud your effort here to make things clear and simple, but I still think that you are blurring the definition of the page controller pattern by mixing the page controller and the front controller patterns together. Someone coming here wanting to understand the page controller pattern might be confused by how you are using the pattern. I propose that you name your new pattern something different than page controller to distinguish it from a true page controller pattern (as Fowler and others intended).

    Thanks,

    JT
    Last edited by seratonin; Aug 2, 2004 at 11:32.

  24. #24
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pallan
    I ask because I can see the switch statement getting rather large in a single access point for a big site and this would seem to break it up into logical units.
    One solution would be modifying the FC to something like the following :

    PHP Code:
    class FrontController 

        function 
    get_controller($controller)
        {
            
    // untaint to protect against mallicious users
            
    $controller strtr($controller'\/:*?"<>|''_________');
            
    $filename 'includes/controllers/' $controller '.controller.php';
            
    $classname $controller 'Controller';
            if (
    is_file($filename)) {
                include_once(
    $filename);
                return new 
    $classname();
            }
            
    // you might want to return a default controller instead
            
    trigger_error('no such controller : ' $controllerE_USER_WARNING);
            return 
    null;
        }
        function 
    run() 
        { 
            
    $pageController =& $this->get_controller($_GET['page']);
            
    $pageController->execute(); 
            
    $view $pageController->getView(); 
            
    $view->render(); 
        } 


  25. #25
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    (I'm putting this in a separate post to keep things organized a bit)

    You wanted to see a FrontController + PageController + InterceptingFilters in action? Here goes:

    PHP Code:
    class FrontController 

        function 
    run() 
        { 
            
    $filterChain = new SessionTrackingFilter(
                new 
    AuthenticationFilter(
                    new 
    OutputBufferFilter
                    
    (
                        
    $this
                    
    )
                )
            );
            
            
    $filterChain->processRequest();
        }
        
        function 
    processRequest()
        {
            switch (
    $_GET['page']) 
            { 
                case 
    'add'
                    
    $pageController = new UserAddController
                    break; 
                
                case 
    'edit'
                    
    $pageController = new UserEditController
                    break; 
                
                case 
    'list'
                    
    $pageController = new UserListController
                    break; 
            } 
                
            
    $pageController->execute(); 
            
    $view $pageController->getView(); 
            
    $view->render();
        }

    Some explanation first before I show you the rest of the code. As you can see, in the FrontController, instead of directly selecting a PageController, now I set up a chain of InterceptingFilters and at the end of the chain I put the FrontController again. The request now gets processed by the SessionTrackingFilter, which passes it onto the AuthenticationFilter, to the OutputBufferFilter and finally back again to the FrontController.

    Now for the intercepting filters:

    PHP Code:
    class SessionTrackingFilter extends InterceptingFilter
    {
        function 
    __construct($nextFilter)
        {
            
    $this->nextFilter $nextFilter;
        }
        
        function 
    processRequest()
        {
            
    // do whatever needs to be done to start a session
            
    ...
            
            
    // let all the other filters do their work
            
    $this->nextFilter->processRequest();
            
            
    // and after those filters have done their work, close the session
            
    ...
        }
    }

    class 
    authenticationFilter extends InterceptingFilter
    {
        function 
    processRequest()
        {
                if (
    $validCookieFound)
                {
                    
    // the user has been authenticated, so move on to the next filter
                    
    $this->nextFilter->processRequest();
                }
                else
                {
                    
    // whoah, hold up, we need to ask the user for authentication first
                    
                    
    echo 'Please enter your username and password in the form here etc. ';
                    
                    
    // now we do not move on to the next filter, we stop processing the request here
                    // and return control to the previous filter in the chain
                    
    return;
                }
            }
        }
    }

    class 
    OutputBufferFilter extends InterceptingFilter
    {
        function 
    processRequest()
        {
            
    ob_start();
            
            
    $this->nextFilter->processRequest();
            
            
    ob_end_flush();        
        }    

    As you can see, the InterceptingFilters are clean and small classes. If for some section of your website you need a different authorization method, or perhaps you don't want to use sessions, you simply rearrange the chain of filters: reuse them.

    That is the most important advantage I can think of, and it is an advantage that comes from good object oriented design: reusability. You can reuse the filters and rearrange them in any order, something you can't do when you implement their behaviour in a base PageController class (you would theoretically need one for every possible combination of filters in any order).

    For more information about InterceptingFilters, I can also recommend the link seratonin gave: http://www.corej2eepatterns.com/Patt...tingFilter.htm You'll see that the example I gave above is not so much different from the Java code.

    Also
    One solution would be modifying the FC to something like the following + code
    That's what McGruff said


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
  •