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

Support for properties in NEON statement syntax in section services - PART 1 #318

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
88c314a
FactoryDefinition: result definition is added to container [WIP]
dg Feb 4, 2024
1494161
Reapply "LocatorDefinition: deprecated support for create($name) meth…
dg May 16, 2024
08ebd23
opened 4.0-dev
dg Sep 12, 2021
92d6a81
exception messages use [Service ...]\n format [WIP]
dg Dec 11, 2023
1283060
annotations @return are no longer supported (BC break)
dg Jan 16, 2023
74e57c3
annotations @var are no longer supported (BC break)
dg Dec 14, 2023
8bf9be5
removed support for three ... dots
dg Dec 11, 2023
2c03557
removed compatibility for old class names
dg Dec 19, 2022
666abf5
deprecated magic properties (BC break)
dg Sep 24, 2021
4db1c18
LocatorDefinition: removed support for create($name) methods (BC break)
dg Feb 5, 2024
965c203
annotations @inject is deprecated (BC break)
dg Apr 6, 2024
5152375
Resolver: processing of functions like not() moved to PhpGenerator
dg Dec 15, 2021
b1d0216
adjust rendering property/Constant/method by new syntax
mildabre Nov 23, 2024
277bfcf
extending check member type to properties
mildabre Nov 23, 2024
3cc6368
add missing use, extend validating member syntax to $$member or membe…
mildabre Nov 23, 2024
98efd82
add setters needed in parsing member chains and Statement normalization
mildabre Nov 23, 2024
652b515
add support for static properties on class, removing inappropriate ch…
mildabre Nov 23, 2024
30871bd
Added support for parsing unparsed member chains + normalizing Statem…
mildabre Nov 23, 2024
c6e530a
Slight correction of regular expression
mildabre Nov 26, 2024
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 composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
"dev-master": "4.0-dev"
}
}
}
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);
12 changes: 3 additions & 9 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 Expand Up @@ -231,10 +226,9 @@ private function resolveConstants(Neon\Node $node): void
foreach ($items as $item) {
if ($item->value instanceof Neon\Node\LiteralNode
&& is_string($item->value->value)
&& preg_match('#^([\w\\\\]*)::[A-Z]\w+$#D', $item->value->value)
&& defined(ltrim($item->value->value, ':'))
) {
$item->value->value = constant(ltrim($item->value->value, ':'));
&& preg_match('#^([\w\\\\]*)::(\$[a-z_]|[A-Z])\w+$#D', $item->value->value) // constant/stat property
) {
$item->value->value = new Nette\PhpGenerator\Literal(ltrim($item->value->value, ':'));
}
}
}
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
Loading