Skip to content

Commit 2fce9b9

Browse files
miloadaamzMiloslav Hůladg
committed
Guess first parameter for event by type hint (#219)
Co-authored-by: Adam Žurek <[email protected]> Co-authored-by: Miloslav Hůla <[email protected]> Co-authored-by: David Grudl <[email protected]>
1 parent 4423d28 commit 2fce9b9

File tree

4 files changed

+85
-23
lines changed

4 files changed

+85
-23
lines changed

src/Forms/Container.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Container extends Nette\ComponentModel\Container implements \ArrayAccess
2626

2727
private const ARRAY = 'array';
2828

29-
/** @var callable[]&(callable(Container, mixed): void)[]; Occurs when the form is validated */
29+
/** @var callable[]&((callable(Container, array|object|null): void)|(callable(array|object|null): void))[]; Occurs when the form was validated */
3030
public $onValidate = [];
3131

3232
/** @var ControlGroup|null */
@@ -191,10 +191,15 @@ public function validate(array $controls = null): void
191191
$isValid = !$this->getErrors();
192192
foreach ($this->onValidate as $handler) {
193193
$params = Nette\Utils\Callback::toReflection($handler)->getParameters();
194-
$values = isset($params[1]) && $isValid
195-
? $this->getValues($params[1]->getType() instanceof \ReflectionNamedType ? $params[1]->getType()->getName() : null)
196-
: null;
197-
$handler($this, $values);
194+
$types = array_map([Nette\Utils\Reflection::class, 'getParameterType'], $params);
195+
$handler(
196+
!isset($types[0]) || $this instanceof $types[0]
197+
? $this
198+
: ($isValid ? $this->getValues($types[0]) : null),
199+
isset($params[1]) && $isValid
200+
? $this->getValues($types[1])
201+
: null
202+
);
198203
}
199204
}
200205

