Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

check for empty array in ConvertArguments() #317

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['8.1', '8.2', '8.3']
php: ['8.1', '8.2', '8.3', '8.4']

fail-fast: false

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}
],
"require": {
"php": "8.1 - 8.3",
"php": "8.1 - 8.4",
"ext-tokenizer": "*",
"ext-ctype": "*",
"nette/neon": "^3.3 || ^4.0",
Expand All @@ -39,7 +39,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
"dev-master": "4.0-dev"
}
}
}
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The recommended way to install is via Composer:
composer require nette/di
```

It requires PHP version 8.1 and supports PHP up to 8.3.
It requires PHP version 8.1 and supports PHP up to 8.4.

 <!---->

Expand Down
3 changes: 0 additions & 3 deletions src/DI/Config/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,3 @@ interface Adapter
*/
function load(string $file): array;
}


class_exists(IAdapter::class);
5 changes: 0 additions & 5 deletions src/DI/Config/Adapters/NeonAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/DI/Definitions/AccessorDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
));
}
Expand All @@ -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);
}

Expand Down
27 changes: 25 additions & 2 deletions src/DI/Definitions/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 {
Expand Down
18 changes: 12 additions & 6 deletions src/DI/Definitions/FactoryDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class FactoryDefinition extends Definition
private const MethodCreate = 'create';

private Definition $resultDefinition;
private ?string $reference = null;


public function __construct()
Expand All @@ -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,
));
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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));
Expand All @@ -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(),
));
Expand Down
19 changes: 10 additions & 9 deletions src/DI/Definitions/LocatorDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
}
Expand Down Expand Up @@ -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,
));
Expand Down Expand Up @@ -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])) {
Expand Down
20 changes: 14 additions & 6 deletions src/DI/Definitions/ServiceDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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);
Expand Down Expand Up @@ -204,6 +215,3 @@ public function __clone()
$this->setup = unserialize(serialize($this->setup));
}
}


class_exists(Nette\DI\ServiceDefinition::class);
5 changes: 1 addition & 4 deletions src/DI/Definitions/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -63,6 +63,3 @@ public function getEntity(): string|array|Definition|Reference|null
return $this->entity;
}
}


class_exists(Nette\DI\Statement::class);
18 changes: 2 additions & 16 deletions src/DI/Extensions/DecoratorExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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)),
);
}
}
Loading