Skip to content

Commit

Permalink
Fix an optional argument handing
Browse files Browse the repository at this point in the history
  • Loading branch information
emonkak committed Dec 14, 2015
1 parent bac16e8 commit d97479b
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 35 deletions.
27 changes: 16 additions & 11 deletions src/Dependency/DependencyFinders.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Emonkak\Di\ContainerInterface;
use Emonkak\Di\InjectionPolicy\InjectionPolicyInterface;
use Interop\Container\Exception\NotFoundException;

class DependencyFinders
{
Expand Down Expand Up @@ -92,11 +93,14 @@ public static function getParameterDependencies(ContainerInterface $container, I
public static function resolveParameterDependency(ContainerInterface $container, InjectionPolicyInterface $injectionPolicy, \ReflectionParameter $parameter)
{
$key = $injectionPolicy->getParameterKey($parameter);

if ($parameter->isOptional()) {
return $container->has($key) ? $container->resolve($key) : null;
} else {
try {
return $container->resolve($key);
} catch (NotFoundException $e) {
if ($parameter->isOptional()) {
$defaultValue = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null;
return new ValueDependency($defaultValue);
}
throw $e;
}
}

Expand All @@ -109,14 +113,15 @@ public static function resolveParameterDependency(ContainerInterface $container,
public static function resolvePropertyDependency(ContainerInterface $container, InjectionPolicyInterface $injectionPolicy, \ReflectionProperty $property)
{
$key = $injectionPolicy->getPropertyKey($property);

$class = $property->getDeclaringClass();
$values = $class->getDefaultProperties();

if (isset($values[$property->name])) {
return $container->has($key) ? $container->resolve($key) : null;
} else {
try {
return $container->resolve($key);
} catch (NotFoundException $e) {
$class = $property->getDeclaringClass();
$values = $class->getDefaultProperties();
if (isset($values[$property->name])) {
return new ValueDependency($values[$property->name]);
}
throw $e;
}
}
}
6 changes: 6 additions & 0 deletions src/Dependency/DependencyVisitorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ public function visitObjectDependency(ObjectDependency $dependency);
* @return mixed
*/
public function visitReferenceDependency(ReferenceDependency $dependency);

/**
* @param ValueDependency $dependency
* @return mixed
*/
public function visitValueDependency(ValueDependency $dependency);
}
78 changes: 78 additions & 0 deletions src/Dependency/ValueDependency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Emonkak\Di\Dependency;

use Emonkak\Di\ContainerInterface;
use Emonkak\Di\InjectionPolicy\InjectionPolicyInterface;

class ValueDependency implements DependencyInterface
{
/**
* @var mixed
*/
private $value;

/**
* @param mixed $value
*/
public function __construct($value)
{
$this->value = $value;
}

/**
* {@inheritDoc}
*/
public function getValue()
{
return $this->value;
}

/**
* {@inheritDoc}
*/
public function accept(DependencyVisitorInterface $visitor)
{
return $visitor->visitValueDependency($this);
}

/**
* {@inheritDoc}
*/
public function getDependencies()
{
return [];
}

/**
* {@inheritDoc}
*/
public function getKey()
{
return sha1(serialize($this->value));
}

/**
* {@inheritDoc}
*/
public function materializeBy(ContainerInterface $container, \ArrayAccess $pool)
{
return $this->value;
}

/**
* {@inheritDoc}
*/
public function isSingleton()
{
return true;
}

/**
* {@inheritDoc}
*/
public function traverse(callable $callback)
{
$callback($this, $this->getKey());
}
}
15 changes: 15 additions & 0 deletions src/Extras/ClassDiagramGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Emonkak\Di\Dependency\FactoryDependency;
use Emonkak\Di\Dependency\ObjectDependency;
use Emonkak\Di\Dependency\ReferenceDependency;
use Emonkak\Di\Dependency\ValueDependency;

class ClassDiagramGenerator implements DependencyVisitorInterface
{
Expand Down Expand Up @@ -129,6 +130,20 @@ public function visitReferenceDependency(ReferenceDependency $dependency)
}
}

/**
* {@inheritDoc}
*/
public function visitValueDependency(ValueDependency $dependency)
{
$key = $dependency->getKey();
return [
'key' => $key,
'namespace' => '',
'label' => sprintf('{%s}', $this->escape(var_export($dependency->getValue(), true))),
'edges' => []
];
}

/**
* @param DependencyInterface $dependency
* @param \ReflectionClass $class
Expand Down
18 changes: 18 additions & 0 deletions src/Extras/ServiceProviderGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Emonkak\Di\Dependency\FactoryDependency;
use Emonkak\Di\Dependency\ObjectDependency;
use Emonkak\Di\Dependency\ReferenceDependency;
use Emonkak\Di\Dependency\ValueDependency;
use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\Node\Expr;
Expand Down Expand Up @@ -153,6 +154,23 @@ public function visitReferenceDependency(ReferenceDependency $dependency)
return [];
}

/**
* {@inheritDoc}
*/
public function visitValueDependency(ValueDependency $dependency)
{
$deserializeStmt = new Expr\FuncCall(new Name('unserialize'), [
new Scalar\String_(serialize($dependency->getValue()))
]);

$definition = new Expr\Assign(
$this->createContainerAccessor($dependency),
$deserializeStmt
);

return [$definition];
}

/**
* @param DependencyInterface $dependency
* @return Expr
Expand Down
10 changes: 10 additions & 0 deletions src/Scope/SingletonScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Emonkak\Di\Dependency\ObjectDependency;
use Emonkak\Di\Dependency\ReferenceDependency;
use Emonkak\Di\Dependency\SingletonDependency;
use Emonkak\Di\Dependency\ValueDependency;

class SingletonScope implements ScopeInterface, DependencyVisitorInterface
{
Expand Down Expand Up @@ -63,4 +64,13 @@ public function visitReferenceDependency(ReferenceDependency $dependency)
{
return $dependency;
}

/**
* @param ValueDependency $dependency
* @return mixed
*/
public function visitValueDependency(ValueDependency $dependency)
{
return $dependency;
}
}
78 changes: 61 additions & 17 deletions tests/AbstractContrainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,13 @@
namespace Emonkak\Di\Tests
{
use Emonkak\Di\Dependency\DependencyInterface;
use Emonkak\Di\Scope\SingletonScope;
use Emonkak\Di\Tests\AbstractContrainerTest\FooBundle;

abstract class AbstractContrainerTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
$this->container = $this->prepareContainer();
$this->container
->bind('Emonkak\Di\Tests\AbstractContrainerTest\BarInterface')
->to('Emonkak\Di\Tests\AbstractContrainerTest\Bar');
$this->container
->bind('Emonkak\Di\Tests\AbstractContrainerTest\BazInterface')
->to('Emonkak\Di\Tests\AbstractContrainerTest\Baz')
->in(SingletonScope::getInstance());
$this->container->alias('$piyo', '$payo');
$this->container->set('$payo', 'payo');
$this->container->factory('$poyo', function() {
return 'poyo';
});
$this->container->set('$hoge', function() {
});
}

public function testConfigure()
Expand All @@ -39,6 +25,8 @@ public function testConfigure()

public function testResolve()
{
$this->container->configure(new FooBundle());

$fooDependency = $this->container->resolve('Emonkak\Di\Tests\AbstractContrainerTest\Foo');

$this->assertInstanceOf('Emonkak\Di\Dependency\ObjectDependency', $fooDependency);
Expand All @@ -51,6 +39,8 @@ public function testResolve()
*/
public function testMaterialize(DependencyInterface $fooDependency)
{
$this->container->configure(new FooBundle());

$foo = $this->container->materialize($fooDependency);

$this->assertInstanceOf('Emonkak\Di\Tests\AbstractContrainerTest\Foo', $foo);
Expand All @@ -65,15 +55,27 @@ public function testMaterialize(DependencyInterface $fooDependency)
}

/**
* @dataProvider provideResolveThrowsNotFoundException
*
* @expectedException Interop\Container\Exception\NotFoundException
*/
public function testResolveThrowsNotFoundException()
public function testResolveThrowsNotFoundException($key)
{
$this->container->resolve('Emonkak\Di\Tests\AbstractContrainerTest\FooInterface');
$this->container->resolve($key);
}

public function provideResolveThrowsNotFoundException()
{
return [
['Emonkak\Di\Tests\AbstractContrainerTest\Foo'],
['Emonkak\Di\Tests\AbstractContrainerTest\Qux']
];
}

public function testGet()
{
$this->container->configure(new FooBundle());

$foo = $this->container->get('Emonkak\Di\Tests\AbstractContrainerTest\Foo');

$this->assertInstanceOf('Emonkak\Di\Tests\AbstractContrainerTest\Foo', $foo);
Expand All @@ -88,14 +90,47 @@ public function testGet()
$this->assertInstanceOf('stdClass', $this->container->get('stdClass'));
}

public function testHas()
{
$this->container->configure(new FooBundle());

$this->assertTrue($this->container->has('Emonkak\Di\Tests\AbstractContrainerTest\Foo'));
$this->assertFalse($this->container->has('Emonkak\Di\Tests\AbstractContrainerTest\FooInterface'));
}

abstract protected function prepareContainer();
}
}

