From 2fab800029b16996902184d1cc51a12b1f159a32 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 20 May 2020 18:17:16 +0200 Subject: [PATCH] added new internal functions bool(), int(), float(), string() --- src/DI/Helpers.php | 23 ++++++++ src/DI/Resolver.php | 8 +++ tests/DI/Compiler.functions.phpt | 80 ++++++++++++++++++++++++++ tests/DI/Helpers.convertType.phpt | 94 +++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 tests/DI/Compiler.functions.phpt create mode 100644 tests/DI/Helpers.convertType.phpt diff --git a/src/DI/Helpers.php b/src/DI/Helpers.php index d479f18bb..fe6f9d1ec 100644 --- a/src/DI/Helpers.php +++ b/src/DI/Helpers.php @@ -192,4 +192,27 @@ public static function normalizeClass(string $type): string ? (new \ReflectionClass($type))->name : $type; } + + + /** + * Non data-loss type conversion. + * @param mixed + * @return mixed + * @throws Nette\InvalidStateException + */ + public static function convertType($val, string $type) + { + if (is_scalar($val)) { + $norm = ($val === false ? '0' : (string) $val); + if ($type === 'float') { + $norm = preg_replace('#\.0*$#D', '', $norm); + } + $orig = $norm; + settype($norm, $type); + if ($orig === ($norm === false ? '0' : (string) $norm)) { + return $norm; + } + } + throw new Nette\InvalidStateException('Cannot convert ' . (is_scalar($val) ? "'$val'" : gettype($val)) . " to $type."); + } } diff --git a/src/DI/Resolver.php b/src/DI/Resolver.php index ecb1ee43d..42b4dd2a3 100644 --- a/src/DI/Resolver.php +++ b/src/DI/Resolver.php @@ -184,6 +184,14 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo $entity = ['', '!']; break; + case $entity === 'bool': + case $entity === 'int': + case $entity === 'float': + case $entity === 'string': + $arguments = [$arguments[0], $entity]; + $entity = [Helpers::class, 'convertType']; + break; + case is_string($entity): // create class if (!class_exists($entity)) { throw new ServiceCreationException("Class $entity not found."); diff --git a/tests/DI/Compiler.functions.phpt b/tests/DI/Compiler.functions.phpt new file mode 100644 index 000000000..884aa1dfd --- /dev/null +++ b/tests/DI/Compiler.functions.phpt @@ -0,0 +1,80 @@ +args[$nm] = $args; + } +} + + +const NUM = 231; + +$compiler = new DI\Compiler; +$compiler->setDynamicParameterNames(['dynamic']); +$container = createContainer($compiler, ' +parameters: + t: true + f: false + fn: ::constant(NUM) + not: not(%f%) + string: string(%f%) + +services: + ok: + factory: Service + setup: + - not( not(%f%), not(%t%), not(%fn%), not(%dynamic%), %not% ) + - string( string(%f%), string(%t%), string(%fn%), string(%dynamic%), %string% ) + - bool( bool(%f%), bool(%t%) ) + - int( int(%f%), int(%t%), int(%fn%), int(%dynamic%) ) + - float( float(%f%), float(%t%), float(%fn%), float(%dynamic%) ) + + bad1: Service(bool(123)) + bad2: + factory: Service + setup: + - method(bool(123)) +', ['dynamic' => 123]); + + +$obj = $container->getByName('ok'); + +Assert::same( + [ + 'not' => [true, false, false, false, true], + 'string' => ['0', '1', '231', '123', '0'], + 'bool' => [false, true], + 'int' => [0, 1, 231, 123], + 'float' => [0.0, 1.0, 231.0, 123.0], + ], + $obj->args +); + + +Assert::exception(function () use ($container) { + $container->getByName('bad1'); +}, Nette\InvalidStateException::class, "Cannot convert '123' to bool."); + +Assert::exception(function () use ($container) { + $container->getByName('bad2'); +}, Nette\InvalidStateException::class, "Cannot convert '123' to bool."); diff --git a/tests/DI/Helpers.convertType.phpt b/tests/DI/Helpers.convertType.phpt new file mode 100644 index 000000000..9d900cbc3 --- /dev/null +++ b/tests/DI/Helpers.convertType.phpt @@ -0,0 +1,94 @@ +