Skip to content

Commit

Permalink
Fix overriding annotations with config + refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mnapoli committed Jul 29, 2017
1 parent 5540f71 commit 76a084a
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 209 deletions.
13 changes: 3 additions & 10 deletions src/Container.php
Expand Up @@ -13,8 +13,6 @@
use DI\Definition\Resolver\DefinitionResolver;
use DI\Definition\Resolver\ResolverDispatcher;
use DI\Definition\Source\DefinitionArray;
use DI\Definition\Source\DefinitionSource;
use DI\Definition\Source\MutableDefinitionSource;
use DI\Definition\Source\ReflectionBasedAutowiring;
use DI\Definition\Source\SourceChain;
use DI\Invoker\DefinitionParameterResolver;
Expand Down Expand Up @@ -45,7 +43,7 @@ class Container implements ContainerInterface, FactoryInterface, \DI\InvokerInte
protected $resolvedEntries = [];

/**
* @var DefinitionSource
* @var SourceChain
*/
private $definitionSource;

Expand Down Expand Up @@ -88,7 +86,7 @@ class Container implements ContainerInterface, FactoryInterface, \DI\InvokerInte
* @param ContainerInterface $wrapperContainer If the container is wrapped by another container.
*/
public function __construct(
DefinitionSource $definitionSource = null,
SourceChain $definitionSource = null,
ProxyFactory $proxyFactory = null,
ContainerInterface $wrapperContainer = null
) {
Expand Down Expand Up @@ -364,11 +362,6 @@ private function resolveDefinition(Definition $definition, array $parameters = [

protected function setDefinition(string $name, Definition $definition)
{
if (! $this->definitionSource instanceof MutableDefinitionSource) {
// This can happen if you instantiate the container yourself
throw new \LogicException('The container has not been initialized correctly');
}

// Clear existing entry if it exists
if (array_key_exists($name, $this->resolvedEntries)) {
unset($this->resolvedEntries[$name]);
Expand All @@ -394,7 +387,7 @@ private function getInvoker() : \Invoker\InvokerInterface
return $this->invoker;
}

private function createDefaultDefinitionSource() : DefinitionSource
private function createDefaultDefinitionSource() : SourceChain
{
$source = new SourceChain([new ReflectionBasedAutowiring]);
$source->setMutableDefinitionSource(new DefinitionArray([], new ReflectionBasedAutowiring));
Expand Down
97 changes: 1 addition & 96 deletions src/Definition/AutowireDefinition.php
Expand Up @@ -4,104 +4,9 @@

namespace DI\Definition;

use DI\Definition\ObjectDefinition\MethodInjection;

/**
* @author Matthieu Napoli <matthieu@mnapoli.fr>
*/
class AutowireDefinition extends ObjectDefinition implements HasSubDefinition
class AutowireDefinition extends ObjectDefinition
{
public function getSubDefinitionName() : string
{
return $this->getClassName();
}

/**
* {@inheritdoc}
*
* @deprecated
*/
public function setSubDefinition(Definition $definition)
{
if (! $definition instanceof self) {
return;
}

// The current prevails
if ($this->className === null) {
$this->setClassName($definition->className);
}
if ($this->lazy === null) {
$this->lazy = $definition->lazy;
}

// Merge constructor injection
$this->mergeConstructorInjection($definition);

// Merge property injections
$this->mergePropertyInjections($definition);

// Merge method injections
$this->mergeMethodInjections($definition);
}

public function setDefaultConstructorInjection(MethodInjection $injection)
{
if ($this->constructorInjection !== null) {
// Merge
$this->constructorInjection->merge($injection);
} else {
// Set
$this->constructorInjection = $injection;
}
}

private function mergeConstructorInjection(ObjectDefinition $definition)
{
if ($definition->getConstructorInjection() !== null) {
if ($this->constructorInjection !== null) {
// Merge
$this->constructorInjection->merge($definition->getConstructorInjection());
} else {
// Set
$this->constructorInjection = $definition->getConstructorInjection();
}
}
}

private function mergePropertyInjections(ObjectDefinition $definition)
{
foreach ($definition->propertyInjections as $propertyName => $propertyInjection) {
if (! isset($this->propertyInjections[$propertyName])) {
// Add
$this->propertyInjections[$propertyName] = $propertyInjection;
}
}
}

private function mergeMethodInjections(ObjectDefinition $definition)
{
foreach ($definition->methodInjections as $methodName => $calls) {
if (array_key_exists($methodName, $this->methodInjections)) {
$this->mergeMethodCalls($calls, $methodName);
} else {
// Add
$this->methodInjections[$methodName] = $calls;
}
}
}

private function mergeMethodCalls(array $calls, string $methodName)
{
foreach ($calls as $index => $methodInjection) {
// Merge
if (array_key_exists($index, $this->methodInjections[$methodName])) {
// Merge
$this->methodInjections[$methodName][$index]->merge($methodInjection);
} else {
// Add
$this->methodInjections[$methodName][$index] = $methodInjection;
}
}
}
}
24 changes: 24 additions & 0 deletions src/Definition/ObjectDefinition.php
Expand Up @@ -108,6 +108,17 @@ public function setConstructorInjection(MethodInjection $constructorInjection)
$this->constructorInjection = $constructorInjection;
}

public function completeConstructorInjection(MethodInjection $injection)
{
if ($this->constructorInjection !== null) {
// Merge
$this->constructorInjection->merge($injection);
} else {
// Set
$this->constructorInjection = $injection;
}
}

/**
* @return PropertyInjection[] Property injections
*/
Expand Down Expand Up @@ -153,6 +164,19 @@ public function addMethodInjection(MethodInjection $methodInjection)
$this->methodInjections[$method][] = $methodInjection;
}

public function completeFirstMethodInjection(MethodInjection $injection)
{
$method = $injection->getMethodName();

if (isset($this->methodInjections[$method][0])) {
// Merge
$this->methodInjections[$method][0]->merge($injection);
} else {
// Set
$this->addMethodInjection($injection);
}
}

public function setLazy(bool $lazy = null)
{
$this->lazy = $lazy;
Expand Down
9 changes: 4 additions & 5 deletions src/Definition/Source/AnnotationBasedAutowiring.php
Expand Up @@ -6,7 +6,6 @@

use DI\Annotation\Inject;
use DI\Annotation\Injectable;
use DI\Definition\AutowireDefinition;
use DI\Definition\EntryReference;
use DI\Definition\Exception\AnnotationException;
use DI\Definition\ObjectDefinition;
Expand Down Expand Up @@ -53,15 +52,15 @@ public function __construct($ignorePhpDocErrors = false)
$this->ignorePhpDocErrors = (bool) $ignorePhpDocErrors;
}

public function autowire(string $name, AutowireDefinition $definition = null)
public function autowire(string $name, ObjectDefinition $definition = null)
{
$className = $definition ? $definition->getClassName() : $name;

if (!class_exists($className) && !interface_exists($className)) {
return $definition;
}

$definition = $definition ?: new AutowireDefinition($name);
$definition = $definition ?: new ObjectDefinition($name);

$class = new ReflectionClass($className);

Expand Down Expand Up @@ -161,9 +160,9 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef
}

if ($method->isConstructor()) {
$objectDefinition->setConstructorInjection($methodInjection);
$objectDefinition->completeConstructorInjection($methodInjection);
} else {
$objectDefinition->addMethodInjection($methodInjection);
$objectDefinition->completeFirstMethodInjection($methodInjection);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Definition/Source/Autowiring.php
Expand Up @@ -4,8 +4,8 @@

namespace DI\Definition\Source;

use DI\Definition\AutowireDefinition;
use DI\Definition\Exception\InvalidDefinition;
use DI\Definition\ObjectDefinition;

/**
* Source of definitions for entries of the container.
Expand All @@ -18,7 +18,7 @@ interface Autowiring
* Autowire the given definition.
*
* @throws InvalidDefinition An invalid definition was found.
* @return AutowireDefinition|null
* @return ObjectDefinition|null
*/
public function autowire(string $name, AutowireDefinition $definition = null);
public function autowire(string $name, ObjectDefinition $definition = null);
}
4 changes: 2 additions & 2 deletions src/Definition/Source/NoAutowiring.php
Expand Up @@ -4,8 +4,8 @@

namespace DI\Definition\Source;

use DI\Definition\AutowireDefinition;
use DI\Definition\Exception\InvalidDefinition;
use DI\Definition\ObjectDefinition;

/**
* Implementation used when autowiring is completely disabled.
Expand All @@ -14,7 +14,7 @@
*/
class NoAutowiring implements Autowiring
{
public function autowire(string $name, AutowireDefinition $definition = null)
public function autowire(string $name, ObjectDefinition $definition = null)
{
throw new InvalidDefinition(sprintf(
'Cannot autowire entry "%s" because autowiring is disabled',
Expand Down
8 changes: 4 additions & 4 deletions src/Definition/Source/ReflectionBasedAutowiring.php
Expand Up @@ -4,8 +4,8 @@

namespace DI\Definition\Source;

use DI\Definition\AutowireDefinition;
use DI\Definition\EntryReference;
use DI\Definition\ObjectDefinition;
use DI\Definition\ObjectDefinition\MethodInjection;

/**
Expand All @@ -15,22 +15,22 @@
*/
class ReflectionBasedAutowiring implements DefinitionSource, Autowiring
{
public function autowire(string $name, AutowireDefinition $definition = null)
public function autowire(string $name, ObjectDefinition $definition = null)
{
$className = $definition ? $definition->getClassName() : $name;

if (!class_exists($className) && !interface_exists($className)) {
return $definition;
}

$definition = $definition ?: new AutowireDefinition($name);
$definition = $definition ?: new ObjectDefinition($name);

// Constructor
$class = new \ReflectionClass($className);
$constructor = $class->getConstructor();
if ($constructor && $constructor->isPublic()) {
$constructorInjection = MethodInjection::constructor($this->getParametersDefinition($constructor));
$definition->setDefaultConstructorInjection($constructorInjection);
$definition->completeConstructorInjection($constructorInjection);
}

return $definition;
Expand Down
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace DI\Test\IntegrationTest\Definitions\AutowireDefinition;

class Class1
{
}
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace DI\Test\IntegrationTest\Definitions\AutowireDefinition;

use DI\Annotation\Inject;

class ConstructorInjection
{
/**
* @var \stdClass
*/
public $autowiredParameter;

/**
* @var Class1
*/
public $overloadedParameter;

/**
* Force the injection of a specific value for the first parameter. (when using annotations)
* @Inject({"autowiredParameter"="anotherStdClass"})
*/
public function __construct(\stdClass $autowiredParameter, Class1 $overloadedParameter)
{
$this->autowiredParameter = $autowiredParameter;
$this->overloadedParameter = $overloadedParameter;
}
}
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace DI\Test\IntegrationTest\Definitions\AutowireDefinition;

use DI\Annotation\Inject;

class MethodInjection
{
/**
* @var \stdClass
*/
public $autowiredParameter;

/**
* @var Class1
*/
public $overloadedParameter;

/**
* Force the injection of a specific value for the first parameter. (when using annotations)
* @Inject({"autowiredParameter"="anotherStdClass"})
*/
public function setFoo(\stdClass $autowiredParameter, Class1 $overloadedParameter)
{
$this->autowiredParameter = $autowiredParameter;
$this->overloadedParameter = $overloadedParameter;
}
}

0 comments on commit 76a084a

Please sign in to comment.