From 936b512957f813616cd55f1e40402e14ff390c22 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Tue, 20 Jun 2023 19:34:11 +0300 Subject: [PATCH 1/6] Adding cycle/annotated 4.0 support (#74) --- composer.json | 2 +- .../Locator/ListenerEmbeddingsLocator.php | 53 ++++++++++++++++++ .../Locator/ListenerEntityLocator.php | 54 +++++++++++++++++++ src/Bootloader/AnnotatedBootloader.php | 34 ++++++++---- src/Bootloader/PrototypeBootloader.php | 7 +-- tests/app/Entities/Address.php | 21 ++++++++ .../Locator/ListenerEmbeddingsLocatorTest.php | 53 ++++++++++++++++++ .../Locator/ListenerEntityLocatorTest.php | 52 ++++++++++++++++++ .../Bootloader/AnnotatedBootloaderTest.php | 12 +++++ .../Command/CycleOrm/MigrateCommandTest.php | 4 ++ 10 files changed, 279 insertions(+), 13 deletions(-) create mode 100644 src/Annotated/Locator/ListenerEmbeddingsLocator.php create mode 100644 src/Annotated/Locator/ListenerEntityLocator.php create mode 100644 tests/app/Entities/Address.php create mode 100644 tests/src/Annotated/Locator/ListenerEmbeddingsLocatorTest.php create mode 100644 tests/src/Annotated/Locator/ListenerEntityLocatorTest.php diff --git a/composer.json b/composer.json index 07b7333..3941428 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ ], "require": { "php": ">=8.1", - "cycle/annotated": "^3.1", + "cycle/annotated": "^4.0", "cycle/migrations": "^4.0.1", "cycle/orm": "^2.0.2", "cycle/schema-migrations-generator": "^2.1", diff --git a/src/Annotated/Locator/ListenerEmbeddingsLocator.php b/src/Annotated/Locator/ListenerEmbeddingsLocator.php new file mode 100644 index 0000000..0718827 --- /dev/null +++ b/src/Annotated/Locator/ListenerEmbeddingsLocator.php @@ -0,0 +1,53 @@ +reader->firstClassMetadata($class, Embeddable::class); + } catch (\Exception $e) { + throw new AnnotationException($e->getMessage(), (int) $e->getCode(), $e); + } + + if ($attribute !== null) { + $this->embeddings[] = new Embedding($attribute, $class); + } + } + + public function finalize(): void + { + $this->collected = true; + } + + public function getEmbeddings(): array + { + if (!$this->collected) { + throw new AnnotationException(\sprintf('Tokenizer did not finalize %s listener.', self::class)); + } + + return $this->embeddings; + } +} diff --git a/src/Annotated/Locator/ListenerEntityLocator.php b/src/Annotated/Locator/ListenerEntityLocator.php new file mode 100644 index 0000000..b9be91c --- /dev/null +++ b/src/Annotated/Locator/ListenerEntityLocator.php @@ -0,0 +1,54 @@ +reader->firstClassMetadata($class, Attribute::class); + } catch (\Exception $e) { + throw new AnnotationException($e->getMessage(), (int) $e->getCode(), $e); + } + + if ($attribute !== null) { + $this->entities[] = new Entity($attribute, $class); + } + } + + public function finalize(): void + { + $this->collected = true; + } + + public function getEntities(): array + { + if (!$this->collected) { + throw new AnnotationException(\sprintf('Tokenizer did not finalize %s listener.', self::class)); + } + + return $this->entities; + } +} diff --git a/src/Bootloader/AnnotatedBootloader.php b/src/Bootloader/AnnotatedBootloader.php index ba0b45c..1fad6ae 100644 --- a/src/Bootloader/AnnotatedBootloader.php +++ b/src/Bootloader/AnnotatedBootloader.php @@ -8,14 +8,15 @@ use Spiral\Attributes\ReaderInterface; use Spiral\Boot\Bootloader\Bootloader; use Spiral\Bootloader\Attributes\AttributesBootloader; -use Spiral\Tokenizer\Bootloader\TokenizerBootloader; -use Spiral\Tokenizer\ClassesInterface; +use Spiral\Cycle\Annotated\Locator\ListenerEmbeddingsLocator; +use Spiral\Cycle\Annotated\Locator\ListenerEntityLocator; +use Spiral\Tokenizer\Bootloader\TokenizerListenerBootloader; final class AnnotatedBootloader extends Bootloader { protected const DEPENDENCIES = [ SchemaBootloader::class, - TokenizerBootloader::class, + TokenizerListenerBootloader::class, AttributesBootloader::class, ]; @@ -27,6 +28,11 @@ final class AnnotatedBootloader extends Bootloader Annotated\MergeIndexes::class => [self::class, 'initMergeIndexes'], ]; + protected const SINGLETONS = [ + ListenerEntityLocator::class => ListenerEntityLocator::class, + ListenerEmbeddingsLocator::class => ListenerEmbeddingsLocator::class, + ]; + public function init(SchemaBootloader $schema): void { $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\Embeddings::class); @@ -36,14 +42,25 @@ public function init(SchemaBootloader $schema): void $schema->addGenerator(SchemaBootloader::GROUP_RENDER, Annotated\MergeIndexes::class); } - private function initEmbeddings(ClassesInterface $classes, ReaderInterface $reader): Annotated\Embeddings - { - return new Annotated\Embeddings($classes, $reader); + public function boot( + TokenizerListenerBootloader $tokenizer, + ListenerEntityLocator $entityLocator, + ListenerEmbeddingsLocator $embeddingsLocator + ): void { + $tokenizer->addListener($entityLocator); + $tokenizer->addListener($embeddingsLocator); } - public function initEntities(ClassesInterface $classes, ReaderInterface $reader): Annotated\Entities + private function initEmbeddings( + ReaderInterface $reader, + ListenerEmbeddingsLocator $embeddingsLocator + ): Annotated\Embeddings { + return new Annotated\Embeddings($embeddingsLocator, $reader); + } + + public function initEntities(ReaderInterface $reader, ListenerEntityLocator $entityLocator): Annotated\Entities { - return new Annotated\Entities($classes, $reader); + return new Annotated\Entities($entityLocator, $reader); } public function initMergeColumns(ReaderInterface $reader): Annotated\MergeColumns @@ -61,4 +78,3 @@ public function initMergeIndexes(ReaderInterface $reader): Annotated\MergeIndexe return new Annotated\MergeIndexes($reader); } } - diff --git a/src/Bootloader/PrototypeBootloader.php b/src/Bootloader/PrototypeBootloader.php index 440fca6..52f09f9 100644 --- a/src/Bootloader/PrototypeBootloader.php +++ b/src/Bootloader/PrototypeBootloader.php @@ -9,15 +9,16 @@ use Cycle\ORM; use Doctrine\Inflector\Rules\English\InflectorFactory; use Psr\Container\ContainerInterface; +use Spiral\Boot\AbstractKernel; use Spiral\Boot\Bootloader\Bootloader; use Spiral\Prototype\Bootloader\PrototypeBootloader as BasePrototypeBootloader; final class PrototypeBootloader extends Bootloader { - public function boot(BasePrototypeBootloader $prototype, ContainerInterface $container): void + public function boot(AbstractKernel $kernel): void { - $this->bindDatabase($prototype); - $this->bindCycle($prototype, $container); + $kernel->bootstrapped($this->bindDatabase(...)); + $kernel->bootstrapped($this->bindCycle(...)); } private function bindDatabase(BasePrototypeBootloader $prototype): void diff --git a/tests/app/Entities/Address.php b/tests/app/Entities/Address.php new file mode 100644 index 0000000..e61d44a --- /dev/null +++ b/tests/app/Entities/Address.php @@ -0,0 +1,21 @@ +listen(new \ReflectionClass(Address::class)); + $locator->finalize(); + + $this->assertEquals( + [ + new Embedding( + new Embeddable(), + new \ReflectionClass(Address::class) + ), + ], + $locator->getEmbeddings()); + } + + public function testListenWithoutAttribute(): void + { + $locator = new ListenerEmbeddingsLocator(new AttributeReader()); + $locator->listen(new \ReflectionClass(User::class)); + $locator->finalize(); + + $this->assertSame([], $locator->getEmbeddings()); + } + + public function testGetEmbeddingsWithoutFinalize(): void + { + $this->expectException(AnnotationException::class); + $this->expectExceptionMessage( + \sprintf('Tokenizer did not finalize %s listener.', ListenerEmbeddingsLocator::class) + ); + + $locator = new ListenerEmbeddingsLocator(new AttributeReader()); + $locator->getEmbeddings(); + } +} diff --git a/tests/src/Annotated/Locator/ListenerEntityLocatorTest.php b/tests/src/Annotated/Locator/ListenerEntityLocatorTest.php new file mode 100644 index 0000000..8b8487c --- /dev/null +++ b/tests/src/Annotated/Locator/ListenerEntityLocatorTest.php @@ -0,0 +1,52 @@ +listen(new \ReflectionClass(User::class)); + $locator->finalize(); + + $this->assertEquals( + [ + new Entity( + new \Cycle\Annotated\Annotation\Entity(repository: UserRepository::class), + new \ReflectionClass(User::class) + ), + ], + $locator->getEntities()); + } + + public function testListenWithoutAttribute(): void + { + $locator = new ListenerEntityLocator(new AttributeReader()); + $locator->listen(new \ReflectionClass(\stdClass::class)); + $locator->finalize(); + + $this->assertSame([], $locator->getEntities()); + } + + public function testGetEntitiesWithoutFinalize(): void + { + $this->expectException(AnnotationException::class); + $this->expectExceptionMessage( + \sprintf('Tokenizer did not finalize %s listener.', ListenerEntityLocator::class) + ); + + $locator = new ListenerEntityLocator(new AttributeReader()); + $locator->getEntities(); + } +} diff --git a/tests/src/Bootloader/AnnotatedBootloaderTest.php b/tests/src/Bootloader/AnnotatedBootloaderTest.php index 10d9883..81cf550 100644 --- a/tests/src/Bootloader/AnnotatedBootloaderTest.php +++ b/tests/src/Bootloader/AnnotatedBootloaderTest.php @@ -7,6 +7,8 @@ use Cycle\Annotated; use Cycle\Schema\GeneratorInterface; use Spiral\Attributes\ReaderInterface; +use Spiral\Cycle\Annotated\Locator\ListenerEmbeddingsLocator; +use Spiral\Cycle\Annotated\Locator\ListenerEntityLocator; use Spiral\Tests\BaseTest; final class AnnotatedBootloaderTest extends BaseTest @@ -40,4 +42,14 @@ public function testGetsAnnotatedMergeIndexes(): void { $this->assertContainerBound(Annotated\MergeIndexes::class, GeneratorInterface::class); } + + public function testGetsListenerEntityLocator(): void + { + $this->assertContainerBoundAsSingleton(ListenerEntityLocator::class, ListenerEntityLocator::class); + } + + public function testGetsListenerEmbeddingsLocator(): void + { + $this->assertContainerBoundAsSingleton(ListenerEmbeddingsLocator::class, ListenerEmbeddingsLocator::class); + } } diff --git a/tests/src/Console/Command/CycleOrm/MigrateCommandTest.php b/tests/src/Console/Command/CycleOrm/MigrateCommandTest.php index 7961e3b..61c1633 100644 --- a/tests/src/Console/Command/CycleOrm/MigrateCommandTest.php +++ b/tests/src/Console/Command/CycleOrm/MigrateCommandTest.php @@ -8,6 +8,7 @@ use Cycle\Annotated\Annotation\Entity; use Cycle\ORM\SchemaInterface; use Spiral\Boot\MemoryInterface; +use Spiral\Cycle\Annotated\Locator\ListenerEntityLocator; use Spiral\Cycle\Config\CycleConfig; use Spiral\Files\Files; use Spiral\Tests\ConsoleTest; @@ -76,6 +77,9 @@ class Tag PHP ); + $listener = $this->getContainer()->get(ListenerEntityLocator::class); + $listener->listen(new \ReflectionClass(\Spiral\App\Entities\Tag::class)); + $this->assertConsoleCommandOutputContainsStrings('cycle:migrate', ['-r' => true], [ 'default.tags', 'create table', From 46b9378845c6cc3e22d07d77c215ade63b28fc2c Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Fri, 27 Oct 2023 15:13:22 +0300 Subject: [PATCH 2/6] Add PrototypeBootloader to DEPENDENCIES --- src/Bootloader/PrototypeBootloader.php | 4 ++++ tests/app/Entities/Role.php | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Bootloader/PrototypeBootloader.php b/src/Bootloader/PrototypeBootloader.php index 52f09f9..7d6bf0e 100644 --- a/src/Bootloader/PrototypeBootloader.php +++ b/src/Bootloader/PrototypeBootloader.php @@ -15,6 +15,10 @@ final class PrototypeBootloader extends Bootloader { + protected const DEPENDENCIES = [ + BasePrototypeBootloader::class, + ]; + public function boot(AbstractKernel $kernel): void { $kernel->bootstrapped($this->bindDatabase(...)); diff --git a/tests/app/Entities/Role.php b/tests/app/Entities/Role.php index fd75a1c..72b956a 100644 --- a/tests/app/Entities/Role.php +++ b/tests/app/Entities/Role.php @@ -6,9 +6,9 @@ use Cycle\Annotated\Annotation\Column; use Cycle\Annotated\Annotation\Entity; -use Spiral\App\Repositories\RoleRepositoryInterface; +use Spiral\App\Repositories\RoleRepository; -#[Entity(repository: RoleRepositoryInterface::class)] +#[Entity(repository: RoleRepository::class)] class Role { #[Column(type: 'primary')] From 75dfcaffb880de0102c5a5239be4553a70412e21 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Tue, 19 Dec 2023 14:56:19 +0200 Subject: [PATCH 3/6] Move tokenizer listeners to init method --- src/Bootloader/AnnotatedBootloader.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Bootloader/AnnotatedBootloader.php b/src/Bootloader/AnnotatedBootloader.php index 1fad6ae..f22d332 100644 --- a/src/Bootloader/AnnotatedBootloader.php +++ b/src/Bootloader/AnnotatedBootloader.php @@ -33,22 +33,20 @@ final class AnnotatedBootloader extends Bootloader ListenerEmbeddingsLocator::class => ListenerEmbeddingsLocator::class, ]; - public function init(SchemaBootloader $schema): void - { - $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\Embeddings::class); - $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\Entities::class); - $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\TableInheritance::class); - $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\MergeColumns::class); - $schema->addGenerator(SchemaBootloader::GROUP_RENDER, Annotated\MergeIndexes::class); - } - - public function boot( + public function init( + SchemaBootloader $schema, TokenizerListenerBootloader $tokenizer, ListenerEntityLocator $entityLocator, ListenerEmbeddingsLocator $embeddingsLocator ): void { $tokenizer->addListener($entityLocator); $tokenizer->addListener($embeddingsLocator); + + $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\Embeddings::class); + $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\Entities::class); + $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\TableInheritance::class); + $schema->addGenerator(SchemaBootloader::GROUP_INDEX, Annotated\MergeColumns::class); + $schema->addGenerator(SchemaBootloader::GROUP_RENDER, Annotated\MergeIndexes::class); } private function initEmbeddings( From 0469737ec7f79ef0d7b43d2c7c8841a5aff44bb8 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Tue, 19 Dec 2023 16:01:08 +0200 Subject: [PATCH 4/6] Add TargetAttribute --- src/Annotated/Locator/ListenerEmbeddingsLocator.php | 2 ++ src/Annotated/Locator/ListenerEntityLocator.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Annotated/Locator/ListenerEmbeddingsLocator.php b/src/Annotated/Locator/ListenerEmbeddingsLocator.php index 0718827..d5a35d9 100644 --- a/src/Annotated/Locator/ListenerEmbeddingsLocator.php +++ b/src/Annotated/Locator/ListenerEmbeddingsLocator.php @@ -9,8 +9,10 @@ use Cycle\Annotated\Locator\Embedding; use Cycle\Annotated\Locator\EmbeddingLocatorInterface; use Spiral\Attributes\ReaderInterface; +use Spiral\Tokenizer\Attribute\TargetAttribute; use Spiral\Tokenizer\TokenizationListenerInterface; +#[TargetAttribute(Embeddable::class, useAnnotations: true)] final class ListenerEmbeddingsLocator implements EmbeddingLocatorInterface, TokenizationListenerInterface { /** diff --git a/src/Annotated/Locator/ListenerEntityLocator.php b/src/Annotated/Locator/ListenerEntityLocator.php index b9be91c..710006d 100644 --- a/src/Annotated/Locator/ListenerEntityLocator.php +++ b/src/Annotated/Locator/ListenerEntityLocator.php @@ -9,8 +9,10 @@ use Cycle\Annotated\Locator\Entity; use Cycle\Annotated\Locator\EntityLocatorInterface; use Spiral\Attributes\ReaderInterface; +use Spiral\Tokenizer\Attribute\TargetAttribute; use Spiral\Tokenizer\TokenizationListenerInterface; +#[TargetAttribute(Attribute::class, useAnnotations: true)] final class ListenerEntityLocator implements EntityLocatorInterface, TokenizationListenerInterface { /** From d8d50b1054484ed714e0f4124805980406ae4b7e Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Fri, 5 Jan 2024 16:49:15 +0200 Subject: [PATCH 5/6] Up spiral/framework version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b44a763..e255b6e 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "cycle/schema-builder": "^2.6", "doctrine/inflector": "^1.4 || ^2.0", "spiral/attributes": "^2.10 || ^3.0", - "spiral/framework": "^3.3", + "spiral/framework": "^3.11.1", "spiral/reactor": "^3.0", "spiral/scaffolder": "^3.0", "spiral/prototype": "^3.0", From 785e63aa68639fc15897766b7dd014470e9c9293 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Fri, 5 Jan 2024 17:06:39 +0200 Subject: [PATCH 6/6] Up spiral/validator version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e255b6e..d41f874 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "mockery/mockery": "^1.5", "phpunit/phpunit": "^9.5.20", "spiral/testing": "^2.4", - "spiral/validator": "^1.2", + "spiral/validator": "^1.5", "vimeo/psalm": "^4.27" }, "autoload": {