SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 51
  1. #1
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Design Patterns Catalogue

    Hello, I got thinking today that with all the discussion about patterns, that what we need is a catelog of patterns that us PHP developers use day to day, so I've started this thread.

    The idea is that members who use a pattern, any will do I suppose so long as the posted example works, has the revalant underlying script, etc and is PHP, will be as kind to post it to this thread?

    Then, whenever someone reads about a particular pattern, or even post, they can start a thread about it, to discuss their issue(s) further in regards to that pattern. The idea is that this thread will be a catelog of pattern examples, with no discussion, so to avoid bloating this thread.

    SweatJe is about to publish a new book later this year (summer) on PHP patterns, and I get the idea that this thread could be a supplement to that book, so what someone can't find in SweatJe's book, they'll maybe find it here, in this thread...

    Anyways, I'll kick things off with two examples

    Decorator
    ---------

    Purpose of this pattern is to add extra functionality to the decorated class at run time. So you are not altering the class(es) that are to be decorated, thus you are extending the life of the said class(es).

    PHP Code:
    abstract class AbstractRating {
            protected 
    $decoratable;
            
            public function 
    __construct$decoratable ) {
                
    $this -> decoratable $decoratable;
            }
            
            abstract public function 
    getRating();
        }

        class 
    PoorRating extends AbstractRating {
            protected 
    $rating 1;
            
            public function 
    __construct$decoratable ) {
                
    parent::__construct$decoratable );
            }
            
            public function 
    getRating() {
                return 
    $this -> decoratable -> getRating() + $this -> rating;
            }
        }
        
        class 
    AverageRating extends AbstractRating {
            protected 
    $rating 2;
            
            public function 
    __construct$decoratable ) {
                
    parent::__construct$decoratable );
            }
            
            public function 
    getRating() {
                return 
    $this -> decoratable -> getRating() + $this -> rating;
            }
        }
        
        class 
    GoodRating extends AbstractRating {
            protected 
    $rating 3;
            
            public function 
    __construct$decoratable ) {
                
    parent::__construct$decoratable );
            }
            
            public function 
    getRating() {
                return 
    $this -> decoratable -> getRating() + $this -> rating;
            }
        }
        
        class 
    Ratings {
            private 
    $rating 3;
            
            public function 
    __construct() {
            }
            
            public function 
    getRating() {
                return 
    $this -> rating// typeof integer
            
    }
        }
        
        
    $rating = new GoodRating( new AverageRating( new Ratings ) );
        
    // we are decorating the Ratings object
        
    echo( $rating -> getRating() ); 
    ViewHelper
    ----------

    Purpose of this pattern is to separate functionality away from the View. The important point of using this pattern is to remember to separate the domain from the presentation, as I have done.

    For example you'd use if you wanted to output tabular data with alternating rows of colour. In this case, the Template class would have the presentational HTML for this, with the ListHelper class having the logic to decide which HTML to use, from the Template class.

    PHP Code:
    // controller
    $helper = new ListHelper'list.template.tpl' );
    $helper -> run$data );
    ...
    $view = new ExampleView'template.tpl' );
    $view -> add'list'$helper -> toHtml() );
    ... 
    PHP Code:
    class ListHelper {
    private 
    $Template;

    public function 
    __construct$filename ) {
    $this -> template = new Template$filename );
    }

    public function 
    run$resultset ) {
    $html '';
    foreach( 
    $resultset as $row ) {
    $id $row['id'];
    $firstname $row['firstname'];
    $lastname $row['lastname'];
    $html .= $this -> template -> parse$id$firstname$lastname );
    }
    $this -> template -> setHtml$html );
    }

    public function 
    toHtml() {
    return 
    $this -> template -> getHtml();
    }
    }

    class 
    Template {
    private 
    $html '';
    private 
    $fragment;

    public function 
    __construct$filename ) {
    $this -> fragment = @file_get_contents$filename );
    }

    public function 
    setHtml$html ) {
    $this -> html $html;
    }

    public function 
    getHtml() {
    return 
    $this -> html;
    }

    public function 
    parse$id$firstname$lastname ) {
    $temp ereg_replace'<id />'$id$this -> fragment );
    $temp ereg_replace'<firstname />'$firstname$temp );
    $temp ereg_replace'<lastname />'$lastname$temp );
    return 
    $temp;
    }

    Last edited by Dr Livingston; Apr 2, 2005 at 03:11. Reason: Add the purpose of each pattern

  2. #2
    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)
    It would probably be better to use a wiki for that ?

  3. #3
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yep, but I have no available web space at the moment

  4. #4
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Rome
    Posts
    77
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I can donate! I'd be happy to help you with a few Mb!

  5. #5
    SitePoint Zealot
    Join Date
    Oct 2004
    Location
    naperville
    Posts
    189
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'd be interested in this as well, webspace and all. I'll set up a wiki on philbrodeur.com if no one minds the domain name If it actually gets going I can set it up as phpwiki.com or whatever.

  6. #6
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, was hoping to keep it to these forums, if the idea took off, and I hope it does, it'd be a sticky thread

    I just thought the forums were the best options, from the point of view of topical discussions of these blighters

  7. #7
    Currently Occupied; Till Sunda Andrew-J2000's Avatar
    Join Date
    Aug 2001
    Location
    London
    Posts
    2,475
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What happened to phppatterns.com, it seems short lived. It would be nice to have a Wiki there (relevant domain), where people can contribute freely, however Harry seems to have disappeared lately?

  8. #8
    SitePoint Zealot sike's Avatar
    Join Date
    Oct 2002
    Posts
    174
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    why don't you use http://www.wiki.cc/php/Main_Page ?

  9. #9
    SitePoint Evangelist jplush76's Avatar
    Join Date
    Nov 2003
    Location
    Los Angeles, CA
    Posts
    460
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Andrew-J2000
    What happened to phppatterns.com, it seems short lived. It would be nice to have a Wiki there (relevant domain), where people can contribute freely, however Harry seems to have disappeared lately?
    I've been wondering that myself...
    I've emailed him a couple times but haven't heard anything back and haven't seen anything from him in a while.
    My-Bic - Easiest AJAX/PHP Framework Around
    Now Debug PHP scripts with Firebug!

  10. #10
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP Patterns is still there as far as I know, but there has been no fresh content for a long time. Not sure what has happened to Harry but hope it's nothing serious.

    As for a Wiki, I hope it doesn't go the same way as PHP Patterns. But where ever this catelog ends up, it has to be easily accessable for everyone, and allow discussions as I see it, as without the discussions, it's all pointless really.

  11. #11
    SitePoint Zealot
    Join Date
    Oct 2004
    Location
    naperville
    Posts
    189
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The only thing wrong with forums is orginization - each pattern really should have its own thread and then we would need a "master thread".

    Edit - I'm not convinced the ratings example is so hot; you're not adding functionality but rather a different type of rating. Is this really the general purpose of the pattern? No offense; I'm still learning some of this stuff.

  12. #12
    SitePoint Enthusiast
    Join Date
    Jun 2004
    Location
    London
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi all,

    A while back not to long ago i created a sourceforge project. http://sourceforge.net/projects/standardpattern/
    With a simular idea in mind patterns with class examples and unit tests using "Open Source" programming languages php, python, ruby ...
    Never actually done anything with the project.

    Something along the lines of http://patternshare.org/ would be nice.
    This is a cool view of all the patterns at patternshare.org http://patternshare.org/default.aspx...rganizingTable

    Note: patternshare.org smells of Microsoft. http://toolbar.netcraft.com/site_rep...tternshare.org
    Last edited by davro; Mar 31, 2005 at 15:33.
    David Stevens, create-inspire
    PHP London, www.phplondon.org

  13. #13
    Massimiliano Bruno Giordano sid egg's Avatar
    Join Date
    Aug 2004
    Location
    Canada
    Posts
    1,280
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Obligatory spelling correction:

    Catalog.
    GamesLib.com - the slickest, most complete and
    easily navigatible flash games site on the web.

  14. #14
    Non-Member melancholic's Avatar
    Join Date
    Nov 2004
    Location
    Australia
    Posts
    447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Obligatory obligatory spelling correction:

    Catalogue

  15. #15
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm not convinced the ratings example is so hot;
    I know the example is overly simplistic, but this is what I arrived at whilst understanding this pattern. What the example does however show, is how a Decorator should look like, from the inside point of view. Ie, how a Decorator works internally as I had trouble following what examples have in the past, been posted to these forums

    I was actually looking forwards to a lot more enthusiasm for this, and now I'm disappointed that no one else has contributed

    Come on gurus, don't be shy, give up your patterns...

  16. #16
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, here goes nothing:

    Data Mapper
    PHP Code:
    // Base class
    class DataMapper
    {
      var 
    $dbh;

      function 
    insert($data)
      {
        
    trigger_error("Abstract call...");
      }

      function 
    delete($id)
      {
        
    trigger_error("Abstract call...");
      }

      function 
    update($data)
      {
        
    trigger_error("Abstract call...");
      }
    }

    class 
    ProductMapper extends DataMapper
    {
      function 
    ProductMapper(&$dbh)
      {
        
    $this->dbh =& $dbh;
      }

      function 
    insert($data)
      {
        
    /* Application specific, but for example:
            $this->dbh->query("INSERT INTO users VALUE(" . $data['username'] . ", " . $data['password']); */
      
    }

      function 
    delete($data)
      {
        
    /* Application specific, e.g:
            $this->dbh->query("DELETE FROM users WHERE id = " . (int) $id); */
      
    }

      function 
    update($data)
      {
        
    /* Application specific, e.g:
            $this->dbh->query("UPDATE users SET username = " . $data . " WHERE id = " . $data['id']); */
      
    }

      
    // Maybe some other functions too...

      
    function getAll() {...}

      function 
    findById($id) {...}

      function 
    findByFoo($bar) {...}


  17. #17
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by melancholic
    Obligatory obligatory spelling correction:

    Catalogue
    Obligatory pedantry...

    Catalog is the US spelling so could probably be considered acceptable.

  18. #18
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Chain Of Responsibility
    ---------------------

    Using a SWITCH to delegate a decision has it's drawbacks, for example you need to change the script to add another decicion. With the CoR you do not need to change anything, you just add a new handler, provided you adhere to the interface.

    Btw, this is the 'classic' GoF (Group of Four) pattern I've posted.

    PHP Code:
        // generic handlers
        
    $h1 = new Handler1;
        
    $h2 = new Handler2;
        
        
    // handle a given request
        
    $h1 -> setHandler$h2 );
        
    $h1 -> handleRequest$request );
        
        abstract class 
    Handler {
            protected 
    $successor;
            
            public function 
    __construct() {
            }
            
            public function 
    setHandlerHandler $successor ) {
                
    $this -> successor $successor;
            }
            
            abstract public function 
    handleRequest$request );
        }
        
        class 
    Handler1 extends Handler {
            public function 
    __construct() {
                
    parent::__construct();
            }
            
            public function 
    handleRequest$request ) {
                if( 
    $request == 'add' ) {
                    
    // do add
                
    } else {
                    if( 
    $this -> successor != NULL ) {
                        
    $this -> successor -> handleRequest$request );
                    }
                }
            }
        }
        
        class 
    Handler2 extends Handler {
            public function 
    __construct() {
                
    parent::__construct();
            }
            
            public function 
    handleRequest$request ) {
                if( 
    $request == 'view' ) {
                    
    // do view
                
    } else {
                    if( 
    $this -> successor != NULL ) {
                        
    $this -> successor -> handleRequest$request );
                    }
                }
            }
        } 
    And another example as requested (below)

    PHP Code:
    class AdminController extends ActionChainController {
            public 
    $view;
            
            public function 
    __construct() {
                
    parent::__construct'Create' );
                
    parent::attach'Modify' );
                
    parent::attach'Remove' );
                
    parent::attach'Index' );
            }
            
            public function 
    getView() {
                return 
    $this -> view;
            }
            
            public function 
    executeHttpRequest $reqHttpResponse $res ) { 
                
    $request $req -> getParameter'cmd' );
                if( empty( 
    $request ) ) {
                    
    $request 'index';
                }
                
    $this -> process$request );
                
                
            }
        } 
    PHP Code:
    interface IAction {
            public function 
    isSecure();
            public function 
    getView();
        }
        
        interface 
    IActionChain {
            public function 
    attach$handler );
            public function 
    process$request );
        }
        
        abstract class 
    Action implements IAction {
            protected 
    $view;
            
            public function 
    __construct() {
            }
            
            public function 
    isSecure() {
                return 
    true;
            }
            
            public function 
    getView() {
                return 
    $this -> view;
            }
            abstract public function 
    executeHttpRequest $reqHttpResponse $res );
        }
        
        abstract class 
    ActionChain implements IActionIActionChain {
            protected 
    $view;
            protected 
    $count = -1;
            protected 
    $handlers = array();
            
            public function 
    __construct$handler ) {
                
    $this -> handlers[++$this -> count] = new $handler$this );
            }
            
            public function 
    attach$handler ) {
                
    $this -> doAttach( new $handler$this ) );
            }
            
            public function 
    process$request ) {
                
    $handle $this -> handlers[0];
                
    $handle -> handleRequest$request );
            }
            
            public function 
    isSecure() {
                return 
    true;
            }
            
            public function 
    getView() {
                return 
    $this -> view;
            }
            abstract public function 
    executeHttpRequest $reqHttpResponse $res );
            
            private function 
    doAttach$handler ) {
                
    $temp $this -> handlers[$this -> count];
                
    $temp -> setHandler$handler );
                
    $this -> handlers[++$this -> count] = $handler;
            }
        } 
    Last edited by Dr Livingston; Apr 2, 2005 at 12:06. Reason: Add the purpose of this pattern

  19. #19
    SitePoint Enthusiast
    Join Date
    Jun 2004
    Location
    London
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Basic Patterns:
    HttpRequest
    FrontController
    Controller
    ---------------------
    PHP Code:
    class HttpRequest
    {
        function 
    HttpRequest() { }
        
        function 
    doGet() {
            return 
    $_GET;
        }
        function 
    doPost() {
            return 
    $_POST;
        }

    PHP Code:
    class FrontController extends Controller
    {
        function 
    FrontController() {
            
    $Http  = new HttpRequest();
            
    $this->setListMerge($Http->doGet(), $Http->doPost());
        }

    PHP Code:
    class Controller
    {
        var 
    $data = array();

        function 
    Controller() { }    
      
        function 
    setList($array) {
            
    $this->data $array;
        }  
        function 
    setListMerge($array1$array2) {
            
    $this->setList(array_merge($array1$array2));
        }
        function 
    getList() {
            return 
    $this->data;
        }    
        function 
    getListItem($item) {
            return 
    $this->data[$item];
        }
        function 
    getListItemByNotation($item$notation$rid) {
            
    $note = array();
            
    $note explode('.'$this->getListItem($item));
            return 
    $note[$rid];
        }
        function 
    isEmpty() {
            if (
    count($this->data) <= 0) {
                return 
    true;
            } else {
                return 
    false;
            }
        }

    Last edited by davro; Apr 1, 2005 at 16:49.
    David Stevens, create-inspire
    PHP London, www.phplondon.org

  20. #20
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    sorry dudes, but without an explanation ( goals, raison d`etre ) of each pattern ... its just gibberish to the uneducated viewer ... & if educated then they dont need the example

  21. #21
    SitePoint Addict mx2k's Avatar
    Join Date
    Jan 2005
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    just a suggestion, if you want to do a pattern repository, you might want to include both php4 + php5 examples if possible. alot of people still have to stay within the php4 realm because of shared hosting or other reasons. plus that might add to appeal and help people migrate over to php5 in the long run as well.

    and a second suggestion, keep the thread alive, but also maybe use a wiki or repository somewhere else or even another forum attached to this one. that sums up the discussion here, but keep the discussion here cause you never know who might show up with something good to add.

    i love the idea Dr. L cause idiots like me have to read books like head first design patterns and professional php5

  22. #22
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I certainly like to see code so appreciate the postings. I also to agree firepages that without the simple description, explaining the problem and describing how it works the are not much help. Patterns are not implementations and showing implementations without context reduces the communication value of patterns.

    I also have some questions about the patterns listed and I think it is the discussion if the ideas of the pattern that are of value.

    For instance, overrunner's Data Mapper look a lot like the Table Data Gateway pattern to me. Table Data Gateway is a fairly simple pattern to describe and give examples of. Data Mapper is considerably more complex and is often implemented used a combination of patterns. In fact several different combinations are possible.

    Dr Livingston's is a good example of Chain Of Responsibility. I would be interested in seeing other examples. There was a discussion recently that for the request the Intercepting Filter is a better choice, but for controllers Chain Of Responsibility is the way to go. So showing Chain Of Responsibility combined with the Command pattern would be of interest.

    Of davro's patterns only Front Controller is a pattern that I know. I do not think HTTP Request and Controller are patterns (correct me if I'm wrong). And the Front Controller as shown does not seem to dispatch which is a central function of the Front Controller pattern. Though I like the idea of having a base Controller class for Front, Page and Application Controllers.
    Christopher

  23. #23
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So showing Chain Of Responsibility combined with the Command pattern would be of interest.
    I don't think that the combination of these two patterns are of any benifit to either one, as to me there is some conflict? Both patterns work on a Request of some kind, but what I can say is that Command works wonders with a Helper class, much like a ViewHelper.

    PHP Code:
    // ...
    $helper = new RequestHelper$this -> req ); // pass Request object
    $command $helper -> getCommand();
    ... 
    PHP Code:
    class RequestHelper {
    private 
    $req;

    public function 
    __constructHttpRequest $req ) {
    $this -> req $req;
    }

    public function 
    getCommand() {
    // here you verify command requested, etc
    // and return an instance of the class to be executed, as 
    // in an action
    }

    private function 
    isCommandFile$command ) {
    if( empty( 
    $command ) ) {
    $command 'default';
    }
    return 
    'commands/'.$command.'.php';
    }

    You may also add other tasks to this Helper in relation to a Request, but it's a fine line to what you put in it. Hope that helps, as I can't see Command and CoR working together, sorry

  24. #24
    SitePoint Enthusiast
    Join Date
    Jun 2004
    Location
    London
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi all,

    Sorry i can see how my last post might have added some entropy to the domain.
    Hopefully this post might help things a little, or maybe not.

    Abstract Controller Patterns:
    FrontController http://www.martinfowler.com/eaaCatal...ontroller.html
    ApplicationController http://www.martinfowler.com/eaaCatal...ontroller.html
    PageController http://www.martinfowler.com/eaaCatal...ontroller.html
    ---------------------
    PHP Code:
    class FrontController extends Controller
    {
        function 
    FrontController() {
            
    $Http  = new HttpRequest();
            
    $this->setListMerge($Http->doGet(), $Http->doPost());
        }
    }

    class 
    ApplicationController
    {
        function 
    ApplicationController() {
            
    $Request  = new FrontController();
            
    // do-main
        
    }
    }

    class 
    PageController
    {
        function 
    PageController() {
            
    $Request  = new FrontController();
            
    // do-main
        
    }

    Concrete Controller
    PHP Code:
    class Controller
    {
        var 
    $data = array();

        function 
    Controller() { }    
      
        function 
    setList($array) {
            
    $this->data $array;
        }  
        function 
    setListMerge($array1$array2) {
            
    $this->setList(array_merge($array1$array2));
        }
        function 
    getList() {
            return 
    $this->data;
        }    
        function 
    getListItem($item) {
            return 
    $this->data[$item];
        }
        function 
    getListItemByNotation($item$notation$rid) {
            
    $note = array();
            
    $note explode($notation$this->getListItem($item));
            return 
    $note[$rid];
        }
        function 
    isEmpty() {
            if (
    count($this->data) <= 0) {
                return 
    true;
            } else {
                return 
    false;
            }
        }

    HTTP Handler Object
    PHP Code:
    class HttpRequest
    {
        function 
    HttpRequest() { }
        
        function 
    doGet() {
            return 
    $_GET;
        }
        function 
    doPost() {
            return 
    $_POST;
        }

    Last edited by davro; Apr 3, 2005 at 09:09.
    David Stevens, create-inspire
    PHP London, www.phplondon.org

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

    This is a useful pattern to learn where you need to construct hierarchy data structures. The example I've posted below is for an XML file, which I use to construct a web page on the fly, but the hierarchy structure could be from the database. It doesn't matter really.

    First, the XML file

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <fragments>
    	<fragment>
    		<id>page</id>
    		<parent></parent>
    		<controller></controller>
    		<fragment>
    			<id>header</id>
    			<parent>page</parent>
    			<controller></controller>
    		</fragment>
    		<fragment>
    			<id>body</id>
    			<parent>page</parent>
    			<controller></controller>
    			<fragment>
    				<id>partition</id>
    				<parent>body</parent>
    				<controller></controller>
    			</fragment>
    		</fragment>
    		<fragment>
    			<id>footer</id>
    			<parent>page</parent>
    			<controller></controller>
    		</fragment>
    	</fragment>
    </fragments>
    Now the script,

    PHP Code:
    interface IWalker {
            public function 
    __construct$children );
            public function 
    walkIParser $parser );
        }
        
        class 
    XmlWalker implements IWalker {
            private 
    $children;
            
            public function 
    __construct$children ) {
                if( !
    $children instanceof DomNodeList ) {
                    throw new 
    IllegalParameterException'thrown exception on, expected parameter(s) not found.' );
                    break;
                }
                
    $this -> children $children;
            }
            
            public function 
    walkIParser $parser ) {
                foreach( 
    $this -> children as $child ) {
                    if( 
    $child instanceof DomElement ) {
                        
    $parser -> push$child );
                        try {
                            
    $walker = new XmlWalker$child -> childNodes );
                            
    $walker -> walk$parser );
                        } catch( 
    IllegalParameterException $e ) {
                            die( 
    $e -> getMessage() );
                        }
                    }
                }
            }
        }

    class 
    ApplicationFaultException extends Exception {
            public function 
    __construct$message ) {
                
    parent::__construct$message );
            }
        }
        
        class 
    IllegalParameterException extends Exception {
            public function 
    __construct$message ) {
                
    parent::__construct$message );
            }
        }
        
        interface 
    IParser {
            public function 
    getRoot();
            public function 
    push$fragment ); // DomElement
        
    }
        
        class 
    XmlAdaptableCompositeParser implements IParser {
            private 
    $decoratable;
            
            public function 
    __construct$decoratable ) {
                
    $this -> decoratable $decoratable;
            }
            
            public function 
    getRoot() {
                return 
    $this -> decoratable -> getRoot();
            }
            
            public function 
    push$fragment ) {
                if( 
    $fragment -> nodeName == 'fragment' ) {
                    return 
    $this -> decoratable -> push$fragment );
                }
            }
        }
        
        class 
    XmlCompositeParser implements IParser {
            private 
    $root;
            
            public function 
    __construct$fragment ) {
                if( !
    $fragment instanceof DomElement ) {
                    throw new 
    IllegalParameterException'thrown exception on, expected parameter(s) not found.' );
                    break;
                }
                
    $this -> root = new Composite$fragment );
            }
            
            public function 
    getRoot() {
                return 
    $this -> root;
            }
            
            public function 
    push$fragment ) {
                
    $composite = new Composite$fragment );
                if( 
    $tmp $this -> traverse$this -> getRoot(), $fragment ) ) {
                    
    $tmp -> attach$composite );
                }
            }
            
            private function 
    traverse$composite$fragment ) {
                
    $parent $fragment -> getElementsByTagName'parent' );
                
    $parent $parent -> item) -> nodeValue;
                if( 
    $composite -> getId() == $parent ) {
                    return 
    $composite;
                } else {
                    if( 
    $composite -> hasChildren() ) {
                        
    $children $composite -> getChildren();
                        foreach( 
    $children as $child ) {
                            
    $c = new Composite$fragment );
                            if( 
    $tmp $this -> traverse$child$fragment ) ) {
                                
    $tmp -> attach$c );
                            }
                        }
                    }
                }
            }
        }
        
        class 
    Composite extends Component {
            public function 
    __construct$fragment ) {
                if( !
    $fragment instanceof DomElement ) {
                    throw new 
    IllegalParameterException'throw exception on, expected parameter(s) not found.' );
                    break;
                }
                
    parent::__construct$fragment );
            }
        }
        
        abstract class 
    Component {
            protected 
    $id;
            protected 
    $parent;
            protected 
    $template;
            protected 
    $children = array();
            protected 
    $controller;
            
            public function 
    __construct$fragment ) { 
                
    $this -> fragment $fragment;
                
    $this -> id $this -> getNode'id' );
                
    $this -> controller $this -> getNode'controller' );
            }
            
            public function 
    hasChildren() {
                return 
    count$this -> children );
            }
            
            public function 
    getChildren() {
                return 
    $this -> children;
            }
            
            public function 
    getNode$node ) {
                
    $items $this -> fragment -> getElementsByTagName$node );
                return 
    $items -> item) -> nodeValue;
            }
            
            public function 
    setTemplate$template ) {
                
    $this -> template $template;
            }
            
            public function 
    getTemplate() {
                return 
    $this -> template;
            }
            
            public function 
    getController() {
                return 
    $this -> controller;
            }
            
            public function 
    getId() {
                return 
    $this -> id;
            }
            
            public function 
    attach$composite ) {
                
    $this -> children[] = $composite;
            }
        } 
    And use it with this for example,

    PHP Code:
    $dom = new DomDocument;
        
    $dom -> load'test.xml' );
        
    $fragment $dom -> documentElement -> childNodes;
        
        
    $walker = new XmlWalker$fragment -> item) -> childNodes );
        
    // require a decorator to filter tags by the name of 'fragment'
        
    $parser = new XmlAdaptableCompositeParser( new XmlCompositeParser$fragment -> item) ) );
        
    $walker -> walk$parser );
        
        echo( 
    '<pre>' ); print_r$parser -> getRoot() ); echo( '</pre>' ); 

    EDIT: 22/01/06

    If you find that you want to apply a number of filters prior to the controller, via a number of decorators, then you could take a what changes I made later;

    Note that there is no controller node as such from earlier examples, as the controller it's self is applied as a filter as well.

    Code:
    ...
    <fragment>
    			<id>header</id>
    			<parent>page</parent>
    			<filters>
    <filter name="PageController" pathname="pathname/to/file" />
    <filter name="FilterOneController" pathname="pathname/to/file" />
    <filter name="FilterTwoController" pathname="pathname/to/file" />
    </filters>
    		</fragment>
    ...
    Now, from XmlCompositeParser:ush( $fragment ); you would need to do the following before you add the composite to the composite structure, it's self;

    PHP Code:
    // ...
    $filters $fragment -> getElementsByTagName'filters' );
                
    $filters $filters -> item); 
                
    $tmp = array();
                if( 
    $filters instanceof DomElement ) {
                    foreach( 
    $filters -> childNodes as $filter ) {
                        if( 
    $filter instanceof DomElement ) {
                            
    $name $filter -> getAttribute'name' );
                            
    $pathname $filter -> getAttribute'pathname' );
                            include_once( 
    $pathname.strtolower$name ).'.php' );
                            
    $tmp[] = $name;
                            
                        }
                    }
                }
                
    $temp = array();
                
    $cl array_shift$tmp );
                
    $temp[] = $cl;
                foreach( 
    $tmp as $class ) {
                    
    $temp[] = new $classarray_shift$temp ) );
                }

    $composite array_shift$temp ); // holds newly generated decorators
                
    if( $tmp $this -> traverse$this -> getRoot(), $fragment ) ) {
                    
    $tmp -> attach$composite );
                } 
    For example, here is an example node, and it's output

    Code:
    ...
    <filters>
    					<filter name="Controller" pathname="controllers/" />
    					<filter name="ThirdController" pathname="controllers/" />
    					<filter name="SecondController" pathname="controllers/" />
    					<filter name="FirstController" pathname="controllers/" />
    				</filters>
    ...
    Code:
    Array
    (
        [0] => FirstController Object
            (
                [decorated:private] => SecondController Object
                    (
                        [decorated:private] => ThirdController Object
                            (
                                [decorated:private] => Controller
                            )
    
                    )
    
            )
    
    )
    PHP Code:
    class Controller {
            private 
    $decorated;
            
            public function 
    __construct() {
            }
            
        }

    class 
    FirstController {
            private 
    $decorated;
            
            public function 
    __construct$decorated ) {
                
    $this -> decorated $decorated;
            }
            
        }

    class 
    SecondController {
            private 
    $decorated;
            
            public function 
    __construct$decorated ) {
                
    $this -> decorated $decorated;
            }
            
        }

    class 
    ThirdController {
            private 
    $decorated;
            
            public function 
    __construct$decorated ) {
                
    $this -> decorated $decorated;
            }
            
        } 
    The decoration therefore happens automatically for you, just remember though to set the ordering correctly, and it's better to implement a common Interface as well.

    Yours, Dr Livingston
    Last edited by Dr Livingston; Jan 22, 2006 at 13:44.


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
  •