SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 39
  1. #1
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PicoContainer for PHP (Dependency Injection)

    Hi,

    Yesterday Iíve committed PHP5 version of PicoContainer (http://www.picocontainer.org/). You can grab source code along with tests from the Codehaus CVS repository (http://www.picocontainer.org/Source+Repositories). Module name is Ė yep Ė you are right Ė php. Iíve been working on this project for the last few weeks and have got some thoughts I would like to share. For those folks who are not familiar with DI concept (also known as Inversion of Control), please read Pico introduction (http://www.picocontainer.org/Two+minute+tutorial) or Martin Fowlerís article (http://www.martinfowler.com/articles/injection.html).

    First of all, why the hell bother with Dependency Injection for PHP5??? Idea of DI is well known in the Java world (Spring, Pico, Avalon and others), but PHP is not Java Ė thatís clear. We have a quite different runtime environment: canít preload and cache in memory all those fancy objects. But PHP and Java programs share common property: they will change a lot during they lifetime. There is one thing I hate about PHP: there are so many programs written in PHP, but itís so hard to find real good, well defined library for PHP. This makes as to write the same code over and over again. OK, we have wonderful tool at hand, as we can write programs in PHP fast. Thatís great, but why not to have standard libraries and assembly them fast into sophisticated, stable web applications???

    What do I hope from DI? That it will force as to think about interfaces. When using DI you simply canít (and donít have to!) clutter your scripts with globals, singletons and spaghetti code. You start thinking in different way. It was amazing for me how often clear design simply emerged in front of my eyes when I started thinking about object and itís dependencies defined in the constructor.

    So, proof of concept is ready for use in the codehaus repository. Iíll try to provide documentation (both in form of API doc and manuals), so people can put hands on Pico for PHP. But what I would love to do is to put this little beast into real open-source project. Given real problems in the real project we can discuss DI for PHP pros and cons. lastcraft, sweatje, Brenden, zimba: are your still wiling to help? zimba suggested to port Mojavi, but in my opinion itís to early. Maybe itís better to start with testing framework (mockís injection) as we can focus on pure dependencies resolving, rather than struggling with all those controllers, request and other MVC stuff.

    Cheers,
    pawelik

  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)
    So far I just had a chance to download it, locate the tests and run them. I will dig into it a bit more when I get into work today.

    One minor suggestion, you might want to end test/index.php with
    PHP Code:
    if (TextReporter::inCli()) {
            exit (
    $test->run(new TextReporter()) ? 1);
    }
    $test->run(new HtmlReporter()); 
    to give the user flexibility to run either CLI or in a browser.

    Regards,
    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
    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)
    Hi pawelik,

    Still digesting pico a bit and trying to think about how I would apply it to more realistic examples.

    In my own home-brewed DI, I allow for either injection or default construction. My classes often have several dependancies, so I took to passing them in as a keyed array so I would not have to track the specific order of parameters.

    To switch over to picocontainter, the first thing would be I could ditch the default construction, because the container would always be able to produce the desired real class or the mock you are injecting, so the only issue is how to address multiple depenancies for injection. It is my take that you would have to write some sort of a custom ConstructorInjectionComponentAdapter to accomodate this, or did I miss how multiple dependancies are handled somehow?

    Looks good so far.

    Regards,
    Jason

  4. #4
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I took a look at your work, pawelik, looking good, this project is looking more and more interesting by the minute

    I have whats probably a very silly question about your design; why is there a need to declare MutablePicoContainer and PicoContainer as two separate interfaces? Would a container ever only implement the second without implementing the first?

    Would it be a good idea to implement into the ServiceLocator the capability to use both constructor style injection as well as setter injection? This flexibility would allow for the minimal redesign of existing classes, and also open up usage to a larger user base. As a potential user of the project, the less I have to modify my domain classes, the more likely I am to use this service locator.

    Jason,
    Here are a couple of examples of usage that I can think of, just off the top of my head, based on the projects I've worked on recently:
    • Authenticator class which is likely to live embedded within your domain model classes, using the service locator you can easily switch between authentication mechanisms without breaking a sweat (no pun intended )
    • Payment gateway functionality within an ecommerce application: sometimes you might want to test your checkout and order submission process without actually contacting the payment gateway server, the container would allow for the switching between a mock payment gateway class and the real thing in a dynamic way. Moreover, different gateways implement their communications strategies differently, and a service locator would allow for the usage of different "payment" classes so long as they adhered to a common interface. Even when the payment gateway in use is always the same, I have run into the situation where parameters are different depending on which "store" you are viewing (Im talking about an ecommerce application that runs off the same database to provide different storefronts to different websites). In my current solution I am resorting to a very ugly global-like style to initialize the payment classes with parameters such as 'username', 'password' or 'url' for the gateway. PicoContainer would be the ideal and most elegant way to preconfigure these services away from the controller code.
    • Logging services, which I currently implement as a singleton, but this restricts me to having to modify every class that uses the logger if I ever want to either unit test them or switch to a different logging mechanism.


    Is it a good idea to call it PicoContainer? should it be a straight port of the java implementation? could there be aditional functionality that we might want to have in PHP that is not present in the original Java PicoContainer? (or viceversa).

    Most of my doubts regarding the ideal functionality come from having read quite a bit about Ruby's Needle lately (take a look, I'm sure it will spark some ideas) and realizing that DI can be much more than a class container or a singleton registry, once you start to think about all the useful ways to implement a Service Locator. Personally I would love to see much of the functionality included in Needle in this project (so long as it makes sense in PHP). Of course, if that were the case, this container wouldnt be much of a "pico" any more, would it?
    Garcia

  5. #5
    SitePoint Member
    Join Date
    Jan 2005
    Location
    Seaside, Ca
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just what I have been looking for. I even started coding my, very limited, port of Spring's Bean Factory.

    I can't wait to start using this.

  6. #6
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje

    One minor suggestion, you might want to end test/index.php with
    PHP Code:
    if (TextReporter::inCli()) {
            exit (
    $test->run(new TextReporter()) ? 1);
    }
    $test->run(new HtmlReporter()); 
    to give the user flexibility to run either CLI or in a browser.
    OK, I'll comitt this change today.

    Cheers,
    Pawelik

  7. #7
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Sydney
    Posts
    43
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am also interested in this.

    Hopefully I can actually find a good use for it.

  8. #8
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,

    Quote Originally Posted by sweatje
    In my own home-brewed DI, I allow for either injection or default construction.
    Iím not sure what do You mean by ďdefault constructionĒ here. Constructor with all arguments with defaults, that You can call as no-argument constructor? Sorry, itís not so clear for me.

    Quote Originally Posted by sweatje
    My classes often have several dependancies, so I took to passing them in as a keyed array so I would not have to track the specific order of parameters.
    Iím assuming that by Ąseveral dependenciesĒ You mean component (object) with several dependencies expressed as constructor params. Am I right? If so, have a look at the following examples.

    First of all we can have a class with concrete dependencies defined in the constructorís params:

    PHP Code:
    class SeveralDependanciesWithConcencrateClasses
    {
        private 
    $simpleTouchable;
        private 
    $alternativeTouchable
        
        function 
    __construct(SimpleTouchable $simpleTouchableAlternativeTouchable $alternativeTouchable)
        {
            
    $this->simpleTouchable $simpleTouchable;
            
    $this->alternativeTouchable $alternativeTouchable;
        }
        
        function 
    touch()
        {
            
    $this->simpleTouchable->touch();
            
    $this->alternativeTouchable->touch();
        }

    and than test. Of course all the dependencies are resolved by the container without extra information from us.

    PHP Code:
        function testDependsOnTwoDifferentWithoutParams()
        {
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('SimpleTouchable');
            
    $pico->registerComponentImplementation('AlternativeTouchable');
            
    $pico->registerComponentImplementation('SeveralDependanciesWithConcencrateClasses');
            
            
    $ci $pico->getComponentInstance('SeveralDependanciesWithConcencrateClasses');
            
    $this->assertNotNull($ci);
        } 
    Now, lets say we have a constructor witch takes 2 depended objects, both implementing the same interface:

    PHP Code:
    class SeveralDependanciesWithInterfaces
    {
        private 
    $simpleTouchable;
        private 
    $alternativeTouchable
        
        function 
    __construct(Touchable $simpleTouchableTouchable $alternativeTouchable)
        {
            
    $this->simpleTouchable $simpleTouchable;
            
    $this->alternativeTouchable $alternativeTouchable;
        }
        
        function 
    touch()
        {
            
    $this->simpleTouchable->touch();
            
    $this->alternativeTouchable->touch();
        }
    }


        function 
    testDependsOnTwoDifferentWithtInterfaceWithoutParams()
        {
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('SimpleTouchable');
            
    $pico->registerComponentImplementation('AlternativeTouchable');
            
    $pico->registerComponentImplementation('SeveralDependanciesWithInterfaces');
            
            try
            {
                
    $this->assertNotNull($pico->getComponentInstance('SeveralDependanciesWithInterfaces'));
                
    $this->fail();
            }
            catch (
    AmbiguousComponentResolutionException $e)
            {
                
    $this->pass();
            }
        } 
    Here automatic resolution will fail, as container has no clue what to do with two components matching constructorís criteria. We must give hint to the container in form of component parameters:

    PHP Code:
    class SeveralDependanciesWithInterfaceAndConcencrateClass
    {
        private 
    $simpleTouchable;
        private 
    $alternativeTouchable
        
        function 
    __construct(SimpleTouchable $simpleTouchableTouchable $alternativeTouchable)
        {
            
    $this->simpleTouchable $simpleTouchable;
            
    $this->alternativeTouchable $alternativeTouchable;
        }
        
        function 
    touch()
        {
            
    $this->simpleTouchable->touch();
            
    $this->alternativeTouchable->touch();
        }
    }

     function 
    testDependsOnTwoDifferentWithtParams()    
        {
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('SimpleTouchable');
            
    $pico->registerComponentImplementation('AlternativeTouchable');
            
    $pico->registerComponentImplementation(
                
    'SeveralDependanciesWithInterfaces'//key 
                
    'SeveralDependanciesWithInterfaces'//class name
                
    array('simpleTouchable' => new BasicComponentParameter('SimpleTouchable'),
                      
    'alternativeTouchable' => new BasicComponentParameter('AlternativeTouchable'))); //params - hint
                      
            
    $ci $pico->getComponentInstance('SeveralDependanciesWithInterfaces');           
            
    $this->assertNotNull($ci);
            
    $ci->touch();    
        }
        
        function 
    testDependsOnTwoDifferentWithtParamAndAutoWire()    
        {
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('SimpleTouchable');
            
    $pico->registerComponentImplementation('AlternativeTouchable');
            
    $pico->registerComponentImplementation('SeveralDependanciesWithInterfaceAndConcencrateClass',
                                                   
    'SeveralDependanciesWithInterfaceAndConcencrateClass',
                                                   array(
    'alternativeTouchable' => new BasicComponentParameter('AlternativeTouchable')));            
                      
            
    $ci $pico->getComponentInstance('SeveralDependanciesWithInterfaceAndConcencrateClass');           
            
    $this->assertNotNull($ci);
            
    $ci->touch();    
        } 
        
        function 
    testDependsOnTwoDifferentOnlyWithtAutoWire()
        {
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('SimpleTouchable');
            
    $pico->registerComponentImplementation('Touchable','AlternativeTouchable');
            
    $pico->registerComponentImplementation('SeveralDependanciesWithInterfaceAndConcencrateClass');
            
            
    $ci $pico->getComponentInstance('SeveralDependanciesWithInterfaceAndConcencrateClass');           
            
    $this->assertNotNull($ci);
            
    $ci->touch();
        } 
    I hope itíll clear up possible methods of dependency configuration. If you mean sth else by a Ąseveral dependenciesĒ, please, provide fragment of code, as I think it will be the easiest way to communicate.

    Quote Originally Posted by sweatje
    To switch over to picocontainter, the first thing would be I could ditch the default construction, because the container would always be able to produce the desired real class or the mock you are injecting, so the only issue is how to address multiple depenancies for injection. It is my take that you would have to write some sort of a custom ConstructorInjectionComponentAdapter to accomodate this, or did I miss how multiple dependancies are handled somehow?
    No problem with custom ComponentAdapter. I have couple of them to write (SetterInjection, LazyInclude etc.) Letís first make sure we understand each other, thought.

    Cheers,
    pawelik

  9. #9
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi ghurtado,

    Thnx for Your thoughtful replay.

    Quote Originally Posted by ghurtado

    I have whats probably a very silly question about your design; why is there a need to declare MutablePicoContainer and PicoContainer as two separate interfaces? Would a container ever only implement the second without implementing the first?
    No, itís impossible to implement only the former without implementing the first, as:

    PHP Code:
    interface MutablePicoContainer extends PicoContainer 
    {
    ...

    The point here is to make clear distinction between component retrieval (PicoContainer) and registering them (could have several interfaces here).

    Quote Originally Posted by ghurtado
    Would it be a good idea to implement into the ServiceLocator the capability to use both constructor style injection as well as setter injection? This flexibility would allow for the minimal redesign of existing classes, and also open up usage to a larger user base. As a potential user of the project, the less I have to modify my domain classes, the more likely I am to use this service locator.
    Definitely agree. SetterInjectionCA is on my TODO list. I think itís a matter of 2 weeks to implement one.

    Quote Originally Posted by ghurtado
    Is it a good idea to call it PicoContainer? should it be a straight port of the java implementation? could there be aditional functionality that we might want to have in PHP that is not present in the original Java PicoContainer? (or viceversa).
    I ask myself those questions all the time :-)
    Should it be called Pico? Yes, I think so. Should it strictly follow Java design? Of course not! Java version was inspiration, starting point. Now we can evolve in the directions that makes sense for PHP (ex. Lazy include).

    Quote Originally Posted by ghurtado
    Most of my doubts regarding the ideal functionality come from having read quite a bit about Ruby's Needle lately (take a look, I'm sure it will spark some ideas) and realizing that DI can be much more than a class container or a singleton registry, once you start to think about all the useful ways to implement a Service Locator. Personally I would love to see much of the functionality included in Needle in this project (so long as it makes sense in PHP). Of course, if that were the case, this container wouldnt be much of a "pico" any more, would it?
    Thnx for the link, Iíll definitely have look at Needle. But some thoughts here. I would like to avoid big, fat, just another framework build around DI. Thatís the route Javaís Spring took. I donít want to start new framework project. Rather, prepare configuration kernel to be embedded in different frameworks.

    Cheers,
    pawelik

  10. #10
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jgchristopher
    Just what I have been looking for. I even started coding my, very limited, port of Spring's Bean Factory.

    I can't wait to start using this.
    Thatís great. Let me know if you discover any bug or need new feature.

    Cheers,
    pawelik

  11. #11
    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)
    Quote Originally Posted by pawelik
    Iím not sure what do You mean by ďdefault constructionĒ here. Constructor with all arguments with defaults, that You can call as no-argument constructor? Sorry, itís not so clear for me.
    Yes, basically you have figured it out.

    "Normally" I call the object without any arguments to the constructor, and it knows enought about where other objects are (singletons, registries, classname to just instanciate, etc ...) to create all the dependant objects itself. Thus the application "knits" itself together without significant intervention on my part.

    Now at other times, in this object which might have five or six dependancies, of which one or two I want to have "non-default" (ie, testing w/ mocks). For a couple of reasons:
    a) I am lazy and did not want to keep looking up the parameter order
    b) it helps in PHP4 with object references
    I used an associative array with key names for the dependant objects rather than multiple parameters.

    I think I will have to get a little better feel for Pico before I decide if I need to write and "associative array component adapter" or just ditch it and go back to the ordered parameters.

    Thanks much for the posted example, I will definitly go back and investigate.

    Does Pico ever get into problems with recursive dependencies?

    i.e.
    PHP Code:
    class A(B $B) {}
    class 
    B(C $C) {}
    class 
    C(A $A) {} 

  12. #12
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    Yes, basically you have figured it out.

    "Normally" I call the object without any arguments to the constructor, and it knows enought about where other objects are (singletons, registries, classname to just instanciate, etc ...) to create all the dependant objects itself. Thus the application "knits" itself together without significant intervention on my part.
    So there is a case where we could get rid of all those nasty Singletons, hard-coded dependencies and so on. After all, this is what Pico is all about, isnít it?

    Quote Originally Posted by sweatje
    Now at other times, in this object which might have five or six dependancies, of which one or two I want to have "non-default" (ie, testing w/ mocks). For a couple of reasons:
    a) I am lazy and did not want to keep looking up the parameter order
    b) it helps in PHP4 with object references
    I used an associative array with key names for the dependant objects rather than multiple parameters.
    From my point of view, Parameters in Pico are exactly the same as Yours associative array. You donít have to remember about parameters order, itís Ďparameter nameí => ParameterObject array.

    Quote Originally Posted by sweatje
    I think I will have to get a little better feel for Pico before I decide if I need to write and "associative array component adapter" or just ditch it and go back to the ordered parameters.
    If You could post example of the real code, I could try to transform it to a Pico version.

    Quote Originally Posted by sweatje

    Does Pico ever get into problems with recursive dependencies?

    i.e.
    PHP Code:
    class A(B $B) {}
    class 
    B(C $C) {}
    class 
    C(A $A) {} 
    No, it will fail with CyclicDependencyException:

    PHP Code:

       
    function testFailWithCyclicDependency()
        {        
            
    $pico = new DefaultPicoContainer();
            
    $pico->registerComponentImplementation('A');
            
    $pico->registerComponentImplementation('B');
            
    $pico->registerComponentImplementation('C');                
           
            try
            {
                
    $c2 $pico->getComponentInstance('A');
                
    $this->fail();
            }
            catch (
    CyclicDependencyException $e)
            {
                
    $this->pass();
            }               
        } 

    Cheers,
    pawelik

  13. #13
    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)
    Hi pawelik,

    Just some more minor tweaks to the tests I saw as I was poking around:

    Code:
     $ cvs diff DefaultPicoContainerTests.php
    Index: DefaultPicoContainerTests.php
    ===================================================================
    RCS file: /home/projects/picocontainer/scm/php/test/DefaultPicoContainerTests.php,v
    retrieving revision 1.1
    diff -c -r1.1 DefaultPicoContainerTests.php
    *** DefaultPicoContainerTests.php       7 Feb 2005 17:14:59 -0000       1.1
    --- DefaultPicoContainerTests.php       24 Feb 2005 15:19:21 -0000
    ***************
    *** 101,107 ****
              $girl = $pico->getComponentInstance('Girl');
              $this->assertNotNull($girl);
    
    !         $girl->kissSomeone();
          }
    
    
    --- 101,107 ----
              $girl = $pico->getComponentInstance('Girl');
              $this->assertNotNull($girl);
    
    !         $this->assertWantedPattern('/kissed.*girl/i',$girl->kissSomeone());
          }
    
    
    ***************
    *** 130,143 ****
              $boy1 = $pico->getComponentInstance('Boy');
              $boy2 = $pico->getComponentInstance('Boy');
    
    !         if ($boy1 === $boy2)
    !         {
    !             $this->fail();
    !         }
    !         else
    !         {
    !             $this->pass();
    !         }
          }
    
          function testGetAdapterWithTypeWhereTypeIsSubclass()
    --- 130,144 ----
              $boy1 = $pico->getComponentInstance('Boy');
              $boy2 = $pico->getComponentInstance('Boy');
    
    !         $this->assertCopy($boy1, $boy2);
    !         //if ($boy1 === $boy2)
    !         //{
    !         //    $this->fail();
    !         //}
    !         //else
    !         //{
    !         //    $this->pass();
    !         //}
          }
    
          function testGetAdapterWithTypeWhereTypeIsSubclass()
    I think that whole if/else block is the functional equiavlent of the standard SimpleTest assertion assertCopy.

  14. #14
    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)
    Just a quick sanity check here (or maybe not so quick, given how long the post turned out). I started playing around with how to use Pico in a more realistic setting, and this is basically the results of my experimentation.

    Started with a "Model" class which needs an ADOdbConnection object passed to it in the constructor. I had a function acting as a parameterized factory for these connections, so it seemed I needed a proxy class which would take my function parameter as a constructor argument, create the connection and proxy calls to it. This is what I came up with:

    PHP Code:
    /**
     * proxy class for amp_adodb_connection generated ADOconnections
     */
    class AmpAdodbConn {
        protected 
    $conn;
        public function 
    __construct($db) {
            
    $this->conn amp_adodb_connection($db);
        }
        public function 
    __call($method$args) {
            return 
    call_user_func_array(array($this->conn$method), $args);
        }

    So to start using this, we have:
    PHP Code:
    $pico = new DefaultPicoContainer;
    $pico->registerComponent(
        new 
    CachingComponentAdapter(
            new 
    ConstructorInjectionComponentAdapter(
                 
    'conn','AmpAdodbConn'
                
    ,array('db' => new ConstantParameter('prdcrm')
                ))));        

    $c $pico->getComponentInstance('conn');

    $rs $c->execute('select user,sysdate from dual');
    var_dump($rs->fetchRow()); 
    Next, we need to have our "Model" class automatically accept this connection from the PicoContainer.

    PHP Code:
    class BaseCdplanModel {
        protected 
    $conn;
        function 
    __construct(AmpAdodbConn $db) {
            
    $this->conn $db;
        }
        
    // ...
    }

    class 
    CDPlan extends BaseCdplanModel {
        const 
    PLANTS_FUNCT 'get_plants';
        const 
    PLANTS_SESSION_CACHE '__Plants_List__';
        public function 
    getPlants($requery=false) {
            if (
    $requery$this->clearSessionCache(self::PLANTS_SESSION_CACHE);
            return 
    $this->sessionCacheSqlFunct(
                 
    self::PLANTS_SESSION_CACHE
                
    ,self::PLANTS_FUNCT
                
    ,self::RS_AS_FIELD_ARRAY
                
    ,array()
                ,
    'PLANT');
        }        

    and in our Pico setup:
    PHP Code:
    $pico = new DefaultPicoContainer;
    $pico->registerComponent(
        new 
    CachingComponentAdapter(
            new 
    ConstructorInjectionComponentAdapter(
                 
    'conn','AmpAdodbConn'
                
    ,array('db' => new ConstantParameter('prdcrm')
                ))));        
    $pico->registerComponent(
        new 
    CachingComponentAdapter(
            new 
    ConstructorInjectionComponentAdapter('cdp','CDPlan')));

    $p $pico->getComponentInstance('cdp');
    var_dump($p->getPlants());

    $p2 $pico->getComponentInstance('cdp');
    var_dump($p === $p2); //check for the CachingComponent 
    Also, so far so go. Next step was to integrate with WACT views and controllers. We have to have a way to have a WACT controller do lazy initialization but know enough about the pico container to ask for it to initalize the view.

    Here was my attempt at that:
    PHP Code:
    class PicoViewProxy {
        protected 
    $pico;
        protected 
    $class;
        protected 
    $view;
        public function 
    __construct($pico$class) {
            
    $this->pico $pico;
            
    $this->class $class;
        }
        protected function 
    lazyLoad() {
            if (!(
    $this->view instanceof View)) {
                if (!
    class_exists($this->class)) {
                    require_once 
    'views/'.$this->class.'.php';
                }
                
    $this->view $this->pico->getComponentInstance($this->class);
            }
        }
        public function 
    __call($method$args) {
            
    $this->lazyLoad();
            return 
    call_user_func_array(array($this->view$method), $args);
        }
    }

    class 
    ApplicationController {
        static function 
    registerComponents($pico) {
            
    $pico->registerComponent(
                new 
    CachingComponentAdapter(
                    new 
    ConstructorInjectionComponentAdapter(
                         
    'conn','AmpAdodbConn'
                        
    ,array('db' => new ConstantParameter('prdcrm')
                        ))));        
            
    $pico->registerComponent(
                new 
    CachingComponentAdapter(
                    new 
    ConstructorInjectionComponentAdapter('cdp','CDPlan')));        
        }
        static function 
    addPages($pico$page_ctrlr) {
            foreach(array(
    'plan'=>'PlanView') as $view => $class) {
                
    $pico->registerComponent(
                    new 
    ConstructorInjectionComponentAdapter($class$class));
                
    $page_ctrlr->addView($view, new PicoViewProxy($pico$class));
            }
            
    $page_ctrlr->setDefaultView(new PicoViewProxy($pico'PlanView'));
        }
    }

    class 
    PlanView extends View {
        protected 
    $cdp;
        const 
    TEMPLATE '/plan_view.html';
        function 
    __construct(CDPlan $cdp) {
            
    $this->cdp $cdp;
            
    parent::View(self::TEMPLATE);
        }
        function 
    Prepare($controller$request$ds) {
            
    var_dump($this->cdp->getPlants()); // just a quick test to see everything is hooked up
        
    }

    and then my bootstrap file becomes:

    PHP Code:
    $pico = new DefaultPicoContainer;
    ApplicationController::registerComponents($pico);

    $page_ctrlr = new ParameterDispatchController;
    $page_ctrlr->setParameterName(VIEW);
    ApplicationController::addPages($pico$page_ctrlr);
    $page_ctrlr->start(); 
    Does this all seem resonable or not? Is there easier ways to accomplish what I am trying to do?

    It seems like it would be nice to have a component adapter which could include the source file if the class was not defined, similar to the WACT Handle class.

  15. #15
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,

    I'll post longer replay on monday, after having closer at Your code, but here only quick remark.

    Quote Originally Posted by sweatje
    Just a quick sanity check here (or maybe not so quick, given how long the post turned out). I started playing around with how to use Pico in a more realistic setting, and this is basically the results of my experimentation.
    Thnx for playing with it!

    [QUOTE=sweatje]

    Started with a "Model" class which needs an ADOdbConnection object passed to it in the constructor. I had a function acting as a parameterized factory for these connections, so it seemed I needed a proxy class which would take my function parameter as a constructor argument, create the connection and proxy calls to it. This is what I came up with:


    Quote Originally Posted by sweatje

    [php]
    So to start using this, we have:
    PHP Code:
    $pico = new DefaultPicoContainer;
    $pico->registerComponent(
        new 
    CachingComponentAdapter(
            new 
    ConstructorInjectionComponentAdapter(
                 
    'conn','AmpAdodbConn'
                
    ,array('db' => new ConstantParameter('prdcrm')
                ))));        

    $c $pico->getComponentInstance('conn');

    $rs $c->execute('select user,sysdate from dual');
    var_dump($rs->fetchRow()); 
    There is much easier way to register component. You may achieve the same result with:

    PHP Code:

    $pico
    ->registerComponent('AmpAdodbConn''AmpAdodbConn',array('db' => new ConstantParameter('prdcrm')); 
    And then:

    PHP Code:

    $c 
    $pico->getComponentInstance('AmpAdodbConn'); 

    Default CA factory will create cache-decorated, CIComponentAdapter. Less code to write, isn't it?

    Cheers,
    pawelik

  16. #16
    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)
    Quote Originally Posted by pawelik
    There is much easier way to register component. You may achieve the same result with:

    PHP Code:
    $pico->registerComponent('AmpAdodbConn''AmpAdodbConn',array('db' => new ConstantParameter('prdcrm')); 
    Default CA factory will create cache-decorated, CIComponentAdapter. Less code to write, isn't it?
    That sounds much better. When I do this, I get
    Code:
    Fatal error: 
    Argument 1 must be an object of class ComponentAdapter in
    /home/sweatje/public_html/picophp/src/PicoContainer.php on line 132
    Is there something I need to do to specify a default CA factory?

  17. #17
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    That sounds much better. When I do this, I get
    Code:
    Fatal error: 
    Argument 1 must be an object of class ComponentAdapter in
    /home/sweatje/public_html/picophp/src/PicoContainer.php on line 132
    Sorrrry! You have to use another method of registration (registerComponentImplementation):

    PHP Code:
     $pico->registerComponentImplementation('AmpAdodbConn''AmpAdodbConn',array('db' => new ConstantParameter('prdcrm')); 
    Cheers,
    pawelik

  18. #18
    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)
    Quote Originally Posted by pawelik
    Sorrrry! You have to use another method of registration (registerComponentImplementation):

    PHP Code:
     $pico->registerComponentImplementation('AmpAdodbConn''AmpAdodbConn',array('db' => new ConstantParameter('prdcrm')); 
    Cheers,
    pawelik
    Works great! Thanks.
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  19. #19
    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)
    If you add
    PHP Code:
    error_reporting(E_ALL); 
    as the first line of your index.php test script, you get 39 undefined index key errors when running the tests:

    Code:
    sweatje@devweb test $ php index.php
    Test Started: Fri Feb 25 10:31:56 CST 2005
    
    All Pico tests
    Exception 1!
    Unexpected PHP error [Undefined index:  AlternativeTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 2!
    Unexpected PHP error [Undefined index:  Touchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 3!
    Unexpected PHP error [Undefined index:  param1] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 4!
    Unexpected PHP error [Undefined index:  param1] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 5!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 6!
    Unexpected PHP error [Undefined index:  Girl] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 7!
    Unexpected PHP error [Undefined index:  boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 8!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    Exception 9!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 10!
    Unexpected PHP error [Undefined index:  st] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 11!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 12!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    Exception 13!
    Unexpected PHP error [Undefined index:  boykey] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 14!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 15!
    Unexpected PHP error [Undefined index:  boykey] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 16!
    Unexpected PHP error [Undefined index:  boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 17!
    Unexpected PHP error [Undefined index:  girl] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 18!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    Exception 19!
    Unexpected PHP error [Undefined index:  boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 20!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 21!
    Unexpected PHP error [Undefined index:  Girl] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 22!
    Unexpected PHP error [Undefined index:  boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 23!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 24!
    Unexpected PHP error [Undefined index:  boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    Exception 25!
    Unexpected PHP error [Undefined index:  Boy] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 26!
    Unexpected PHP error [Undefined index:  DerivedTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 27!
    Unexpected PHP error [Undefined index:  DependsOnSimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 28!
    Unexpected PHP error [Undefined index:  touchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 29!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    Exception 30!
    Unexpected PHP error [Undefined index:  boykey] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 31!
    Unexpected PHP error [Undefined index:  C1] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 32!
    Unexpected PHP error [Undefined index:  C2] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 33!
    Unexpected PHP error [Undefined index:  c1] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 34!
    Unexpected PHP error [Undefined index:  c2] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 35!
    Unexpected PHP error [Undefined index:  SimpleTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 36!
    Unexpected PHP error [Undefined index:  DerivedTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 37!
    Unexpected PHP error [Undefined index:  DependsOnTouchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [134]
    Exception 38!
    Unexpected PHP error [Undefined index:  touchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/ComponentAdapter.php] line [164]
    Exception 39!
    Unexpected PHP error [Undefined index:  Touchable] severity [E_NOTICE] in [/home/sweatje/public_html/picophp/src/PicoContainer.php] line [65]
    FAILURES!!!
    Test cases run: 4/4, Passes: 25, Failures: 0, Exceptions: 39
    Test Completed: Fri Feb 25 10:31:56 CST 2005

  20. #20
    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)
    Just as a followup to the prior post, adding the error suppresion operator in these three locations will correct the problem for you:

    PHP Code:
    sweatje@devweb src cvs diff
    Index
    ComponentAdapter.php
    ===================================================================
    RCS file: /home/projects/picocontainer/scm/php/src/ComponentAdapter.php,v
    retrieving revision 1.1
    diff 
    --r1.1 ComponentAdapter.php
    *** ComponentAdapter.php        7 Feb 2005 17:14:59 -0000       1.1
    --- ComponentAdapter.php        25 Feb 2005 17:28:54 -0000
    ***************
    *** 
    161,167 ****
                   {
                      foreach(
    $constr_all_params as $k => $v)
                      {                                                                                                     
    !                     if (
    $params[$v->getName()]!=null)
                          {
                              
    //supplied param - hint
                              
    $param_to_pass_to_constr[$k] = $params[$v->getName()];
    --- 
    161,167 ----
                   {
                      foreach(
    $constr_all_params as $k => $v)
                      {                                                                                                     
    !                     if (@
    $params[$v->getName()]!=null)
                          {
                              
    //supplied param - hint
                              
    $param_to_pass_to_constr[$k] = $params[$v->getName()];
    IndexPicoContainer.php
    ===================================================================
    RCS file: /home/projects/picocontainer/scm/php/src/PicoContainer.php,v
    retrieving revision 1.1
    diff 
    --r1.1 PicoContainer.php
    *** PicoContainer.php   7 Feb 2005 17:14:59 -0000       1.1
    --- PicoContainer.php   25 Feb 2005 17:28:54 -0000
    ***************
    *** 
    62,68 ****

          public function 
    getComponentAdapter($componentKey)
          {
    !         return 
    $this->_componentAdapters[$componentKey];
          }


    --- 
    62,68 ----

          public function 
    getComponentAdapter($componentKey)
          {
    !         return @
    $this->_componentAdapters[$componentKey];
          }


    ***************
    *** 
    131,137 ****

          public function 
    registerComponent(ComponentAdapter $componentAdapter)
          {
    !         if (
    is_null($this->_componentAdapters[$componentAdapter->getComponentKey()]))
              {
                  
    $this->_componentAdapters[$componentAdapter->getComponentKey()] = $componentAdapter;
              }
    --- 
    131,137 ----

          public function 
    registerComponent(ComponentAdapter $componentAdapter)
          {
    !         if (
    is_null(@$this->_componentAdapters[$componentAdapter->getComponentKey()]))
              {
                  
    $this->_componentAdapters[$componentAdapter->getComponentKey()] = $componentAdapter;
              } 

  21. #21
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wow... What a discussion this has turned out to be

    Reading this thread and the previous one that kicked things off, this could be something. SweatJe, like where your going with your scripts you've posted btw, not sure if this will help anyone but I've just gone and attached a PDF

    For those wondering what Dependency Injection is, but I think Fowler's lengthy read about sums it up anyways.

  22. #22
    SitePoint Enthusiast
    Join Date
    Jul 2004
    Location
    In front of my computer
    Posts
    96
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    Wow... What a discussion this has turned out to be

    Reading this thread and the previous one that kicked things off, this could be something. SweatJe, like where your going with your scripts you've posted btw, not sure if this will help anyone but I've just gone and attached a PDF

    For those wondering what Dependency Injection is, but I think Fowler's lengthy read about sums it up anyways.
    A lenghtly discussion that leads to nothing. I was quite surprised of the reactions, after I launched the thread. But for now it seams pretty dead. I understand my responsibilities as a thread starter was to continue to feed the discussion. It just that I'm absorbed by other projects and real life

    The main problem is that we need to reduce overhead by using this technique. This, some documentation, php5 becoming mainstream and it will become popular.
    participate to the best Php Wiki
    my blog ...

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

    A lenghtly discussion that leads to nothing.
    I wouldn't say that. I've been aware of DI for a while now and never had the time to read up on it much, but you starting this thread has rekindled my interest in it.

    But the point of me posting again is that it will take folks a bit of time to catch up and learn more about this, then I'm sure the interest will pick up again. Stranger things have happened

    So please continue developing your script.

  24. #24
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by zimba
    A lenghtly discussion that leads to nothing.
    ??? Why do You think so? We've started discusion on how to build in Pico in WACT. This could lead to general solutions for embending Pico in frameworks.

    Quote Originally Posted by zimba
    The main problem is that we need to reduce overhead by using this technique. This, some documentation, php5 becoming mainstream and it will become popular.
    Yes, we have to reduce overhead. But I recognise Pico as not a general-purpose library (like Smarty or ADODB) but rather sth that should be part of frameworks.

    Cheers,
    Pawelik

  25. #25
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Warsaw, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston

    So please continue developing your script.
    I will! Expect new release with support for lazy including in a week or so.

    Thnx for attaching PDF.

    Cheers,
    pawelik


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
  •