Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method for getting specific definition #192

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"nette/neon": "^3.0",
"nette/php-generator": "^3.2",
"nette/robot-loader": "^3.2",
"nette/utils": "^3.0"
"nette/utils": "^3.0.1"
},
"require-dev": {
"nette/tester": "^2.0",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The recommended way to install is via Composer:
composer require nette/di
```

It requires PHP version 5.6 and supports PHP up to 7.2. The dev-master version requires PHP 7.1.
It requires PHP version 7.1 and supports PHP up to 7.3.


Usage
Expand Down
11 changes: 8 additions & 3 deletions src/DI/CompilerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ abstract class CompilerExtension
/** @var string */
protected $name;

/** @var array */
/** @var array|object */
protected $config = [];


Expand All @@ -41,19 +41,24 @@ public function setCompiler(Compiler $compiler, string $name)


/**
* @param array|object $config
* @return static
*/
public function setConfig(array $config)
public function setConfig($config)
{
if (!is_array($config) && !is_object($config)) {
throw new Nette\InvalidArgumentException;
}
$this->config = $config;
return $this;
}


/**
* Returns extension configuration.
* @return array|object
*/
public function getConfig(): array
public function getConfig()
{
return $this->config;
}
Expand Down
15 changes: 14 additions & 1 deletion src/DI/Config/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class Loader

private $loadedFiles = [];

private $parameters = [];


/**
* Reads configuration from file.
Expand All @@ -52,7 +54,8 @@ public function load(string $file, ?bool $merge = true): array
$res = [];
if (isset($data[self::INCLUDES_KEY])) {
Validators::assert($data[self::INCLUDES_KEY], 'list', "section 'includes' in file '$file'");
foreach ($data[self::INCLUDES_KEY] as $include) {
$includes = Nette\DI\Helpers::expand($data[self::INCLUDES_KEY], $this->parameters);
foreach ($includes as $include) {
$include = $this->expandIncludedFile($include, $file);
$res = Helpers::merge($this->load($include, $merge), $res);
}
Expand Down Expand Up @@ -119,4 +122,14 @@ private function getAdapter(string $file): Adapter
}
return is_object($this->adapters[$extension]) ? $this->adapters[$extension] : new $this->adapters[$extension];
}


/**
* @return static
*/
public function setParameters(array $params)
{
$this->parameters = $params;
return $this;
}
}
13 changes: 6 additions & 7 deletions src/DI/Config/Processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ public function normalizeConfig($config): array
return ['factory' => $config];

} elseif (is_array($config)) {
if (isset($config['class']) && !isset($config['factory'])) {
$config['factory'] = null;
}
foreach (['class' => 'type', 'dynamic' => 'imported'] as $alias => $original) {
if (array_key_exists($alias, $config)) {
if (array_key_exists($original, $config)) {
Expand Down Expand Up @@ -195,22 +198,18 @@ private function updateServiceDefinition(Definitions\ServiceDefinition $definiti
{
$config = self::processArguments($config);

if (array_key_exists('type', $config) || array_key_exists('factory', $config)) {
if (array_key_exists('factory', $config)) {
$definition->setFactory($config['factory']);
$definition->setType(null);
$definition->setFactory(null);
}

if (array_key_exists('type', $config)) {
if ($config['type'] instanceof Statement) {
trigger_error("Service '$name': option 'type' or 'class' should be changed to 'factory'.", E_USER_DEPRECATED);
$definition->setFactory($config['type']);
} else {
$definition->setType($config['type']);
}
$definition->setFactory($config['type']);
}

if (array_key_exists('factory', $config)) {
$definition->setFactory($config['factory']);
}

if (array_key_exists('arguments', $config)) {
Expand Down
55 changes: 55 additions & 0 deletions src/DI/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,61 @@ public function getDefinition(string $name): Definition
}


public function getServiceDefinition(string $name): Nette\DI\Definitions\ServiceDefinition
{
$service = $this->getDefinition($name);
if (!$service instanceof Nette\DI\Definitions\ServiceDefinition) {
throw new MissingServiceException("ServiceDefinition with name '$name' not found.");
}

return $service;
}


public function getAccessorDefinition(string $name): Nette\DI\Definitions\AccessorDefinition
{
$service = $this->getDefinition($name);
if (!$service instanceof Nette\DI\Definitions\AccessorDefinition) {
throw new MissingServiceException("AccessorDefinition with name '$name' not found.");
}

return $service;
}


public function getFactoryDefinition(string $name): Nette\DI\Definitions\FactoryDefinition
{
$service = $this->getDefinition($name);
if (!$service instanceof Nette\DI\Definitions\FactoryDefinition) {
throw new MissingServiceException("FactoryDefinition with name '$name' not found.");
}

return $service;
}


public function getLocatorDefinition(string $name): Nette\DI\Definitions\LocatorDefinition
{
$service = $this->getDefinition($name);
if (!$service instanceof Nette\DI\Definitions\LocatorDefinition) {
throw new MissingServiceException("LocatorDefinition with name '$name' not found.");
}

return $service;
}


public function getImportedDefinition(string $name): Nette\DI\Definitions\ImportedDefinition
{
$service = $this->getDefinition($name);
if (!$service instanceof Nette\DI\Definitions\ImportedDefinition) {
throw new MissingServiceException("ImportedDefinition with name '$name' not found.");
}

return $service;
}


/**
* Gets all service definitions.
* @return Definition[]
Expand Down
5 changes: 1 addition & 4 deletions src/DI/Extensions/InjectExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ public static function getInjectProperties(string $class): array
foreach (get_class_vars($class) as $name => $foo) {
$rp = new \ReflectionProperty($class, $name);
if (DI\Helpers::parseAnnotation($rp, 'inject') !== null) {
if ($type = DI\Helpers::parseAnnotation($rp, 'var')) {
$type = Reflection::expandClassName($type, Reflection::getPropertyDeclaringClass($rp));
}
$res[$name] = $type;
$res[$name] = DI\Helpers::getPropertyType($rp);
}
}
ksort($res);
Expand Down
14 changes: 14 additions & 0 deletions src/DI/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,20 @@ public static function getReturnType(\ReflectionFunctionAbstract $func): ?string
}


public static function getPropertyType(\ReflectionProperty $prop): ?string
{
if ($type = Reflection::getPropertyType($prop)) {
return ($prop->getType()->allowsNull() ? '?' : '') . $type;
} elseif ($type = preg_replace('#\s.*#', '', (string) self::parseAnnotation($prop, 'var'))) {
$class = Reflection::getPropertyDeclaringClass($prop);
return preg_replace_callback('#[\w\\\\]+#', function ($m) use ($class) {
return Reflection::expandClassName($m[0], $class);
}, $type);
}
return null;
}


public static function normalizeClass(string $type): string
{
return class_exists($type) || interface_exists($type)
Expand Down
44 changes: 44 additions & 0 deletions tests/DI/Compiler.extensionOverride.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class FooExtension extends Nette\DI\CompilerExtension
$builder->addDefinition('one8')
->setFactory('Lorem', [1])
->addSetup('__construct', [2]);
$builder->addDefinition('one9')
->setFactory('Lorem', [1]);
$builder->addDefinition('one10')
->setFactory('Lorem', [1]);

$builder->addDefinition('two1')
->setType('Lorem')
Expand Down Expand Up @@ -101,6 +105,12 @@ class FooExtension extends Nette\DI\CompilerExtension
$builder->addDefinition('two9')
->setType('Lorem')
->setFactory('Factory::createLorem', [1, 2]);
$builder->addDefinition('two10')
->setType('Lorem')
->setFactory('Factory::createLorem', [1]);
$builder->addDefinition('two11')
->setType('Lorem')
->setFactory('Factory::createLorem', [1]);

$builder->addDefinition('three1')
->setFactory('Factory::createLorem', [1]);
Expand All @@ -116,6 +126,10 @@ class FooExtension extends Nette\DI\CompilerExtension
->setFactory('Factory::createLorem', [1]);
$builder->addDefinition('three7')
->setFactory('Factory::createLorem', [1]);
$builder->addDefinition('three8')
->setFactory('Factory::createLorem', [1]);
$builder->addDefinition('three9')
->setFactory('Factory::createLorem', [1]);
}
}

Expand Down Expand Up @@ -166,6 +180,16 @@ Assert::same([
'Ipsum::__construct ',
], Notes::fetch());

Assert::exception(function () use ($container) {
$container->getService('one9');
}, TypeError::class, 'Return value of %a%::createServiceOne9() must be an instance of Ipsum, instance of Lorem returned');
Notes::fetch();

Assert::type(Ipsum::class, $container->getService('one10'));
Assert::same([
'Ipsum::__construct ',
], Notes::fetch());


Assert::type(Ipsum::class, $container->getService('two1'));
Assert::same([
Expand Down Expand Up @@ -217,6 +241,16 @@ Assert::same([
'Lorem::__construct 2 new',
], Notes::fetch());

Assert::exception(function () use ($container) {
$container->getService('two11');
}, TypeError::class, 'Return value of %a%::createServiceTwo11() must be an instance of Ipsum, instance of Lorem returned');
Notes::fetch();

Assert::type(Ipsum::class, $container->getService('two12'));
Assert::same([
'Ipsum::__construct ',
], Notes::fetch());



Assert::type(Ipsum::class, $container->getService('three1'));
Expand Down Expand Up @@ -253,3 +287,13 @@ Assert::type(Ipsum::class, $container->getService('three7'));
Assert::same([
'Ipsum::__construct 2',
], Notes::fetch());

Assert::exception(function () use ($container) {
$container->getService('three8');
}, TypeError::class, 'Return value of %a%::createServiceThree8() must be an instance of Ipsum, instance of Lorem returned');
Notes::fetch();

Assert::type(Ipsum::class, $container->getService('three9'));
Assert::same([
'Ipsum::__construct ',
], Notes::fetch());
6 changes: 3 additions & 3 deletions tests/DI/CompilerExtension.loadDefinitionsFromConfig.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ $compilerExtension = (new CompilerExtension)->setCompiler($compiler, 'blog');
$compilerExtension->loadDefinitionsFromConfig($config['services']);


Assert::same('@blog.articles', $builder->getDefinition('blog.comments')->getFactory()->arguments[1]);
Assert::equal(new Reference('blog.articles'), $builder->getDefinition('blog.articlesList')->getFactory()->arguments[0]);
Assert::equal(new Reference('blog.comments'), $builder->getDefinition('blog.commentsControl')->getFactory()->arguments[0]->getEntity());
Assert::same('@blog.articles', $builder->getServiceDefinition('blog.comments')->getFactory()->arguments[1]);
Assert::equal(new Reference('blog.articles'), $builder->getServiceDefinition('blog.articlesList')->getFactory()->arguments[0]);
Assert::equal(new Reference('blog.comments'), $builder->getServiceDefinition('blog.commentsControl')->getFactory()->arguments[0]->getEntity());
2 changes: 1 addition & 1 deletion tests/DI/Config.Processor.normalizeConfig.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Assert::same(['implement' => Iface::class, 'tagged' => 123], $processor->normali


// aliases
Assert::same(['type' => 'val'], $processor->normalizeConfig(['class' => 'val']));
Assert::same(['factory' => null, 'type' => 'val'], $processor->normalizeConfig(['class' => 'val']));
Assert::same(['imported' => 'val'], $processor->normalizeConfig(['dynamic' => 'val']));

Assert::exception(function () use ($processor) {
Expand Down
38 changes: 38 additions & 0 deletions tests/DI/ContainerBuilder.getAccessorDefinition.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

/**
* Test: Nette\DI\ContainerBuilder::getAccessorDefinition()
*/

declare(strict_types=1);

use Nette\DI;
use Tester\Assert;


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

interface AccessorDefinition
{
public function get();
}

$builder = new DI\ContainerBuilder;
$definitionOne = $builder->addAccessorDefinition('one')
->setImplement(AccessorDefinition::class)
->setClass(\stdClass::class);

$builder->addDefinition('two')
->setType(stdClass::class);


$definition = $builder->getAccessorDefinition('one');
Assert::same($definitionOne, $definition);

Assert::exception(function () use ($builder) {
$builder->getAccessorDefinition('unknown');
}, Nette\DI\MissingServiceException::class, "Service 'unknown' not found.");

Assert::exception(function () use ($builder) {
$builder->getAccessorDefinition('two');
}, Nette\DI\MissingServiceException::class, "AccessorDefinition with name 'two' not found.");
33 changes: 33 additions & 0 deletions tests/DI/ContainerBuilder.getFactoryDefinition.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* Test: Nette\DI\ContainerBuilder::getFactoryDefinition()
*/

declare(strict_types=1);

use Nette\DI;
use Tester\Assert;


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

$builder = new DI\ContainerBuilder;
$definitionOne = $builder->addFactoryDefinition('one');
$definitionOne->getResultDefinition()
->setFactory(SplFileInfo::class);

$builder->addDefinition('two')
->setType(stdClass::class);


$definition = $builder->getFactoryDefinition('one');
Assert::same($definitionOne, $definition);

Assert::exception(function () use ($builder) {
$builder->getFactoryDefinition('unknown');
}, Nette\DI\MissingServiceException::class, "Service 'unknown' not found.");

Assert::exception(function () use ($builder) {
$builder->getFactoryDefinition('two');
}, Nette\DI\MissingServiceException::class, "FactoryDefinition with name 'two' not found.");
Loading