SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    SitePoint Addict chiefmonkey's Avatar
    Join Date
    Aug 2002
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    FrontController and Interceptor Filters (again)

    I have been thinking about adding the Interceptor filter pattern to my framework for a few days now, but I can't really decide on the best way to do it. PoEAA suggests you wrap your handler with the IF, but I can't really see a way of doing so.

    My main thought is the handler method is resposible for executing the command and forwading to the correct view.

    (simplified)
    PHP Code:
      public function handleRequest() {
                  
    $cmd $this->AppController->getCommand$request ) ) 
                  
    $cmd->execute$request );
                  
    $this->forward$this->AppController->getView$request ) ); 
          } 
    Now suppose I was to add IF's and let's say an AuthenticationFilter failed. What would be the best way to then execute the command and view relevant to the failure. Would it simply be a case of throwing an exception or invoking an Error command.

    G
    Got Sig!

  2. #2
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    perhaps something on the order of
    PHP Code:
    public function handleRequest() {
                  
    $cmd $this->AppController->getCommand$request ) )
                  try {
                  
    $cmd->execute$request );
                  
    $this->forward$this->AppController->getView$request ) );
                  } 
                  catch (
    exception $e) {
                  
    // dispatch to error handler
                  
    }
          } 
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  3. #3
    SitePoint Addict chiefmonkey's Avatar
    Join Date
    Aug 2002
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I still need to implement the filters. So I was roughly thinking of..

    PHP Code:
              public function handleRequest() {
               
            try{ 
            
    $processor =   new LogFilter( new AuthFilter(
                                          new 
    InputFilter(             
                                          new 
    Processor()
                                          ))); 
              
    $processor->process$request )
            
               
    $cmd $this->AppController->getCommand$request 
            
                         
    $cmd->execute$request )  
            
                         } catch(
    Exception $e) {
                            
    //Catch error thrown in the Filter classes                                       
                    
                       

    Got Sig!

  4. #4
    SitePoint Guru
    Join Date
    Feb 2006
    Location
    Pittsburgh, Los Angeles
    Posts
    706
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    When I've done this in the past I modeled it after way it was solved in the servlet api (part of j2ee). You just have a filter class (interface) with a single method "filter(request, FilterChain), in the method you can do some work and then decide whether you want to call the next filter by calling "FilterChain.next(request)" or you can decide to stop the chain by not calling it so the next filters + command aren't executed. The last node in the chain would be the Command.

  5. #5
    SitePoint Addict chiefmonkey's Avatar
    Join Date
    Aug 2002
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Snaily
    When I've done this in the past I modeled it after way it was solved in the servlet api (part of j2ee). You just have a filter class (interface) with a single method "filter(request, FilterChain), in the method you can do some work and then decide whether you want to call the next filter by calling "FilterChain.next(request)" or you can decide to stop the chain by not calling it so the next filters + command aren't executed. The last node in the chain would be the Command.
    The CoR is ideal for what I want, as I need to bail out when/if one of the filters fails.

    Although in my case the last node in chain does not call command. The easiest was I could see was if there was a failure in the chain to set the 'cmd' property in the Request class to 'ErrorCommand'.

    PHP Code:
     public function handleRequest( ) {
       
    //perform filter actions 
       //on failure set cmd option in request to Errorcommand

       
    $cmd $this->AppController->getCommand$request 
       
    $cmd->execute$request )  
       
    $this->forward$this->AppController->getView$request )
     } 
    it's not as graceful as I would like it, but it works.
    Got Sig!

  6. #6
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Umm...

    Why not add your Application Controller to the filter chain as well, to be treated as a filter as such? Then you can execute the required command pre process, and fetch the view as required post process? That is how I did it a while back, even though I don't currently use the Intercepting Filter at the moment

  7. #7
    SitePoint Guru
    Join Date
    Feb 2006
    Location
    Pittsburgh, Los Angeles
    Posts
    706
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The easiest was I could see was if there was a failure in the chain to set the 'cmd' property in the Request class to 'ErrorCommand'.
    Using a "FilterChain" or some sort would avoid all this, it really does seem the best way to deal with.
    I was just looking at the "symfony" framework and they seemed to have based what they do on the servlet api too, although they appeared to add some stuff.
    Why not add your Application Controller to the filter chain as well, to be treated as a filter as such?
    You often want the ability to have filters only filter some url...or a single (or group) of commands (or whatever is doing the work), so then there needs to be something that builds the "execution plan" before the frist fiter is called.

  8. #8
    SitePoint Addict chiefmonkey's Avatar
    Join Date
    Aug 2002
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Snaily
    Using a "FilterChain" or some sort would avoid all this, it really does seem the best way to deal with.
    Yes the filterchain is probably the best way of doing it. However I can't see a better way of doing it other than altering the request object and then exiting the chain. By having my command execution outside of the chain I allow for objects which fall off the end to be executed (working on the basis that if it does then it has been processed correctly)

    If I understand you correctly are you saying that the command execution should be moved to within the filter, with perhaps a catch all at the end?

    George
    Got Sig!

  9. #9
    SitePoint Guru
    Join Date
    Feb 2006
    Location
    Pittsburgh, Los Angeles
    Posts
    706
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    By having my command execution outside of the chain I allow for objects which fall off the end to be executed
    I'm not sure what you mean by this.
    If I understand you correctly are you saying that the command execution should be moved to within the filter, with perhaps a catch all at the end?
    The last resource of the "FilterChain" should be what is actually doing the work. So the constructor of the FilterChain would possibly take a list of filters and the command (better way would pass it some config object it could build things from). Doing this allows you to filter the request on its way to the command and on the way back (any code done after you call $filterChain->next($request) will happen after the command executed this is nice for likes like caching).

    Anyhow, how you actually use this really depends on the rest of your architecture, in particular how you are managing your "Views" and such. When I used it I had a response object too, which controlled which view would be used (based on values set by the filters/command). So in the
    controller you had something like this:
    PHP Code:
    $filterChain = new FilterChain(....);
    $response = new Response(...);
    $request = new Request(...);
    // this will call the first resource, and then its up to that resource whether the next will be used.
    $filterChain->next($request$response);
    $response->commit(); 

  10. #10
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Shouldn't Filters be (binary) Trees rather than Chains? This enables each filter to know how to continue on success or on failure. Let me illustrate
    PHP Code:
    class Assertion {
        function 
    __construct($success true$failure false) {
            
    $this->next = array($failure$success);
        }
        function 
    exec($r) {
            
    $next $this->next[intval($this->is_true($r))];
            return 
    is_object($next) ? $next->exec($r) : $next;
        }
    }

    class 
    HaveEmail extends Assertion {
        function 
    is_true($r) { return isset($r['email']); }
    }
    class 
    HaveCustid extends Assertion {
        function 
    is_true($r) { return isset($r['customerid']); }
    }
    class 
    HavePass extends Assertion {
        function 
    is_true($r) { return isset($r['pass']); }
    }

    // login with email OR customer ID

    $flow =
        new 
    HaveEmail(
            
    /* on success */ 
            
    new HavePass("[email OK]""[invalid password]"),
            
    /* on failure */ 
            
    new HaveCustid(
                
    /* on success */ 
                
    new HavePass("[customerid OK]""[invalid password]"),
                
    /* on failure */ 
                
    "[login failed]"
            
    )
        );

    print 
    $flow->exec(array('email' => 'a''pass' => 'x'));
    print 
    $flow->exec(array('customerid' => 'a''pass' => 'x'));
    print 
    $flow->exec(array('email' => 'a'));
    print 
    $flow->exec(array('pass' => 'x')); 

  11. #11
    SitePoint Addict chiefmonkey's Avatar
    Join Date
    Aug 2002
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I see as more of a linked list. After all if the filter fails, then you do not call the next() method. I suppose if you were to have a more complex chain then you could use some type of n-ary tree

    Thanks for the input everyone.

    George
    Got Sig!


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
  •