From 3f8f212b02d5c17feb97a7e0a39ab306f40c06ca Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 10 Jun 2018 18:57:00 +0200 Subject: [PATCH] ContainerBuilder::completeStatement() improved error message --- src/DI/ContainerBuilder.php | 53 ++++++++++++-------- tests/DI/ContainerBuilder.factory.error.phpt | 24 ++++----- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/DI/ContainerBuilder.php b/src/DI/ContainerBuilder.php index d442bf2f1..7b54f63dc 100644 --- a/src/DI/ContainerBuilder.php +++ b/src/DI/ContainerBuilder.php @@ -673,29 +673,40 @@ public function completeStatement(Statement $statement) } } - array_walk_recursive($arguments, function (&$val) { - if ($val instanceof Statement) { - $val = $this->completeStatement($val); - - } elseif ($val === $this) { - trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED); - $val = self::literal('$this'); - - } elseif ($val instanceof ServiceDefinition) { - $val = '@' . current(array_keys($this->getDefinitions(), $val, true)); - - } elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') { - $pair = explode('::', $val, 2); - $name = $this->getServiceName($pair[0]); - if (!isset($pair[1])) { // @service - $val = '@' . $name; - } elseif (preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) { // @service::CONSTANT - $val = self::literal($this->getDefinition($name)->getType() . '::' . $pair[1]); - } else { // @service::property - $val = new Statement(['@' . $name, '$' . $pair[1]]); + try { + array_walk_recursive($arguments, function (&$val) { + if ($val instanceof Statement) { + $val = $this->completeStatement($val); + + } elseif ($val === $this) { + trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED); + $val = self::literal('$this'); + + } elseif ($val instanceof ServiceDefinition) { + $val = '@' . current(array_keys($this->getDefinitions(), $val, true)); + + } elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') { + $pair = explode('::', $val, 2); + $name = $this->getServiceName($pair[0]); + if (!isset($pair[1])) { // @service + $val = '@' . $name; + } elseif (preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) { // @service::CONSTANT + $val = self::literal($this->getDefinition($name)->getType() . '::' . $pair[1]); + } else { // @service::property + $val = new Statement(['@' . $name, '$' . $pair[1]]); + } } + }); + + } catch (ServiceCreationException $e) { + if ((is_string($entity) || is_array($entity)) && !strpos($e->getMessage(), ' (used in')) { + $desc = is_string($entity) + ? $entity . '::__construct' + : (is_string($entity[0]) ? ($entity[0] . '::') : 'method ') . $entity[1]; + $e->setMessage($e->getMessage() . " (used in $desc)"); } - }); + throw $e; + } return new Statement($entity, $arguments); } diff --git a/tests/DI/ContainerBuilder.factory.error.phpt b/tests/DI/ContainerBuilder.factory.error.phpt index df99212cb..015df147c 100644 --- a/tests/DI/ContainerBuilder.factory.error.phpt +++ b/tests/DI/ContainerBuilder.factory.error.phpt @@ -164,14 +164,14 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setFactory('Good', [new Statement('Unknown')]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Unknown not found."); +}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Unknown not found. (used in Good::__construct)"); // fail in argument Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setFactory('Good', [new Statement('Bad8')]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Bad8 has private constructor."); +}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Bad8 has private constructor. (used in Good::__construct)"); abstract class Bad9 @@ -238,7 +238,7 @@ services: b: stdClass bad: ConstructorParam(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct)"); // autowiring fail in chain @@ -260,7 +260,7 @@ services: b: stdClass bad: MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (used in method foo)"); // autowiring fail in argument @@ -271,7 +271,7 @@ services: b: stdClass bad: Good(ConstructorParam()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (needed by \$x in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (needed by \$x in ConstructorParam::__construct()) (used in Good::__construct)"); // forced autowiring fail in argument @@ -282,7 +282,7 @@ services: b: stdClass bad: Good(ConstructorParam(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct)"); // autowiring fail in chain in argument @@ -293,7 +293,7 @@ services: b: stdClass bad: Good(MethodParam()::foo()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (needed by \$x in MethodParam::foo())"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (needed by \$x in MethodParam::foo()) (used in Good::__construct)"); // forced autowiring fail in chain in argument @@ -304,7 +304,7 @@ services: b: stdClass bad: Good(MethodParam()::foo(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in method foo)"); // forced autowiring fail in property passing @@ -318,7 +318,7 @@ services: setup: - $a = @\stdClass '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::\$a)"); // autowiring fail in rich property passing @@ -332,7 +332,7 @@ services: setup: - $a = MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in method foo)"); // autowiring fail in method calling @@ -360,7 +360,7 @@ services: setup: - bar(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::bar)"); // autowiring fail in rich method calling @@ -374,4 +374,4 @@ services: setup: - bar(MethodParam()::foo(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b"); +}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in method foo)");