Skip to content

Commit 44c5dbf

Browse files
committed
Presenter: throws exception when parameter has scalar type hint & no default value and argument is missing [Closes #112]
1 parent 894f204 commit 44c5dbf

File tree

3 files changed

+32
-41
lines changed

3 files changed

+32
-41
lines changed

src/Application/LinkGenerator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public function link($dest, array $params = [])
5656
if ($action === '') {
5757
$action = UI\Presenter::DEFAULT_ACTION;
5858
}
59-
if ($params && (method_exists($class, $method = $class::formatActionMethod($action))
60-
|| method_exists($class, $method = $class::formatRenderMethod($action)))
59+
if (method_exists($class, $method = $class::formatActionMethod($action))
60+
|| method_exists($class, $method = $class::formatRenderMethod($action))
6161
) {
6262
UI\Presenter::argsToParams($class, $method, $params);
6363
}

src/Application/UI/Presenter.php

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -873,9 +873,8 @@ protected function createRequest($component, $destination, array $args, $mode)
873873
if (!$reflection->hasCallableMethod($method)) {
874874
throw new InvalidLinkException("Unknown signal '$signal', missing handler {$reflection->getName()}::$method()");
875875
}
876-
if ($args) { // convert indexed parameters to named
877-
self::argsToParams(get_class($component), $method, $args);
878-
}
876+
// convert indexed parameters to named
877+
self::argsToParams(get_class($component), $method, $args);
879878
}
880879

881880
// counterpart of IStatePersistent
@@ -901,28 +900,27 @@ protected function createRequest($component, $destination, array $args, $mode)
901900
$current = ($action === '*' || strcasecmp($action, $this->action) === 0) && $presenterClass === get_class($this);
902901

903902
$reflection = new PresenterComponentReflection($presenterClass);
904-
if ($args || $destination === 'this') {
905-
// counterpart of run() & tryCall()
906-
$method = $presenterClass::formatActionMethod($action);
903+
904+
// counterpart of run() & tryCall()
905+
$method = $presenterClass::formatActionMethod($action);
906+
if (!$reflection->hasCallableMethod($method)) {
907+
$method = $presenterClass::formatRenderMethod($action);
907908
if (!$reflection->hasCallableMethod($method)) {
908-
$method = $presenterClass::formatRenderMethod($action);
909-
if (!$reflection->hasCallableMethod($method)) {
910-
$method = NULL;
911-
}
909+
$method = NULL;
912910
}
911+
}
913912

914-
// convert indexed parameters to named
915-
if ($method === NULL) {
916-
if (array_key_exists(0, $args)) {
917-
throw new InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method.");
918-
}
913+
// convert indexed parameters to named
914+
if ($method === NULL) {
915+
if (array_key_exists(0, $args)) {
916+
throw new InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method.");
917+
}
919918

920-
} elseif ($destination === 'this') {
921-
self::argsToParams($presenterClass, $method, $args, $this->params);
919+
} elseif ($destination === 'this') {
920+
self::argsToParams($presenterClass, $method, $args, $this->params);
922921

923-
} else {
924-
self::argsToParams($presenterClass, $method, $args);
925-
}
922+
} else {
923+
self::argsToParams($presenterClass, $method, $args);
926924
}
927925

928926
// counterpart of IStatePersistent
@@ -1015,7 +1013,9 @@ public static function argsToParams($class, $method, & $args, $supplemental = []
10151013
$i = 0;
10161014
$rm = new \ReflectionMethod($class, $method);
10171015
foreach ($rm->getParameters() as $param) {
1016+
list($type, $isClass) = PresenterComponentReflection::getParameterType($param);
10181017
$name = $param->getName();
1018+
10191019
if (array_key_exists($i, $args)) {
10201020
$args[$name] = $args[$i];
10211021
unset($args[$i]);
@@ -1026,16 +1026,15 @@ public static function argsToParams($class, $method, & $args, $supplemental = []
10261026

10271027
} elseif (array_key_exists($name, $supplemental)) {
10281028
$args[$name] = $supplemental[$name];
1029-
1030-
} else {
1031-
continue;
10321029
}
10331030

1034-
if ($args[$name] === NULL) {
1035-
continue;
1031+
if (!isset($args[$name])) {
1032+
if ($param->isDefaultValueAvailable() || $type === 'NULL' || $type === 'array' || $isClass) {
1033+
continue;
1034+
}
1035+
throw new InvalidLinkException("Missing parameter \$$name required by $class::{$rm->getName()}()");
10361036
}
10371037

1038-
list($type, $isClass) = PresenterComponentReflection::getParameterType($param);
10391038
if (!PresenterComponentReflection::convertType($args[$name], $type, $isClass)) {
10401039
throw new InvalidLinkException(sprintf(
10411040
'Argument $%s passed to %s() must be %s, %s given.',
@@ -1046,22 +1045,14 @@ public static function argsToParams($class, $method, & $args, $supplemental = []
10461045
));
10471046
}
10481047

1049-
if ($param->isDefaultValueAvailable()) {
1050-
$def = $param->getDefaultValue();
1051-
} else {
1052-
$def = NULL;
1053-
if (!$isClass) {
1054-
settype($def, $type);
1055-
}
1056-
}
1048+
$def = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL;
10571049
if ($args[$name] === $def || ($def === NULL && $args[$name] === '')) {
10581050
$args[$name] = NULL; // value transmit is unnecessary
10591051
}
10601052
}
10611053

10621054
if (array_key_exists($i, $args)) {
1063-
$method = $rm->getName();
1064-
throw new InvalidLinkException("Passed more parameters than method $class::$method() expects.");
1055+
throw new InvalidLinkException("Passed more parameters than method $class::{$rm->getName()}() expects.");
10651056
}
10661057
}
10671058

tests/UI/Presenter.link().php7.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ class TestPresenter extends Application\UI\Presenter
144144
Assert::same('/index.php?int=0&bool=0&action=params&presenter=Test', $this->link('params', ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => '']));
145145
Assert::same('/index.php?action=params&presenter=Test', $this->link('params', ['int' => new stdClass]));
146146

147-
Assert::same('/index.php?action=hints&presenter=Test', $this->link('hints', []));
148-
Assert::same('/index.php?action=hints&presenter=Test', $this->link('hints', ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
147+
Assert::same('#error: Missing parameter $int required by TestPresenter::actionHints()', $this->link('hints', []));
148+
Assert::same('#error: Missing parameter $int required by TestPresenter::actionHints()', $this->link('hints', ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
149149
Assert::same('/index.php?int=1&bool=1&str=abc&arr%5B0%5D=1&action=hints&presenter=Test', $this->link('hints', ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]]));
150-
Assert::same('/index.php?action=hints&presenter=Test', $this->link('hints', ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => []]));
150+
Assert::same('/index.php?int=0&bool=0&action=hints&presenter=Test', $this->link('hints', ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => []]));
151151
Assert::same('#error: Argument $int passed to TestPresenter::actionHints() must be int, string given.', $this->link('hints', ['int' => '']));
152152
Assert::same('#error: Argument $int passed to TestPresenter::actionHints() must be int, stdClass given.', $this->link('hints', ['int' => new stdClass]));
153153
Assert::same('#error: Argument $int passed to TestPresenter::actionHints() must be int, array given.', $this->link('hints', ['int' => []]));

0 commit comments

Comments
 (0)