Skip to content

Commit

Permalink
Lazy injections declared at class level
Browse files Browse the repository at this point in the history
  • Loading branch information
mnapoli committed Oct 10, 2013
1 parent 4e0fff0 commit 743dd80
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 37 deletions.
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -13,7 +13,7 @@
}
},
"require": {
"php": ">=5.3.0",
"php": ">=5.4.0",
"doctrine/annotations": "1.*",
"doctrine/cache": "1.*",
"myclabs/php-enum": "1.*",
Expand Down
17 changes: 16 additions & 1 deletion src/DI/Annotation/Injectable.php
Expand Up @@ -24,13 +24,18 @@
*/
final class Injectable
{

/**
* The scope of an class: prototype, singleton
* @var Scope|null
*/
private $scope;

/**
* Should the object be lazy-loaded
* @var boolean|null
*/
private $lazy;

/**
* @param array $values
*/
Expand All @@ -39,6 +44,9 @@ public function __construct(array $values)
if (isset($values['scope'])) {
$this->scope = new Scope($values['scope']);
}
if (isset($values['lazy'])) {
$this->lazy = (boolean) $values['lazy'];
}
}

/**
Expand All @@ -49,4 +57,11 @@ public function getScope()
return $this->scope;
}

/**
* @return boolean|null
*/
public function isLazy()
{
return $this->lazy;
}
}
21 changes: 9 additions & 12 deletions src/DI/Container.php
Expand Up @@ -114,13 +114,12 @@ public function get($name, $useProxy = false)
// It's a class
if ($definition instanceof ClassDefinition) {
// Return a proxy class
if ($useProxy) {
return $this->getProxy($definition->getClassName());
if ($useProxy || $definition->isLazy()) {
$instance = $this->getProxy($definition);
} else {
$instance = $this->getNewInstance($definition);
}

// Create the instance
$instance = $this->getNewInstance($definition);

if ($definition->getScope() == Scope::SINGLETON()) {
// If it's a singleton, store the newly created instance
$this->entries[$name] = $instance;
Expand Down Expand Up @@ -264,17 +263,15 @@ private function getNewInstance(ClassDefinition $classDefinition)
/**
* Returns a proxy instance
*
* @param string $classname
* @param ClassDefinition $definition
* @return object Proxy instance
*/
private function getProxy($classname)
private function getProxy(ClassDefinition $definition)
{
$container = $this;

$proxy = $this->proxyFactory->createProxy(
$classname,
function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) use ($container, $classname) {
$wrappedObject = $container->get($classname);
$definition->getClassName(),
function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) use ($definition) {
$wrappedObject = $this->getNewInstance($definition);
$initializer = null; // turning off further lazy initialization
return true;
}
Expand Down
9 changes: 7 additions & 2 deletions src/DI/Definition/Source/AnnotationDefinitionSource.php
Expand Up @@ -78,8 +78,13 @@ public function getDefinition($name)
. $e->getMessage());
}

if ($injectableAnnotation !== null && $injectableAnnotation->getScope()) {
$classDefinition->setScope($injectableAnnotation->getScope());
if ($injectableAnnotation) {
if ($injectableAnnotation->getScope()) {
$classDefinition->setScope($injectableAnnotation->getScope());
}
if ($injectableAnnotation->isLazy() !== null) {
$classDefinition->setLazy($injectableAnnotation->isLazy());
}
}

// Browse the class properties looking for annotated properties
Expand Down
14 changes: 14 additions & 0 deletions src/DI/DefinitionHelper/ObjectDefinitionHelper.php
Expand Up @@ -26,6 +26,11 @@ class ObjectDefinitionHelper implements DefinitionHelper
*/
private $className;

/**
* @var boolean|null
*/
private $lazy;

/**
* @var Scope|null
*/
Expand Down Expand Up @@ -54,6 +59,12 @@ public function __construct($className = null)
$this->className = $className;
}

public function lazy()
{
$this->lazy = true;
return $this;
}

public function withScope(Scope $scope)
{
$this->scope = $scope;
Expand Down Expand Up @@ -88,6 +99,9 @@ public function getDefinition($entryName)
{
$definition = new ClassDefinition($entryName, $this->className);

if ($this->lazy !== null) {
$definition->setLazy($this->lazy);
}
if ($this->scope !== null) {
$definition->setScope($this->scope);
}
Expand Down
2 changes: 0 additions & 2 deletions tests/IntegrationTests/DI/Fixtures/Class1.php
Expand Up @@ -18,7 +18,6 @@
*/
class Class1
{

/**
* @Inject
* @var Class2
Expand Down Expand Up @@ -119,5 +118,4 @@ public function method4(LazyDependency $param1)
{
$this->method4Param1 = $param1;
}

}
2 changes: 0 additions & 2 deletions tests/IntegrationTests/DI/Fixtures/Class2.php
Expand Up @@ -14,13 +14,11 @@
*/
class Class2
{

/**
* @return boolean
*/
public function getBoolean()
{
return true;
}

}
5 changes: 3 additions & 2 deletions tests/IntegrationTests/DI/Fixtures/LazyDependency.php
Expand Up @@ -9,18 +9,19 @@

namespace IntegrationTests\DI\Fixtures;

use DI\Annotation\Injectable;

/**
* Fixture class
* @Injectable(lazy=true)
*/
class LazyDependency
{

/**
* @return boolean
*/
public function getValue()
{
return true;
}

}
3 changes: 2 additions & 1 deletion tests/IntegrationTests/DI/Fixtures/definitions.php
Expand Up @@ -37,5 +37,6 @@

'namedDependency' => Entry::object(Class2::class),

LazyDependency::class => Entry::object(),
LazyDependency::class => Entry::object()
->lazy(),
];
21 changes: 7 additions & 14 deletions tests/IntegrationTests/DI/InjectionTest.php
Expand Up @@ -28,7 +28,6 @@ class InjectionTest extends \PHPUnit_Framework_TestCase
const DEFINITION_ANNOTATIONS = 2;
const DEFINITION_ARRAY = 3;
const DEFINITION_PHP = 4;
const DEFINITION_ARRAY_FROM_FILE = 5;

/**
* PHPUnit data provider: generates container configurations for running the same tests for each configuration possible
Expand All @@ -42,9 +41,11 @@ public static function containerProvider()
$builder->useAnnotations(false);
$containerReflection = $builder->build();
$containerReflection->addDefinitions([
'foo' => 'bar',
Interface1::class => Entry::object(Implementation1::class),
'namedDependency' => Entry::object(Class2::class),
'foo' => 'bar',
Interface1::class => Entry::object(Implementation1::class),
'namedDependency' => Entry::object(Class2::class),
LazyDependency::class => Entry::object()
->lazy(),
]);

// Test with a container using annotations and reflection
Expand Down Expand Up @@ -92,21 +93,14 @@ public static function containerProvider()
$containerPHP->set(Interface1::class, Entry::object(Implementation1::class)
->withScope(Scope::SINGLETON()));
$containerPHP->set('namedDependency', Entry::object(Class2::class));
$containerPHP->set(LazyDependency::class, Entry::object());

// Test with a container using array configuration loaded from file
$builder = new ContainerBuilder();
$builder->useReflection(false);
$builder->useAnnotations(false);
$containerArrayFromFile = $builder->build();
$containerArrayFromFile->addDefinitions(require __DIR__ . '/Fixtures/definitions.php');
$containerPHP->set(LazyDependency::class, Entry::object()
->lazy());

return array(
array(self::DEFINITION_REFLECTION, $containerReflection),
array(self::DEFINITION_ANNOTATIONS, $containerAnnotations),
array(self::DEFINITION_ARRAY, $containerArray),
array(self::DEFINITION_PHP, $containerPHP),
array(self::DEFINITION_ARRAY_FROM_FILE, $containerArrayFromFile),
);
}

Expand Down Expand Up @@ -275,5 +269,4 @@ public function testScope($type, Container $container)
$class3_2 = $container->get('IntegrationTests\DI\Fixtures\Interface1');
$this->assertSame($class3_1, $class3_2);
}

}

0 comments on commit 743dd80

Please sign in to comment.