diff --git a/composer.json b/composer.json index f8342787f..d217ca664 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } } } diff --git a/src/DI/Config/Adapter.php b/src/DI/Config/Adapter.php index 25e9cecd8..a9b7004b6 100644 --- a/src/DI/Config/Adapter.php +++ b/src/DI/Config/Adapter.php @@ -20,6 +20,3 @@ interface Adapter */ function load(string $file): array; } - - -class_exists(IAdapter::class); diff --git a/src/DI/Config/Adapters/NeonAdapter.php b/src/DI/Config/Adapters/NeonAdapter.php index d806cd319..90c629c50 100644 --- a/src/DI/Config/Adapters/NeonAdapter.php +++ b/src/DI/Config/Adapters/NeonAdapter.php @@ -180,11 +180,6 @@ private function removeUnderscoreVisitor(Neon\Node $node): void if ($attr->value instanceof Neon\Node\LiteralNode && $attr->value->value === '_') { unset($node->attributes[$i]); $index = true; - - } elseif ($attr->value instanceof Neon\Node\LiteralNode && $attr->value->value === '...') { - trigger_error("Replace ... with _ in configuration file '$this->file'.", E_USER_DEPRECATED); - unset($node->attributes[$i]); - $index = true; } } } diff --git a/src/DI/Definitions/AccessorDefinition.php b/src/DI/Definitions/AccessorDefinition.php index bd6c1a1a5..5063d2d26 100644 --- a/src/DI/Definitions/AccessorDefinition.php +++ b/src/DI/Definitions/AccessorDefinition.php @@ -28,8 +28,8 @@ public function setImplement(string $interface): static { if (!interface_exists($interface)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface '%s' not found.", - $this->getName(), + "[%s]\nInterface '%s' not found.", + $this->getDescriptor(), $interface, )); } @@ -44,19 +44,19 @@ public function setImplement(string $interface): static || count($rc->getMethods()) > 1 ) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface %s must have just one non-static method get().", - $this->getName(), + "[%s]\nInterface %s must have just one non-static method get().", + $this->getDescriptor(), $interface, )); } elseif ($method->getNumberOfParameters()) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Method %s::get() must have no parameters.", - $this->getName(), + "[%s]\nMethod %s::get() must have no parameters.", + $this->getDescriptor(), $interface, )); } - Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::get()"); + Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::get()", $this->getDescriptor()); return parent::setType($interface); } diff --git a/src/DI/Definitions/Definition.php b/src/DI/Definitions/Definition.php index ca96659b8..5d6bdadb4 100644 --- a/src/DI/Definitions/Definition.php +++ b/src/DI/Definitions/Definition.php @@ -46,6 +46,29 @@ final public function getName(): ?string } + final public function isAnonymous(): bool + { + return !$this->name || ctype_digit($this->name); + } + + + public function getDescriptor(): string + { + if (!$this->isAnonymous()) { + return "Service '$this->name'" . ($this->type ? " of type $this->type" : ''); + + } elseif ($this->type) { + return "Service of type $this->type"; + + } elseif ($this->name) { + return "Service '$this->name'"; + + } else { + return 'Service ?'; + } + } + + protected function setType(?string $type): static { if ($this->autowired && $this->notifier && $this->type !== $type) { @@ -56,8 +79,8 @@ protected function setType(?string $type): static $this->type = null; } elseif (!class_exists($type) && !interface_exists($type)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Class or interface '%s' not found.", - $this->name, + "[%s]\nClass or interface '%s' not found.", + $this->getDescriptor(), $type, )); } else { diff --git a/src/DI/Definitions/FactoryDefinition.php b/src/DI/Definitions/FactoryDefinition.php index 7c2e69caa..7ed5eb933 100644 --- a/src/DI/Definitions/FactoryDefinition.php +++ b/src/DI/Definitions/FactoryDefinition.php @@ -24,6 +24,7 @@ final class FactoryDefinition extends Definition private const MethodCreate = 'create'; private Definition $resultDefinition; + private ?string $reference = null; public function __construct() @@ -36,8 +37,8 @@ public function setImplement(string $interface): static { if (!interface_exists($interface)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface '%s' not found.", - $this->getName(), + "[%s]\nInterface '%s' not found.", + $this->getDescriptor(), $interface, )); } @@ -46,13 +47,13 @@ public function setImplement(string $interface): static $method = $rc->getMethods()[0] ?? null; if (!$method || $method->isStatic() || $method->name !== self::MethodCreate || count($rc->getMethods()) > 1) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface %s must have just one non-static method create().", - $this->getName(), + "[%s]\nInterface %s must have just one non-static method create().", + $this->getDescriptor(), $interface, )); } - Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::create()"); + Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::create()", $this->getDescriptor()); return parent::setType($interface); } @@ -87,6 +88,10 @@ public function resolveType(Nette\DI\Resolver $resolver): void { if (!$this->getType()) { throw new ServiceCreationException('Type is missing in definition of service.'); + + } elseif ($this->reference === null) { + $this->resultDefinition->setAutowired(false); + $this->reference = $resolver->getContainerBuilder()->addDefinition(null, $this->resultDefinition)->getName(); } $type = Type::fromReflection(new \ReflectionMethod($this->getType(), self::MethodCreate)); @@ -105,7 +110,8 @@ public function resolveType(Nette\DI\Resolver $resolver): void if (!$type->allows($resultDef->getType())) { throw new ServiceCreationException(sprintf( - 'Factory for %s cannot create incompatible %s type.', + "[%s]\nFactory for %s cannot create incompatible %s type.", + $this->getDescriptor(), $type, $resultDef->getType(), )); diff --git a/src/DI/Definitions/LocatorDefinition.php b/src/DI/Definitions/LocatorDefinition.php index fe8b3aecd..6c9d96628 100644 --- a/src/DI/Definitions/LocatorDefinition.php +++ b/src/DI/Definitions/LocatorDefinition.php @@ -25,31 +25,32 @@ final class LocatorDefinition extends Definition public function setImplement(string $interface): static { if (!interface_exists($interface)) { - throw new Nette\InvalidArgumentException(sprintf("Service '%s': Interface '%s' not found.", $this->getName(), $interface)); + throw new Nette\InvalidArgumentException(sprintf("[%s]\nInterface '%s' not found.", $this->getDescriptor(), $interface)); } $methods = (new \ReflectionClass($interface))->getMethods(); if (!$methods) { - throw new Nette\InvalidArgumentException(sprintf("Service '%s': Interface %s must have at least one method.", $this->getName(), $interface)); + throw new Nette\InvalidArgumentException(sprintf("[%s]\nInterface %s must have at least one method.", $this->getDescriptor(), $interface)); } foreach ($methods as $method) { if ($method->isStatic() || !( - (preg_match('#^(get|create)$#', $method->name) && $method->getNumberOfParameters() === 1) + ($method->name === 'get' && $method->getNumberOfParameters() === 1) || (preg_match('#^(get|create)[A-Z]#', $method->name) && $method->getNumberOfParameters() === 0) )) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Method %s::%s() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static.", - $this->getName(), + "[%s]\nMethod %s::%s() does not meet the requirements: is create*(), get*() or get(\$name) and is non-static.", + $this->getDescriptor(), $interface, $method->name, )); } - if ($method->getNumberOfParameters() === 0) { + if ($method->name !== 'get') { Nette\DI\Helpers::ensureClassType( Nette\Utils\Type::fromReflection($method), "return type of $interface::$method->name()", + $this->getDescriptor(), allowNullable: true, ); } @@ -110,8 +111,8 @@ public function complete(Nette\DI\Resolver $resolver): void foreach ($resolver->getContainerBuilder()->findByTag($this->tagged) as $name => $tag) { if (isset($this->references[$tag])) { trigger_error(sprintf( - "Service '%s': duplicated tag '%s' with value '%s'.", - $this->getName(), + "[%s]\nDuplicated tag '%s' with value '%s'.", + $this->getDescriptor(), $this->tagged, $tag, )); @@ -152,7 +153,7 @@ public function generateMethod(Nette\PhpGenerator\Method $method, Nette\DI\PhpGe $methodInner->setBody('if (!isset($this->mapping[$name])) { ' . ($nullable ? 'return null;' : 'throw new Nette\DI\MissingServiceException("Service \'$name\' is not defined.");') . ' } -return $this->container->' . $m[1] . 'Service($this->mapping[$name]);') +return $this->container->getService($this->mapping[$name]);') ->addParameter('name'); } elseif (isset($this->references[$name])) { diff --git a/src/DI/Definitions/ServiceDefinition.php b/src/DI/Definitions/ServiceDefinition.php index 6cec76a86..0bf42d48e 100644 --- a/src/DI/Definitions/ServiceDefinition.php +++ b/src/DI/Definitions/ServiceDefinition.php @@ -16,9 +16,9 @@ /** * Definition of standard service. * - * @property string|null $class - * @property Statement $factory - * @property Statement[] $setup + * @property-deprecated string|null $class + * @property-deprecated Statement $factory + * @property-deprecated Statement[] $setup */ final class ServiceDefinition extends Definition { @@ -36,6 +36,17 @@ public function __construct() } + public function getDescriptor(): string + { + $entity = $this->getEntity(); + if ($entity && $this->isAnonymous()) { + return 'Service ' . (is_string($entity) ? "of type $entity" : Nette\DI\Helpers::entityToString($entity)); + } + + return parent::getDescriptor(); + } + + public function setType(?string $type): static { return parent::setType($type); @@ -204,6 +215,3 @@ public function __clone() $this->setup = unserialize(serialize($this->setup)); } } - - -class_exists(Nette\DI\ServiceDefinition::class); diff --git a/src/DI/Definitions/Statement.php b/src/DI/Definitions/Statement.php index cd80f6d44..8010b4b95 100644 --- a/src/DI/Definitions/Statement.php +++ b/src/DI/Definitions/Statement.php @@ -15,7 +15,7 @@ /** * Assignment or calling statement. * - * @property string|array|Definition|Reference|null $entity + * @property-deprecated string|array|Definition|Reference|null $entity */ final class Statement implements Nette\Schema\DynamicParameter { @@ -63,6 +63,3 @@ public function getEntity(): string|array|Definition|Reference|null return $this->entity; } } - - -class_exists(Nette\DI\Statement::class); diff --git a/src/DI/Extensions/DecoratorExtension.php b/src/DI/Extensions/DecoratorExtension.php index e5a4cc129..43c8aeaa9 100644 --- a/src/DI/Extensions/DecoratorExtension.php +++ b/src/DI/Extensions/DecoratorExtension.php @@ -50,11 +50,7 @@ public function beforeCompile(): void public function addSetups(string $type, array $setups): void { - foreach ($this->findByType($type) as $def) { - if ($def instanceof Definitions\FactoryDefinition) { - $def = $def->getResultDefinition(); - } - + foreach ($this->getContainerBuilder()->findByType($type) as $def) { foreach ($setups as $setup) { if (is_array($setup)) { $setup = new Definitions\Statement(key($setup), array_values($setup)); @@ -69,18 +65,8 @@ public function addSetups(string $type, array $setups): void public function addTags(string $type, array $tags): void { $tags = Nette\Utils\Arrays::normalize($tags, filling: true); - foreach ($this->findByType($type) as $def) { + foreach ($this->getContainerBuilder()->findByType($type) as $def) { $def->setTags($def->getTags() + $tags); } } - - - private function findByType(string $type): array - { - return array_filter( - $this->getContainerBuilder()->getDefinitions(), - fn(Definitions\Definition $def): bool => is_a($def->getType(), $type, true) - || ($def instanceof Definitions\FactoryDefinition && is_a($def->getResultType(), $type, allow_string: true)), - ); - } } diff --git a/src/DI/Extensions/InjectExtension.php b/src/DI/Extensions/InjectExtension.php index 4c40b30c0..8b0979010 100644 --- a/src/DI/Extensions/InjectExtension.php +++ b/src/DI/Extensions/InjectExtension.php @@ -35,13 +35,8 @@ public function getConfigSchema(): Nette\Schema\Schema public function beforeCompile(): void { foreach ($this->getContainerBuilder()->getDefinitions() as $def) { - if ($def->getTag(self::TagInject)) { - $def = $def instanceof Definitions\FactoryDefinition - ? $def->getResultDefinition() - : $def; - if ($def instanceof Definitions\ServiceDefinition) { - $this->updateDefinition($def); - } + if ($def instanceof Definitions\ServiceDefinition && $def->getTag(self::TagInject)) { + $this->updateDefinition($def); } } } @@ -67,7 +62,7 @@ private function updateDefinition(Definitions\ServiceDefinition $def): void } if ($builder) { - self::checkType($class, $property, $type, $builder); + self::checkType($class, $property, $type, $builder, $def); } array_unshift($setups, $inject); } @@ -117,19 +112,15 @@ public static function getInjectProperties(string $class): array { $res = []; foreach ((new \ReflectionClass($class))->getProperties() as $rp) { - $hasAttr = $rp->getAttributes(DI\Attributes\Inject::class); - if ($hasAttr || DI\Helpers::parseAnnotation($rp, 'inject') !== null) { + if ( + $rp->getAttributes(DI\Attributes\Inject::class) + || DI\Helpers::parseAnnotation($rp, 'inject') !== null + ) { if (!$rp->isPublic() || $rp->isStatic() || $rp->isReadOnly()) { throw new Nette\InvalidStateException(sprintf('Property %s for injection must not be static, readonly and must be public.', Reflection::toString($rp))); } - $type = Nette\Utils\Type::fromReflection($rp); - if (!$type && !$hasAttr && ($annotation = DI\Helpers::parseAnnotation($rp, 'var'))) { - $annotation = Reflection::expandClassName($annotation, Reflection::getPropertyDeclaringClass($rp)); - $type = Nette\Utils\Type::fromString($annotation); - } - - $res[$rp->getName()] = DI\Helpers::ensureClassType($type, 'type of property ' . Reflection::toString($rp)); + $res[$rp->getName()] = DI\Helpers::ensureClassType(Nette\Utils\Type::fromReflection($rp), 'type of property ' . Reflection::toString($rp)); } } @@ -148,7 +139,7 @@ public static function callInjects(DI\Container $container, object $service): vo } foreach (self::getInjectProperties($service::class) as $property => $type) { - self::checkType($service, $property, $type, $container); + self::checkType($service, $property, $type, $container, null); $service->$property = $container->getByType($type); } } @@ -159,11 +150,13 @@ private static function checkType( string $name, ?string $type, DI\Container|DI\ContainerBuilder $container, + ?Definitions\Definition $def, ): void { if (!$container->getByType($type, throw: false)) { throw new Nette\DI\MissingServiceException(sprintf( - 'Service of type %s required by %s not found. Did you add it to configuration file?', + "%sService of type %s required by %s not found.\nDid you add it to configuration file?", + $def ? '[' . $def->getDescriptor() . "]\n" : '', $type, Reflection::toString(new \ReflectionProperty($class, $name)), )); diff --git a/src/DI/Extensions/SearchExtension.php b/src/DI/Extensions/SearchExtension.php index eb872534d..5fcc435d4 100644 --- a/src/DI/Extensions/SearchExtension.php +++ b/src/DI/Extensions/SearchExtension.php @@ -110,6 +110,7 @@ public function findClasses(\stdClass $config): array && (!$rejectRE || !preg_match($rejectRE, $rc->name)) && (!$acceptParent || Arrays::some($acceptParent, fn($nm) => $rc->isSubclassOf($nm))) && (!$rejectParent || Arrays::every($rejectParent, fn($nm) => !$rc->isSubclassOf($nm))) + && (self::hasAutowireArguments($rc->getConstructor())) ) { $found[] = $rc->name; } @@ -156,4 +157,18 @@ private static function buildNameRegexp(array $masks): ?string return $res ? '#^(' . implode('|', $res) . ')$#i' : null; } + + + private static function hasAutowireArguments(?\ReflectionMethod $constructor): bool + { + if ($constructor !== null) { + try { + Nette\DI\Resolver::autowireArguments($constructor, [], static fn() => new \stdClass()); + } catch (Nette\DI\ServiceCreationException) { + return false; + } + } + + return true; + } } diff --git a/src/DI/Extensions/ServicesExtension.php b/src/DI/Extensions/ServicesExtension.php index 8bb50257d..8e35ea635 100644 --- a/src/DI/Extensions/ServicesExtension.php +++ b/src/DI/Extensions/ServicesExtension.php @@ -53,7 +53,7 @@ private function loadDefinition(?string $name, \stdClass $config): void $this->getContainerBuilder()->removeDefinition($name); return; } elseif (!empty($config->alteration) && !$this->getContainerBuilder()->hasDefinition($name)) { - throw new Nette\DI\InvalidConfigurationException('missing original definition for alteration.'); + throw new Nette\DI\InvalidConfigurationException('Missing original definition for alteration.'); } $def = $this->retrieveDefinition($name, $config); @@ -68,7 +68,12 @@ private function loadDefinition(?string $name, \stdClass $config): void $this->{$methods[$config->defType]}($def, $config); $this->updateDefinition($def, $config); } catch (\Throwable $e) { - throw new Nette\DI\InvalidConfigurationException(($name ? "Service '$name': " : '') . $e->getMessage(), 0, $e); + $message = $e->getMessage(); + if ($name && !str_starts_with($message, '[Service ')) { + $message = "[Service '$name']\n$message"; + } + + throw new Nette\DI\InvalidConfigurationException($message, 0, $e); } } @@ -169,7 +174,7 @@ private function updateFactoryDefinition(Definitions\FactoryDefinition $definiti } if (isset($config->inject)) { - $definition->addTag(InjectExtension::TagInject, $config->inject); + $resultDef->addTag(InjectExtension::TagInject, $config->inject); } } diff --git a/src/DI/Helpers.php b/src/DI/Helpers.php index 610239b8d..16d6b44ba 100644 --- a/src/DI/Helpers.php +++ b/src/DI/Helpers.php @@ -202,6 +202,7 @@ public static function prefixServiceName(mixed $config, string $namespace): mixe /** * Returns an annotation value. + * @deprecated */ public static function parseAnnotation(\Reflector $ref, string $name): ?string { @@ -211,6 +212,8 @@ public static function parseAnnotation(\Reflector $ref, string $name): ?string $re = '#[\s*]@' . preg_quote($name, '#') . '(?=\s|$)(?:[ \t]+([^@\s]\S*))?#'; if ($ref->getDocComment() && preg_match($re, trim($ref->getDocComment(), '/*'), $m)) { + $alt = $name === 'inject' ? '#[Nette\DI\Attributes\Inject]' : 'alternative'; + trigger_error("Annotation @$name is deprecated, use $alt (used in " . Reflection::toString($ref) . ')', E_USER_DEPRECATED); return $m[1] ?? ''; } @@ -218,31 +221,23 @@ public static function parseAnnotation(\Reflector $ref, string $name): ?string } - public static function getReturnTypeAnnotation(\ReflectionFunctionAbstract $func): ?Type - { - $type = preg_replace('#[|\s].*#', '', (string) self::parseAnnotation($func, 'return')); - if (!$type || $type === 'object' || $type === 'mixed') { - return null; - } elseif ($func instanceof \ReflectionMethod) { - $type = $type === '$this' ? 'static' : $type; - $type = Reflection::expandClassName($type, $func->getDeclaringClass()); - } - - return Type::fromString($type); - } - - - public static function ensureClassType(?Type $type, string $hint, bool $allowNullable = false): string + public static function ensureClassType( + ?Type $type, + string $hint, + string $descriptor = '', + bool $allowNullable = false, + ): string { + $descriptor = $descriptor ? "[$descriptor]\n" : ''; if (!$type) { - throw new ServiceCreationException(sprintf('%s is not declared.', ucfirst($hint))); + throw new ServiceCreationException(sprintf('%s%s is not declared.', $descriptor, ucfirst($hint))); } elseif (!$type->isClass() || (!$allowNullable && $type->allows('null'))) { - throw new ServiceCreationException(sprintf("%s is expected to not be %sbuilt-in/complex, '%s' given.", ucfirst($hint), $allowNullable ? '' : 'nullable/', $type)); + throw new ServiceCreationException(sprintf("%s%s is expected to not be %sbuilt-in/complex, '%s' given.", $descriptor, ucfirst($hint), $allowNullable ? '' : 'nullable/', $type)); } $class = $type->getSingleName(); if (!class_exists($class) && !interface_exists($class)) { - throw new ServiceCreationException(sprintf("Class '%s' not found.\nCheck the %s.", $class, $hint)); + throw new ServiceCreationException(sprintf("%sClass '%s' not found.\nCheck the %s.", $descriptor, $class, $hint)); } return $class; @@ -282,4 +277,22 @@ public static function convertType(mixed $value, string $type): mixed $type, )); } + + + public static function entityToString(string|array|Reference $entity, bool $inner = false): string + { + if (is_string($entity)) { + return $entity . ($inner ? '()' : ''); + + } elseif ($entity instanceof Reference) { + return '@' . $entity->getValue(); + + } else { + [$a, $b] = $entity; + return self::entityToString($a instanceof Statement ? $a->getEntity() : $a, inner: true) + . '::' + . $b + . (str_contains($b, '$') ? '' : '()'); + } + } } diff --git a/src/DI/PhpGenerator.php b/src/DI/PhpGenerator.php index bbb4b574c..e475cd085 100644 --- a/src/DI/PhpGenerator.php +++ b/src/DI/PhpGenerator.php @@ -96,7 +96,7 @@ public function generateMethod(Definitions\Definition $def): Php\Method return $method; } catch (\Throwable $e) { - throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e); + throw new ServiceCreationException(sprintf("[%s]\n%s", $def->getDescriptor(), $e->getMessage()), 0, $e); } } @@ -113,6 +113,15 @@ public function formatStatement(Statement $statement): string case is_string($entity) && str_contains($entity, '?'): // PHP literal return $this->formatPhp($entity, $arguments); + case $entity === 'not': + return $this->formatPhp('!(?)', $arguments); + + case $entity === 'bool': + case $entity === 'int': + case $entity === 'float': + case $entity === 'string': + return $this->formatPhp('?::?(?, ?)', [Helpers::class, 'convertType', $arguments[0], $entity]); + case is_string($entity): // create class return $arguments ? $this->formatPhp("new $entity(...?:)", [$arguments]) diff --git a/src/DI/Resolver.php b/src/DI/Resolver.php index 3e6afc3ff..819fc34ee 100644 --- a/src/DI/Resolver.php +++ b/src/DI/Resolver.php @@ -122,20 +122,10 @@ public function resolveEntityType(Statement $statement): ?string $this->addDependency($reflection); - $type = Nette\Utils\Type::fromReflection($reflection) ?? ($annotation = Helpers::getReturnTypeAnnotation($reflection)); - if ($type && !in_array($type->getSingleName(), ['object', 'mixed'], strict: true)) { - if (isset($annotation)) { - trigger_error('Annotation @return should be replaced with native return type at ' . Callback::toString($entity), E_USER_DEPRECATED); - } - - return Helpers::ensureClassType( - $type, - sprintf('return type of %s()', Callback::toString($entity)), - allowNullable: true, - ); - } - - return null; + $type = Nette\Utils\Type::fromReflection($reflection); + return $type && !in_array($type->getSingleName(), ['object', 'mixed'], strict: true) + ? Helpers::ensureClassType($type, sprintf('return type of %s()', Callback::toString($entity)), allowNullable: true) + : null; } elseif ($entity instanceof Reference) { // alias or factory return $this->resolveReferenceType($entity); @@ -202,13 +192,6 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo break; case $entity === 'not': - if (count($arguments) !== 1) { - throw new ServiceCreationException(sprintf('Function %s() expects 1 parameter, %s given.', $entity, count($arguments))); - } - - $entity = ['', '!']; - break; - case $entity === 'bool': case $entity === 'int': case $entity === 'float': @@ -216,9 +199,6 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo if (count($arguments) !== 1) { throw new ServiceCreationException(sprintf('Function %s() expects 1 parameter, %s given.', $entity, count($arguments))); } - - $arguments = [$arguments[0], $entity]; - $entity = [Helpers::class, 'convertType']; break; case is_string($entity): // create class @@ -303,9 +283,21 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo try { $arguments = $this->completeArguments($arguments); + } catch (ServiceCreationException $e) { - if (!str_contains($e->getMessage(), ' (used in')) { - $e->setMessage($e->getMessage() . " (used in {$this->entityToString($entity)})"); + if (!str_contains($e->getMessage(), "\nRelated to")) { + if (is_string($entity)) { + $desc = $entity . '::__construct()'; + } else { + $desc = Helpers::entityToString($entity); + $desc = preg_replace('~@self::~A', '', $desc); + } + + if ($currentServiceAllowed) { + $desc .= ' in setup'; + } + + $e->setMessage($e->getMessage() . "\nRelated to $desc."); } throw $e; @@ -442,25 +434,16 @@ public function addDependency(\ReflectionClass|\ReflectionFunctionAbstract|strin private function completeException(\Throwable $e, Definition $def): ServiceCreationException { - if ($e instanceof ServiceCreationException && str_starts_with($e->getMessage(), "Service '")) { + $message = $e->getMessage(); + if ($e instanceof ServiceCreationException && str_starts_with($message, '[Service ')) { return $e; } - $name = $def->getName(); - $type = $def->getType(); - if ($name && !ctype_digit($name)) { - $message = "Service '$name'" . ($type ? " (type of $type)" : '') . ': '; - } elseif ($type) { - $message = "Service of type $type: "; - } elseif ($def instanceof Definitions\ServiceDefinition && $def->getEntity()) { - $message = 'Service (' . $this->entityToString($def->getEntity()) . '): '; - } else { - $message = ''; + if ($tmp = $def->getType()) { + $message = str_replace(" $tmp::", ' ' . preg_replace('~.*\\\\~', '', $tmp) . '::', $message); } - $message .= $type - ? str_replace("$type::", preg_replace('~.*\\\\~', '', $type) . '::', $e->getMessage()) - : $e->getMessage(); + $message = '[' . $def->getDescriptor() . "]\n" . $message; return $e instanceof ServiceCreationException ? $e->setMessage($message) @@ -468,33 +451,6 @@ private function completeException(\Throwable $e, Definition $def): ServiceCreat } - private function entityToString($entity): string - { - $referenceToText = fn(Reference $ref): string => $ref->isSelf() && $this->currentService - ? '@' . $this->currentService->getName() - : '@' . $ref->getValue(); - if (is_string($entity)) { - return $entity . '::__construct()'; - } elseif ($entity instanceof Reference) { - $entity = $referenceToText($entity); - } elseif (is_array($entity)) { - if (!str_contains($entity[1], '$')) { - $entity[1] .= '()'; - } - - if ($entity[0] instanceof Reference) { - $entity[0] = $referenceToText($entity[0]); - } elseif (!is_string($entity[0])) { - return $entity[1]; - } - - return implode('::', $entity); - } - - return (string) $entity; - } - - private function convertReferences(array $arguments): array { array_walk_recursive($arguments, function (&$val): void { @@ -606,20 +562,20 @@ private static function autowireArgument(\ReflectionParameter $parameter, callab } catch (MissingServiceException) { $res = null; } catch (ServiceCreationException $e) { - throw new ServiceCreationException("{$e->getMessage()} (required by $desc)", 0, $e); + throw new ServiceCreationException(sprintf("%s\nRequired by %s.", $e->getMessage(), $desc), 0, $e); } if ($res !== null || $parameter->isOptional()) { return $res; } elseif (class_exists($class) || interface_exists($class)) { throw new ServiceCreationException(sprintf( - 'Service of type %s required by %s not found. Did you add it to configuration file?', + "Service of type %s required by %s not found.\nDid you add it to configuration file?", $class, $desc, )); } else { throw new ServiceCreationException(sprintf( - "Class '%s' required by %s not found. Check the parameter type and 'use' statements.", + "Class '%s' required by %s not found.\nCheck the parameter type and 'use' statements.", $class, $desc, )); diff --git a/src/compatibility.php b/src/compatibility.php deleted file mode 100644 index f0a0e53fe..000000000 --- a/src/compatibility.php +++ /dev/null @@ -1,39 +0,0 @@ -addConfig([ Assert::exception( fn() => $compiler->setClassName($class)->compile(), DI\InvalidConfigurationException::class, - "Service 's3': missing original definition for alteration.", + "[Service 's3'] +Missing original definition for alteration.", ); diff --git a/tests/DI/Compiler.extensionOverride.errors.phpt b/tests/DI/Compiler.extensionOverride.errors.phpt index a4b942814..945f0e5b5 100644 --- a/tests/DI/Compiler.extensionOverride.errors.phpt +++ b/tests/DI/Compiler.extensionOverride.errors.phpt @@ -21,4 +21,5 @@ services: bad: alteration: yes '); -}, Nette\DI\InvalidConfigurationException::class, "Service 'bad': missing original definition for alteration."); +}, Nette\DI\InvalidConfigurationException::class, "[Service 'bad'] +Missing original definition for alteration."); diff --git a/tests/DI/Compiler.first-class-callable.phpt b/tests/DI/Compiler.first-class-callable.phpt index c2601dff0..d4f51376e 100644 --- a/tests/DI/Compiler.first-class-callable.phpt +++ b/tests/DI/Compiler.first-class-callable.phpt @@ -50,7 +50,8 @@ Assert::exception(function () { $compiler = new DI\Compiler; $compiler->addConfig($loader->load(Tester\FileMock::create($config, 'neon'))); $compiler->compile(); -}, Nette\DI\ServiceCreationException::class, 'Service of type Closure: Cannot create closure for Service(...)'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Service] +Cannot create closure for Service(...)'); // Invalid callable 2 @@ -63,4 +64,6 @@ Assert::exception(function () { $compiler = new DI\Compiler; $compiler->addConfig($loader->load(Tester\FileMock::create($config, 'neon'))); $compiler->compile(); -}, Nette\DI\ServiceCreationException::class, 'Service of type Service: Cannot create closure for Service(...) (used in Service::__construct())'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Service] +Cannot create closure for Service(...) +Related to Service::__construct().'); diff --git a/tests/DI/Compiler.functions.phpt b/tests/DI/Compiler.functions.phpt index 0afb97a42..08831b44c 100644 --- a/tests/DI/Compiler.functions.phpt +++ b/tests/DI/Compiler.functions.phpt @@ -93,5 +93,7 @@ Assert::exception( - Service(bool(123, 10)) '), Nette\InvalidStateException::class, - 'Service of type Service: Function bool() expects 1 parameter, 2 given. (used in Service::__construct())', + '[Service of type Service] +Function bool() expects 1 parameter, 2 given. +Related to Service::__construct().', ); diff --git a/tests/DI/Compiler.generatedFactory.phpt b/tests/DI/Compiler.generatedFactory.phpt index 81068a106..eac013e90 100644 --- a/tests/DI/Compiler.generatedFactory.phpt +++ b/tests/DI/Compiler.generatedFactory.phpt @@ -266,7 +266,8 @@ Assert::exception(function () { $builder->addFactoryDefinition('one') ->setImplement(Bad2::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad2): Type of \$bar in Bad2::create() doesn't match type in Bad1 constructor."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad2] +Type of \$bar in Bad2::create() doesn't match type in Bad1 constructor."); @@ -287,7 +288,8 @@ Assert::exception(function () { $builder->addFactoryDefinition('one') ->setImplement(Bad4::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad4): Cannot implement Bad4::create(): factory method parameters (\$baz) are not matching Bad3::__construct() parameters (\$bar). Did you mean to use '\$bar' in factory method?"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad4] +Cannot implement Bad4::create(): factory method parameters (\$baz) are not matching Bad3::__construct() parameters (\$bar). Did you mean to use '\$bar' in factory method?"); @@ -308,4 +310,5 @@ Assert::exception(function () { $builder->addFactoryDefinition('one') ->setImplement(Bad6::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad6): Cannot implement Bad6::create(): factory method parameters (\$baz) are not matching Bad5::__construct() parameters (\$xxx)."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad6] +Cannot implement Bad6::create(): factory method parameters (\$baz) are not matching Bad5::__construct() parameters (\$xxx)."); diff --git a/tests/DI/Compiler.generatedLocator.phpt b/tests/DI/Compiler.generatedLocator.phpt index 34816729e..d33b219c5 100644 --- a/tests/DI/Compiler.generatedLocator.phpt +++ b/tests/DI/Compiler.generatedLocator.phpt @@ -63,10 +63,7 @@ services: one: Locator(a: @lorem1, b: LoremChild) two: Locator(tagged: a) - three: LocatorFactory(a: @lorem1, b: LoremChild) - four: LocatorFactory(tagged: b) five: LocatorN(tagged: a) - six: LocatorFactoryN(tagged: a) seven: Locator(a: @lorem1) eight: Locator(a: LoremChild()) '); @@ -95,29 +92,12 @@ Assert::exception( "Service '3' is not defined.", ); -// factory -$three = $container->getService('three'); -Assert::type(Lorem::class, $three->create('a')); -Assert::type(LoremChild::class, $three->create('b')); -Assert::notSame($three->create('a'), $three->create('a')); - -// tagged factory -$four = $container->getService('four'); -Assert::type(Lorem::class, $four->create('3')); -Assert::notSame($container->getService('lorem3'), $four->create('3')); - // nullable accessor $five = $container->getService('five'); Assert::type(Lorem::class, $five->get('1')); Assert::type(Lorem::class, $five->get('2')); Assert::null($five->get('3')); -// nullable factory -$six = $container->getService('six'); -Assert::type(Lorem::class, $six->create('1')); -Assert::type(Lorem::class, $six->create('2')); -Assert::null($six->create('3')); - // accessor with one service $one = $container->getService('seven'); Assert::type(Lorem::class, $one->get('a')); diff --git a/tests/DI/Container.inject.properties.phpt b/tests/DI/Container.inject.properties.phpt index b633c0f8b..73324665c 100644 --- a/tests/DI/Container.inject.properties.phpt +++ b/tests/DI/Container.inject.properties.phpt @@ -7,6 +7,7 @@ declare(strict_types=1); use Nette\DI; +use Nette\DI\Attributes\Inject; use Tester\Assert; @@ -23,20 +24,17 @@ class Foo implements IFoo class Test1 { - /** @inject @var stdClass */ - public $varA; - - /** @var stdClass @inject */ - public $varB; + #[Inject] + public stdClass $varA; } class Test2 extends Test1 { - /** @var stdClass @inject */ - public $varC; + #[Inject] + public stdClass $varC; - /** @var IFoo @inject */ - public $varD; + #[Inject] + public IFoo $varD; } @@ -52,6 +50,5 @@ $container = createContainer($builder); $test = new Test2; $container->callInjects($test); Assert::type(stdClass::class, $test->varA); -Assert::type(stdClass::class, $test->varB); Assert::type(stdClass::class, $test->varC); Assert::type(Foo::class, $test->varD); diff --git a/tests/DI/ContainerBuilder.autowiring.novalue.phpt b/tests/DI/ContainerBuilder.autowiring.novalue.phpt index 1a9b7cca4..3aee26fda 100644 --- a/tests/DI/ContainerBuilder.autowiring.novalue.phpt +++ b/tests/DI/ContainerBuilder.autowiring.novalue.phpt @@ -24,7 +24,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType(Foo::class); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Foo): Parameter \$x in Foo::__construct() has no class type or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "[Service 'foo' of type Foo] +Parameter \$x in Foo::__construct() has no class type or default value, so its value must be specified."); class Bar @@ -38,7 +39,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType(Bar::class); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Bar): Parameter \$x in Bar::__construct() has no class type or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "[Service 'foo' of type Bar] +Parameter \$x in Bar::__construct() has no class type or default value, so its value must be specified."); class Bar2 diff --git a/tests/DI/ContainerBuilder.create.error.phpt b/tests/DI/ContainerBuilder.create.error.phpt index 0af01c12c..858c22231 100644 --- a/tests/DI/ContainerBuilder.create.error.phpt +++ b/tests/DI/ContainerBuilder.create.error.phpt @@ -17,14 +17,16 @@ require __DIR__ . '/../bootstrap.php'; testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setType('X')->setCreator('Unknown'); -}, Nette\InvalidArgumentException::class, "Service 'one': Class or interface 'X' not found."); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Class or interface 'X' not found."); testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition(null)->setCreator('Unknown'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service (Unknown::__construct()): Class 'Unknown' not found."); +}, Nette\DI\ServiceCreationException::class, "[Service of type Unknown] +Class 'Unknown' not found."); testException('', function () { @@ -32,7 +34,8 @@ testException('', function () { $builder->addDefinition('one')->setCreator('@two'); $builder->addDefinition('two')->setCreator('Unknown'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'two': Class 'Unknown' not found."); +}, Nette\InvalidStateException::class, "[Service 'two'] +Class 'Unknown' not found."); testException('', function () { @@ -40,28 +43,32 @@ testException('', function () { $builder->addDefinition('one')->setCreator(new Reference('two')); $builder->addDefinition('two')->setCreator('Unknown'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'two': Class 'Unknown' not found."); +}, Nette\InvalidStateException::class, "[Service 'two'] +Class 'Unknown' not found."); testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator('stdClass::foo'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method stdClass::foo() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method stdClass::foo() is not callable."); testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator('Nette\DI\Container::foo'); // has __magic $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method Nette\\DI\\Container::foo() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method Nette\\DI\\Container::foo() is not callable."); testException('', function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement('Unknown'); -}, Nette\InvalidArgumentException::class, "Service 'one': Interface 'Unknown' not found."); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Interface 'Unknown' not found."); @@ -74,7 +81,8 @@ testException('', function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement(Bad4::class); -}, Nette\InvalidStateException::class, 'Return type of Bad4::create() is not declared.'); +}, Nette\InvalidStateException::class, "[Service 'one'] +Return type of Bad4::create() is not declared."); interface Bad5 @@ -87,7 +95,8 @@ testException('', function () { $builder->addAccessorDefinition('one') ->setImplement(Bad5::class); $builder->complete(); -}, Nette\InvalidArgumentException::class, "Service 'one': Method Bad5::get() must have no parameters."); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Method Bad5::get() must have no parameters."); class Bad6 @@ -101,7 +110,8 @@ testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator('Bad6::create'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service 'one': Method Bad6::create() is not callable."); +}, Nette\DI\ServiceCreationException::class, "[Service 'one'] +Method Bad6::create() is not callable."); class Bad7 @@ -115,7 +125,8 @@ testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator('Bad7::create'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service 'one': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'one'] +Unknown service type, specify it or declare return type of factory method."); class Bad8 @@ -129,7 +140,8 @@ testException('', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setType(Bad8::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad8): Class Bad8 has private constructor."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad8] +Class Bad8 has private constructor."); class Good @@ -143,13 +155,17 @@ testException('fail in argument', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator(Good::class, [new Statement('Unknown')]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class 'Unknown' not found. (used in Good::__construct())"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Good] +Class 'Unknown' not found. +Related to Good::__construct()."); testException('fail in argument', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator(Good::class, [new Statement(Bad8::class)]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Bad8 has private constructor. (used in Good::__construct())"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Good] +Class Bad8 has private constructor. +Related to Good::__construct()."); abstract class Bad9 @@ -163,7 +179,8 @@ testException('abstract class cannot be instantiated', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setType(Bad9::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad9): Class Bad9 is abstract."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad9] +Class Bad9 is abstract."); trait Bad10 @@ -177,7 +194,8 @@ testException('trait cannot be instantiated', function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setCreator('Bad10::method'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method Bad10::method() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method Bad10::method() is not callable."); class ConstructorParam @@ -201,7 +219,9 @@ services: b: stdClass bad: ConstructorParam '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b (required by \$x in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type ConstructorParam] +Multiple services of type stdClass found: a, b +Required by \$x in ConstructorParam::__construct()."); testException('forced autowiring fail', function () { @@ -211,7 +231,9 @@ services: b: stdClass bad: ConstructorParam(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type ConstructorParam] +Multiple services of type stdClass found: a, b +Related to ConstructorParam::__construct()."); testException('autowiring fail in chain', function () { @@ -221,7 +243,9 @@ services: b: stdClass bad: MethodParam()::foo() '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo()."); testException('forced autowiring fail in chain', function () { @@ -231,7 +255,9 @@ services: b: stdClass bad: MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo()."); testException('autowiring fail in argument', function () { @@ -241,7 +267,10 @@ services: b: stdClass bad: Good(ConstructorParam()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (required by \$x in ConstructorParam::__construct()) (used in Good::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Required by \$x in ConstructorParam::__construct(). +Related to Good::__construct()."); testException('forced autowiring fail in argument', function () { @@ -251,7 +280,9 @@ services: b: stdClass bad: Good(ConstructorParam(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to ConstructorParam::__construct()."); testException('autowiring fail in chain in argument', function () { @@ -261,7 +292,10 @@ services: b: stdClass bad: Good(MethodParam()::foo()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo()) (used in Good::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo(). +Related to Good::__construct()."); testException('forced autowiring fail in chain in argument', function () { @@ -271,7 +305,9 @@ 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 (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo()."); testException('forced autowiring fail in property passing', function () { @@ -284,7 +320,9 @@ services: setup: - $a = @\stdClass '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::\$a)"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to \$a in setup."); testException('autowiring fail in rich property passing', function () { @@ -297,7 +335,9 @@ services: setup: - $a = MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo() in setup."); testException('autowiring fail in method calling', function () { @@ -310,7 +350,9 @@ services: setup: - foo '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo()."); testException('forced autowiring fail in method calling', function () { @@ -323,7 +365,9 @@ services: setup: - bar(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::bar())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to bar() in setup."); testException('autowiring fail in rich method calling', function () { @@ -336,4 +380,6 @@ services: setup: - bar(MethodParam()::foo(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo() in setup."); diff --git a/tests/DI/ContainerBuilder.error.phpt b/tests/DI/ContainerBuilder.error.phpt index 33c369aeb..9633cf6e1 100644 --- a/tests/DI/ContainerBuilder.error.phpt +++ b/tests/DI/ContainerBuilder.error.phpt @@ -7,6 +7,7 @@ declare(strict_types=1); use Nette\DI; +use Nette\DI\Definitions\Statement; use Tester\Assert; @@ -21,7 +22,8 @@ $builder->addDefinition('one') Assert::exception( fn() => $builder->complete(), Nette\InvalidStateException::class, - "Service 'one' (type of stdClass): Expected function, method or property name, '1234' given.", + "[Service 'one' of type stdClass] +Expected function, method or property name, '1234' given.", ); @@ -48,5 +50,33 @@ $builder->addDefinition('one') Assert::exception( fn() => $builder->complete(), Nette\InvalidStateException::class, - "Service 'one' (type of stdClass): Missing argument for \$prop[].", + "[Service 'one' of type stdClass] +Missing argument for \$prop[].", +); + + + +$builder = new DI\ContainerBuilder; +$builder->addDefinition(null) + ->setFactory([new Statement('Unknown'), 'foo']); + +Assert::exception( + fn() => $builder->complete(), + Nette\DI\ServiceCreationException::class, + "[Service Unknown()::foo()] +Class 'Unknown' not found.", +); + + + +$builder = new DI\ContainerBuilder; +$builder->addDefinition(null) + ->setFactory('stdClass') + ->addSetup([new Statement('Unknown'), 'foo']); + +Assert::exception( + fn() => $builder->complete(), + Nette\DI\ServiceCreationException::class, + "[Service of type stdClass] +Class 'Unknown' not found.", ); diff --git a/tests/DI/ContainerBuilder.recursive.phpt b/tests/DI/ContainerBuilder.recursive.phpt index 8ee4fdb7a..cbd0f08f2 100644 --- a/tests/DI/ContainerBuilder.recursive.phpt +++ b/tests/DI/ContainerBuilder.recursive.phpt @@ -30,5 +30,6 @@ $builder->addDefinition('two') Assert::exception( fn() => createContainer($builder), Nette\DI\ServiceCreationException::class, - "Service 'two': Circular reference detected for services: one, two.", + "[Service 'two'] +Circular reference detected for services: one, two.", ); diff --git a/tests/DI/ContainerBuilder.resolveTypes.next.phpt b/tests/DI/ContainerBuilder.resolveTypes.next.phpt index f19770352..7f078690c 100644 --- a/tests/DI/ContainerBuilder.resolveTypes.next.phpt +++ b/tests/DI/ContainerBuilder.resolveTypes.next.phpt @@ -24,52 +24,24 @@ class Lorem class Factory { - /** @return Lorem */ - public function createClassPhpDoc() - { - return []; - } - - public function createClass(): Lorem { return []; } - /** @return Lorem|null */ - public function createNullableClassPhpDoc() - { - return []; - } - - public function createNullableClass(): ?Lorem { return []; } - /** @return array */ - public function createScalarPhpDoc() - { - return []; - } - - public function createScalar(): array { return []; } - /** @return object */ - public function createObjectPhpDoc() - { - return (object) null; - } - - public function createObject(): object { return (object) null; @@ -82,13 +54,6 @@ class Factory } - /** @return mixed */ - public function createMixedPhpDoc() - { - return (object) null; - } - - public function createMixed(): mixed { return (object) null; @@ -115,13 +80,6 @@ class Factory require __DIR__ . '/../bootstrap.php'; -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createClassPhpDoc']), 'next']); - $container = @createContainer($builder); // @return is deprecated -}); - Assert::noError(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') @@ -129,13 +87,6 @@ Assert::noError(function () { $container = createContainer($builder); }); -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createNullableClassPhpDoc']), 'next']); - $container = @createContainer($builder); // @return is deprecated -}); - Assert::noError(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') @@ -143,66 +94,42 @@ Assert::noError(function () { $container = createContainer($builder); }); -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createScalarPhpDoc']), 'next']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalarPhpDoc() is expected to not be built-in/complex, 'array' given."); - Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([new Statement([Factory::class, 'createScalar']), 'next']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalar() is expected to not be built-in/complex, 'array' given."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createObjectPhpDoc']), 'next']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createScalar() is expected to not be built-in/complex, 'array' given."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([new Statement([Factory::class, 'createObject']), 'next']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([new Statement([Factory::class, 'createObjectNullable']), 'next']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createMixedPhpDoc']), 'next']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([new Statement([Factory::class, 'createMixed']), 'next']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([new Statement([Factory::class, 'createGeneric']), 'next']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Class 'T' not found. -Check the return type of Factory::createGeneric()."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([new Statement([Factory::class, 'createUnion']), 'next']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createUnion() is expected to not be built-in/complex, 'stdClass|array' given."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createUnion() is expected to not be built-in/complex, 'stdClass|array' given."); diff --git a/tests/DI/ContainerBuilder.resolveTypes.phpt b/tests/DI/ContainerBuilder.resolveTypes.phpt index 67cb3ea47..09c639bf5 100644 --- a/tests/DI/ContainerBuilder.resolveTypes.phpt +++ b/tests/DI/ContainerBuilder.resolveTypes.phpt @@ -15,52 +15,24 @@ use Tester\Assert; class Factory { - /** @return stdClass */ - public function createClassPhpDoc() - { - return []; - } - - public function createClass(): stdClass { return []; } - /** @return stdClass|null */ - public function createNullableClassPhpDoc() - { - return []; - } - - public function createNullableClass(): ?stdClass { return []; } - /** @return array */ - public function createScalarPhpDoc() - { - return []; - } - - public function createScalar(): array { return []; } - /** @return object */ - public function createObjectPhpDoc() - { - return (object) null; - } - - public function createObject(): object { return (object) null; @@ -73,13 +45,6 @@ class Factory } - /** @return mixed */ - public function createMixedPhpDoc() - { - return (object) null; - } - - public function createMixed(): mixed { return (object) null; @@ -106,13 +71,6 @@ class Factory require __DIR__ . '/../bootstrap.php'; -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createClassPhpDoc']); - $container = @createContainer($builder); // @return is deprecated -}); - Assert::noError(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') @@ -120,13 +78,6 @@ Assert::noError(function () { $container = createContainer($builder); }); -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createNullableClassPhpDoc']); - $container = @createContainer($builder); // @return is deprecated -}); - Assert::noError(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') @@ -134,66 +85,42 @@ Assert::noError(function () { $container = createContainer($builder); }); -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createScalarPhpDoc']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalarPhpDoc() is expected to not be built-in/complex, 'array' given."); - Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([Factory::class, 'createScalar']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalar() is expected to not be built-in/complex, 'array' given."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createObjectPhpDoc']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createScalar() is expected to not be built-in/complex, 'array' given."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([Factory::class, 'createObject']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([Factory::class, 'createObjectNullable']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createMixedPhpDoc']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([Factory::class, 'createMixed']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setCreator([Factory::class, 'createGeneric']); - $container = @createContainer($builder); // @return is deprecated -}, Nette\DI\ServiceCreationException::class, "Service 'a': Class 'T' not found. -Check the return type of Factory::createGeneric()."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') ->setCreator([Factory::class, 'createUnion']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createUnion() is expected to not be built-in/complex, 'stdClass|array' given."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createUnion() is expected to not be built-in/complex, 'stdClass|array' given."); diff --git a/tests/DI/ContainerBuilder.selfdependency.phpt b/tests/DI/ContainerBuilder.selfdependency.phpt index be8c5b77b..360871d0f 100644 --- a/tests/DI/ContainerBuilder.selfdependency.phpt +++ b/tests/DI/ContainerBuilder.selfdependency.phpt @@ -28,5 +28,7 @@ $builder->addDefinition(null) Assert::exception( fn() => createContainer($builder), Nette\DI\ServiceCreationException::class, - 'Service of type Foo: Service of type Foo required by $foo in Foo::__construct() not found. Did you add it to configuration file?', + '[Service of type Foo] +Service of type Foo required by $foo in Foo::__construct() not found. +Did you add it to configuration file?', ); diff --git a/tests/DI/DecoratorExtension.factories.phpt b/tests/DI/DecoratorExtension.factories.phpt index ba99a41dc..6b9b2e92a 100644 --- a/tests/DI/DecoratorExtension.factories.phpt +++ b/tests/DI/DecoratorExtension.factories.phpt @@ -30,7 +30,7 @@ $compiler->addExtension('foo', new class extends DI\CompilerExtension { public function beforeCompile() { $this->getContainerBuilder() - ->addFactoryDefinition('bar') + ->addFactoryDefinition('fac1') ->setImplement(FooFactory::class); } }); @@ -45,16 +45,16 @@ decorator: FooFactory: tags: [a] services: - foo: {implement: FooFactory} + fac2: {implement: FooFactory} '); $builder = $compiler->getContainerBuilder(); -Assert::true($builder->getDefinition('foo')->getTag(DI\Extensions\InjectExtension::TagInject)); -Assert::true($builder->getDefinition('foo')->getTag('a')); -Assert::count(1, $builder->getDefinition('foo')->getResultDefinition()->getSetup()); +Assert::true($builder->getDefinition('fac1')->getTag('a')); +Assert::count(1, $builder->getDefinition('fac1')->getResultDefinition()->getSetup()); +Assert::true($builder->getDefinition('fac1')->getResultDefinition()->getTag(DI\Extensions\InjectExtension::TagInject)); -Assert::true($builder->getDefinition('bar')->getTag(DI\Extensions\InjectExtension::TagInject)); -Assert::true($builder->getDefinition('bar')->getTag('a')); -Assert::count(1, $builder->getDefinition('bar')->getResultDefinition()->getSetup()); +Assert::true($builder->getDefinition('fac2')->getTag('a')); +Assert::count(1, $builder->getDefinition('fac2')->getResultDefinition()->getSetup()); +Assert::true($builder->getDefinition('fac2')->getResultDefinition()->getTag(DI\Extensions\InjectExtension::TagInject)); diff --git a/tests/DI/Definitions.AccessorDefinition.api.phpt b/tests/DI/Definitions.AccessorDefinition.api.phpt index adb04bebf..23c3ec302 100644 --- a/tests/DI/Definitions.AccessorDefinition.api.phpt +++ b/tests/DI/Definitions.AccessorDefinition.api.phpt @@ -54,49 +54,57 @@ interface Good1 Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad2 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad2 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad3 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad3 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad4 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad4 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad5::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad5::get() must have no parameters."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad5::get() must have no parameters.'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad6::class); -}, Nette\DI\ServiceCreationException::class, 'Return type of Bad6::get() is not declared.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad6::get() is not declared.'); Assert::noError(function () { diff --git a/tests/DI/Definitions.AccessorDefinition.resolve.phpt b/tests/DI/Definitions.AccessorDefinition.resolve.phpt index 014e2caf0..d03e48290 100644 --- a/tests/DI/Definitions.AccessorDefinition.resolve.phpt +++ b/tests/DI/Definitions.AccessorDefinition.resolve.phpt @@ -28,13 +28,15 @@ Assert::exception(function () { $def = new AccessorDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad1::class); -}, Nette\DI\ServiceCreationException::class, 'Return type of Bad1::get() is not declared.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad1::get() is not declared.'); Assert::noError(function () { @@ -63,4 +65,5 @@ Assert::exception(function () { $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); $resolver->completeDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good1: Service of type stdClass not found. Did you add it to configuration file?'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Good1] +Service of type stdClass not found. Did you add it to configuration file?'); diff --git a/tests/DI/Definitions.FactoryDefinition.api.phpt b/tests/DI/Definitions.FactoryDefinition.api.phpt index 787435a5c..6a7a6c370 100644 --- a/tests/DI/Definitions.FactoryDefinition.api.phpt +++ b/tests/DI/Definitions.FactoryDefinition.api.phpt @@ -48,43 +48,50 @@ interface Good1 Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad2 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad2 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad3 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad3 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad4 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad4 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad5::class); -}, Nette\DI\ServiceCreationException::class, 'Return type of Bad5::create() is not declared.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad5::create() is not declared.'); Assert::noError(function () { diff --git a/tests/DI/Definitions.FactoryDefinition.resolve.phpt b/tests/DI/Definitions.FactoryDefinition.resolve.phpt index 97f280234..79410b22a 100644 --- a/tests/DI/Definitions.FactoryDefinition.resolve.phpt +++ b/tests/DI/Definitions.FactoryDefinition.resolve.phpt @@ -28,13 +28,15 @@ Assert::exception(function () { $def = new FactoryDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type is missing in definition of service.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type is missing in definition of service.'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad1::class); -}, Nette\DI\ServiceCreationException::class, 'Return type of Bad1::create() is not declared.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad1::create() is not declared.'); Assert::noError(function () { @@ -75,4 +77,5 @@ Assert::exception(function () { $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good1: Factory for stdClass cannot create incompatible DateTime type.'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Good1] +Factory for stdClass cannot create incompatible DateTime type.'); diff --git a/tests/DI/Definitions.ImportedDefinition.phpt b/tests/DI/Definitions.ImportedDefinition.phpt index c5dd8fc1f..6b5d6c122 100644 --- a/tests/DI/Definitions.ImportedDefinition.phpt +++ b/tests/DI/Definitions.ImportedDefinition.phpt @@ -16,14 +16,16 @@ require __DIR__ . '/../bootstrap.php'; testException('Unknown class', function () { $def = new ImportedDefinition; $def->setType('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Class or interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Class or interface 'Foo' not found."); testException('Unknown type', function () { $def = new ImportedDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); test('', function () { diff --git a/tests/DI/Definitions.LocatorDefinition.api.phpt b/tests/DI/Definitions.LocatorDefinition.api.phpt index 50a771bd0..826eaa44e 100644 --- a/tests/DI/Definitions.LocatorDefinition.api.phpt +++ b/tests/DI/Definitions.LocatorDefinition.api.phpt @@ -50,11 +50,6 @@ interface Good1 public function get($name); } -interface Good2 -{ - public function create($name); -} - interface Good3 { public function createA(): stdClass; @@ -66,49 +61,57 @@ interface Good3 Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have at least one method."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have at least one method.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad2::create() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad2::create() does not meet the requirements: is create*(), get*() or get($name) and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad3::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad3::get() does not meet the requirements: is create*(), get*() or get($name) and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad4::foo() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad4::foo() does not meet the requirements: is create*(), get*() or get($name) and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad5::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad5::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad5::get() does not meet the requirements: is create*(), get*() or get($name) and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad6::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad6::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad6::get() does not meet the requirements: is create*(), get*() or get($name) and is non-static.'); Assert::noError(function () { @@ -119,14 +122,6 @@ Assert::noError(function () { }); -Assert::noError(function () { - $def = new LocatorDefinition; - $def->setImplement(Good2::class); - Assert::same(Good2::class, $def->getImplement()); - Assert::same(Good2::class, $def->getType()); -}); - - Assert::noError(function () { $def = new LocatorDefinition; $def->setImplement(Good3::class); diff --git a/tests/DI/Definitions.LocatorDefinition.render.create.phpt b/tests/DI/Definitions.LocatorDefinition.render.create.phpt deleted file mode 100644 index 4c649129f..000000000 --- a/tests/DI/Definitions.LocatorDefinition.render.create.phpt +++ /dev/null @@ -1,64 +0,0 @@ -setName('abc'); - $def->setImplement(Good::class); - $def->setReferences(['first' => '@a', 'second' => 'stdClass']); - - $builder = new Nette\DI\ContainerBuilder; - $builder->addDefinition('a')->setType(stdClass::class); - $resolver = new Nette\DI\Resolver($builder); - - $resolver->resolveDefinition($def); - $resolver->completeDefinition($def); - - $phpGenerator = new Nette\DI\PhpGenerator($builder); - $method = $phpGenerator->generateMethod($def); - - Assert::match( - <<<'XX' - public function createServiceAbc(): Good - { - return new class ($this) implements Good { - private $mapping = ['first' => 'a', 'second' => 'a']; - - - public function __construct( - private $container, - ) { - } - - - public function create($name): stdClass - { - if (!isset($this->mapping[$name])) { - throw new Nette\DI\MissingServiceException("Service '$name' is not defined."); - } - return $this->container->createService($this->mapping[$name]); - } - }; - } - XX, - $method->__toString(), - ); -}); diff --git a/tests/DI/Definitions.LocatorDefinition.resolve.phpt b/tests/DI/Definitions.LocatorDefinition.resolve.phpt index 4d1383ed0..7696e71bd 100644 --- a/tests/DI/Definitions.LocatorDefinition.resolve.phpt +++ b/tests/DI/Definitions.LocatorDefinition.resolve.phpt @@ -33,7 +33,8 @@ testException('', function () { $def = new LocatorDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); test('', function () { diff --git a/tests/DI/Definitions.ServiceDefinition.phpt b/tests/DI/Definitions.ServiceDefinition.phpt index c433a6473..2a413dcb9 100644 --- a/tests/DI/Definitions.ServiceDefinition.phpt +++ b/tests/DI/Definitions.ServiceDefinition.phpt @@ -17,7 +17,8 @@ require __DIR__ . '/../bootstrap.php'; testException('Unknown type', function () { $def = new ServiceDefinition; $def->setType('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Class or interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Class or interface 'Foo' not found."); test('type versus entity I.', function () { $def = new ServiceDefinition; diff --git a/tests/DI/Helpers.getReturnType.phpt b/tests/DI/Helpers.getReturnType.phpt deleted file mode 100644 index 9a0a47cbf..000000000 --- a/tests/DI/Helpers.getReturnType.phpt +++ /dev/null @@ -1,30 +0,0 @@ - A\AInjected::class, - 'varC' => A\AInjected::class, - ], InjectExtension::getInjectProperties(A\AClass::class)); -} diff --git a/tests/DI/InjectExtension.getInjectProperties().php80.phpt b/tests/DI/InjectExtension.getInjectProperties().php80.phpt deleted file mode 100644 index e24155f65..000000000 --- a/tests/DI/InjectExtension.getInjectProperties().php80.phpt +++ /dev/null @@ -1,38 +0,0 @@ - InjectExtension::getInjectProperties(AClass::class), - Nette\InvalidStateException::class, - "Type of property AClass::\$var is expected to not be nullable/built-in/complex, 'AClass|stdClass' given.", -); - -Assert::same([ - 'varA' => 'stdClass', -], InjectExtension::getInjectProperties(EClass::class)); diff --git a/tests/DI/InjectExtension.getInjectProperties().phpt b/tests/DI/InjectExtension.getInjectProperties().phpt index 79c00b86e..c7c997a1b 100644 --- a/tests/DI/InjectExtension.getInjectProperties().phpt +++ b/tests/DI/InjectExtension.getInjectProperties().phpt @@ -6,93 +6,51 @@ declare(strict_types=1); -namespace A -{ - class AClass - { - /** @var AInjected @inject */ - public $varA; +use Nette\DI\Attributes\Inject; +use Nette\DI\Extensions\InjectExtension; +use Tester\Assert; + - /** @var B\BInjected @inject */ - public $varB; +class AClass +{ + #[Inject] + public AInjected $varA; - /** @var AInjected @inject */ - public $varC; + #[Inject] + public BInjected $varB; - /** @var AInjected */ - public $varD; - } + public $varD; - class AInjected - { - } + #[Inject] + public stdClass $varF; } -namespace A\B +class BadClass { - use A; - - class BClass extends A\AClass - { - /** @var BInjected @inject */ - public $varF; - } - - class BInjected - { - } + #[Inject] + public AClass|stdClass $var; } -namespace C +class AInjected { - use A\AInjected; - use A\B; - use C\CInjected as CAlias; - - class CClass - { - /** @var AInjected @inject */ - public $var1; - - /** @var B\BInjected @inject */ - public $var2; - - /** @var CAlias @inject */ - public $var3; - - /** @var CInjected @inject */ - public $var4; - } - - class CInjected - { - } } -namespace { - use Nette\DI\Extensions\InjectExtension; - use Tester\Assert; +class BInjected +{ +} - require __DIR__ . '/../bootstrap.php'; +require __DIR__ . '/../bootstrap.php'; - Assert::same([ - 'varA' => A\AInjected::class, - 'varB' => A\B\BInjected::class, - 'varC' => A\AInjected::class, - ], InjectExtension::getInjectProperties(A\AClass::class)); - Assert::same([ - 'varA' => A\AInjected::class, - 'varB' => A\B\BInjected::class, - 'varC' => A\AInjected::class, - 'varF' => A\B\BInjected::class, - ], InjectExtension::getInjectProperties(A\B\BClass::class)); +Assert::same([ + 'varA' => AInjected::class, + 'varB' => BInjected::class, + 'varF' => stdClass::class, +], InjectExtension::getInjectProperties(AClass::class)); - Assert::same([ - 'var1' => A\AInjected::class, - 'var2' => A\B\BInjected::class, - 'var3' => C\CInjected::class, - 'var4' => C\CInjected::class, - ], InjectExtension::getInjectProperties(C\CClass::class)); -} +Assert::exception( + fn() => InjectExtension::getInjectProperties(BadClass::class), + Nette\InvalidStateException::class, + "Type of property BadClass::\$var is expected to not be nullable/built-in/complex, 'AClass|stdClass' given.", +); diff --git a/tests/DI/InjectExtension.getInjectProperties().traits.phpt b/tests/DI/InjectExtension.getInjectProperties().traits.phpt index 1fc6c211e..ba4022d49 100644 --- a/tests/DI/InjectExtension.getInjectProperties().traits.phpt +++ b/tests/DI/InjectExtension.getInjectProperties().traits.phpt @@ -16,11 +16,12 @@ namespace A namespace B { use A\AInjected; + use Nette\DI\Attributes\Inject; trait BTrait { - /** @var AInjected @inject */ - public $varA; + #[Inject] + public AInjected $varA; } } diff --git a/tests/DI/NeonAdapter.preprocess.phpt b/tests/DI/NeonAdapter.preprocess.phpt index 7b59be016..350dbd259 100644 --- a/tests/DI/NeonAdapter.preprocess.phpt +++ b/tests/DI/NeonAdapter.preprocess.phpt @@ -70,17 +70,6 @@ Assert::equal( ); -// ... deprecated -$data = @$adapter->load(Tester\FileMock::create(' -- Class(arg1, ..., [...]) -', 'neon')); - -Assert::equal( - [new Statement('Class', ['arg1', 2 => ['...']])], - $data, -); - - // @ escaping $data = @$adapter->load(Tester\FileMock::create(' - @@double diff --git a/tests/DI/Resolver.autowireArguments.errors.phpt b/tests/DI/Resolver.autowireArguments.errors.phpt index 700a48bfb..1cf867667 100644 --- a/tests/DI/Resolver.autowireArguments.errors.phpt +++ b/tests/DI/Resolver.autowireArguments.errors.phpt @@ -21,7 +21,8 @@ Assert::exception( function () {}, ), Nette\DI\ServiceCreationException::class, - 'Service of type stdClass required by $x in {closure}() not found. Did you add it to configuration file?', + 'Service of type stdClass required by $x in {closure}() not found. +Did you add it to configuration file?', ); @@ -33,7 +34,8 @@ Assert::exception( function () {}, ), Nette\DI\ServiceCreationException::class, - "Class 'Foo' required by \$x in {closure}() not found. Check the parameter type and 'use' statements.", + "Class 'Foo' required by \$x in {closure}() not found. +Check the parameter type and 'use' statements.", ); @@ -69,7 +71,8 @@ Assert::exception( fn($type) => $type === Test::class ? new Test : null, ), Nette\DI\ServiceCreationException::class, - 'Service of type stdClass required by $arg in {closure}() not found. Did you add it to configuration file?', + 'Service of type stdClass required by $arg in {closure}() not found. +Did you add it to configuration file?', ); diff --git a/tests/DI/fixtures/Helpers.getReturnType.php b/tests/DI/fixtures/Helpers.getReturnType.php deleted file mode 100644 index 93bb93e5b..000000000 --- a/tests/DI/fixtures/Helpers.getReturnType.php +++ /dev/null @@ -1,49 +0,0 @@ - ['foo' => true], 'InterfaceOk1' => ['ok' => true], 'InterfaceOk2' => ['ok' => true], + 'stdClass' => [], ], $services); diff --git a/tests/SearchExtension/classes.phpt b/tests/SearchExtension/classes.phpt index cea9cfac7..4d21f9087 100644 --- a/tests/SearchExtension/classes.phpt +++ b/tests/SearchExtension/classes.phpt @@ -23,6 +23,7 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -53,6 +54,7 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -102,4 +104,5 @@ Assert::same([ 'ExtendsStdClass', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); diff --git a/tests/SearchExtension/duplicates.phpt b/tests/SearchExtension/duplicates.phpt index d8b2eec98..c52f03a71 100644 --- a/tests/SearchExtension/duplicates.phpt +++ b/tests/SearchExtension/duplicates.phpt @@ -28,4 +28,5 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); diff --git a/tests/SearchExtension/files.phpt b/tests/SearchExtension/files.phpt index b72a55147..3fdea3b07 100644 --- a/tests/SearchExtension/files.phpt +++ b/tests/SearchExtension/files.phpt @@ -23,6 +23,7 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -41,6 +42,7 @@ Assert::same([ 'ExtendsStdClass', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -63,6 +65,7 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -83,4 +86,5 @@ Assert::same([ 'ExtendsStdClass', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); diff --git a/tests/SearchExtension/parents.phpt b/tests/SearchExtension/parents.phpt index bf8bf1254..c36fb78f2 100644 --- a/tests/SearchExtension/parents.phpt +++ b/tests/SearchExtension/parents.phpt @@ -23,6 +23,7 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); @@ -99,4 +100,5 @@ Assert::same([ 'Foo\\ClassBar', 'InterfaceOk1', 'InterfaceOk2', + 'stdClass', ], array_keys($services)); diff --git a/tests/SearchExtension/tags.phpt b/tests/SearchExtension/tags.phpt index 7c2002658..6064d0be1 100644 --- a/tests/SearchExtension/tags.phpt +++ b/tests/SearchExtension/tags.phpt @@ -24,6 +24,7 @@ Assert::same([ 'ExtendsStdClass' => ['a' => 1, 'b' => 2], 'InterfaceOk1' => ['a' => 1, 'b' => 2], 'InterfaceOk2' => ['a' => 1, 'b' => 2], + 'stdClass' => [], ], $services); @@ -43,4 +44,5 @@ Assert::same([ 'ExtendsStdClass' => [], 'InterfaceOk1' => [], 'InterfaceOk2' => [], + 'stdClass' => [], ], $services);