Skip to content

Commit

Permalink
Adding cycle/annotated 4.0 support (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
msmakouz authored Jun 20, 2023
1 parent 0048710 commit 936b512
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 13 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
53 changes: 53 additions & 0 deletions src/Annotated/Locator/ListenerEmbeddingsLocator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace Spiral\Cycle\Annotated\Locator;

use Cycle\Annotated\Annotation\Embeddable;
use Cycle\Annotated\Exception\AnnotationException;
use Cycle\Annotated\Locator\Embedding;
use Cycle\Annotated\Locator\EmbeddingLocatorInterface;
use Spiral\Attributes\ReaderInterface;
use Spiral\Tokenizer\TokenizationListenerInterface;

final class ListenerEmbeddingsLocator implements EmbeddingLocatorInterface, TokenizationListenerInterface
{
/**
* @var Embedding[]
*/
private array $embeddings = [];
private bool $collected = false;

public function __construct(
private readonly ReaderInterface $reader
) {
}

public function listen(\ReflectionClass $class): void
{
try {
$attribute = $this->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;
}
}
54 changes: 54 additions & 0 deletions src/Annotated/Locator/ListenerEntityLocator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Spiral\Cycle\Annotated\Locator;

use Cycle\Annotated\Annotation\Entity as Attribute;
use Cycle\Annotated\Exception\AnnotationException;
use Cycle\Annotated\Locator\Entity;
use Cycle\Annotated\Locator\EntityLocatorInterface;
use Spiral\Attributes\ReaderInterface;
use Spiral\Tokenizer\TokenizationListenerInterface;

final class ListenerEntityLocator implements EntityLocatorInterface, TokenizationListenerInterface
{
/**
* @var Entity[]
*/
private array $entities = [];
private bool $collected = false;

public function __construct(
private readonly ReaderInterface $reader
) {
}

public function listen(\ReflectionClass $class): void
{
try {
/** @var Attribute $attribute */
$attribute = $this->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;
}
}
34 changes: 25 additions & 9 deletions src/Bootloader/AnnotatedBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
];

Expand All @@ -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);
Expand All @@ -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
Expand All @@ -61,4 +78,3 @@ public function initMergeIndexes(ReaderInterface $reader): Annotated\MergeIndexe
return new Annotated\MergeIndexes($reader);
}
}

7 changes: 4 additions & 3 deletions src/Bootloader/PrototypeBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/app/Entities/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Spiral\App\Entities;

use Cycle\Annotated\Annotation\Embeddable;
use Cycle\Annotated\Annotation\Column;

#[Embeddable]
class Address
{
#[Column(type: 'string')]
public string $country;

#[Column(type: 'string(32)')]
public string $city;

#[Column(type: 'string(100)')]
public string $address;
}
53 changes: 53 additions & 0 deletions tests/src/Annotated/Locator/ListenerEmbeddingsLocatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Annotated\Locator;

use Cycle\Annotated\Annotation\Embeddable;
use Cycle\Annotated\Exception\AnnotationException;
use Cycle\Annotated\Locator\Embedding;
use PHPUnit\Framework\TestCase;
use Spiral\App\Entities\Address;
use Spiral\App\Entities\User;
use Spiral\Attributes\AttributeReader;
use Spiral\Cycle\Annotated\Locator\ListenerEmbeddingsLocator;

final class ListenerEmbeddingsLocatorTest extends TestCase
{
public function testListen(): void
{
$locator = new ListenerEmbeddingsLocator(new AttributeReader());
$locator->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();
}
}
52 changes: 52 additions & 0 deletions tests/src/Annotated/Locator/ListenerEntityLocatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Annotated\Locator;

use Cycle\Annotated\Exception\AnnotationException;
use Cycle\Annotated\Locator\Entity;
use PHPUnit\Framework\TestCase;
use Spiral\App\Entities\User;
use Spiral\App\Repositories\UserRepository;
use Spiral\Attributes\AttributeReader;
use Spiral\Cycle\Annotated\Locator\ListenerEntityLocator;

final class ListenerEntityLocatorTest extends TestCase
{
public function testListen(): void
{
$locator = new ListenerEntityLocator(new AttributeReader());
$locator->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();
}
}
12 changes: 12 additions & 0 deletions tests/src/Bootloader/AnnotatedBootloaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
4 changes: 4 additions & 0 deletions tests/src/Console/Command/CycleOrm/MigrateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 936b512

Please sign in to comment.