From 6aed7a28ac29bef93f7de2f50b79e22a6e2dd833 Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Mon, 14 Aug 2023 15:46:27 +0200 Subject: [PATCH 1/5] tdd --- .../Attribute/InitialValueCallbackTest.php | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/Func/Attribute/InitialValueCallbackTest.php diff --git a/tests/Func/Attribute/InitialValueCallbackTest.php b/tests/Func/Attribute/InitialValueCallbackTest.php new file mode 100644 index 0000000..e4f0ef6 --- /dev/null +++ b/tests/Func/Attribute/InitialValueCallbackTest.php @@ -0,0 +1,98 @@ +map($data, $throwExceptionOnMissing, $allowNullable, $useSource); + $this->assertEquals(new \DateTime('2023-01-01 00:00:00'), $output->test); + } + } + } + } + + /** @test */ + public function shouldNotUseIncomingTimeForOutput(): void + { + $data = [ + 'test' => new \DateTime('2021-01-01 00:00:00'), + ]; + foreach ([true, false] as $throwExceptionOnMissing) { + foreach ([true, false] as $allowNullable) { + $output = $this->map($data, $throwExceptionOnMissing, $allowNullable, false); + $this->assertEquals(new \DateTime('2023-01-01 00:00:00'), $output->test); + } + } + } + + /** @test */ + public function shouldUseIncomingTimeForOutput(): void + { + $data = [ + 'test' => new \DateTime('2021-01-01 00:00:00'), + ]; + foreach ([true, false] as $throwExceptionOnMissing) { + foreach ([true, false] as $allowNullable) { + $output = $this->map($data, $throwExceptionOnMissing, $allowNullable, true); + $this->assertEquals(new \DateTime('2021-01-01 00:00:00'), $output->test); + } + } + } + + private function map(array $data, bool $throwExceptionOnMissing, bool $allowNullable, bool $useSource): InitialValueCallbackNullableUseSourceTester|InitialValueCallbackNullableTester|InitialValueCallbackUseSourceTester|InitialValueCallbackTester + { + return (new ExpressionBuilder( + Blueprint::create( + $allowNullable + ? ($useSource ? InitialValueCallbackNullableUseSourceTester::class : InitialValueCallbackNullableTester::class) + : ($useSource ? InitialValueCallbackUseSourceTester::class : InitialValueCallbackTester::class) + ), + new ArrayExpressionBuilder(), + new ReflectionClassExpressionBuilder(), + new FunctionExpressionBuilder(), + false + ))->build($throwExceptionOnMissing)->getMapper()->map($data); + } +} From 2cabffa7d5858f15b6a5d4166a54b7647ae26420 Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Mon, 14 Aug 2023 15:46:38 +0200 Subject: [PATCH 2/5] little fix of doc --- src/Expression/Builder/AbstractBuilder.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Expression/Builder/AbstractBuilder.php b/src/Expression/Builder/AbstractBuilder.php index 7d7188d..9b4b311 100644 --- a/src/Expression/Builder/AbstractBuilder.php +++ b/src/Expression/Builder/AbstractBuilder.php @@ -55,8 +55,9 @@ public function getSetterFinalExpression(Blueprint $blueprint, string $functionI /** * @return string - * Placeholders list: - * {{name}} + * + * Placeholders list: + * {{name}} * * {{setterAssignment:var}} * {{setterAssignment:basic}} @@ -128,9 +129,10 @@ protected function getGetterExpressionTemplate( /** * @return string - * Placeholders list: - * {{getterExpression}} - * {{sourceIteratorAssignment}} + * + * Placeholders list: + * {{getterExpression}} + * {{sourceIteratorAssignment}} * * {{function}} * {{functionVariable}} From 09eb2b8476e0d5fcd19709e39a68f4f3fadc5cd1 Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Mon, 14 Aug 2023 15:46:56 +0200 Subject: [PATCH 3/5] maybe it's good idea, maybe not, idk --- src/Expression/Assets/Expression.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Expression/Assets/Expression.php b/src/Expression/Assets/Expression.php index 309b358..313406e 100644 --- a/src/Expression/Assets/Expression.php +++ b/src/Expression/Assets/Expression.php @@ -70,10 +70,12 @@ public function build(Property $source, Property $target): self $hasFunction = !empty($this->function); $isPathUsed = (bool) $this->function?->pathVariable; + $initialCallback = $target->hasDedicatedInitCallback(true) ? $target->getInitialCallbackAttribute(true) : null; if ($target->isCollection()) { $itemExpressionArgs = [ - $target->hasDedicatedInitCallback(true), + (bool) $initialCallback, + true, false, !empty($this->collectionItemCallbacksExpression), @@ -197,6 +199,7 @@ private function applyCallbacks(Property $source, Property $target): void */ private function newExpression( bool $hasDedicatedGetter, + bool $useInitialCallback, bool $throwExceptionOnMissingRequiredValue, bool $hasDefaultValue, bool $hasCallbacks, From 16027c660593ffa46db091f8e1b4167efdd05886 Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Tue, 15 Aug 2023 09:59:59 +0200 Subject: [PATCH 4/5] . --- src/Expression/Assets/Expression.php | 14 ++++++++++++-- src/Expression/Assets/Getter.php | 3 +++ .../AnonymousObjectExpressionBuilder.php | 19 ++++++++++--------- .../Builder/ArrayExpressionBuilder.php | 19 ++++++++++--------- .../ReflectionClassExpressionBuilder.php | 19 ++++++++++--------- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/Expression/Assets/Expression.php b/src/Expression/Assets/Expression.php index 313406e..f56eec8 100644 --- a/src/Expression/Assets/Expression.php +++ b/src/Expression/Assets/Expression.php @@ -71,11 +71,12 @@ public function build(Property $source, Property $target): self $hasFunction = !empty($this->function); $isPathUsed = (bool) $this->function?->pathVariable; $initialCallback = $target->hasDedicatedInitCallback(true) ? $target->getInitialCallbackAttribute(true) : null; + $useInitialCallbackInsteadOfGetter = $initialCallback?->useSourceInsteadIfExists ?? false; if ($target->isCollection()) { $itemExpressionArgs = [ (bool) $initialCallback, - + $useInitialCallbackInsteadOfGetter, true, false, !empty($this->collectionItemCallbacksExpression), @@ -99,8 +100,13 @@ public function build(Property $source, Property $target): self $itemExpression = str_replace(array_keys($itemExpressionPlaceholders), array_values($itemExpressionPlaceholders), $itemExpression); } while ($this->hasNotFilledPlaceholders(array_keys($itemExpressionPlaceholders), $itemExpression)); + + $initialCallback = $target->hasDedicatedInitCallback(false) ? $target->getInitialCallbackAttribute(false) : null; + $useInitialCallbackInsteadOfGetter = $initialCallback?->useSourceInsteadIfExists ?? false; + $expressionArgs = [ $target->hasDedicatedInitCallback(false), + $useInitialCallbackInsteadOfGetter, $this->throwExceptionOnMissingRequiredValue, $target->hasDefaultValue(), !empty($this->callbacksExpression), @@ -115,8 +121,11 @@ public function build(Property $source, Property $target): self [$expression, $expressionPlaceholders] = $this->newExpression(...$expressionArgs); $expressionPlaceholders['{{preAssignmentExpression}}'] = $itemExpression; } else { + $initialCallback = $target->hasDedicatedInitCallback(false) ? $target->getInitialCallbackAttribute(false) : null; + $useInitialCallbackInsteadOfGetter = $initialCallback?->useSourceInsteadIfExists ?? false; $expressionArgs = [ $target->hasDedicatedInitCallback(false), + $useInitialCallbackInsteadOfGetter, $this->throwExceptionOnMissingRequiredValue, $target->hasDefaultValue(), !empty($this->callbacksExpression), @@ -199,7 +208,7 @@ private function applyCallbacks(Property $source, Property $target): void */ private function newExpression( bool $hasDedicatedGetter, - bool $useInitialCallback, + bool $useInitialCallbackInsteadOfGetter, bool $throwExceptionOnMissingRequiredValue, bool $hasDefaultValue, bool $hasCallbacks, @@ -212,6 +221,7 @@ private function newExpression( ): array { $getterExpressionArgs = [ $hasDedicatedGetter, + $useInitialCallbackInsteadOfGetter, $throwExceptionOnMissingRequiredValue, $hasDefaultValue, $hasCallbacks, diff --git a/src/Expression/Assets/Getter.php b/src/Expression/Assets/Getter.php index 29428ac..4757649 100644 --- a/src/Expression/Assets/Getter.php +++ b/src/Expression/Assets/Getter.php @@ -8,6 +8,7 @@ class Getter { public const STATEMENTS_ORDER = [ 'hasDedicatedGetter', + 'useInitialCallbackInsteadOfGetter', 'throwExceptionOnMissingRequiredValue', 'hasDefaultValue', 'hasCallbacks', @@ -28,6 +29,7 @@ public function __construct( public function getExpressionTemplate( bool $hasDedicatedGetter, + bool $useInitialCallbackInsteadOfGetter, bool $throwExceptionOnMissingRequiredValue, bool $hasDefaultValue, bool $hasCallbacks, @@ -45,6 +47,7 @@ public function getExpressionTemplate( */ public function getExpressions( bool $hasDedicatedGetter, + bool $useInitialCallbackInsteadOfGetter, bool $throwExceptionOnMissingRequiredValue, bool $hasDefaultValue, bool $hasCallbacks, diff --git a/src/Expression/Builder/AnonymousObjectExpressionBuilder.php b/src/Expression/Builder/AnonymousObjectExpressionBuilder.php index f64782e..240b260 100644 --- a/src/Expression/Builder/AnonymousObjectExpressionBuilder.php +++ b/src/Expression/Builder/AnonymousObjectExpressionBuilder.php @@ -58,15 +58,16 @@ public function getGetter(Property $property): Getter $expressions = []; $expressionTemplates = []; - for ($i = 0; $i < 128; ++$i) { - $key = str_pad(decbin($i), 7, '0', STR_PAD_LEFT); + for ($i = 0; $i < 256; ++$i) { + $key = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); $hasDedicatedGetter = '1' === $key[0]; - $throwExceptionOnMissingRequiredValue = '1' === $key[1]; - $hasDefaultValue = '1' === $key[2]; - $hasCallbacks = '1' === $key[3]; - $hasValueNotFoundCallbacks = '1' === $key[4]; - $isCollection = '1' === $key[5]; - $preAssignmentExpression = '1' === $key[6]; + $useInitialCallbackInsteadOfGetter = '1' === $key[1]; + $throwExceptionOnMissingRequiredValue = '1' === $key[2]; + $hasDefaultValue = '1' === $key[3]; + $hasCallbacks = '1' === $key[4]; + $hasValueNotFoundCallbacks = '1' === $key[5]; + $isCollection = '1' === $key[6]; + $preAssignmentExpression = '1' === $key[7]; if ($hasDefaultValue) { $throwExceptionOnMissingRequiredValue = true; @@ -94,7 +95,7 @@ public function getGetter(Property $property): Getter '{{varAssignment:basic:default}}' => $preAssignmentExpression ? "\${{var}} ??= {{defaultValue}};\n" : "\${{var}} = {{getterAssignment:basic}} ?? {{defaultValue}};\n", '{{varAssignnmet:item}}' => "\${{var}} = \$item;\n", '{{varAssignment:dedicated}}' => "\${{var}} = {{dedicatedGetter}};\n", - '{{varAssignment:dedicated:default}}' => "if ({{existsStatement}}) {\n" + '{{varAssignment:dedicated:default}}' => ($useInitialCallbackInsteadOfGetter ? "if (!{{existsStatement}}) {\n" : "if ({{existsStatement}}) {\n") ."\t\${{var}} = {{dedicatedGetter}};\n" ."} else {\n" ."\t\${{var}} = {{defaultValue}};\n" diff --git a/src/Expression/Builder/ArrayExpressionBuilder.php b/src/Expression/Builder/ArrayExpressionBuilder.php index a2adb7b..73f4247 100644 --- a/src/Expression/Builder/ArrayExpressionBuilder.php +++ b/src/Expression/Builder/ArrayExpressionBuilder.php @@ -59,15 +59,16 @@ public function getGetter(Property $property): Getter $expressions = []; $expressionTemplates = []; - for ($i = 0; $i < 128; ++$i) { - $key = str_pad(decbin($i), 7, '0', STR_PAD_LEFT); + for ($i = 0; $i < 256; ++$i) { + $key = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); $hasDedicatedGetter = '1' === $key[0]; - $throwExceptionOnMissingRequiredValue = '1' === $key[1]; - $hasDefaultValue = '1' === $key[2]; - $hasCallbacks = '1' === $key[3]; - $hasValueNotFoundCallbacks = '1' === $key[4]; - $isCollection = '1' === $key[5]; - $preAssignmentExpression = '1' === $key[6]; + $useInitialCallbackInsteadOfGetter = '1' === $key[1]; + $throwExceptionOnMissingRequiredValue = '1' === $key[2]; + $hasDefaultValue = '1' === $key[3]; + $hasCallbacks = '1' === $key[4]; + $hasValueNotFoundCallbacks = '1' === $key[5]; + $isCollection = '1' === $key[6]; + $preAssignmentExpression = '1' === $key[7]; if ($hasDefaultValue) { $throwExceptionOnMissingRequiredValue = true; @@ -95,7 +96,7 @@ public function getGetter(Property $property): Getter '{{varAssignment:basic:default}}' => $preAssignmentExpression ? "\${{var}} ??= {{defaultValue}};\n" : "\${{var}} = {{getterAssignment:basic}} ?? {{defaultValue}};\n", '{{varAssignnmet:item}}' => "\${{var}} = \$item;\n", '{{varAssignment:dedicated}}' => "\${{var}} = {{dedicatedGetter}};\n", - '{{varAssignment:dedicated:default}}' => "if ({{existsStatement}}) {\n" + '{{varAssignment:dedicated:default}}' => ($useInitialCallbackInsteadOfGetter ? "if (!{{existsStatement}}) {\n" : "if ({{existsStatement}}) {\n") ."\t\${{var}} = {{dedicatedGetter}};\n" ."} else {\n" ."\t\${{var}} = {{defaultValue}};\n" diff --git a/src/Expression/Builder/ReflectionClassExpressionBuilder.php b/src/Expression/Builder/ReflectionClassExpressionBuilder.php index b1fa5b3..26a070e 100644 --- a/src/Expression/Builder/ReflectionClassExpressionBuilder.php +++ b/src/Expression/Builder/ReflectionClassExpressionBuilder.php @@ -107,15 +107,16 @@ public function getGetter(Property $property): Getter $expressions = []; $expressionTemplates = []; - for ($i = 0; $i < 128; ++$i) { - $key = str_pad(decbin($i), 7, '0', STR_PAD_LEFT); + for ($i = 0; $i < 256; ++$i) { + $key = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); $hasDedicatedGetter = '1' === $key[0]; - $throwExceptionOnMissingRequiredValue = '1' === $key[1]; - $hasDefaultValue = '1' === $key[2]; - $hasCallbacks = '1' === $key[3]; - $hasValueNotFoundCallbacks = '1' === $key[4]; - $isCollection = '1' === $key[5]; - $preAssignmentExpression = '1' === $key[6]; + $useInitialCallbackInsteadOfGetter = '1' === $key[1]; + $throwExceptionOnMissingRequiredValue = '1' === $key[2]; + $hasDefaultValue = '1' === $key[3]; + $hasCallbacks = '1' === $key[4]; + $hasValueNotFoundCallbacks = '1' === $key[5]; + $isCollection = '1' === $key[6]; + $preAssignmentExpression = '1' === $key[7]; if ($hasDefaultValue) { $throwExceptionOnMissingRequiredValue = true; @@ -143,7 +144,7 @@ public function getGetter(Property $property): Getter '{{varAssignment:basic:default}}' => $preAssignmentExpression ? "\${{var}} ??= {{defaultValue}};\n" : "\${{var}} = {{getterAssignment:basic:default}};\n", '{{varAssignnmet:item}}' => "\${{var}} = \$item;\n", '{{varAssignment:dedicated}}' => "\${{var}} = {{dedicatedGetter}};\n", - '{{varAssignment:dedicated:default}}' => "if ({{existsStatement}} && {{defaultValue}} !== {{getterAssignment:basic}}) {\n" + '{{varAssignment:dedicated:default}}' => ($useInitialCallbackInsteadOfGetter ? "if (!{{existsStatement}}) {\n" : "if ({{existsStatement}}) {\n") ."\t\${{var}} = {{dedicatedGetter}};\n" ."} else {\n" ."\t\${{var}} = {{defaultValue}};\n" From ffc9f865b6df15919c98f957cd5eb0b6d2c2f301 Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Tue, 15 Aug 2023 10:20:00 +0200 Subject: [PATCH 5/5] . --- src/Expression/Assets/Expression.php | 2 -- src/Expression/Builder/AbstractBuilder.php | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Expression/Assets/Expression.php b/src/Expression/Assets/Expression.php index 313406e..957c241 100644 --- a/src/Expression/Assets/Expression.php +++ b/src/Expression/Assets/Expression.php @@ -75,7 +75,6 @@ public function build(Property $source, Property $target): self if ($target->isCollection()) { $itemExpressionArgs = [ (bool) $initialCallback, - true, false, !empty($this->collectionItemCallbacksExpression), @@ -199,7 +198,6 @@ private function applyCallbacks(Property $source, Property $target): void */ private function newExpression( bool $hasDedicatedGetter, - bool $useInitialCallback, bool $throwExceptionOnMissingRequiredValue, bool $hasDefaultValue, bool $hasCallbacks, diff --git a/src/Expression/Builder/AbstractBuilder.php b/src/Expression/Builder/AbstractBuilder.php index 9b4b311..06ccc03 100644 --- a/src/Expression/Builder/AbstractBuilder.php +++ b/src/Expression/Builder/AbstractBuilder.php @@ -129,7 +129,7 @@ protected function getGetterExpressionTemplate( /** * @return string - * + * * Placeholders list: * {{getterExpression}} * {{sourceIteratorAssignment}}