Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use tokenizer listeners instead of tokenizer class locator #84

Merged
merged 2 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false"
backupStaticAttributes="false" colors="true" verbose="false" convertErrorsToExceptions="true"
convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false"
stopOnFailure="false" stopOnError="false" stderr="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory>src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Test Suite">
<directory>tests/src</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<ini name="memory_limit" value="-1"/>
</php>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
backupGlobals="false"
colors="true"
processIsolation="false"
stopOnFailure="false"
stopOnError="false"
stderr="false"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
>
<testsuites>
<testsuite name="Test Suite">
<directory>tests/src</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<ini name="memory_limit" value="-1"/>
</php>
<source>
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
101 changes: 41 additions & 60 deletions src/Bootloader/TemporalBridgeBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use Spiral\TemporalBridge\WorkerFactoryInterface;
use Spiral\TemporalBridge\WorkersRegistry;
use Spiral\TemporalBridge\WorkersRegistryInterface;
use Spiral\Tokenizer\ClassesInterface;
use Spiral\Tokenizer\TokenizerListenerRegistryInterface;
use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\WorkflowClient;
use Temporal\Client\WorkflowClientInterface;
Expand Down Expand Up @@ -56,15 +56,46 @@ public function defineDependencies(): array
public function defineSingletons(): array
{
return [
TemporalWorkerFactoryInterface::class => [self::class, 'initWorkerFactory'],
TemporalWorkerFactoryInterface::class => static fn(
DataConverterInterface $dataConverter,
): TemporalWorkerFactoryInterface => new TemporalWorkerFactory(
dataConverter: $dataConverter,
rpc: Goridge::create(),
),
WorkerFactoryInterface::class => WorkerFactory::class,
DeclarationLocatorInterface::class => [self::class, 'initDeclarationLocator'],
WorkflowClientInterface::class => [self::class, 'initWorkflowClient'],

DeclarationLocatorInterface::class => static fn() => new DeclarationLocator(
reader: new AttributeReader(),
),

WorkflowClientInterface::class => static fn(
TemporalConfig $config,
DataConverterInterface $dataConverter,
PipelineProvider $pipelineProvider,
ServiceClientInterface $serviceClient,
): WorkflowClientInterface => new WorkflowClient(
serviceClient: $serviceClient,
options: $config->getClientOptions(),
converter: $dataConverter,
interceptorProvider: $pipelineProvider,
),
WorkersRegistryInterface::class => WorkersRegistry::class,
ScheduleClientInterface::class => [self::class, 'initScheduleClient'],
DataConverterInterface::class => [self::class, 'initDataConverter'],

ScheduleClientInterface::class => static fn(
TemporalConfig $config,
DataConverterInterface $dataConverter,
ServiceClientInterface $serviceClient,
): ScheduleClientInterface => new ScheduleClient(
serviceClient: $serviceClient,
options: $config->getClientOptions(),
converter: $dataConverter,
),

DataConverterInterface::class => static fn() => DataConverter::createDefault(),
PipelineProvider::class => [self::class, 'initPipelineProvider'],
ServiceClientInterface::class => [self::class, 'initServiceClient'],
ServiceClientInterface::class => static fn(
TemporalConfig $config,
): ServiceClientInterface => ServiceClient::create($config->getAddress()),
];
}

Expand All @@ -78,9 +109,11 @@ public function init(
AbstractKernel $kernel,
EnvironmentInterface $env,
ConsoleBootloader $console,
TokenizerListenerRegistryInterface $tokenizer,
DeclarationLocator $locator,
): void {
$this->initConfig($env);

$tokenizer->addListener($locator);
$console->addCommand(Commands\InfoCommand::class);
$kernel->addDispatcher($this->factory->make(Dispatcher::class));
}
Expand Down Expand Up @@ -133,41 +166,6 @@ protected function initConfig(EnvironmentInterface $env): void
);
}

protected function initWorkflowClient(
TemporalConfig $config,
DataConverterInterface $dataConverter,
PipelineProvider $pipelineProvider,
ServiceClientInterface $serviceClient,
): WorkflowClientInterface {
return new WorkflowClient(
serviceClient: $serviceClient,
options: $config->getClientOptions(),
converter: $dataConverter,
interceptorProvider: $pipelineProvider,
);
}

protected function initDataConverter(): DataConverterInterface
{
return DataConverter::createDefault();
}

protected function initWorkerFactory(DataConverterInterface $dataConverter,): TemporalWorkerFactoryInterface
{
return new TemporalWorkerFactory(
dataConverter: $dataConverter,
rpc: Goridge::create(),
);
}

protected function initDeclarationLocator(ClassesInterface $classes,): DeclarationLocatorInterface
{
return new DeclarationLocator(
classes: $classes,
reader: new AttributeReader(),
);
}