namespace Emonkak\Di\Tests\AbstractContrainerTest
{
use Emonkak\Di\AbstractContainer;
use Emonkak\Di\Annotation\Inject;
use Emonkak\Di\Annotation\Qualifier;
use Emonkak\Di\ContainerConfiguratorInterface;
use Emonkak\Di\Scope\SingletonScope;

class FooBundle implements ContainerConfiguratorInterface
{
public function configure(AbstractContainer $container)
{
$container
->bind('Emonkak\Di\Tests\AbstractContrainerTest\BarInterface')
->to('Emonkak\Di\Tests\AbstractContrainerTest\Bar');
$container
->bind('Emonkak\Di\Tests\AbstractContrainerTest\BazInterface')
->to('Emonkak\Di\Tests\AbstractContrainerTest\Baz')
->in(SingletonScope::getInstance());
$container->alias('$piyo', '$payo');
$container->set('$payo', 'payo');
$container->factory('$poyo', function() {
return 'poyo';
});
$container->set('$hoge', function() {
return 'hoge';
});
}
}

class Foo implements FooInterface
{
Expand Down Expand Up @@ -159,6 +194,15 @@ public function setPoyo($poyo)
}
}

class Qux
{
/**
* @Inject
* @Qualifier("$huga")
*/
public $huga;
}

interface FooInterface
{
}
Expand Down
Loading

0 comments on commit d97479b

Please sign in to comment.