Browse Source

Fix #18396: Fix not throw `InvalidConfigException` when failed to instantiate class via DI container in some cases

tags/2.0.39.3
Sergei Predvoditelev 4 years ago committed by GitHub
parent
commit
22d3255890
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 36
      framework/di/Container.php
  3. 41
      tests/framework/di/ContainerTest.php
  4. 12
      tests/framework/di/stubs/Kappa.php
  5. 37
      tests/framework/di/stubs/Zeta.php

1
framework/CHANGELOG.md

@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.40 under development
------------------------
- Bug #18396: Fix not throw `InvalidConfigException` when failed to instantiate class via DI container in some cases (vjik)
- Enh #18200: Add `maxlength` attribute by default to the input text when it is an active field within a `yii\grid\DataColumn` (rad8329)
2.0.39.2 November 13, 2020

36
framework/di/Container.php

@ -9,6 +9,8 @@ namespace yii\di;
use ReflectionClass;
use ReflectionException;
use ReflectionNamedType;
use ReflectionParameter;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
@ -493,7 +495,7 @@ class Container extends Component
* Returns the dependencies of the specified class.
* @param string $class class name, interface name or alias name
* @return array the dependencies of the specified class.
* @throws InvalidConfigException if a dependency cannot be resolved or if a dependency cannot be fulfilled.
* @throws NotInstantiableException if a dependency cannot be resolved or if a dependency cannot be fulfilled.
*/
protected function getDependencies($class)
{
@ -505,7 +507,12 @@ class Container extends Component
try {
$reflection = new ReflectionClass($class);
} catch (\ReflectionException $e) {
throw new InvalidConfigException('Failed to instantiate component or class "' . $class . '".', 0, $e);
throw new NotInstantiableException(
$class,
'Failed to instantiate component or class "' . $class . '".',
0,
$e
);
}
$constructor = $reflection->getConstructor();
@ -522,14 +529,28 @@ class Container extends Component
try {
$c = $param->getClass();
} catch (ReflectionException $e) {
if (!$this->isNulledParam($param)) {
$notInstantiableClass = null;
if (PHP_VERSION_ID >= 70000) {
$type = $param->getType();
if ($type instanceof ReflectionNamedType) {
$notInstantiableClass = $type->getName();
}
}
throw new NotInstantiableException(
$notInstantiableClass,
$notInstantiableClass === null ? 'Can not instantiate unknown class.' : null
);
} else {
$c = null;
}
}
$isClass = $c !== null;
}
$className = $isClass ? $c->getName() : null;
if ($className !== null) {
$dependencies[$param->getName()] = Instance::of($className, true);
$dependencies[$param->getName()] = Instance::of($className, $this->isNulledParam($param));
} else {
$dependencies[$param->getName()] = $param->isDefaultValueAvailable()
? $param->getDefaultValue()
@ -545,6 +566,15 @@ class Container extends Component
}
/**
* @param ReflectionParameter $param
* @return bool
*/
private function isNulledParam($param)
{
return $param->isOptional() || (PHP_VERSION_ID >= 70100 && $param->getType()->allowsNull());
}
/**
* Resolves dependencies by replacing them with the actual object instances.
* @param array $dependencies the dependencies
* @param ReflectionClass $reflection the class reflection associated with the dependencies

41
tests/framework/di/ContainerTest.php

@ -22,9 +22,11 @@ use yiiunit\framework\di\stubs\Car;
use yiiunit\framework\di\stubs\Corge;
use yiiunit\framework\di\stubs\Foo;
use yiiunit\framework\di\stubs\FooProperty;
use yiiunit\framework\di\stubs\Kappa;
use yiiunit\framework\di\stubs\Qux;
use yiiunit\framework\di\stubs\QuxInterface;
use yiiunit\framework\di\stubs\QuxFactory;
use yiiunit\framework\di\stubs\Zeta;
use yiiunit\TestCase;
/**
@ -580,4 +582,43 @@ class ContainerTest extends TestCase
'Hello',
]);
}
public function dataNotInstantiableException()
{
return [
[Bar::className()],
[Kappa::className()],
];
}
/**
* @dataProvider dataNotInstantiableException
*
* @see https://github.com/yiisoft/yii2/pull/18379
*
* @param string $class
*/
public function testNotInstantiableException($class)
{
$this->expectException('yii\di\NotInstantiableException');
(new Container())->get($class);
}
public function testNullTypeConstructorParameters()
{
if (PHP_VERSION_ID < 70100) {
$this->markTestSkipped('Can not be tested on PHP < 7.1');
return;
}
$zeta = (new Container())->get(Zeta::className());
$this->assertInstanceOf(Beta::className(), $zeta->beta);
$this->assertInstanceOf(Beta::className(), $zeta->betaNull);
$this->assertNull($zeta->color);
$this->assertNull($zeta->colorNull);
$this->assertNull($zeta->qux);
$this->assertNull($zeta->quxNull);
$this->assertNull($zeta->unknown);
$this->assertNull($zeta->unknownNull);
}
}

12
tests/framework/di/stubs/Kappa.php

@ -0,0 +1,12 @@
<?php
namespace yiiunit\framework\di\stubs;
use yii\base\BaseObject;
class Kappa extends BaseObject
{
public function __construct(Unknown $unknown)
{
}
}

37
tests/framework/di/stubs/Zeta.php

@ -0,0 +1,37 @@
<?php
namespace yiiunit\framework\di\stubs;
use yii\base\BaseObject;
class Zeta extends BaseObject
{
public $beta = false;
public $betaNull = false;
public $color = false;
public $colorNull = false;
public $qux = false;
public $quxNull = false;
public $unknown = false;
public $unknownNull = false;
public function __construct(
?Beta $beta,
?AbstractColor $color,
?QuxInterface $qux,
?Unknown $unknown,
?Beta $betaNull = null,
?AbstractColor $colorNull = null,
?QuxInterface $quxNull = null,
?Unknown $unknownNull = null
) {
$this->beta = $beta;
$this->betaNull = $betaNull;
$this->color = $color;
$this->colorNull = $colorNull;
$this->qux = $qux;
$this->quxNull = $quxNull;
$this->unknown = $unknown;
$this->unknownNull = $unknownNull;
}
}
Loading…
Cancel
Save