Changeset 844

Show
Ignore:
Timestamp:
08/19/07 15:43:22 (1 year ago)
Author:
schst
Message:

Some cleanup, added several tests, added the ability to mark an injection as optional, removed old injection code, changed JSON-RPC-Processor to use new injection facilities to inject the session

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/experiments/people/schst/ioc/simple.php

    r810 r844  
    8080     * 
    8181     * @param Window $concrete 
    82      * @Inject 
     82     * @Inject(optional=true) 
    8383     */ 
    8484    public function setWindow(Window $window) { 
     
    102102stubClassLoader::load('net.stubbles.ioc.injection.stubBinder'); 
    103103 
    104 $injector = new stubInjector(); 
    105 $binder = new stubBinder($injector); 
     104$binder = new stubBinder(); 
    106105 
    107106$binder->bind('Tire')->to('Goodyear'); 
     
    113112$binder->bind('Window'); 
    114113 
     114$injector = $binder->getInjector(); 
     115 
    115116$vehicle = $injector->getInstance('Vehicle'); 
    116117$vehicle->getDriver()->sayHello(); 
  • trunk/src/main/php/net/stubbles/examples/service/RememberNameService.php

    r770 r844  
    1111 * Simple service to demonstrate stateful services. 
    1212 * 
    13  * @Inject(Session) 
    1413 * @author      Stephan Schmidt <schst@stubbles.net> 
    1514 * @package     stubbles_examples 
     
    3130     * 
    3231     * @param stubSession $session 
     32     * @Inject 
    3333     */ 
    3434    public function setSession(stubSession $session) { 
  • trunk/src/main/php/net/stubbles/ioc/injection/annotations/stubImplementedByAnnotation.php

    r820 r844  
    99 */ 
    1010 
    11 stubClassLoader::load('net.stubbles.reflection.annotations.stubAbstractAnnotation'); 
     11stubClassLoader::load('net.stubbles.reflection.annotations.stubAbstractAnnotation', 
     12                      'net.stubbles.reflection.stubReflectionClass'); 
    1213 
    1314/** 
     
    2324     * default implementation 
    2425     * 
    25      * @var  array 
     26     * @var  stubReflectionClass 
    2627     */ 
    2728    protected $defaultImplementation; 
     
    3031     * sets the list of class names to inject 
    3132     * 
    32      * @param  string  $value 
     33     * @param  stubReflectionClass  $value 
    3334     */ 
    34     public function setValue($value) 
     35    public function setValue(stubReflectionClass $value) 
    3536    { 
    3637        $this->defaultImplementation = $value; 
     
    5051     * Get the default implementation 
    5152     * 
    52      * @return  array 
     53     * @return  stubReflectionClass 
    5354     */ 
    5455    public function getDefaultImplementation() 
  • trunk/src/main/php/net/stubbles/ioc/injection/annotations/stubInjectAnnotation.php

    r809 r844  
    11<?php 
    22/** 
    3  * Annotation to handle dependency injections. 
     3 * Annotation to mark a method that is used for 
     4 * dependency injection 
    45 * 
    5  * @author      Frank Kleine <mikey@stubbles.net> 
     6 * @author      Stephan Schmidt <schst@stubbles.net> 
    67 * @package     stubbles 
    78 * @subpackage  ioc_injection 
    89 */ 
    9 stubClassLoader::load('net.stubbles.reflection.reflection', 
    10                       'net.stubbles.ioc.injection.stubInjectionException', 
    11                       'net.stubbles.ioc.injection.stubInjectionMap' 
    12 ); 
     10stubClassLoader::load('net.stubbles.reflection.annotations.stubAbstractAnnotation'); 
     11 
    1312/** 
    14  * Annotation to handle dependency injections. 
     13 * Annotation to mark a method that is used for 
     14 * dependency injection 
    1515 * 
    1616 * @package     stubbles 
    1717 * @subpackage  ioc_injection 
    18  * @todo        think about a public static addPrefix() method that will 
    19  *              discard prefixes from injections for method and property names 
    2018 */ 
    2119class stubInjectAnnotation extends stubAbstractAnnotation 
    2220{ 
    2321    /** 
    24      * list of class names to inject 
     22     * whether the injection is optional 
    2523     * 
    26      * @var  array 
     24     * @var  boolean 
    2725     */ 
    28     protected $injections = array()
     26    protected $optional = false
    2927 
    3028    /** 
    31      * sets the list of class names to inject 
     29     * sets, whether the injection is optional 
    3230     * 
    33      * @param  string  $value 
     31     * @param  boolean  $optional 
    3432     */ 
    35     public function setValue($value
     33    public function setOptional($optional
    3634    { 
    37         $this->injections = explode(':', $value)
     35        $this->optional = $optional
    3836    } 
    3937 
     
    4543    public function getAnnotationTarget() 
    4644    { 
    47         return stubAnnotation::TARGET_ALL
     45        return stubAnnotation::TARGET_METHOD
    4846    } 
    4947 
    5048    /** 
    51      * returns the list of injections 
     49     * Checks, whether the injection is optional 
    5250     * 
    53      * @return array 
     51     * @return boolean 
    5452     */ 
    55     public function getInjections() 
    56     { 
    57         return $this->injections; 
    58     } 
    59  
    60     /** 
    61      * processes all injections 
    62      * 
    63      * @param   stubReflectionClass     $refClass           the reflection class for $injectible 
    64      * @param   stubInjectionProvider   $injectionProvider  map of values to inject 
    65      * @param   object                  $injectible         the class to inject into 
    66      * @throws  stubInjectionException 
    67      */ 
    68     protected function handleInjections(stubReflectionClass $refClass, stubInjectionProvider $injectionProvider, $injectible) 
    69     { 
    70         foreach ($this->injections as $injection) { 
    71             if ($injectionProvider->hasInjection($injection) == false) { 
    72                 $className = ($injectible instanceof stubObject) ? ($injectible->getClassName()) : (get_class($injectible)); 
    73                 throw new stubInjectionException('Injectible ' . $className . ' needs ' . $injection . ' but it was not given in list of injected classes.'); 
    74             } 
    75  
    76             if (substr($injection, 0, 4) == 'stub') { 
    77                 $injectionShort = substr($injection, 4); 
    78             } else { 
    79                 $injectionShort = $injection; 
    80             } 
    81  
    82             $methodName = 'set' . ucfirst($injectionShort); 
    83             if ($refClass->hasMethod($methodName) == true && $refClass->getMethod($methodName)->isPublic() == true) { 
    84                 try { 
    85                     $refClass->getMethod($methodName)->invoke($injectible, $injectionProvider->getInjection($injection)); 
    86                 } catch (ReflectionException $re) { 
    87                     throw new stubInjectionException('Could not inject ' . $injection . ': ' . $re->getMessage()); 
    88                 } 
    89             } elseif ($refClass->hasProperty($injectionShort) == true && $refClass->getProperty($injectionShort)->isPublic() == true) { 
    90                 $refClass->getProperty($injectionShort)->setValue($injectible, $injectionProvider->getInjection($injection)); 
    91             } elseif ($refClass->hasMethod('__set') == true && $refClass->getMethod('__set')->isPublic() == true) { 
    92                 $refClass->getMethod('__set')->invoke($injectible, $injection, $injectionProvider->getInjection($injection)); 
    93             } else { 
    94                 $className = ($injectible instanceof stubObject) ? ($injectible->getClassName()) : (get_class($injectible)); 
    95                 throw new stubInjectionException('Injectible ' . $className . ' has no method or property that accepts injection ' . $injection); 
    96             } 
    97         } 
    98     } 
    99  
    100     /** 
    101      * static call to hide all injection details 
    102      * 
    103      * @param   stubInjectionProvider   $injectionProvider  map of values to inject 
    104      * @param   object                  $injectible         the class to inject into 
    105      * @throws  stubInjectionException 
    106      */ 
    107     public static function factory(stubInjectionProvider $injectionProvider, $injectible) 
    108     { 
    109         if (is_object($injectible) == false) { 
    110             throw new stubInjectionException('Given injectible is not an object. Can only inject into objects.'); 
    111         } 
    112  
    113         $refClass = new stubReflectionClass(get_class($injectible)); 
    114         if ($refClass->hasAnnotation('Inject') == true) { 
    115             $inject = $refClass->getAnnotation('Inject'); 
    116             $inject->handleInjections($refClass, $injectionProvider, $injectible); 
    117         } 
     53    public function isOptional() { 
     54        return $this->optional; 
    11855    } 
    11956} 
  • trunk/src/main/php/net/stubbles/ioc/injection/annotations/stubNamedAnnotation.php

    r825 r844  
    2121     * Name 
    2222     * 
    23      * @var  array 
     23     * @var  string 
    2424     */ 
    2525    protected $name; 
  • trunk/src/main/php/net/stubbles/ioc/injection/stubBinder.php

    r825 r844  
    4545     * @param stubInjector $injector 
    4646     */ 
    47     public function __construct(stubInjector $injector) { 
    48         $this->injector = $injector; 
     47    public function __construct(stubInjector $injector = null) { 
     48        if ($injector === null) { 
     49            $this->injector = new stubInjector(); 
     50        } else { 
     51            $this->injector = $injector; 
     52        } 
    4953    } 
    5054 
     
    6064        return $binding; 
    6165    } 
     66 
     67    /** 
     68     * Get an injector for this binder 
     69     * 
     70     * @return stubInjector 
     71     */ 
     72    public function getInjector() { 
     73        return $this->injector; 
     74    } 
    6275} 
    6376?> 
  • trunk/src/main/php/net/stubbles/ioc/injection/stubBinding.php

    r835 r844  
    1010 * @subpackage  ioc_injection 
    1111 */ 
    12  
     12stubClassLoader::load('net.stubbles.ioc.injection.exceptions.stubBindingException'); 
    1313/** 
    1414 * Binding to bind an interface to an implementation 
     
    190190            foreach ($method->getParameters() as $param) { 
    191191                $class = $param->getClass(); 
     192                $type  = $class->getName(); 
    192193                $name  = null; 
    193194                if ($method->hasAnnotation('Named')) { 
    194195                    $name = $method->getAnnotation('Named')->getName(); 
    195196                } 
    196                 $paramValues[] = $this->injector->getInstance($class->getName(), $name); 
     197                if (!$this->injector->hasBinding($type, $name)) { 
     198                    if ($method->getAnnotation('Inject')->isOptional()) { 
     199                        continue 2; 
     200                    } 
     201                    throw new stubBindingException("Could not create instance of {$this->type}. No binding for type {$type} specified."); 
     202                } 
     203                $paramValues[] = $this->injector->getInstance($type, $name); 
    197204            } 
    198205            $method->invokeArgs($instance, $paramValues); 
  • trunk/src/main/php/net/stubbles/ioc/injection/stubInjector.php

    r835 r844  
    2020 * @package     stubbles 
    2121 * @subpackage  ioc_injection 
     22 * @todo        Improve the check for the index update 
    2223 */ 
    23 class stubInjector extends stubBaseObject
     24class stubInjector extends stubBaseObject implements stubClonable
    2425 
    2526    /** 
     
    9697    } 
    9798 
     99    /** 
     100     * Get the binding for a name and type 
     101     * 
     102     * @param string $type 
     103     * @param string $name 
     104     * @return stubBinding 
     105     * @todo    This method should also take care of implicit bindings 
     106     */ 
    98107    protected function getBinding($type, $name = null) { 
    99108        if ($name !== null) { 
     
    107116        return null; 
    108117    } 
     118 
     119    /** 
     120     * Check, whether a binding for a type is available 
     121     * 
     122     * @param string $type 
     123     * @param string $name 
     124     * @return boolean 
     125     */ 
     126    public function hasBinding($type, $name = null) { 
     127        if (!empty($this->bindings)) { 
     128            $this->updateIndex(); 
     129        } 
     130 
     131        return ($this->getBinding($type, $name) != null); 
     132    } 
    109133} 
    110134?> 
  • trunk/src/main/php/net/stubbles/service/jsonrpc/stubJsonRpcProcessor.php

    r793 r844  
    1515                      'net.stubbles.service.annotations.stubWebMethodAnnotation', 
    1616                      'net.stubbles.service.jsonrpc.stubJsonRpcResponse', 
    17                       'net.stubbles.ioc.injection.injection
     17                      'net.stubbles.ioc.injection.stubBinder
    1818); 
    1919/** 
     
    106106            throw new stubFileNotFoundException($configFile); 
    107107        } 
    108          
     108 
    109109        return $configFile; 
    110110    } 
     
    161161                continue; 
    162162            } 
    163              
     163 
    164164            try { 
    165165                $this->response->write($generator->generateJavascriptProxy($serviceConfig['className'], $jsClass)); 
     
    188188            $result .= "console.{$level}('" . addslashes($line) . "');\n"; 
    189189        } 
    190          
     190 
    191191        return $result; 
    192192    } 
     
    205205            return; 
    206206        } 
    207          
     207 
    208208        if (!isset($phpJsonObj->id)) { 
    209209            $this->response->writeFault(null, 'Invalid request: No id given.'); 
    210210            return; 
    211211        } 
    212          
     212 
    213213        if (!isset($phpJsonObj->method)) { 
    214214            $this->response->writeFault($phpJsonObj->id, 'Invalid request: No method given.'); 
    215215            return; 
    216216        } 
    217          
     217 
    218218        if (!isset($phpJsonObj->params)) { 
    219219            $this->response->writeFault($phpJsonObj->id, 'Invalid request: No params given.'); 
     
    268268            throw new stubException('Invalid request: method-Pattern has to be <className>.<methodName>.'); 
    269269        } 
    270          
     270 
    271271        list($className, $methodName) = explode('.', $methodName); 
    272272        if (!isset($this->classMap[$className])) { 
    273273            throw new stubException('Unknown class ' . $className . '.'); 
    274274        } 
    275          
     275 
    276276        $clazz = new stubReflectionClass($this->classMap[$className]['className']); 
    277277        if ($clazz->hasMethod($methodName) == false) { 
    278278            throw new stubException('Unknown method ' . $className . '.' . $methodName . '.'); 
    279279        } 
    280          
     280 
    281281        $method = $clazz->getMethod($methodName); 
    282282        if (!$method->hasAnnotation('WebMethod')) { 
    283283            throw new stubException('Method ' . $className . '.' . $methodName . ' is no WebMethod.'); 
    284284        } 
    285          
     285 
    286286        return array('class' => $clazz, 'method' => $method); 
    287287    } 
     
    301301            throw new stubException('Invalid amount of parameters passed.'); 
    302302        } 
    303  
    304         $instance     = $class->newInstance(); 
    305         $injectionMap = new stubInjectionMap(); 
    306         $injectionMap->addInjection('Session', $this->session); 
    307  
    308         stubInjectAnnotation::factory($injectionMap, $instance); 
     303        $binder   = new stubBinder(); 
     304        $binder->bind('stubSession')->toInstance($this->session); 
     305        $instance     = $binder->getInjector()->getInstance($class->getName()); 
    309306        return $method->invokeArgs($instance, $params); 
    310307    } 
     
    327324                throw new stubException('Param '. $paramName . ' is missing.'); 
    328325            } 
    329              
     326 
    330327            array_push($paramValues, $paramValue); 
    331328        } 
    332          
     329 
    333330        return $paramValues; 
    334331    } 
  • trunk/src/test/php/net/stubbles/ioc/IOCTestSuite.php

    r308 r844  
    44 * 
    55 * @author      Frank Kleine <mikey@stubbles.net> 
     6 * @author      Stephan Schmidt <schst@stubbles.net> 
    67 * @package     stubbles 
    78 * @subpackage  test 
     
    2122    { 
    2223        $this->TestSuite('All ioc tests'); 
     24        $this->addTestFile(dirname(__FILE__) . '/injection/annotations/stubImplementedByAnnotationTestCase.php'); 
    2325        $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectAnnotationTestCase.php'); 
    24         $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectionMapTestCase.php'); 
     26        $this->addTestFile(dirname(__FILE__) . '/injection/annotations/stubNamedAnnotationTestCase.php'); 
     27        $this->addTestFile(dirname(__FILE__) . '/injection/annotations/stubSingletonAnnotationTestCase.php'); 
     28 
     29        $this->addTestFile(dirname(__FILE__) . '/injection/stubBinderTestCase.php'); 
     30 
     31        $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectorBasicTestCase.php'); 
     32        $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectorImplementedByTestCase.php'); 
     33        $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectorNamedTestCase.php'); 
     34        $this->addTestFile(dirname(__FILE__) . '/injection/stubInjectorSingletonTestCase.php'); 
    2535    } 
    2636} 
  • trunk/src/test/php/net/stubbles/ioc/injection/stubInjectAnnotationTestCase.php

    r808 r844  
    33 * Test for net.stubbles.ioc.injection.annotations.stubInjectAnnotation 
    44 * 
    5  * @author      Frank Kleine <mikey@stubbles.net> 
     5 * @author      Stephan Schmidt <schst@stubbles.net> 
    66 * @package     stubbles 
    77 * @subpackage  ioc_injection_test 
    88 */ 
    99stubClassLoader::load('net.stubbles.ioc.injection.annotations.stubInjectAnnotation'); 
    10 class TestInjection1 extends stubBaseObject {} 
    11 class TestInjection2 extends stubBaseObject {} 
    12 class TestInjection3 extends stubBaseObject {} 
    13 class stubTestInjection4 extends stubBaseObject {} 
    14 /** 
    15  * class for testing injections 
    16  * 
    17  * @Inject(TestInjection1:TestInjection2:TestInjection3) 
    18  */ 
    19 class TestInjectible1 
    20 { 
    21     protected $TestInjection1; 
    22     public $TestInjection2; 
    2310 
    24     public function setTestInjection1($i) 
    25     { 
    26         $this->TestInjection1 = $i; 
    27     } 
    28  
    29     public function getTestInjection1() 
    30     { 
    31         return $this->TestInjection1; 
    32     } 
    33  
    34     public function __set($name, $value) 
    35     { 
    36         $this->$name = $value; 
    37     } 
    38 } 
    39 /** 
    40  * class for testing injections 
    41  * 
    42  * @Inject(TestInjection1:TestInjection2:TestInjection3) 
    43  */ 
    44 class TestInjectible2 
    45 { 
    46 } 
    47 /** 
    48  * class for testing injections 
    49  * 
    50  * @Inject(stubTestInjection4:stubTestInjection5) 
    51  */ 
    52 class TestInjectible3 
    53 { 
    54     protected $TestInjection4; 
    55     public $TestInjection5; 
    56  
    57     public function setTestInjection4($i) 
    58     { 
    59         $this->TestInjection4 = $i; 
    60     } 
    61  
    62     public function getTestInjection4() 
    63     { 
    64         return $this->TestInjection4; 
    65     } 
    66 } 
    6711/** 
    6812 * Test for net.stubbles.ioc.injection.annotations.stubInjectAnnotation 
     
    7418{ 
    7519    /** 
    76      * injection map to use for tests 
    77      * 
    78      * @var  stubInjectionMap 
    79      */ 
    80     protected $injectionMap; 
    81  
    82     /** 
    8320     * set up test environment 
    8421     */ 
    8522    public function setUp() 
    8623    { 
    87         $this->injectionMap = new stubInjectionMap(); 
    88         $this->injectionMap->addInjection('TestInjection1', new TestInjection1()); 
    89         $this->injectionMap->addInjection('TestInjection2', new TestInjection2()); 
    90         $this->injectionMap->addInjection('TestInjection3', new TestInjection3()); 
    91         $this->injectionMap->addInjection('stubTestInjection4', new stubTestInjection4()); 
    92         $this->injectionMap->addInjection('stubTestInjection5', new stubTestInjection4()); 
    9324    } 
     25 
    9426    /** 
    9527     * test that the injection names are handles properly 
    9628     */ 
    97     public function testInjections() 
     29    public function testAnnotation() 
    9830    { 
    9931        $inject = new stubInjectAnnotation(); 
    100         $inject->setValue('TestInjection1:TestInjection2:TestInjection3'); 
    101         $this->assertEqual($inject->getInjections(), array('TestInjection1', 'TestInjection2', 'TestInjection3')); 
    102     } 
    10332 
    104     /** 
    105      * check that the handling works as expected 
    106      */ 
    107     public function testHandlingOk() 
    108     { 
    109         $testInjectible = new TestInjectible1(); 
    110         stubInjectAnnotation::factory($this->injectionMap, $testInjectible); 
    111         $test1a = $this->injectionMap->getInjection('TestInjection1'); 
    112         $test1b = $testInjectible->getTestInjection1(); 
    113         $this->assertReference($test1a, $test1b); 
    114     } 
     33        $this->assertEqual(stubAnnotation::TARGET_METHOD, $inject->getAnnotationTarget()); 
     34        $this->assertFalse($inject->isOptional()); 
    11535 
    116     /** 
    117      * check that the handling works as expected 
    118      */ 
    119     public function testHandlingMissingInjectedClass() 
    120     { 
    121         $testInjectible = new TestInjectible1(); 
    122         $this->expectException('stubInjectionException'); 
    123         stubInjectAnnotation::factory(new stubInjectionMap(), $testInjectible); 
    124     } 
    125  
    126     /** 
    127      * check that the handling works as expected 
    128      */ 
    129     public function testHandlingMissingMethodAndProperty() 
    130     { 
    131         $testInjectible = new TestInjectible2(); 
    132         $this->expectException('stubInjectionException'); 
    133         stubInjectAnnotation::factory($this->injectionMap, $testInjectible); 
    134     } 
    135  
    136     /** 
    137      * check that the handling works as expected 
    138      */ 
    139     public function testHandlingWithoutAnnotation() 
    140     { 
    141         Mock::generate('TestInjectible1'); 
    142         $testInjectible = new MockTestInjectible1(); 
    143         $testInjectible->expectNever('setTestInjection1'); 
    144         $testInjectible->expectNever('__set'); 
    145         stubInjectAnnotation::factory($this->injectionMap, $testInjectible); 
    146     } 
    147  
    148     /** 
    149      * check that the handling works as expected 
    150      */ 
    151     public function testHandlingWrongInjectible() 
    152     { 
    153         $this->expectException('stubInjectionException'); 
    154         stubInjectAnnotation::factory($this->injectionMap, 'foo'); 
    155     } 
    156  
    157     public function testStubPrefix() 
    158     { 
    159         $testInjectible = new TestInjectible3(); 
    160         stubInjectAnnotation::factory($this->injectionMap, $testInjectible); 
    161         $test4a = $this->injectionMap->getInjection('stubTestInjection4'); 
    162         $test4b = $testInjectible->getTestInjection4(); 
    163         $this->assertReference($test4a, $test4b); 
    164         $test5a = $this->injectionMap->getInjection('stubTestInjection5'); 
    165         $test5b = $testInjectible->TestInjection5; 
    166         $this->assertReference($test5a, $test5b); 
     36        $inject->setOptional(true); 
     37        $this->assertTrue($inject->isOptional()); 
    16738    } 
    16839}