SitePoint Sponsor

User Tag List

Results 1 to 20 of 20
  1. #1
    SitePoint Member
    Join Date
    Mar 2005
    Posts
    24
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    A Front Controller

    How many of you use a front controller? What all do you put in there besides just a switch statement to instantiate new classes or add new files? If you have multiple classes that perform key functions, but should be separated, how do you keep them all organized in an easy to access manner?

    Those are just a few questions I have, because I've been wanting to build a decent base application code, but it always turns out bad or sloppy.

    I guess one other thing, does anyone know of an open source example with a good front controller?

    Thanks

  2. #2
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you have multiple classes that perform key functions, but should be separated, how do you keep them all organized in an easy to access manner?
    From what I can understand of your question, I believe some kind of mapper would solve this problem

  3. #3
    SitePoint Member
    Join Date
    Mar 2005
    Posts
    24
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    From what I can understand of your question, I believe some kind of mapper would solve this problem
    Me being a complete beginner when it comes to design patterns and application design, I am confused as to what you are saying. Perhaps could you provide a link or an explanation?

    Thanks for responding.

  4. #4
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A mapper isn't a design pattern, but a method to map a request to a controller, such as taken from the Front Controller thread, here is what I have used in the past,

    PHP Code:
    try {
    $fc = new FrontController(
    $request_handler = new RequestHandler( new HttpRequest() ), new RequestMapper( array() ) );
    $fc -> dispatch();
    } catch( ... ) {

    PHP Code:
    interface IController {
            public function 
    __constructIRequestHandler $request_handlerIRequestMapper $request_mapper );
            public function 
    attachIFilter $filter );
        }
        
        abstract class 
    BaseFrontController implements IController {
            protected 
    $request_handler;
            protected 
    $request_mapper;
            protected 
    $filters = array();
            
            public function 
    __constructIRequestHandler $request_handlerIRequestMapper $request_mapper ) {
                
    $this -> request_handler $request_handler;
                
    $this -> request_mapper $request_mapper;
            }
            
            public function 
    attachIFilter $filter ) {
                
    $this -> filters[] = $filter;
            }
            
            public function 
    dispatch() {
                foreach( 
    $this -> filters as $filter ) {
                    
    $filter -> preProcess();
                }
                
    $this -> process();
                foreach( 
    array_reverse$this -> filters ) as $filter ) {
                    
    $filter -> postProcess();
                }
            }
            
            abstract protected function 
    process();
        }

    interface 
    IRequestHandler {
            public function 
    getLang();
            public function 
    getRequestMethod();
            public function 
    getRequestParameter$request_parameter );
            public function 
    __constructHttpRequest $http_request );
        }
        
        abstract class 
    BaseRequestHandler implements IRequestHandler {
            protected 
    $http_request;
            
            public function 
    __constructHttpRequest $http_request ) {
                
    $this -> http_request $http_request;
            }
            
            public function 
    getLang() {
                if( 
    $lang $this -> getRequestParameter'lang' ) ) {
                    return 
    $lang;
                } 
                return 
    'en';
            }
            
            public function 
    getRequestMethod() {
                return ( 
    strcasecmp$_SERVER['REQUEST_METHOD'], 'POST' ) == )? 'POST':'GET';
            }
            
            public function 
    getRequestParameter$request_parameter ) {
                if( 
    $this -> http_request -> getParameter$request_parameter ) ) {
                    return 
    $this -> http_request -> getParameter$request_parameter );
                } else if( 
    $this -> http_request -> getSession$request_parameter ) ) {
                    return 
    $this -> http_request -> getSession$request_parameter );
                } else if( 
    $this -> http_request -> getCookie$request_parameter ) ) {
                    return 
    $this -> http_request -> getCookie$request_parameter );
                } else {
                    return 
    false;
                }
            }
        }

    class 
    RequestHandler extends BaseRequestHandler {
            public function 
    __constructHttpRequest $http_request ) {
                
    parent::__construct$http_request );
            }
            
            public function 
    getTemplateRoot() {
                return 
    $_SERVER['DOCUMENT_ROOT'].'/public_html/admin/workspace/templates/'.$this -> getLang().'/';
            }
            
            public function 
    setSession$parameter$value ) {
                
    $this -> http_request -> setSession$parameter$value );
            }
            
            public function 
    getSession$session_parameter ) {
                if( 
    $this -> http_request -> getSession$session_parameter ) ) {
                    return 
    $this -> http_request -> getSession$session_parameter );
                }
                return 
    false;
            }
        }

    class 
    RequestMapper implements IRequestMapper {
            public function 
    __construct$parameters ) {
                if( !
    is_array$parameters ) ) {
                    throw new 
    IllegalParameterException(
                        
    'required application parameter(s) are not accessable or parameter(s) type are invalid'E_USER_WARNING
                    
    );
                }
            }
            
            public function 
    mapRequestIRequestHandler $request_handler ) {
                
            }
        } 
    In the concrete class method process(); you would take the request and pass it to the class method mapRequest(); which belongs to the RequestMapper class. It's that class method - mapRequest(); - that maps the request to a controller, which is then passed back to the Front Controller.

  5. #5
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Forte925
    Me being a complete beginner when it comes to design patterns and application design, I am confused as to what you are saying. Perhaps could you provide a link or an explanation?
    Here is a link to my fork of the Skeleton thread code. It has a simple FrontController with plug-in Action Mappers -- there is even an example app using the FrontController in there somewhere. Click here to download
    Christopher

  6. #6
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    PHP Code:
    interface IController {
            public function 
    __constructIRequestHandler $request_handlerIRequestMapper $request_mapper );
            public function 
    attachIFilter $filter );
        } 
    Wait a sec, doc, why does Controller need an attach() function? Your example is a bit.. skewed. I don't seem to quite get it.

  7. #7
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah... That is where the Intercepting Filter fits in, where I can for example, attach a LogIn Filter which validates the user before any further execution

  8. #8
    SitePoint Zealot
    Join Date
    Oct 2004
    Location
    naperville
    Posts
    189
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Doc, whats up with the use of exceptions? Is it your "default action"? It seems odd (to me!) in this case.

  9. #9
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What do you mean the use of exceptions? I get the impression that you are talking about the try... catch block that wraps the initial script instantiation?

    Well, I do that as I tend to throw exceptions up a level, regardless of where the exception took place. I find it a lot easier to let something else handle an exception, which usually means the client script.

    In some cases, there is no client script, so it falls back to that one try... catch block; It's kind of a preventitive measure to prevent exception messages being displayed. The thing is though, there may be x number of exception types.

    So, from my point of view, when I throw an exception back up the hierarchy, I kind of substitute the thrown exception, for another one that may be more appropriate. I think that is an important factor to remember.

    You can have exceptions that are assocciated with the type of error that caused the exception, but you can't catch all exception types, so you need to reduce he number of types, to a more common type.

    By type of exception, I suppose I mean the exception name(s), of which should represent the kind of exception it represents.

  10. #10
    SitePoint Member
    Join Date
    Mar 2005
    Posts
    24
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems like I am digging myself further into a hole. Wouldn't it just be easier to store the classes in something like an array? (or at least references to the classes). It sounded like a cheap method, so thats why I asked about that.

    Perhaps I misunderstood the meaning of front controller. Isn't it what initiates other classes to be used inside the script? If it isn't, then I guess a better term to use would be the base/main class.

  11. #11
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Forte925
    It seems like I am digging myself further into a hole. Wouldn't it just be easier to store the classes in something like an array? (or at least references to the classes). It sounded like a cheap method, so thats why I asked about that.
    The point of a Mapper is to map the "action" parameter to a class name. You can do this with an algorithm (the usual way in PHP) or look up the class name in a map (which would be your array I suppose).

    Quote Originally Posted by Forte925
    Perhaps I misunderstood the meaning of front controller. Isn't it what initiates other classes to be used inside the script? If it isn't, then I guess a better term to use would be the base/main class.
    A Front Controller instansiates and then executes an object based on an "action" parameter. The details of how it does that can vary a little. Usually the object to be executed is in the form in the Command pattern, which usually boils down to it has an execute() method. A Front Controller typically only dispatches one object.
    Christopher

  12. #12
    SitePoint Guru Galo's Avatar
    Join Date
    May 2005
    Location
    Holland!
    Posts
    852
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    From what I can understand of your question, I believe some kind of mapper would solve this problem
    Don't they call that a Facade, cause they are common within a controller, from there you can specify a concrete controller which get's implemented by the abstraction imho....

    on place where all requests come in which get delegated to concrete instances...
    Business as usual is off the menu folks, ...

  13. #13
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    United Kingdom
    Posts
    208
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    Ah... That is where the Intercepting Filter fits in, where I can for example, attach a LogIn Filter which validates the user before any further execution
    Wouldn't it make sense to implement Intercepting Filters as Commands, so they receieve the request and response and can act on them if need be? Seems that is preferable than for example the filter doing a HTTP header redirect on failed authentication.

  14. #14
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Whats wrong with doing a redirect though? What you are suggesting is that there should be a Command or an Action which is executed as an alternative to display the login screen, rather that doing so via a redirect.

    I can't see a clean way of doing that myself at the moment...

  15. #15
    SitePoint Member
    Join Date
    Mar 2005
    Posts
    24
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So what I really need is a front controller as well as a loader for other files/classes?
    So would that be like an application controller?

  16. #16
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    United Kingdom
    Posts
    208
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    Whats wrong with doing a redirect though? What you are suggesting is that there should be a Command or an Action which is executed as an alternative to display the login screen, rather that doing so via a redirect.

    I can't see a clean way of doing that myself at the moment...
    I was thinking something like the following. Assume AuthenticationAction is part of a Chain of Responsibility, and gets called before the GET requested action.
    PHP Code:
    class AuthenticationAction extends Action
    {
      public function 
    __construct(){}
      public function 
    executeRequest $requestResponse $response )
      {
        
    parent::__construct$request$response );
        
    // If user doesn't authenticate, show the login form
        
    if( $userDoesNotAuthenticate )
        {
          
    $view = new LoginFormView$request$response );
          
    $response->setView$view );
          return 
    $response;
        }
        else
         
    // Otherwise call GET requested action
        
    {
          return 
    $this->successor->execute$request$response );
        }
      }
    }
    // Another possibility - a caching filter
    class CachingAction extends Action
    {
      public function 
    __construct(){}
      public function 
    executeRequest $requestResponse $response )
      {
        
    parent::__construct$request$response );
        
    // Check if cache exists
        
    if( $cacheExists )
        {
          
    $view = new CachedPageView$request$response );
          
    $response->setView$view );
          return 
    $response;
        }
        
    // Or continue request and create cache
        
    else
        {
          
    $response $this->successor->execute$request$response );
          
    $cache = new CachePage$response );
          return 
    $response;
        }
      }

    I just feel that sending HTTP redirect feels like exiting the application flow only to rejoin it at another point. Just my2c I guess

  17. #17
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Forte925
    So what I really need is a front controller as well as a loader for other files/classes?
    So would that be like an application controller?
    A Front Controller is a file/class loader (and dispatcher) in PHP. An Application Controller is an example of one of the many types of things (often Controllers) that a Front Controller dispatches.

    Application Controllers are often mentioned in association with "wizard" type sequences of interdependent and prerequsite pages. The are perhaps the most complex of the different types of controllers.
    Christopher

  18. #18
    SitePoint Member
    Join Date
    Mar 2005
    Posts
    24
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think I finally get it. Thanks everyone.

  19. #19
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Shrike
    I just feel that sending HTTP redirect feels like exiting the application flow only to rejoin it at another point. Just my2c I guess
    But what about the fact that when you switch views (no redirect), your url is misleading? Maybe that's not really an issue?

    M

  20. #20
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    But what about the fact that when you switch views (no redirect), your url is misleading? Maybe that's not really an issue?
    How is a URL that shows what you tried to do misleading? URLs don't always "work". I don't think it is our job to echo back meaningful URLs. The usual behaviour is to leave the URL line untouched and report the results in the content area.
    Christopher


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
  •