From 7916644031e5576ed80a109fe8da6ebacd53c613 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 23 Sep 2023 18:47:04 +0200 Subject: [PATCH] added attribute #Parameter --- src/Application/Attributes/Parameter.php | 18 ++++ src/Application/UI/Component.php | 2 +- src/Application/UI/ComponentReflection.php | 34 +++++-- tests/UI/Presenter.getParameters.phpt | 107 +++++++++++++++++++++ 4 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 src/Application/Attributes/Parameter.php create mode 100644 tests/UI/Presenter.getParameters.phpt diff --git a/src/Application/Attributes/Parameter.php b/src/Application/Attributes/Parameter.php new file mode 100644 index 000000000..11e8a7b10 --- /dev/null +++ b/src/Application/Attributes/Parameter.php @@ -0,0 +1,18 @@ +getReflection(); - foreach ($reflection->getPersistentParams() as $name => $meta) { + foreach ($reflection->getParameters() as $name => $meta) { if (isset($params[$name])) { // nulls are ignored if (!$reflection->convertType($params[$name], $meta['type'])) { throw new Nette\Application\BadRequestException(sprintf( diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index cc7584165..46d348097 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -33,9 +33,9 @@ final class ComponentReflection extends \ReflectionClass /** - * Returns array of persistent properties. They are public and have attribute #[Persistent] or annotation @persistent. + * Returns array of class properties that are public and have attribute #[Persistent] or #[Parameter] or annotation @persistent. */ - public function getPersistentParams(): array + public function getParameters(): array { $params = &self::$ppCache[$this->getName()]; if ($params !== null) { @@ -45,9 +45,10 @@ public function getPersistentParams(): array $params = []; $isPresenter = $this->isSubclassOf(Presenter::class); foreach ($this->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { - if (!$prop->isStatic() - && (self::parseAnnotation($prop, 'persistent') - || (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Persistent::class))) + if ($prop->isStatic()) { + continue; + } elseif (self::parseAnnotation($prop, 'persistent') + || (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Persistent::class)) ) { $default = $prop->getDefaultValue(); $params[$prop->getName()] = [ @@ -55,16 +56,20 @@ public function getPersistentParams(): array 'type' => self::getPropertyType($prop, $default), 'since' => $isPresenter ? Nette\Utils\Reflection::getPropertyDeclaringClass($prop)->getName() : null, ]; + } elseif (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Parameter::class)) { + $params[$prop->getName()] = [ + 'type' => $prop->getType() ? (string) $prop->getType() : 'mixed', + ]; } } if ($this->getParentClass()->isSubclassOf(Component::class)) { $parent = new self($this->getParentClass()->getName()); - foreach ($parent->getPersistentParams() as $name => $meta) { - if (isset($params[$name])) { - $params[$name]['since'] = $meta['since']; - } else { + foreach ($parent->getParameters() as $name => $meta) { + if (!isset($params[$name])) { $params[$name] = $meta; + } elseif (array_key_exists('since', $params[$name])) { + $params[$name]['since'] = $meta['since']; } } } @@ -73,6 +78,17 @@ public function getPersistentParams(): array } + /** + * Returns array of persistent properties. They are public and have attribute #[Persistent] or annotation @persistent. + */ + public function getPersistentParams(): array + { + return array_filter($this->getParameters(), function ($param) { + return array_key_exists('since', $param); + }); + } + + public function getPersistentComponents(): array { $class = $this->getName(); diff --git a/tests/UI/Presenter.getParameters.phpt b/tests/UI/Presenter.getParameters.phpt new file mode 100644 index 000000000..d58407de9 --- /dev/null +++ b/tests/UI/Presenter.getParameters.phpt @@ -0,0 +1,107 @@ + [ + 'def' => null, + 'type' => 'scalar', + 'since' => 'OnePresenter', + ], + ], + (new ComponentReflection(OnePresenter::class))->getParameters() + ); + + Assert::same( + [ + 'yes1' => [ + 'def' => null, + 'type' => 'scalar', + 'since' => 'OnePresenter', + ], + ], + (new ComponentReflection(TwoPresenter::class))->getParameters() + ); + +} else { + Assert::same( + [ + 'yes1' => [ + 'def' => null, + 'type' => 'scalar', + 'since' => 'OnePresenter', + ], + 'yes2' => [ + 'def' => null, + 'type' => 'scalar', + 'since' => 'OnePresenter', + ], + 'yes3' => [ + 'type' => 'mixed', + ], + ], + (new ComponentReflection(OnePresenter::class))->getParameters() + ); + + Assert::same( + [ + 'yes2' => [ + 'type' => 'mixed', + ], + 'yes4' => [ + 'type' => 'mixed', + ], + 'yes1' => [ + 'def' => null, + 'type' => 'scalar', + 'since' => 'OnePresenter', + ], + 'yes3' => [ + 'type' => 'mixed', + ], + ], + (new ComponentReflection(TwoPresenter::class))->getParameters() + ); +}