Skip to content

Commit 585523a

Browse files
committed
added attribute #Parameter
1 parent 399cd8e commit 585523a

File tree

4 files changed

+152
-11
lines changed

4 files changed

+152
-11
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Application\Attributes;
11+
12+
use Attribute;
13+
14+
15+
#[Attribute(Attribute::TARGET_PROPERTY)]
16+
class Parameter
17+
{
18+
}

src/Application/UI/Component.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public static function getReflection(): ComponentReflection
157157
public function loadState(array $params): void
158158
{
159159
$reflection = $this->getReflection();
160-
foreach ($reflection->getPersistentParams() as $name => $meta) {
160+
foreach ($reflection->getParameters() as $name => $meta) {
161161
if (isset($params[$name])) { // nulls are ignored
162162
if (!$reflection->convertType($params[$name], $meta['type'])) {
163163
throw new Nette\Application\BadRequestException(sprintf(

src/Application/UI/ComponentReflection.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ final class ComponentReflection extends \ReflectionClass
3333

3434

3535
/**
36-
* Returns array of persistent properties. They are public and have attribute #[Persistent] or annotation @persistent.
36+
* Returns array of class properties that are public and have attribute #[Persistent] or #[Parameter] or annotation @persistent.
3737
*/
38-
public function getPersistentParams(): array
38+
public function getParameters(): array
3939
{
4040
$params = &self::$ppCache[$this->getName()];
4141
if ($params !== null) {
@@ -46,26 +46,31 @@ public function getPersistentParams(): array
4646
$isPresenter = $this->isSubclassOf(Presenter::class);
4747
$defaults = $this->getDefaultProperties();
4848
foreach ($this->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
49-
if (!$prop->isStatic()
50-
&& (self::parseAnnotation($prop, 'persistent')
51-
|| (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Persistent::class)))
49+
if ($prop->isStatic()) {
50+
continue;
51+
} elseif (self::parseAnnotation($prop, 'persistent')
52+
|| (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Persistent::class))
5253
) {
5354
$default = $defaults[$prop->getName()] ?? null;
5455
$params[$prop->getName()] = [
5556
'def' => $default,
5657
'type' => self::getPropertyType($prop, $default),
5758
'since' => $isPresenter ? Nette\Utils\Reflection::getPropertyDeclaringClass($prop)->getName() : null,
5859
];
60+
} elseif (PHP_VERSION_ID >= 80000 && $prop->getAttributes(Nette\Application\Attributes\Parameter::class)) {
61+
$params[$prop->getName()] = [
62+
'type' => (string) ($prop->getType() ?? 'mixed'),
63+
];
5964
}
6065
}
6166

6267
if ($this->getParentClass()->isSubclassOf(Component::class)) {
6368
$parent = new self($this->getParentClass()->getName());
64-
foreach ($parent->getPersistentParams() as $name => $meta) {
65-
if (isset($params[$name])) {
66-
$params[$name]['since'] = $meta['since'];
67-
} else {
69+
foreach ($parent->getParameters() as $name => $meta) {
70+
if (!isset($params[$name])) {
6871
$params[$name] = $meta;
72+
} elseif (array_key_exists('since', $params[$name])) {
73+
$params[$name]['since'] = $meta['since'];
6974
}
7075
}
7176
}
@@ -74,6 +79,17 @@ public function getPersistentParams(): array
7479
}
7580

7681

82+
/**
83+
* Returns array of persistent properties. They are public and have attribute #[Persistent] or annotation @persistent.
84+
*/
85+
public function getPersistentParams(): array
86+
{
87+
return array_filter($this->getParameters(), function ($param) {
88+
return array_key_exists('since', $param);
89+
});
90+
}
91+
92+
7793
public function getPersistentComponents(): array
7894
{
7995
$class = $this->getName();
@@ -200,7 +216,7 @@ public static function convertType(&$val, string $types): bool
200216
$scalars = ['string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'true' => 1, 'false' => 1, 'boolean' => 1, 'double' => 1, 'integer' => 1];
201217
$testable = ['iterable' => 1, 'object' => 1, 'array' => 1, 'null' => 1];
202218

203-
foreach (explode('|', $types) as $type) {
219+
foreach (explode('|', ltrim($types, '?')) as $type) {
204220
if (isset($scalars[$type])) {
205221
$ok = self::castScalar($val, $type);
206222
} elseif (isset($testable[$type])) {
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Application\UI\Presenter::getRequestParams
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\Application\Attributes\Parameter;
10+
use Nette\Application\Attributes\Persistent;
11+
use Nette\Application\UI\ComponentReflection;
12+
use Nette\Application\UI\Presenter;
13+
use Tester\Assert;
14+
15+
require __DIR__ . '/../bootstrap.php';
16+
17+
18+
class OnePresenter extends Presenter
19+
{
20+
public static $no1;
21+
public $no2;
22+
23+
/** @persistent */
24+
public $yes1;
25+
26+
#[Persistent, Parameter]
27+
public $yes2; /* Parameter is ignored */
28+
29+
#[Parameter]
30+
public $yes3;
31+
}
32+
33+
34+
class TwoPresenter extends OnePresenter
35+
{
36+
#[Parameter]
37+
public $yes2;
38+
public $yes3;
39+
40+
#[Parameter]
41+
public $yes4;
42+
}
43+
44+
45+
if (PHP_VERSION_ID < 80000) {
46+
Assert::same(
47+
[
48+
'yes1' => [
49+
'def' => null,
50+
'type' => 'scalar',
51+
'since' => 'OnePresenter',
52+
],
53+
],
54+
(new ComponentReflection(OnePresenter::class))->getParameters()
55+
);
56+
57+
Assert::same(
58+
[
59+
'yes1' => [
60+
'def' => null,
61+
'type' => 'scalar',
62+
'since' => 'OnePresenter',
63+
],
64+
],
65+
(new ComponentReflection(TwoPresenter::class))->getParameters()
66+
);
67+
68+
} else {
69+
Assert::same(
70+
[
71+
'yes1' => [
72+
'def' => null,
73+
'type' => 'scalar',
74+
'since' => 'OnePresenter',
75+
],
76+
'yes2' => [
77+
'def' => null,
78+
'type' => 'scalar',
79+
'since' => 'OnePresenter',
80+
],
81+
'yes3' => [
82+
'type' => 'mixed',
83+
],
84+
],
85+
(new ComponentReflection(OnePresenter::class))->getParameters()
86+
);
87+
88+
Assert::same(
89+
[
90+
'yes2' => [
91+
'type' => 'mixed',
92+
],
93+
'yes4' => [
94+
'type' => 'mixed',
95+
],
96+
'yes1' => [
97+
'def' => null,
98+
'type' => 'scalar',
99+
'since' => 'OnePresenter',
100+
],
101+
'yes3' => [
102+
'type' => 'mixed',
103+
],
104+
],
105+
(new ComponentReflection(TwoPresenter::class))->getParameters()
106+
);
107+
}

0 commit comments

Comments
 (0)