protected function initPipelineProvider(TemporalConfig $config, FactoryInterface $factory): PipelineProvider
{
/** @var Interceptor[] $interceptors */
Expand All @@ -182,21 +180,4 @@ protected function initPipelineProvider(TemporalConfig $config, FactoryInterface

return new SimplePipelineProvider($interceptors);
}

protected function initServiceClient(TemporalConfig $config): ServiceClientInterface
{
return ServiceClient::create($config->getAddress());
}

protected function initScheduleClient(
TemporalConfig $config,
DataConverterInterface $dataConverter,
ServiceClientInterface $serviceClient,
): ScheduleClientInterface {
return new ScheduleClient(
serviceClient: $serviceClient,
options: $config->getClientOptions(),
converter: $dataConverter,
);
}
}
19 changes: 18 additions & 1 deletion src/Commands/InfoCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ public function perform(
foreach ($workflows as $workflow) {
$table->addRow([
\sprintf('<fg=green>%s</>', $workflow['name']),
$workflow['class'] . "\n" . \sprintf('<fg=blue>%s</>', \str_replace($rootDir, '', $workflow['file'])),
$workflow['class'] . "\n" . \sprintf(
'<fg=blue>%s</>',
self::normalizePath($rootDir, $workflow['file']),
),
$workflow['task_queue'],
]);
}
Expand Down Expand Up @@ -100,4 +103,18 @@ public function perform(

return self::SUCCESS;
}

/**
* @param non-empty-string $rootDir
* @param non-empty-string $file
*/
private static function normalizePath(string $rootDir, string $file): string
{
$file = \str_replace('\\', '/', $file);
$rootDir = \str_replace('\\', '/', $rootDir);

return \str_starts_with($file, $rootDir)
? \substr($file, \strlen($rootDir))
: $file;
}
}
44 changes: 31 additions & 13 deletions src/DeclarationLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,50 @@
namespace Spiral\TemporalBridge;

use Spiral\Attributes\ReaderInterface;
use Spiral\Tokenizer\ClassesInterface;
use Spiral\Core\Attribute\Singleton;
use Spiral\Tokenizer\Attribute\TargetAttribute;
use Spiral\Tokenizer\TokenizationListenerInterface;
use Temporal\Activity\ActivityInterface;
use Temporal\Workflow\WorkflowInterface;

final class DeclarationLocator implements DeclarationLocatorInterface
#[Singleton]
#[TargetAttribute(WorkflowInterface::class)]
#[TargetAttribute(ActivityInterface::class)]
final class DeclarationLocator implements DeclarationLocatorInterface, TokenizationListenerInterface
{
private array $declarations = [];

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

public function getDeclarations(): iterable
{
foreach ($this->classes->getClasses() as $class) {
if ($class->isAbstract() || $class->isInterface() || $class->isEnum()) {
continue;
foreach ($this->declarations as $type => $classes) {
foreach ($classes as $class) {
yield $type => $class;
}
}
}

foreach (\array_merge($class->getInterfaces(), [$class]) as $type) {
if ($this->reader->firstClassMetadata($type, WorkflowInterface::class) !== null) {
yield WorkflowInterface::class => $class;
} elseif ($this->reader->firstClassMetadata($type, ActivityInterface::class) !== null) {
yield ActivityInterface::class => $class;
}
public function listen(\ReflectionClass $class): void
{
if ($class->isAbstract() || $class->isInterface() || $class->isEnum()) {
return;
}

foreach (\array_merge($class->getInterfaces(), [$class]) as $type) {
if ($this->reader->firstClassMetadata($type, WorkflowInterface::class) !== null) {
$this->declarations[WorkflowInterface::class][] = $class;
} elseif ($this->reader->firstClassMetadata($type, ActivityInterface::class) !== null) {
$this->declarations[ActivityInterface::class][] = $class;
}
}
}

public function finalize(): void
{
// do nothing
}
}
4 changes: 2 additions & 2 deletions tests/src/Commands/InfoCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function testInfo(): void
{
$result = $this->runCommand('temporal:info');

$this->assertSame(
$this->assertStringEqualsStringIgnoringLineEndings(
<<<'OUTPUT'

Workflows
Expand All @@ -57,7 +57,7 @@ public function testInfoWithActivities(): void
'--show-activities' => true,
]);

$this->assertSame(
$this->assertStringEqualsStringIgnoringLineEndings(
<<<'OUTPUT'

Workflows
Expand Down
29 changes: 11 additions & 18 deletions tests/src/DeclarationLocatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,14 @@ protected function setUp(): void
{
parent::setUp();

$this->locator = new DeclarationLocator(
$this->classes = m::mock(ClassesInterface::class),
new AttributeReader()
);
$this->locator = new DeclarationLocator(new AttributeReader());
}

public function testEnumClassesShouldBeSkipped(): void
{
$this->classes->shouldReceive('getClasses')->once()->andReturn([
new \ReflectionClass(TestEnum::class),
new \ReflectionClass(TestAbstractClass::class),
new \ReflectionClass(TestInterface::class),
]);
$this->locator->listen(new \ReflectionClass(TestEnum::class));
$this->locator->listen(new \ReflectionClass(TestAbstractClass::class));
$this->locator->listen(new \ReflectionClass(TestInterface::class));

$result = [];

Expand All @@ -45,15 +40,13 @@ public function testEnumClassesShouldBeSkipped(): void

public function testWorkflowsShouldBeRegistered(): void
{
$this->classes->shouldReceive('getClasses')->once()->andReturn([
new \ReflectionClass(TestEnum::class),
new \ReflectionClass(TestAbstractClass::class),
new \ReflectionClass(TestInterface::class),
$workflow1 = new \ReflectionClass(TestWorkflowClass::class),
$workflow2 = new \ReflectionClass(TestWorkflowClassWithInterface::class),
$activity1 = new \ReflectionClass(TestActivityClass::class),
$activity2 = new \ReflectionClass(TestActivityClassWithInterface::class),
]);
$this->locator->listen(new \ReflectionClass(TestEnum::class));
$this->locator->listen(new \ReflectionClass(TestAbstractClass::class));
$this->locator->listen(new \ReflectionClass(TestInterface::class));
$this->locator->listen($workflow1 = new \ReflectionClass(TestWorkflowClass::class));
$this->locator->listen($workflow2 = new \ReflectionClass(TestWorkflowClassWithInterface::class));
$this->locator->listen($activity1 = new \ReflectionClass(TestActivityClass::class));
$this->locator->listen($activity2 = new \ReflectionClass(TestActivityClassWithInterface::class));

$result = [];

Expand Down
Loading