Skip to content

Commit

Permalink
Option autowired can contain list of classes
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 8, 2016
1 parent 6bab21a commit 213c117
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/DI/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ public static function parseService(ServiceDefinition $definition, $config)
}

if (isset($config['autowired'])) {
Validators::assertField($config, 'autowired', 'bool');
Validators::assertField($config, 'autowired', 'bool|string|array');
$definition->setAutowired($config['autowired']);
}

Expand Down
30 changes: 28 additions & 2 deletions src/DI/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,37 @@ public function prepareClassList()
}

// build auto-wiring list
$this->classList = [];
$this->classList = $preferred = [];
foreach ($this->definitions as $name => $def) {
if ($class = $def->getImplement() ?: $def->getClass()) {
$defAutowired = $def->isAutowired();
if (is_array($defAutowired)) {
foreach ($defAutowired as $k => $aclass) {
if ($aclass === self::THIS_SERVICE) {
$defAutowired[$k] = $class;
} elseif (!is_a($class, $aclass, TRUE)) {
throw new ServiceCreationException("Incompatible class $aclass in autowiring definition of service '$name'.");
}
}
}

foreach (class_parents($class) + class_implements($class) + [$class] as $parent) {
$this->classList[$parent][$def->isAutowired() && empty($this->excludedClasses[$parent])][] = (string) $name;
$autowired = $defAutowired && empty($this->excludedClasses[$parent]);
if ($autowired && is_array($defAutowired)) {
$autowired = FALSE;
foreach ($defAutowired as $aclass) {
if (is_a($parent, $aclass, TRUE)) {
if (empty($preferred[$parent]) && isset($this->classList[$parent][TRUE])) {
$this->classList[$parent][FALSE] = array_merge(...$this->classList[$parent]);
}
$preferred[$parent] = $autowired = TRUE;
break;
}
}
} elseif (isset($preferred[$parent])) {
$autowired = FALSE;
}
$this->classList[$parent][$autowired][] = (string) $name;
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/DI/ServiceDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ServiceDefinition
/** @var array */
private $tags = [];

/** @var bool */
/** @var bool|string[] */
private $autowired = TRUE;

/** @var bool */
Expand Down Expand Up @@ -210,19 +210,19 @@ public function getTag($tag)


/**
* @param bool
* @param bool|string|string[]
* @return self
*/
public function setAutowired($state = TRUE)
{
call_user_func($this->notifier);
$this->autowired = (bool) $state;
$this->autowired = is_string($state) || is_array($state) ? (array) $state : (bool) $state;
return $this;
}


/**
* @return bool
* @return bool|string[]
*/
public function isAutowired()
{
Expand Down
68 changes: 68 additions & 0 deletions tests/DI/ContainerBuilder.autowiring.types.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

/**
* Test: Nette\DI\ContainerBuilder and direct types
*/

use Nette\DI;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


interface IFoo
{
}

interface IBar
{
}

class Foo implements IFoo
{
}

class Bar extends Foo implements IBar
{
}

$builder = new DI\ContainerBuilder;
$bar = $builder->addDefinition('bar')
->setClass('Bar')
->setAutowired('Bar');


Assert::same('bar', $builder->getByType('Bar'));
Assert::null($builder->getByType('IBar'));
Assert::null($builder->getByType('Foo'));
Assert::null($builder->getByType('IFoo'));

$bar->setAutowired(['Bar', 'IFoo']);

Assert::same('bar', $builder->getByType('Bar'));
Assert::null($builder->getByType('IBar'));
Assert::same('bar', $builder->getByType('Foo'));
Assert::same('bar', $builder->getByType('IFoo'));

$foo = $builder->addDefinition('foo')
->setClass('Foo')
->setAutowired();

Assert::same('bar', $builder->getByType('Bar'));
Assert::null($builder->getByType('IBar'));
Assert::same('bar', $builder->getByType('Foo'));
Assert::same('bar', $builder->getByType('IFoo'));

$foo->setAutowired('IFoo');

Assert::same('bar', $builder->getByType('Bar'));
Assert::null($builder->getByType('IBar'));

Assert::exception(function () use ($builder) {
$builder->getByType('Foo');
}, DI\ServiceCreationException::class, 'Multiple services of type Foo found: bar, foo');

Assert::exception(function () use ($builder) {
$builder->getByType('IFoo');
}, DI\ServiceCreationException::class, 'Multiple services of type IFoo found: bar, foo');

0 comments on commit 213c117

Please sign in to comment.