Skip to content

Commit

Permalink
UI: added support for PHP 7.1 nullable types
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Sep 21, 2016
1 parent 5237fd7 commit 21f129c
Show file tree
Hide file tree
Showing 4 changed files with 489 additions and 4 deletions.
8 changes: 5 additions & 3 deletions src/Application/UI/ComponentReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ public static function combineArgs(\ReflectionFunctionAbstract $method, $args)
}
} elseif ($param->isDefaultValueAvailable()) {
$res[$i] = $param->getDefaultValue();
} elseif ($type === 'NULL' || $param->allowsNull()) {
$res[$i] = NULL;
} elseif ($type === 'array') {
$res[$i] = [];
} elseif ($type === 'NULL') {
$res[$i] = NULL;
} else {
throw new $exception(sprintf(
'Missing parameter $%s required by %s()',
Expand Down Expand Up @@ -217,7 +217,9 @@ public static function getParameterType(\ReflectionParameter $param)
{
$def = gettype($param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL);
if (PHP_VERSION_ID >= 70000) {
return [(string) $param->getType() ?: $def, $param->hasType() && !$param->getType()->isBuiltin()];
return $param->hasType()
? [PHP_VERSION_ID >= 70100 ? $param->getType()->getName() : (string) $param->getType(), !$param->getType()->isBuiltin()]
: [$def, FALSE];
} elseif ($param->isArray() || $param->isCallable()) {
return [$param->isArray() ? 'array' : 'callable', FALSE];
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/Application/UI/Presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ public static function argsToParams($class, $method, & $args, $supplemental = []
}

if (!isset($args[$name])) {
if (!$param->isDefaultValueAvailable() && $type !== 'NULL' && $type !== 'array') {
if (!$param->isDefaultValueAvailable() && !$param->allowsNull() && $type !== 'NULL' && $type !== 'array') {
$missing[] = $param;
unset($args[$name]);
}
Expand Down
206 changes: 206 additions & 0 deletions tests/UI/ComponentReflection.combineArgs.php71.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<?php

/**
* Test: ComponentReflection::combineArgs()
* @phpVersion 7.1
*/

use Nette\Application\UI\ComponentReflection as Reflection;
use Nette\Application\BadRequestException;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


class MyPresenter
{

public function params($int, $bool, $str, $arr)
{
}

public function hints(int $int, bool $bool, string $str, array $arr)
{
}

public function hintsNulls(?int $int, ?bool $bool, ?string $str, ?array $arr)
{
}

public function hintsDefaults(int $int = 0, bool $bool = FALSE, string $str = '', array $arr = [])
{
}

public function defaults($int = 0, $bool = FALSE, $str = '', $arr = [])
{
}

public function objects(stdClass $req, ?stdClass $opt)
{
}

}


test(function () {
$method = new ReflectionMethod('MyPresenter', 'params');

Assert::same([NULL, NULL, NULL, NULL], Reflection::combineArgs($method, []));
Assert::same([NULL, NULL, NULL, NULL], Reflection::combineArgs($method, ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
Assert::same([1, TRUE, 'abc', '1'], Reflection::combineArgs($method, ['int' => 1, 'bool' => TRUE, 'str' => 'abc', 'arr' => '1']));
Assert::same([0, FALSE, '', ''], Reflection::combineArgs($method, ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => '']));
Assert::equal([NULL, NULL, NULL, new stdClass], Reflection::combineArgs($method, ['arr' => new stdClass]));

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => []]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::params() must be scalar, array given.');
});


test(function () {
$method = new ReflectionMethod('MyPresenter', 'hints');

Assert::same([1, TRUE, 'abc', [1]], Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]]));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => 0, 'bool' => FALSE, 'str' => ''])); // missing 'arr'

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, []);
}, BadRequestException::class, 'Missing parameter $int required by MyPresenter::hints()');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '']);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hints() must be int, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => NULL]);
}, BadRequestException::class, 'Missing parameter $int required by MyPresenter::hints()');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => new stdClass]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hints() must be int, stdClass given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => []]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hints() must be int, array given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '']);
}, BadRequestException::class, 'Argument $bool passed to MyPresenter::hints() must be bool, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']);
}, BadRequestException::class, 'Argument $arr passed to MyPresenter::hints() must be array, string given.');
});


test(function () {
$method = new ReflectionMethod('MyPresenter', 'hintsNulls');

Assert::same([NULL, NULL, NULL, NULL], Reflection::combineArgs($method, []));
Assert::same([NULL, NULL, NULL, NULL], Reflection::combineArgs($method, ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
Assert::same([1, TRUE, 'abc', [1]], Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]]));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => []]));

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '']);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsNulls() must be int, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => new stdClass]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsNulls() must be int, stdClass given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => []]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsNulls() must be int, array given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '']);
}, BadRequestException::class, 'Argument $bool passed to MyPresenter::hintsNulls() must be bool, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']);
}, BadRequestException::class, 'Argument $arr passed to MyPresenter::hintsNulls() must be array, string given.');
});


test(function () {
$method = new ReflectionMethod('MyPresenter', 'hintsDefaults');

Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, []));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
Assert::same([1, TRUE, 'abc', [1]], Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]]));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => []]));

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '']);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsDefaults() must be int, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => new stdClass]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsDefaults() must be int, stdClass given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => []]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::hintsDefaults() must be int, array given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '']);
}, BadRequestException::class, 'Argument $bool passed to MyPresenter::hintsDefaults() must be bool, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']);
}, BadRequestException::class, 'Argument $arr passed to MyPresenter::hintsDefaults() must be array, string given.');
});


test(function () {
$method = new ReflectionMethod('MyPresenter', 'defaults');

Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, []));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => NULL, 'bool' => NULL, 'str' => NULL, 'arr' => NULL]));
Assert::same([1, TRUE, 'abc', [1]], Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]]));
Assert::same([0, FALSE, '', []], Reflection::combineArgs($method, ['int' => 0, 'bool' => FALSE, 'str' => '', 'arr' => []]));

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '']);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::defaults() must be integer, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => new stdClass]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::defaults() must be integer, stdClass given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => []]);
}, BadRequestException::class, 'Argument $int passed to MyPresenter::defaults() must be integer, array given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '']);
}, BadRequestException::class, 'Argument $bool passed to MyPresenter::defaults() must be boolean, string given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']);
}, BadRequestException::class, 'Argument $arr passed to MyPresenter::defaults() must be array, string given.');
});


test(function () {
$method = new ReflectionMethod('MyPresenter', 'objects');

Assert::equal([new stdClass, new stdClass], Reflection::combineArgs($method, ['req' => new stdClass, 'opt' => new stdClass]));

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, []);
}, Nette\InvalidArgumentException::class, 'Missing parameter $req required by MyPresenter::objects()');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['req' => NULL, 'opt' => NULL]);
}, Nette\InvalidArgumentException::class, 'Missing parameter $req required by MyPresenter::objects()');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['req' => $method, 'opt' => NULL]);
}, Nette\InvalidArgumentException::class, 'Argument $req passed to MyPresenter::objects() must be stdClass, ReflectionMethod given.');

Assert::exception(function () use ($method) {
Reflection::combineArgs($method, ['req' => [], 'opt' => NULL]);
}, Nette\InvalidArgumentException::class, 'Argument $req passed to MyPresenter::objects() must be stdClass, array given.');
});
Loading

0 comments on commit 21f129c

Please sign in to comment.