SitePoint Sponsor

User Tag List

Results 1 to 18 of 18
  1. #1
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    DI-SQL, retrieving objects and its dependencies

    Hi, today I started developing something called DI-SQL. I might use it in the future, I don't know yet. I'm exploring the possibility of adding an extra layer to an existing framework architecture to manage package dependencies.

    So, what do you think about having something like DI-SQL?

    For example:

    PHP Code:
    $di = new DI_Statement($config); 
     
    // Constructor dependency injection 
    $stmt $di->prepare("INJECT INTO CLASS 'Foo' VALUES(ComponentA, ComponentB, :param_one)"); 
    $stmt->bindParam(':param_one''Parameter 1'); 
    $obj $stmt->execute(); 
     
    // Constructor and setter dependency injection 
    $dql "INJECT INTO CLASS 'Foo'  
                VALUES(ComponentA, ComponentB, 'arg3', 'arg4') 
            METHOD 'setComponentA' 
                VALUES(ComponentA, 'arg2')"

                
    ...

    // Based on the component specifications (configuration file, php array or XML file)
    $dql "LOAD CLASS 'Foo'";

    ... 
    Any comments, ideas or suggestions are more than welcome.

    Thanks.

  2. #2
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Assuming you have the following classes:

    PHP Code:
    class Foo 
        public function 
    __construct
            
    Foo_Component_Interface $componentA null
            
    Foo_Component_Interface $componentB null
            
    $arg3 null
            
    $arg4 null) { 
        } 
         
        public function 
    setComponentA(Foo_Component_Interface $component$arg2 null) { 
        } 

     
    interface 
    Foo_Component_Interface 

    class 
    Foo_Component_A implements Foo_Component_Interface 

    class 
    Foo_Component_B implements Foo_Component_Interface 

    And the following config array:

    PHP Code:
    $config = array( 
        
    'Foo' => array( 
            
    'class'        => 'Foo'), 
        
    'ComponentA' => array( 
            
    'class'        => 'Foo_Component_A'
            
    'instanceof'   => 'Foo_Component_Interface'), 
        
    'ComponentB' => array( 
            
    'class'        => 'Foo_Component_B'
            
    'instanceof'   => 'Foo_Component_Interface'), 
        ); 
    So, the idea is to add an extra and optional layer to the MVC pattern, one that can easily handle package dependencies. So, I call this architecture MVC+D, and the optional layer will use DI-SQL.

  3. #3
    SitePoint Evangelist
    Join Date
    Mar 2005
    Posts
    423
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm interested in dependency injection at the moment and enjoy seeing the different approaches being taken. Out of interest, why choose the sql-esque structure?

  4. #4
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, the main reason is to handle the complexity for the developer, and what better than SQL to do something like that. It's simple, easy to learn and understand. There are some other query languages, like java's EJB-QL. And I think most of the QL proved that they can abstract the complexity behind a query.

    Code:
    SELECT books.title AS Authors
    FROM books
    JOIN authors 
    ON books.author_id = authors.id
    GROUP BY books.title;
    It's simpler and easier to understand than:

    PHP Code:
    $db->select('title''Authors')
    $db->from('books')
    $db->join('authors', array('books'=>'author_id''authors'=>'id'))
    $db->groupBy(array('books'=>'title')) 
    I'm basically doing the same, but the other way around. I'm adding a query language on top, so you can do stuff like:

    Code:
    LOAD CLASS 'Foo'
    SELECT CONTAINER 'MyContainer'
    OPEN CONTAINER 'MyContainer' ADD (Foo)
    PHP Code:
    $foo $di->query("LOAD CLASS 'Foo'"); 
    But like I said, it's still experimental.

  5. #5
    SitePoint Zealot shoorace's Avatar
    Join Date
    Jun 2005
    Location
    Florida
    Posts
    142
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi, are you aiming to develop a kinda Spring Framework in PHP?
    Wish u the best...

  6. #6
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not really. I'm looking for a better way of dealing with package dependencies in the Zend Framework. At the moment I'm using a DI component, and each package has a Dependencies.php file. But the problem I have using fluent interfaces, is that the more dependencies a package has, the more complex it becomes to inject dependencies and pass values through the constructor and setter methods. That's why I'm thinking that DISQL might be what I'm looking for, or not. That's what I'm trying to find out.

  7. #7
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A quick update and some examples:

    PHP Code:
    try {
        
    $di = new Zend_DI_Statement($config); 
         
        
    // Example 1: Constructor dependency injection 
        
    $stmt $di->prepare("INJECT INTO CLASS 'Foo' VALUES (ComponentA, ComponentB, :param)"); 
        
    $stmt->bindParam(':param''Parameter 1'); 
        
    $foo $stmt->execute(); 
         
        
    // Example 2: Constructor and setter dependency injection 
        
    $dql "INJECT INTO 'Foo'  
                    VALUES (ComponentA, ComponentB) 
                METHOD 'setComponentA' 
                    VALUES (ComponentA, NULL)"
    ;
        
        
    // Execute DIQL statement
        
    $foo $di->query($dql);
        
        
    // Example 3: Retrieve an object and its dependencies
        
    $foo $di->query("NEW INSTANCE 'Foo'");
        
        
    // Example 4: Get an instance of Zend_Foo
        
    $foo $di->query("GET INSTANCE 'Foo'");
        
        
    // Example 5: Complex query
        
    $dql "INJECT INTO 'Foo'  
                    VALUES (ComponentA, ComponentB, :param1) 
                METHOD 'setComponentA' 
                    VALUES (ComponentA, :param2)
                METHOD 'setComponentB' 
                    VALUES (ComponentB, TRUE, :param3, NULL)"
    ;
        
        
    $stmt $di->prepare($dql); 
        
    $stmt->bindParam(':param1''Parameter 1');
        
    $stmt->bindParam(':param2''Parameter 2');
        
    $stmt->bindParam(':param3''Parameter 3'); 
        
    $foo $stmt->execute(); 
        
    } catch (
    Zend_DI_Exception $e) {
        echo 
    $e->getMessage();

    Analysis of the 5th example:

    PHP Code:
    $dql "INJECT INTO 'Foo'  
                VALUES (ComponentA, ComponentB, :param1) 
            METHOD 'setComponentA' 
                VALUES (ComponentA, :param2)
            METHOD 'setComponentB' 
                VALUES (ComponentB, TRUE, :param3, NULL)"
    ;

    $stmt $di->prepare($dql); 
    $stmt->bindParam(':param1''Parameter 1');
    $stmt->bindParam(':param2''Parameter 2');
    $stmt->bindParam(':param3''Parameter 3'); 
    $foo $stmt->execute(); 

    /* The code above does the same as this, the biggest difference is that the example above
       separates configuration from use */
    $componentA = new Zend_Foo_Component_A(); 
    $componentB = new Zend_Foo_Component_B(); 
    $foo = new Zend_Foo($componentA$componentB'Parameter 1'); 
    $foo->setComponentA($componentA'Parameter 2');
    $foo->setComponentB($componentB'Parameter 3'); 
    Zend_Registry::set('Zend_Foo'$foo); 

  8. #8
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What are the added advantages of resolving your dependencies this way? I Don't see any real benefits and a load of added complexity.
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  9. #9
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, that was just an overview of what you can do. The idea was to show how you can inject dependencies and pass values at the same time.

    Now, what I'm proposing solves a particular problem:

    • You don't have to adapt your API to the DI Container, the DI Container adapts to your API.


    If I'm not wrong, 33Degrees spotted this problem with another DI Container, and I took it as a warning sign, and a week after that, I faced the same problem when using another DI container. So, my conclusion was, you cannot refactor an entire framework to add an extra pattern (MVC+D).

    Now, let me show you another example, a simple one:

    Config:

    PHP Code:
    $config = array( 
        
    'Foo' => array( 
            
    'class'        => 'Zend_Foo'
            
    'arguments'    => array(
                
    '__construct' => 'ComponentA, :param',
                
    'setCcomponentB' => 'ComponentB'
            
    ),
        ),
        
    'ComponentA' => array( 
            
    'class'        => 'Zend_Foo_Component_A'
            
    'instanceof'   => 'Zend_Foo_Component_Interface'
        
    ),
        
    'ComponentB' => array( 
            
    'class'        => 'Zend_Foo_Component_B'
            
    'instanceof'   => 'Zend_Foo_Component_Interface'
            'arguments'    
    => array(
                
    '__construct' => 'ComponentC',
            ),
        ), 
        
    'ComponentC' => array( 
            
    'class'        => 'Zend_Foo_Component_C'
            
    'instanceof'   => 'Zend_Foo_Component_Interface'
        
    ), 
    ); 
    Usage:

    PHP Code:
    // Using a fluent interface
    $di = new Zend_DI_Container($config); 
    $foo $di->loadClass('Foo')->binParam(':param''Parameter 1')->newInstance(); 

    // Using DIQL 
    $di = new Zend_DI_Statement($config); 
    $stmt $di->prepare("NEW INSTANCE 'FOO'");  
    $stmt->bindParam(':param''Parameter 1');  
    $foo $stmt->execute(); 
    Using FI, with just 1 line of code, you can load all the dependencies, and the component adapts perfectly to your API.

  10. #10
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jasper Bekkers View Post
    I Don't see any real benefits and a load of added complexity.
    Before:

    PHP Code:
    $componentC = new Zend_Foo_Component_C(); 
    $componentB = new Zend_Foo_Component_B($componentC); 
    $componentA = new Zend_Foo_Component_A(); 
    $foo = new Zend_Foo($componentA'Parameter 1'); 
    $foo->setComponentB($componentB); 
    Zend_Registry::set('Zend_Foo'$foo); 
    After:

    PHP Code:
    $di = new Zend_DI_Container($config); 
    $foo $di->loadClass('Foo')->binParam(':param''Parameter 1')->newInstance(); 

  11. #11
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    Before:

    PHP Code:
    $componentC = new Zend_Foo_Component_C(); 
    $componentB = new Zend_Foo_Component_B($componentC); 
    $componentA = new Zend_Foo_Component_A(); 
    $foo = new Zend_Foo($componentA'Parameter 1'); 
    $foo->setComponentB($componentB); 
    Zend_Registry::set('Zend_Foo'$foo); 
    After:

    PHP Code:
    $di = new Zend_DI_Container($config); 
    $foo $di->loadClass('Foo')->binParam(':param''Parameter 1')->newInstance(); 
    I see the benefits of DI, but I can't say the same for DI-SQL. What's the point? What does it have to offer (of use) that other DI frameworks don't offer?
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  12. #12
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes, the reason why I'm adding a query language is to introduce a standard way of injecting dependencies in PHP, regardless of the component we use. That way we don't have to stick to a component and other developers can use any component regardless of the API, and without the need to face a new learning curve.

    So, that's the main reason I think, standards.

    BTW, I just cam back from Holland, what an amazing country.

  13. #13
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Jasper, like you said, DI-SQL might be pointless, I don't know. That's why I left this message. I'm interesting in hearing from those who are using a DI framework and to know more about the problems that they facing.

    Your feedback is important to me, thanks. Because I'm doing this during the weekends, and I wouldn't like to spend time on something that is pointless of course.

  14. #14
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    So, that's the main reason I think, standards.
    What you're talking about, is a protocol -- an interface. That can be effectuated as a DSL, such as the one, you have created, or within the boundaries of the language syntax. The main benefit of using a custom syntax, is that you can decouple the protocol from the language. For example, XML is language agnostic. In this case, that benefit is dubious, since dependencies are very closely related to the language in the first place.
    I think an effort to create a protocol, within the language, would be much more usable. You could start by analysing some existing containers and describe their interfaces. Then figure out, if you can express them as a single interface somehow.

  15. #15
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Good point. I'll continue doing some research before implementing any of this. Thanks.

  16. #16
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I kind of like the imagination in trying SQL as a dependency injection language but, sorry, I don't think it works.

    Still, having an imagination and maybe being wrong is more important than always being right.

  17. #17
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    So, that's the main reason I think, standards.
    I agree with you when you say that DI needs some sort of standard, but I think it would be more useful if it was supplied by the language. Any other way would be damned hard to standardize (or to get enough momentum to be considered standard). A quick thought experiment on how I think DI could be integrated into the language.

    PHP Code:
    <?php
    interface Report{
        
    ///
        
    public function getTitle();
    }

    interface 
    ReportDisplay{
        public function 
    render(Report $r);
    }

    class 
    ReportDisplay_PDF implements ReportDisplay{
        public function 
    render(Report $r){
            
    ///
        
    }
    }

    class 
    ReportDisplay_HTML implements ReportDisplay{
        public function 
    render(Report $r){
            
    // the null create keyword would be the same as the new keyword, 
            // but making it easy to refactor to a DI later on
            // while still providing the user the capability to 
            // instantiate objects directly
            
    $header null create HTML_Backend_Header($r->getTitle());
        }
    }

    injector ReportInjector{
        public function 
    __register($interface$class);
        
        public function 
    __create($interface){
            
    // the actual new keyword is limited to the injector only
            // the resolve keyword resolves all the other dependencies using this injector
            
    $this->mapping[$interface] = new $class(resolve);
        }
    }

    ReportInject register ReportDisplay as ReportDisplay_PDF;
    ReportInject register Report as SimpleEmployeeReport;

    class 
    FinalOutputThingy{
        public function do(
    injector $injector){
            
    $output $injector create ReportDisplay;
            
    $output->render($injector create Report);
        }
    }
    BTW, I just cam back from Holland, what an amazing country.
    Thanks! (The weather didn't bother you?)
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  18. #18
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very interesting example. I never thought of having something like that integrated into the language (maybe because no one proposed it before?). It would definitely be a great thing to have, in any language. That example makes sql look kind of silly trying to inject dependencies. Excellent stuff, thanks Jasper.


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
  •