From 67be8a6f5af4bd7bb0f847ff77c6f54fd8c7271c Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 5 Jul 2022 20:33:31 +0400 Subject: [PATCH 1/5] Update Column attribute --- src/Annotation/Column.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Annotation/Column.php b/src/Annotation/Column.php index 7e534c20..978301f3 100644 --- a/src/Annotation/Column.php +++ b/src/Annotation/Column.php @@ -29,7 +29,7 @@ final class Column * @param bool $primary Explicitly set column as a primary key. * @param bool $nullable Set column as nullable. * @param mixed|null $default Default column value. - * @param non-empty-string|null $typecast Typecast rule name. + * @param non-empty-string|callable|null $typecast Typecast rule name. * Regarding the default Typecast handler {@see Typecast} the value can be `callable` or * one of ("int"|"float"|"bool"|"datetime") based on column type. * If you want to use another rule you should add in the `typecast` argument of the {@see Entity} attribute @@ -39,7 +39,7 @@ final class Column public function __construct( #[ExpectedValues(values: ['primary', 'bigPrimary', 'enum', 'boolean', 'integer', 'tinyInteger', 'bigInteger', 'string', 'text', 'tinyText', 'longText', 'double', 'float', 'decimal', 'datetime', 'date', 'time', - 'timestamp', 'binary', 'tinyBinary', 'longBinary', 'json', + 'timestamp', 'binary', 'tinyBinary', 'longBinary', 'json', 'uuid', ])] private string $type, private ?string $name = null, From 644781d474615dea66ebe62fa12d14368b083daa Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 5 Jul 2022 20:33:55 +0400 Subject: [PATCH 2/5] Add supporting for enums; add tests --- composer.json | 2 +- src/Configurator.php | 23 +++++---- .../Fixtures/Fixtures19/BackedEnum.php | 11 ++++ .../Fixtures/Fixtures19/BackedEnumWrapper.php | 16 ++++++ .../Annotated/Fixtures/Fixtures19/Booking.php | 27 ++++++++++ .../Functional/Driver/Common/TypecastTest.php | 51 +++++++++++++++++++ 6 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 tests/Annotated/Fixtures/Fixtures19/BackedEnum.php create mode 100644 tests/Annotated/Fixtures/Fixtures19/BackedEnumWrapper.php create mode 100644 tests/Annotated/Fixtures/Fixtures19/Booking.php diff --git a/composer.json b/composer.json index 693d0ba7..a5dc07d2 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "require": { "php": ">=8.0", "spiral/tokenizer": "^2.8", - "cycle/orm": "^2.0.0", + "cycle/orm": "^2.2.0", "cycle/schema-builder": "^2.1.0", "doctrine/annotations": "^1.13", "spiral/attributes": "^2.8", diff --git a/src/Configurator.php b/src/Configurator.php index c90fc76e..d4102a3d 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -251,36 +251,41 @@ public function initField(string $name, Column $column, \ReflectionClass $class, */ public function resolveName(?string $name, \ReflectionClass $class): ?string { - if ($name === null || class_exists($name, true) || interface_exists($name, true)) { + if ($name === null || $this->exists($name)) { return $name; } - $resolved = sprintf( + $resolved = \sprintf( '%s\\%s', $class->getNamespaceName(), - ltrim(str_replace('/', '\\', $name), '\\') + \ltrim(\str_replace('/', '\\', $name), '\\') ); - if (class_exists($resolved, true) || interface_exists($resolved, true)) { - return ltrim($resolved, '\\'); + if ($this->exists($resolved)) { + return \ltrim($resolved, '\\'); } return $name; } + private function exists(string $name): bool + { + return \class_exists($name, true) || \interface_exists($name, true) || \enum_exists($name, true); + } + private function resolveTypecast(mixed $typecast, \ReflectionClass $class): mixed { - if (is_string($typecast) && strpos($typecast, '::') !== false) { + if (\is_string($typecast) && \str_contains($typecast, '::')) { // short definition - $typecast = explode('::', $typecast); + $typecast = \explode('::', $typecast); // resolve class name $typecast[0] = $this->resolveName($typecast[0], $class); } - if (is_string($typecast)) { + if (\is_string($typecast)) { $typecast = $this->resolveName($typecast, $class); - if (class_exists($typecast)) { + if (\class_exists($typecast) && \method_exists($typecast, 'typecast')) { $typecast = [$typecast, 'typecast']; } } diff --git a/tests/Annotated/Fixtures/Fixtures19/BackedEnum.php b/tests/Annotated/Fixtures/Fixtures19/BackedEnum.php new file mode 100644 index 00000000..051f52fb --- /dev/null +++ b/tests/Annotated/Fixtures/Fixtures19/BackedEnum.php @@ -0,0 +1,11 @@ += 8.1 + */ + public function testBackedEnum(ReaderInterface $reader) + { + $tokenizer = new Tokenizer(new TokenizerConfig([ + 'directories' => [__DIR__ . '/../../../Fixtures/Fixtures19'], + 'exclude' => [], + ])); + + $locator = $tokenizer->classLocator(); + + $r = new Registry($this->dbal); + + $schema = (new Compiler())->compile($r, [ + new Embeddings($locator, $reader), + new Entities($locator, $reader), + new ResetTables(), + new MergeColumns($reader), + new GenerateRelations(), + new RenderTables(), + new RenderRelations(), + new MergeIndexes($reader), + new SyncTables(), + new GenerateTypecast(), + ]); + + $this->assertSame( + [ + 'bid' => 'int', + 'be' => BackedEnum::class, + 'bew' => [BackedEnumWrapper::class, 'typecast'], + ], + $schema['booking'][SchemaInterface::TYPECAST] + ); + } } From ac465b0690fa8cc00a292cbdcdcf9047e15ed9ca Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Tue, 5 Jul 2022 16:35:37 +0000 Subject: [PATCH 3/5] Apply fixes from StyleCI --- src/Annotation/Column.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Annotation/Column.php b/src/Annotation/Column.php index 978301f3..5344c44b 100644 --- a/src/Annotation/Column.php +++ b/src/Annotation/Column.php @@ -29,7 +29,7 @@ final class Column * @param bool $primary Explicitly set column as a primary key. * @param bool $nullable Set column as nullable. * @param mixed|null $default Default column value. - * @param non-empty-string|callable|null $typecast Typecast rule name. + * @param callable|non-empty-string|null $typecast Typecast rule name. * Regarding the default Typecast handler {@see Typecast} the value can be `callable` or * one of ("int"|"float"|"bool"|"datetime") based on column type. * If you want to use another rule you should add in the `typecast` argument of the {@see Entity} attribute From f071b2832d24ef4e088fb4c06a11ea3217a108bc Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 5 Jul 2022 20:40:45 +0400 Subject: [PATCH 4/5] Remove enum_exists --- src/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Configurator.php b/src/Configurator.php index d4102a3d..f4d8550a 100644 --- a/src/Configurator.php +++ b/src/Configurator.php @@ -270,7 +270,7 @@ public function resolveName(?string $name, \ReflectionClass $class): ?string private function exists(string $name): bool { - return \class_exists($name, true) || \interface_exists($name, true) || \enum_exists($name, true); + return \class_exists($name, true) || \interface_exists($name, true); } private function resolveTypecast(mixed $typecast, \ReflectionClass $class): mixed From 435d4b9848295cd58114ca48bde6465020492312 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 5 Jul 2022 20:57:44 +0400 Subject: [PATCH 5/5] Improve test --- tests/Annotated/Functional/Driver/Common/InvalidTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Annotated/Functional/Driver/Common/InvalidTest.php b/tests/Annotated/Functional/Driver/Common/InvalidTest.php index 8a83f476..5a13426c 100644 --- a/tests/Annotated/Functional/Driver/Common/InvalidTest.php +++ b/tests/Annotated/Functional/Driver/Common/InvalidTest.php @@ -60,9 +60,9 @@ public function testInvalidRelation(ReaderInterface $reader): void public function testNotDefinedColumnTypeShouldThrowAnException(ReaderInterface $reader): void { $this->expectException(AnnotationException::class); - $this->expectErrorMessage( - 'Some of required arguments [`type`] is missed on `Cycle\Annotated\Tests\Fixtures\Fixtures4\User.id.`' - ); + // $this->expectErrorMessage( + // 'Some of required arguments [`type`] is missed on `Cycle\Annotated\Tests\Fixtures\Fixtures4\User.id.`' + // ); $tokenizer = new Tokenizer(new TokenizerConfig([ 'directories' => [__DIR__ . '/../../../Fixtures/Fixtures4'],