src/Forms/Controls/SubmitButton.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
class SubmitButton extends Button implements Nette\Forms\SubmitterControl
2121
{
22-
/** @var callable[]&(callable(SubmitButton): void)[]; Occurs when the button is clicked and form is successfully validated */
22+
/** @var callable[]&((callable(Nette\Forms\Form|SubmitButton, array|object): void)|(callable(array|object): void))[]; Occurs when the button is clicked and form is successfully validated */
2323
public $onClick = [];
2424

2525
/** @var callable[]&(callable(SubmitButton): void)[]; Occurs when the button is clicked and form is not validated */

src/Forms/Form.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class Form extends Container implements Nette\HtmlStringable
8282
/** @internal protection token ID */
8383
public const PROTECTOR_ID = '_token_';
8484

85-
/** @var callable[]&(callable(Form, mixed): void)[]; Occurs when the form is submitted and successfully validated */
85+
/** @var callable[]&((callable(Form, array|object): void)|(callable(array|object): void))[]; Occurs when the form is submitted and successfully validated */
8686
public $onSuccess = [];
8787

8888
/** @var callable[]&(callable(Form): void)[]; Occurs when the form is submitted and is not valid */
@@ -443,10 +443,19 @@ private function invokeHandlers(iterable $handlers, $button = null): void
443443
{
444444
foreach ($handlers as $handler) {
445445
$params = Nette\Utils\Callback::toReflection($handler)->getParameters();
446-
$values = isset($params[1])
447-
? $this->getValues($params[1]->getType() instanceof \ReflectionNamedType ? $params[1]->getType()->getName() : null)
448-
: null;
449-
$handler($button ?: $this, $values);
446+
$types = array_map([Nette\Utils\Reflection::class, 'getParameterType'], $params);
447+
if (!isset($types[0])) {
448+
$arg0 = $button ?: $this;
449+
} elseif ($this instanceof $types[0]) {
450+
$arg0 = $this;
451+
} elseif ($button instanceof $types[0]) {
452+
$arg0 = $button;
453+
} else {
454+
$arg0 = $this->getValues($types[0]);
455+
}
456+
$arg1 = isset($params[1]) ? $this->getValues($types[1]) : null;
457+
$handler($arg0, $arg1);
458+
450459
if (!$this->isValid()) {
451460
return;
452461
}

tests/Forms/Forms.callbackParameters.phpt

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,26 @@ $types = [];
2626

2727
// Test the closure second parameter to be an ArrayHash instance by default
2828
$f1 = function ($form, $values) use (&$types) {
29-
$types[] = $form instanceof Form;
30-
$types[] = $values instanceof ArrayHash;
29+
$types['f1'][] = $form instanceof Form;
30+
$types['f1'][] = $values instanceof ArrayHash;
3131
};
3232

3333
// Test the closure second parameter to be an array by type-hint
3434
$f2 = function ($form, array $values) use (&$types) {
35-
$types[] = $form instanceof Form;
36-
$types[] = is_array($values);
35+
$types['f2'][] = $form instanceof Form;
36+
$types['f2'][] = is_array($values);
3737
};
3838

3939
// Test the closure second parameter to be an ArrayHash instance by default
4040
$b1 = function ($form, $values) use (&$types) {
41-
$types[] = $form instanceof SubmitButton;
42-
$types[] = $values instanceof ArrayHash;
41+
$types['b1'][] = $form instanceof SubmitButton;
42+
$types['b1'][] = $values instanceof ArrayHash;
4343
};
4444

4545
// Test the closure second parameter to be an array by type-hint
4646
$b2 = function ($form, array $values) use (&$types) {
47-
$types[] = $form instanceof SubmitButton;
48-
$types[] = is_array($values);
47+
$types['b2'][] = $form instanceof SubmitButton;
48+
$types['b2'][] = is_array($values);
4949
};
5050

5151
// Test the second parameter in ArrayHash form to be immutable
@@ -57,10 +57,58 @@ $f5 = function ($form, $values) use (&$arrayHashIsImmutable) {
5757
$arrayHashIsImmutable[] = $values->text === 'a';
5858
};
5959

60-
$form->onSuccess = [$f1, $f2, $f1, $f4, $f5];
61-
$form->onValidate = [$f1, $f2, $f1, $f4, $f5];
62-
$form['btn']->onClick = [$b1, $b2, $b1, $f4, $f5];
60+
// Test the closure single parameter without type-hint
61+
$f6 = function ($form) use (&$types) {
62+
$types['f6'][] = $form instanceof Form;
63+
};
64+
65+
// Test the closure single array parameter
66+
$f7 = function (array $values) use (&$types) {
67+
$types['f7'][] = is_array($values);
68+
};
69+
70+
// Test the closure single Form-typed parameter
71+
$f8 = function (Form $values) use (&$types) {
72+
$types['f8'][] = $values instanceof Form;
73+
};
74+
75+
// Test the closure single not-Form-typed parameter
76+
$f9 = function (ArrayHash $values) use (&$types) {
77+
$types['f9'][] = $values instanceof ArrayHash;
78+
};
79+
80+
// Test the closure single parameter without type-hint
81+
$b3 = function ($form) use (&$types) {
82+
$types['b3'][] = $form instanceof SubmitButton;
83+
};
84+
85+
// Test the closure single array parameter
86+
$b4 = function (array $values) use (&$types) {
87+
$types['b4'][] = is_array($values);
88+
};
89+
90+
// Test the closure single parameter SubmitButton-typed
91+
$b5 = function (SubmitButton $form) use (&$types) {
92+
$types['b5'][] = $form instanceof SubmitButton;
93+
};
94+
95+
96+
$form->onSuccess = [$f1, $f2, $f1, $f4, $f5, $f6, $f7, $f8, $f9];
97+
$form->onValidate = [$f1, $f2, $f1, $f4, $f5, $f6, $f7, $f8, $f9];
98+
$form['btn']->onClick = [$b1, $b2, $b1, $f4, $f5, $b3, $b4, $b5];
6399
$form->fireEvents();
64100

65-
Assert::same([true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true], $types);
101+
Assert::same([
102+
'f1' => [true, true, true, true, true, true, true, true],
103+
'f2' => [true, true, true, true],
104+
'f6' => [true, true],
105+
'f7' => [true, true],
106+
'f8' => [true, true],
107+
'f9' => [true, true],
108+
'b1' => [true, true, true, true],
109+
'b2' => [true, true],
110+
'b3' => [true],
111+
'b4' => [true],
112+
'b5' => [true],
113+
], $types);
66114
Assert::same([true, true, true], $arrayHashIsImmutable);

0 commit comments

Comments
 (0)