diff --git a/psalm.xml b/psalm.xml index d4a2702..c695981 100644 --- a/psalm.xml +++ b/psalm.xml @@ -14,6 +14,12 @@ + + + + + + diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php index b346329..fc27bdf 100644 --- a/src/Bootloader/TemporalBridgeBootloader.php +++ b/src/Bootloader/TemporalBridgeBootloader.php @@ -18,6 +18,7 @@ use Spiral\TemporalBridge\Config\TemporalConfig; use Spiral\TemporalBridge\DeclarationLocator; use Spiral\TemporalBridge\DeclarationLocatorInterface; +use Spiral\TemporalBridge\DeclarationRegistryInterface; use Spiral\TemporalBridge\Dispatcher; use Spiral\TemporalBridge\WorkerFactory; use Spiral\TemporalBridge\WorkerFactoryInterface; @@ -63,8 +64,9 @@ public function defineSingletons(): array rpc: Goridge::create(), ), WorkerFactoryInterface::class => WorkerFactory::class, + DeclarationLocatorInterface::class => DeclarationRegistryInterface::class, - DeclarationLocatorInterface::class => static fn() => new DeclarationLocator( + DeclarationRegistryInterface::class => static fn() => new DeclarationLocator( reader: new AttributeReader(), ), diff --git a/src/Config/TemporalConfig.php b/src/Config/TemporalConfig.php index 9853921..ff4c847 100644 --- a/src/Config/TemporalConfig.php +++ b/src/Config/TemporalConfig.php @@ -32,6 +32,7 @@ */ final class TemporalConfig extends InjectableConfig { + /** @var non-empty-string */ public const CONFIG = 'temporal'; protected array $config = [ diff --git a/src/DeclarationLocator.php b/src/DeclarationLocator.php index 4f44444..bd94549 100644 --- a/src/DeclarationLocator.php +++ b/src/DeclarationLocator.php @@ -14,7 +14,7 @@ #[Singleton] #[TargetAttribute(WorkflowInterface::class)] #[TargetAttribute(ActivityInterface::class)] -final class DeclarationLocator implements DeclarationLocatorInterface, TokenizationListenerInterface +final class DeclarationLocator implements DeclarationRegistryInterface, TokenizationListenerInterface { private array $declarations = []; @@ -23,6 +23,11 @@ public function __construct( ) { } + public function addDeclaration(\ReflectionClass|string $class): void + { + $this->listen($class instanceof \ReflectionClass ? $class : new \ReflectionClass($class)); + } + public function getDeclarations(): iterable { foreach ($this->declarations as $type => $classes) { diff --git a/src/DeclarationLocatorInterface.php b/src/DeclarationLocatorInterface.php index 22f0e2a..ff0c393 100644 --- a/src/DeclarationLocatorInterface.php +++ b/src/DeclarationLocatorInterface.php @@ -7,6 +7,9 @@ use Temporal\Activity\ActivityInterface; use Temporal\Workflow\WorkflowInterface; +/** + * @deprecated Use {@see DeclarationRegistryInterface} instead. + */ interface DeclarationLocatorInterface { /** diff --git a/src/DeclarationRegistryInterface.php b/src/DeclarationRegistryInterface.php new file mode 100644 index 0000000..0091a1d --- /dev/null +++ b/src/DeclarationRegistryInterface.php @@ -0,0 +1,15 @@ +|class-string, ReflectionClass> $declarations */ - $declarations = $this->container->get(DeclarationLocatorInterface::class)->getDeclarations(); + $declarations = $this->container->get(DeclarationRegistryInterface::class)->getDeclarations(); // factory initiates and runs task queue specific activity and workflow workers /** @var WorkerFactoryInterface $factory */ diff --git a/src/Scaffolder/Declaration/ActivityDeclaration.php b/src/Scaffolder/Declaration/ActivityDeclaration.php index 8dd65bc..182059b 100644 --- a/src/Scaffolder/Declaration/ActivityDeclaration.php +++ b/src/Scaffolder/Declaration/ActivityDeclaration.php @@ -13,6 +13,7 @@ final class ActivityDeclaration extends AbstractDeclaration { + /** @var non-empty-string */ public const TYPE = 'activity'; public function __construct( @@ -20,7 +21,7 @@ public function __construct( string $name, ?string $comment = null, ?string $namespace = null, - private ?string $activityName = null, + private readonly ?string $activityName = null, ) { parent::__construct($config, $name, $comment, $namespace); } diff --git a/src/Scaffolder/Declaration/WorkflowDeclaration.php b/src/Scaffolder/Declaration/WorkflowDeclaration.php index f572aa9..df670f5 100644 --- a/src/Scaffolder/Declaration/WorkflowDeclaration.php +++ b/src/Scaffolder/Declaration/WorkflowDeclaration.php @@ -14,6 +14,7 @@ final class WorkflowDeclaration extends AbstractDeclaration { + /** @var non-empty-string */ public const TYPE = 'workflow'; public function __construct( diff --git a/tests/src/DeclarationLocatorTest.php b/tests/src/DeclarationLocatorTest.php index e22d860..9f98ab6 100644 --- a/tests/src/DeclarationLocatorTest.php +++ b/tests/src/DeclarationLocatorTest.php @@ -4,17 +4,14 @@ namespace Spiral\TemporalBridge\Tests; -use Mockery as m; use Spiral\Attributes\AttributeReader; use Spiral\TemporalBridge\DeclarationLocator; -use Spiral\Tokenizer\ClassesInterface; use Temporal\Activity\ActivityInterface; use Temporal\Workflow\WorkflowInterface; final class DeclarationLocatorTest extends TestCase { private DeclarationLocator $locator; - private m\LegacyMockInterface|m\MockInterface $classes; protected function setUp(): void { @@ -68,6 +65,80 @@ public function testWorkflowsShouldBeRegistered(): void $this->assertSame(ActivityInterface::class, $result[3][0]); $this->assertSame($activity2, $result[3][1]); } + + public function testAddDeclarationSkipsNonClasses(): void + { + $this->locator->addDeclaration(TestEnum::class); + $this->locator->addDeclaration(TestAbstractClass::class); + $this->locator->addDeclaration(TestInterface::class); + $this->locator->addDeclaration(new \ReflectionClass(TestEnum::class)); + $this->locator->addDeclaration(new \ReflectionClass(TestAbstractClass::class)); + $this->locator->addDeclaration(new \ReflectionClass(TestInterface::class)); + + $result = []; + + foreach ($this->locator->getDeclarations() as $type => $class) { + $result[] = [$type, $class]; + } + + $this->assertCount(0, $result); + } + + public function testAddDeclarationReflections(): void + { + $this->locator->addDeclaration($workflow1 = new \ReflectionClass(TestWorkflowClass::class)); + $this->locator->addDeclaration($workflow2 = new \ReflectionClass(TestWorkflowClassWithInterface::class)); + $this->locator->addDeclaration($activity1 = new \ReflectionClass(TestActivityClass::class)); + $this->locator->addDeclaration($activity2 = new \ReflectionClass(TestActivityClassWithInterface::class)); + + $result = []; + + foreach ($this->locator->getDeclarations() as $type => $class) { + $result[] = [$type, $class]; + } + + $this->assertCount(4, $result); + + $this->assertSame(WorkflowInterface::class, $result[0][0]); + $this->assertSame($workflow1, $result[0][1]); + + $this->assertSame(WorkflowInterface::class, $result[1][0]); + $this->assertSame($workflow2, $result[1][1]); + + $this->assertSame(ActivityInterface::class, $result[2][0]); + $this->assertSame($activity1, $result[2][1]); + + $this->assertSame(ActivityInterface::class, $result[3][0]); + $this->assertSame($activity2, $result[3][1]); + } + + public function testAddDeclarationClassNames(): void + { + $this->locator->addDeclaration(TestWorkflowClass::class); + $this->locator->addDeclaration(TestWorkflowClassWithInterface::class); + $this->locator->addDeclaration(TestActivityClass::class); + $this->locator->addDeclaration(TestActivityClassWithInterface::class); + + $result = []; + + foreach ($this->locator->getDeclarations() as $type => $class) { + $result[] = [$type, $class]; + } + + $this->assertCount(4, $result); + + $this->assertSame(WorkflowInterface::class, $result[0][0]); + $this->assertSame(TestWorkflowClass::class, $result[0][1]->getName()); + + $this->assertSame(WorkflowInterface::class, $result[1][0]); + $this->assertSame(TestWorkflowClassWithInterface::class, $result[1][1]->getName()); + + $this->assertSame(ActivityInterface::class, $result[2][0]); + $this->assertSame(TestActivityClass::class, $result[2][1]->getName()); + + $this->assertSame(ActivityInterface::class, $result[3][0]); + $this->assertSame(TestActivityClassWithInterface::class, $result[3][1]->getName()); + } } enum TestEnum diff --git a/tests/src/DispatcherTest.php b/tests/src/DispatcherTest.php index 1addc89..b0f5f0c 100644 --- a/tests/src/DispatcherTest.php +++ b/tests/src/DispatcherTest.php @@ -8,7 +8,7 @@ use Spiral\Attributes\AttributeReader; use Spiral\RoadRunnerBridge\RoadRunnerMode; use Spiral\TemporalBridge\Config\TemporalConfig; -use Spiral\TemporalBridge\DeclarationLocatorInterface; +use Spiral\TemporalBridge\DeclarationRegistryInterface; use Spiral\TemporalBridge\DeclarationWorkerResolver; use Spiral\TemporalBridge\Dispatcher; use Spiral\TemporalBridge\Tests\App\SomeActivity; @@ -41,7 +41,7 @@ protected function setUp(): void public function testServeWithoutDeclarations(): void { - $locator = $this->mockContainer(DeclarationLocatorInterface::class); + $locator = $this->mockContainer(DeclarationRegistryInterface::class); $locator->shouldReceive('getDeclarations')->once()->andReturn([]); $registry = $this->mockContainer(WorkersRegistryInterface::class); @@ -59,7 +59,7 @@ public function testServeWithoutDeclarations(): void public function testServeWithDeclarations(): void { - $locator = $this->mockContainer(DeclarationLocatorInterface::class); + $locator = $this->mockContainer(DeclarationRegistryInterface::class); $locator->shouldReceive('getDeclarations')->once()->andReturnUsing(function () { yield WorkflowInterface::class => new \ReflectionClass(SomeWorkflow::class); yield WorkflowInterface::class => new \ReflectionClass(SomeWorkflowWithMultipleWorkers::class);