diff --git a/.editorconfig b/.editorconfig
index 9866c39..d2e3f8e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,3 +9,6 @@ insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
+
+[*.json]
+indent_size = 2
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 14ecdf0..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Changelog
-
-All notable changes to `temporal-bridge` will be documented in this file.
-
-## 1.0.0 - 202X-XX-XX
-
-- initial release
diff --git a/README.md b/README.md
index 2a6af50..f55d6dc 100644
--- a/README.md
+++ b/README.md
@@ -9,531 +9,24 @@
[Temporal](https://temporal.io/) is the simple, scalable open source way to write and run reliable cloud applications.
-## Temporal screencasts
-[](https://youtu.be/goulj2CRNOY)
-
## Requirements
Make sure that your server is configured with following PHP version and extensions:
- PHP 8.1+
-- Spiral framework 3.0+
-
-## Installation
-
-You can install the package via composer:
-
-```bash
-composer require spiral/temporal-bridge
-```
-
-After package install you need to register bootloader from the package.
-
-```php
-protected const LOAD = [
- // ...
- \Spiral\TemporalBridge\Bootloader\TemporalBridgeBootloader::class,
-];
-```
-
-> Note: if you are using [`spiral-packages/discoverer`](https://github.com/spiral-packages/discoverer),
-> you don't need to register bootloader by yourself.
-
-#### Configuration
-
-The package is already configured by default, use these features only if you need to change the default configuration.
-The package provides the ability to configure `address`, `namespace`, `defaultWorker`, `workers` parameters.
-Create file `app/config/temporal.php` and configure options. For example:
-
-```php
-declare(strict_types=1);
-
-use Temporal\Worker\WorkerFactoryInterface;
-use Temporal\Worker\WorkerOptions;
-
-return [
- 'address' => env('TEMPORAL_ADDRESS', 'localhost:7233'),
- 'namespace' => 'App\\Workflow',
- 'defaultWorker' => WorkerFactoryInterface::DEFAULT_TASK_QUEUE,
- 'workers' => [
- 'workerName' => WorkerOptions::new()
- ],
-];
-```
-
-#### RoadRunner configuration
-
-Add `temporal` plugin section in your RoadRunner `rr.yaml` config:
-
-```yaml
-temporal:
- address: localhost:7233
- activities:
- num_workers: 10
-```
-
-#### Temporal
-
-You can run temporal server via docker by using the example below:
-
-> You can find official docker compose files here https://github.com/temporalio/docker-compose
-
-```yaml
-version: '3.5'
-
-services:
- postgresql:
- container_name: temporal-postgresql
- image: postgres:13
- environment:
- POSTGRES_PASSWORD: temporal
- POSTGRES_USER: temporal
- ports:
- - 5432:5432
-
- temporal:
- container_name: temporal
- image: temporalio/auto-setup:1.14.2
- depends_on:
- - postgresql
- environment:
- - DB=postgresql
- - DB_PORT=5432
- - POSTGRES_USER=temporal
- - POSTGRES_PWD=temporal
- - POSTGRES_SEEDS=postgresql
- - DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development.yaml
- ports:
- - 7233:7233
- volumes:
- - ./temporal:/etc/temporal/config/dynamicconfig
-
- temporal-web:
- container_name: temporal-web
- image: temporalio/web:1.13.0
- depends_on:
- - temporal
- environment:
- - TEMPORAL_GRPC_ENDPOINT=temporal:7233
- - TEMPORAL_PERMIT_WRITE_API=true
- ports:
- - 8088:8088
-```
-
-> Please make sure that a configuration file for temporal server exists.
-> `mkdir temporal && touch temporal/development.yaml`
-
-## Creating workflow
-
-You are able to create a new workflow via console command:
-
-```bash
-php app.php temporal:make-workflow MySuperWorkflow
-```
-
-The command will generate the following files with default namespace `App\Workflow`:
-
-```
-project/
- src/
- Workflow/
- MySuperWorkflow/
- MySuperWorkflowInterface
- MySuperWorkflow
-```
-
-> You can redefine default namespace via `app/config/temporal.php` config file.
-
-#### Workflow with activity classes
-
-```bash
-php app.php temporal:make-workflow MySuperWorkflow --with-activity
-```
-
-```
-project/
- src/
- Workflow/
- MySuperWorkflow/
- ...
- MySuperWorkflowHandlerInterface
- MySuperWorkflowHandler
-```
-
-#### Workflow with handler classes
-
-```bash
-php app.php temporal:make-workflow MySuperWorkflow --with-handler
-```
-
-```
-project/
- src/
- Workflow/
- MySuperWorkflow/
- ...
- MySuperWorkflowActivityInterface
- MySuperWorkflowActivity
-```
-
-> You can mixin options `--with-activity --with-handler`
-
-#### Workflow method name definition
-
-```bash
-temporal:make-workflow PingSite -m ping
-```
-
-```php
-#[WorkflowInterface]
-interface PingSiteWorkflowInterface
-{
- #[WorkflowMethod]
- public function ping(string $name): \Generator;
-}
-```
-
-#### Workflow method parameters definition
-
-```bash
-temporal:make-workflow PingSite ... -p url:string -p name:string
-```
-
-```php
-#[WorkflowInterface]
-interface PingSiteWorkflowInterface
-{
- #[WorkflowMethod]
- public function ping(string $url, string $name): \Generator;
-}
-```
-
-#### Workflow query methods definition
-
-```bash
-temporal:make-workflow PingSite ... -r getStatusCode -r getHeaders:array
-```
-
-```php
-#[WorkflowInterface]
-interface PingSiteWorkflowInterface
-{
- #[WorkflowMethod]
- public function ping(...): \Generator;
-
- #[QueryMethod]
- function getStatusCode(): string;
-
- #[QueryMethod]
- function getHeaders(): array;
-}
-```
-
-#### Workflow with namespace definition
-
-```bash
-temporal:make-workflow Domain\\MyPackage\\MoneyTransfer ... -s withdraw -s deposit
-```
-
-## Creating workflow from presets
-
-The package provides the ability to create predefined Workflows. Presets for the package can be provided via third-party
-packages.
-
-**Example of usage**
-
-```bash
-php app.php temporal:make-preset subscribtion-trial CustomerTrialSubscription
-```
-
-A preset will create all necessary classes.
-
-> You can show list of available presets using the console command `php app.php temporal:presets`
-
-#### Creating a preset
-
-A preset class should implement `Spiral\TemporalBridge\Preset\PresetInterface` and should have an
-attribute `Spiral\TemporalBridge\Preset\WorkflowPreset`
-
-```php
-use Spiral\TemporalBridge\Generator\WorkflowInterfaceGenerator;
-use Spiral\TemporalBridge\Generator\SignalWorkflowGenerator;
-use Spiral\TemporalBridge\Generator\ActivityInterfaceGenerator;
-use Spiral\TemporalBridge\Generator\ActivityGenerator;
-use Spiral\TemporalBridge\Generator\HandlerInterfaceGenerator;
-use Spiral\TemporalBridge\Generator\HandlerGenerator;
-use Spiral\TemporalBridge\Preset\PresetInterface;
-use Spiral\TemporalBridge\Preset\WorkflowPreset;
-
-#[WorkflowPreset('signal')]
-final class SignalWorkflow implements PresetInterface
-{
- public function getDescription(): ?string
- {
- return 'Workflow with signals';
- }
-
- public function generators(Context $context): array
- {
- $generators = [
- 'WorkflowInterface' => new WorkflowInterfaceGenerator(),
- 'Workflow' => new SignalWorkflowGenerator(),
- ];
-
- if ($context->hasActivity()) {
- $generators = \array_merge($generators, [
- 'ActivityInterface' => new ActivityInterfaceGenerator(),
- 'Activity' => new ActivityGenerator(),
- ]);
- }
-
- if ($context->hasHandler()) {
- $generators = \array_merge($generators, [
- 'HandlerInterface' => new HandlerInterfaceGenerator(),
- 'Handler' => new HandlerGenerator(),
- ]);
- }
-
- return $generators;
- }
-}
-```
-
-**Please note: If you are using `WorkflowPreset` you have to add a directory with presets to tokenizer.**
-
-```php
-use Spiral\Tokenizer\Bootloader\TokenizerBootloader;
-
-class MyBootloader extends \Spiral\Boot\Bootloader\Bootloader
-{
- protected const DEPENDENCIES = [
- TokenizerBootloader::class
- ];
-
- public function start(TokenizerBootloader $tokenizer)
- {
- $tokenizer->addDirectory(__DIR__..'/presets');
- }
-}
-```
-
-You can omit `WorkflowPreset` attribute and register your preset via Bootloader
-
-```php
-use Spiral\TemporalBridge\Preset\PresetRegistryInterface;
-
-class MyBootloader extends \Spiral\Boot\Bootloader\Bootloader
-{
- public function start(PresetRegistryInterface $registry)
- {
- $registry->register('signal', new SignalWorkflow());
- }
-}
-```
-
-#### Workflow signal methods definition
-
-```bash
-temporal:make-workflow MoneyTransfer ... -s withdraw -s deposit
-```
-
-```php
-#[WorkflowInterface]
-interface MoneyTransferWorkflowInterface
-{
- #[WorkflowMethod]
- public function ping(...): \Generator;
-
- #[SignalMethod]
- function withdraw(): void;
-
- #[SignalMethod]
- function deposit(): void;
-}
-```
-
-> You may discover available workflow samples [here](https://github.com/temporalio/samples-php)
-
-## Usage
-
-Configure temporal address via env variables `.env`
-
-```
-TEMPORAL_ADDRESS=127.0.0.1:7233
-```
-
-### Running workflow
-
-```php
-class PingController
-{
- public function ping(StoreRequest $request, PingSiteHandler $handler): void
- {
- $this->handler->handle(
- $request->url,
- $request->name
- );
- }
-}
-```
-
-## Running workflows and activities with different task queue
-
-Add a `Spiral\TemporalBridge\Attribute\AssignWorker` attribute to your Workflow or Activity with the `name` of the worker.
-This Workflow or Activity will be processed by the specified worker.
-
-**Workflow example:**
-
-```php
- [
- 'worker1' => WorkerOptions::new()
- ],
-];
-```
-
-Or via application bootloader
-
-```php
-register(
- 'worker1',
- WorkerOptions::new()->...
- );
- }
-}
-```
-
-### Custom data converters
-
-Temporal SDK hsa an ability to define custom data converters
-
-By default it uses the following list of data converters:
-
- - `Temporal\DataConverter\NullConverter`
- - `Temporal\DataConverter\BinaryConverter`
- - `Temporal\DataConverter\ProtoJsonConverter`
- - `Temporal\DataConverter\JsonConverter`
-
-If you want to specify custom list of data converters you need to bind your own implementation for
-`Temporal\DataConverter\DataConverterInterface` via container.
-
-```php
-use Spiral\Boot\Bootloader\Bootloader;
-use Temporal\DataConverter\DataConverter;
-use Temporal\DataConverter\DataConverterInterface;
-
-class AppBootloader extends Bootloader
-{
- protected const SINGLETONS = [
- DataConverterInterface::class => [self::class, 'initDataConverter'],
- ];
-
- protected function initDataConverter(): DataConverterInterface
- {
- return new DataConverter(
- new \Temporal\DataConverter\NullConverter(),
- new \Temporal\DataConverter\BinaryConverter(),
- new \App\DataConverter\JmsSerializerConverter(),
- new \Temporal\DataConverter\ProtoJsonConverter(),
- new \Temporal\DataConverter\JsonConverter(),
- );
- }
-}
-```
-
-## Testing
-
-```bash
-composer test
-```
-
-## Changelog
-
-Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
-
-## Contributing
-
-Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.
+- Spiral Framework 3.0+
-## Security Vulnerabilities
+## Documentation, Installation, and Usage Instructions
-Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
+See the [documentation](https://spiral.dev/docs/temporal-configuration) for detailed installation and usage instructions.
-## Credits
+## Useful links
-- [butschster](https://github.com/spiral)
-- [All Contributors](../../contributors)
+- [Temporal screencasts](https://youtu.be/goulj2CRNOY)
+- [Fault tolerant workflow orchestration on PHP](https://www.youtube.com/watch?v=pdxHkIqX62A)
+- [Fault tolerant workflow orchestration on PHP (rus)](https://www.youtube.com/watch?v=mNsjdTnanA4)
+- [Temporal PHP SDK](https://github.com/temporalio/sdk-php/)
## License
-The MIT License (MIT). Please see [License File](LICENSE) for more information.
+MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information. Maintained by [Spiral Scout](https://spiralscout.com).
diff --git a/composer.json b/composer.json
index 393d0d9..1f49803 100644
--- a/composer.json
+++ b/composer.json
@@ -8,13 +8,31 @@
"workflow",
"temporal"
],
- "homepage": "https://github.com/spiral/temporal-bridge",
+ "homepage": "https://spiral.dev",
+ "support": {
+ "issues": "https://github.com/spiral/temporal-bridge/issues",
+ "source": "https://github.com/spiral/temporal-bridge",
+ "docs": "https://spiral.dev/docs",
+ "forum": "https://forum.spiral.dev",
+ "chat": "https://discord.gg/V6EK4he"
+ },
"license": "MIT",
"authors": [
{
- "name": "butschster",
- "email": "butschster@gmail.com",
- "role": "Developer"
+ "name": "Anton Titov (wolfy-j)",
+ "email": "wolfy-j@spiralscout.com"
+ },
+ {
+ "name": "Pavel Butchnev (butschster)",
+ "email": "pavel.buchnev@spiralscout.com"
+ },
+ {
+ "name": "Aleksei Gagarin (roxblnfk)",
+ "email": "alexey.gagarin@spiralscout.com"
+ },
+ {
+ "name": "Maksim Smakouz (msmakouz)",
+ "email": "maksim.smakouz@spiralscout.com"
}
],
"require": {
@@ -22,13 +40,13 @@
"spiral/boot": "^3.0",
"spiral/attributes": "^2.8 || ^3.0",
"spiral/tokenizer": "^3.0",
+ "spiral/scaffolder": "^3.0",
"spiral/roadrunner-bridge": "^2.0 || ^3.0",
- "nette/php-generator": "^4.0",
"temporal/sdk": "^1.3 || ^2.0"
},
"require-dev": {
"spiral/framework": "^3.0",
- "spiral/testing": "^2.0",
+ "spiral/testing": "^2.6",
"vimeo/psalm": "^5.17"
},
"autoload": {
@@ -42,9 +60,15 @@
"Spiral\\TemporalBridge\\Tests\\": "tests/src"
}
},
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/roadrunner-server"
+ }
+ ],
"scripts": {
"test": "vendor/bin/phpunit",
- "psalm": "vendor/bin/psalm --config=psalm.xml ./src"
+ "psalm": "vendor/bin/psalm --no-cache --config=psalm.xml ./src"
},
"config": {
"sort-packages": true,
diff --git a/psalm.xml b/psalm.xml
index 0200c83..d4a2702 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -8,22 +8,17 @@
findUnusedCode="false"
>
-
+
-
+
-
+
-
+
+
-
-
-
-
-
-
-
+
diff --git a/src/Bootloader/PrototypeBootloader.php b/src/Bootloader/PrototypeBootloader.php
index 734ad93..29bbb0e 100644
--- a/src/Bootloader/PrototypeBootloader.php
+++ b/src/Bootloader/PrototypeBootloader.php
@@ -6,18 +6,19 @@
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Prototype\Bootloader\PrototypeBootloader as BasePrototypeBootloader;
-use Spiral\TemporalBridge\WorkflowManagerInterface;
use Temporal\Client\WorkflowClientInterface;
class PrototypeBootloader extends Bootloader
{
- protected const DEPENDENCIES = [
- BasePrototypeBootloader::class,
- ];
+ public function defineDependencies(): array
+ {
+ return [
+ BasePrototypeBootloader::class,
+ ];
+ }
public function boot(BasePrototypeBootloader $prototype): void
{
$prototype->bindProperty('workflow', WorkflowClientInterface::class);
- $prototype->bindProperty('workflowManager', WorkflowManagerInterface::class);
}
}
diff --git a/src/Bootloader/ScaffolderBootloader.php b/src/Bootloader/ScaffolderBootloader.php
new file mode 100644
index 0000000..678ac89
--- /dev/null
+++ b/src/Bootloader/ScaffolderBootloader.php
@@ -0,0 +1,51 @@
+configureCommands($console);
+ $this->configureDeclarations($scaffolder);
+ }
+
+ private function configureCommands(ConsoleBootloader $console): void
+ {
+ $console->addCommand(WorkflowCommand::class);
+ $console->addCommand(ActivityCommand::class);
+ }
+
+ private function configureDeclarations(BaseScaffolderBootloader $scaffolder): void
+ {
+ $scaffolder->addDeclaration(WorkflowDeclaration::TYPE, [
+ 'namespace' => 'Endpoint\\Temporal\\Workflow',
+ 'postfix' => 'Workflow',
+ 'class' => WorkflowDeclaration::class,
+ ]);
+
+ $scaffolder->addDeclaration(ActivityDeclaration::TYPE, [
+ 'namespace' => 'Endpoint\\Temporal\\Activity',
+ 'postfix' => 'Activity',
+ 'class' => ActivityDeclaration::class,
+ ]);
+ }
+}
diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php
index 7c2fb86..1555eab 100644
--- a/src/Bootloader/TemporalBridgeBootloader.php
+++ b/src/Bootloader/TemporalBridgeBootloader.php
@@ -16,16 +16,11 @@
use Spiral\RoadRunnerBridge\Bootloader\RoadRunnerBootloader;
use Spiral\TemporalBridge\Commands;
use Spiral\TemporalBridge\Config\TemporalConfig;
+use Spiral\TemporalBridge\DeclarationLocator;
use Spiral\TemporalBridge\DeclarationLocatorInterface;
use Spiral\TemporalBridge\Dispatcher;
-use Spiral\TemporalBridge\Preset\PresetRegistry;
-use Spiral\TemporalBridge\Preset\PresetRegistryInterface;
use Spiral\TemporalBridge\WorkersRegistry;
use Spiral\TemporalBridge\WorkersRegistryInterface;
-use Spiral\TemporalBridge\Workflow\WorkflowManager;
-use Spiral\TemporalBridge\WorkflowManagerInterface;
-use Spiral\TemporalBridge\WorkflowPresetLocator;
-use Spiral\TemporalBridge\WorkflowPresetLocatorInterface;
use Spiral\Tokenizer\ClassesInterface;
use Temporal\Client\ClientOptions;
use Temporal\Client\GRPC\ServiceClient;
@@ -40,40 +35,39 @@
class TemporalBridgeBootloader extends Bootloader
{
- protected const SINGLETONS = [
- WorkflowPresetLocatorInterface::class => [self::class, 'initWorkflowPresetLocator'],
- WorkflowManagerInterface::class => WorkflowManager::class,
- WorkerFactoryInterface::class => [self::class, 'initWorkerFactory'],
- DeclarationLocatorInterface::class => [self::class, 'initDeclarationLocator'],
- WorkflowClientInterface::class => [self::class, 'initWorkflowClient'],
- WorkersRegistryInterface::class => [self::class, 'initWorkersRegistry'],
- PresetRegistryInterface::class => PresetRegistry::class,
- DataConverterInterface::class => [self::class, 'initDataConverter'],
- ];
+ public function defineDependencies(): array
+ {
+ return [
+ ConsoleBootloader::class,
+ RoadRunnerBootloader::class,
+ ScaffolderBootloader::class,
+ ];
+ }
- protected const DEPENDENCIES = [
- ConsoleBootloader::class,
- RoadRunnerBootloader::class,
- ];
+ public function defineSingletons(): array
+ {
+ return [
+ WorkerFactoryInterface::class => [self::class, 'initWorkerFactory'],
+ DeclarationLocatorInterface::class => [self::class, 'initDeclarationLocator'],
+ WorkflowClientInterface::class => [self::class, 'initWorkflowClient'],
+ WorkersRegistryInterface::class => [self::class, 'initWorkersRegistry'],
+ DataConverterInterface::class => [self::class, 'initDataConverter'],
+ ];
+ }
public function __construct(
- private readonly ConfiguratorInterface $config
+ private readonly ConfiguratorInterface $config,
) {
}
public function init(
AbstractKernel $kernel,
EnvironmentInterface $env,
- ConsoleBootloader $console,
- FactoryInterface $factory
+ FactoryInterface $factory,
): void {
$this->initConfig($env);
$kernel->addDispatcher($factory->make(Dispatcher::class));
-
- $console->addCommand(Commands\MakeWorkflowCommand::class);
- $console->addCommand(Commands\MakePresetCommand::class);
- $console->addCommand(Commands\PresetListCommand::class);
}
public function addWorkerOptions(string $worker, WorkerOptions $options): void
@@ -81,38 +75,27 @@ public function addWorkerOptions(string $worker, WorkerOptions $options): void
$this->config->modify(TemporalConfig::CONFIG, new Append('workers', $worker, $options));
}
- protected function initWorkflowPresetLocator(
- FactoryInterface $factory,
- ClassesInterface $classes
- ): WorkflowPresetLocatorInterface {
- return new WorkflowPresetLocator(
- factory: $factory,
- classes: $classes,
- reader: new AttributeReader()
- );
- }
-
protected function initConfig(EnvironmentInterface $env): void
{
$this->config->setDefaults(
TemporalConfig::CONFIG,
[
'address' => $env->get('TEMPORAL_ADDRESS', '127.0.0.1:7233'),
- 'namespace' => 'App\\Workflow',
+ 'namespace' => 'App\\Endpoint\\Temporal\\Workflow',
'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', WorkerFactoryInterface::DEFAULT_TASK_QUEUE),
'workers' => [],
- ]
+ ],
);
}
protected function initWorkflowClient(
TemporalConfig $config,
- DataConverterInterface $dataConverter
+ DataConverterInterface $dataConverter,
): WorkflowClientInterface {
return WorkflowClient::create(
serviceClient: ServiceClient::create($config->getAddress()),
options: (new ClientOptions())->withNamespace($config->getTemporalNamespace()),
- converter: $dataConverter
+ converter: $dataConverter,
);
}
@@ -122,27 +105,27 @@ protected function initDataConverter(): DataConverterInterface
}
protected function initWorkerFactory(
- DataConverterInterface $dataConverter
+ DataConverterInterface $dataConverter,
): WorkerFactoryInterface {
return new WorkerFactory(
dataConverter: $dataConverter,
- rpc: Goridge::create()
+ rpc: Goridge::create(),
);
}
protected function initDeclarationLocator(
- ClassesInterface $classes
+ ClassesInterface $classes,
): DeclarationLocatorInterface {
- return new \Spiral\TemporalBridge\DeclarationLocator(
+ return new DeclarationLocator(
classes: $classes,
- reader: new AttributeReader()
+ reader: new AttributeReader(),
);
}
protected function initWorkersRegistry(
WorkerFactoryInterface $workerFactory,
FinalizerInterface $finalizer,
- TemporalConfig $config
+ TemporalConfig $config,
): WorkersRegistryInterface {
return new WorkersRegistry($workerFactory, $finalizer, $config);
}
diff --git a/src/Commands/MakePresetCommand.php b/src/Commands/MakePresetCommand.php
deleted file mode 100644
index 7172b56..0000000
--- a/src/Commands/MakePresetCommand.php
+++ /dev/null
@@ -1,60 +0,0 @@
-getPresets() as $name => $preset) {
- $registry->register($name, $preset);
- }
-
- $context = $this->getContext();
- $presetName = $this->argument('preset');
-
- $preset = $registry->findByName($presetName);
- $preset->init($context);
- $generators = $preset->generators($context);
-
- if ($generators === []) {
- $this->error(\sprintf('Generators for preset [%s] are not found.', $presetName));
- return self::INVALID;
- }
-
- if ($this->verifyExistsWorkflow($context)) {
- return self::SUCCESS;
- }
-
- \assert($this->output instanceof OutputInterface);
-
- $generator->generate(
- $this->output,
- $context,
- $generators
- );
-
- return self::SUCCESS;
- }
-}
diff --git a/src/Commands/MakeWorkflowCommand.php b/src/Commands/MakeWorkflowCommand.php
deleted file mode 100644
index 5b97bfd..0000000
--- a/src/Commands/MakeWorkflowCommand.php
+++ /dev/null
@@ -1,71 +0,0 @@
-getContext();
-
- if ($this->verifyExistsWorkflow($context)) {
- return self::SUCCESS;
- }
-
- \assert($this->output instanceof OutputInterface);
-
- $generator->generate(
- $this->output,
- $context,
- $this->defineGenerators($context)
- );
-
- return self::SUCCESS;
- }
-
- private function defineGenerators(Context $context): array
- {
- $generators = [
- 'WorkflowInterface' => new WorkflowInterfaceGenerator(),
- 'Workflow' => new WorkflowGenerator(),
- ];
-
- if ($context->hasActivity()) {
- $generators = \array_merge($generators, [
- 'ActivityInterface' => new ActivityInterfaceGenerator(),
- 'Activity' => new ActivityGenerator(),
- ]);
- }
-
- if ($context->hasHandler()) {
- $generators = \array_merge($generators, [
- 'HandlerInterface' => new HandlerInterfaceGenerator(),
- 'Handler' => new HandlerGenerator(),
- ]);
- }
-
- return $generators;
- }
-}
diff --git a/src/Commands/PresetListCommand.php b/src/Commands/PresetListCommand.php
deleted file mode 100644
index 569a007..0000000
--- a/src/Commands/PresetListCommand.php
+++ /dev/null
@@ -1,55 +0,0 @@
-getPresets() as $name => $preset) {
- $registry->register($name, $preset);
- }
-
- $list = $registry->getList();
- if ($list === []) {
- $this->info('No available Workflow presets found.');
-
- return self::SUCCESS;
- }
-
- \assert($this->output instanceof OutputInterface);
-
- $table = new Table($this->output);
-
- $table->setHeaders(['name', 'description']);
-
- foreach ($list as $name => $preset) {
- $table->addRow([$name, \implode("\n", \str_split(
- (string) $preset->getDescription(), self::DESCRIPTION_LENGTH)
- )]);
- }
-
- $table->render();
-
- $this->newLine();
- $this->info('Use the command below to make a workflow: ');
- $this->comment('php app.php temporal:make-preset preset-name MySuperWorkflow');
- $this->newLine();
-
- return self::SUCCESS;
- }
-}
diff --git a/src/Commands/Scaffolder/ActivityCommand.php b/src/Commands/Scaffolder/ActivityCommand.php
new file mode 100644
index 0000000..6537e0b
--- /dev/null
+++ b/src/Commands/Scaffolder/ActivityCommand.php
@@ -0,0 +1,57 @@
+createDeclaration(ActivityDeclaration::class, [
+ 'activityName' => $this->activityName,
+ ]);
+
+ if ($this->worker !== WorkerFactoryInterface::DEFAULT_TASK_QUEUE) {
+ $declaration->assignWorker($this->worker);
+ }
+
+ foreach ($this->methods as $method) {
+ if (\str_contains($method, ':')) {
+ $array = \explode(separator: ':', string: $method, limit: 2);
+ \assert(\count($array) === 2);
+ [$method, $type] = $array;
+ } else {
+ $type = 'mixed';
+ }
+
+ $declaration->addMethod($method, $type);
+ }
+
+ $this->writeDeclaration($declaration);
+
+ return self::SUCCESS;
+ }
+}
diff --git a/src/Commands/Scaffolder/WorkflowCommand.php b/src/Commands/Scaffolder/WorkflowCommand.php
new file mode 100644
index 0000000..ebf42bf
--- /dev/null
+++ b/src/Commands/Scaffolder/WorkflowCommand.php
@@ -0,0 +1,64 @@
+createDeclaration(WorkflowDeclaration::class, [
+ 'workflowName' => $this->workflowName,
+ ]);
+
+ if ($this->worker !== WorkerFactoryInterface::DEFAULT_TASK_QUEUE) {
+ $declaration->assignWorker($this->worker);
+ }
+
+ foreach ($this->queryMethods as $method) {
+ if (\str_contains($method, ':')) {
+ $array = \explode(separator: ':', string: $method, limit: 2);
+ \assert(\count($array) === 2);
+ [$method, $type] = $array;
+ } else {
+ $type = 'mixed';
+ }
+
+ $declaration->addQueryMethod($method, $type);
+ }
+
+ foreach ($this->signalMethods as $name) {
+ $declaration->addSignalMethod($name);
+ }
+
+ $this->writeDeclaration($declaration);
+
+ return self::SUCCESS;
+ }
+}
diff --git a/src/Commands/WithContext.php b/src/Commands/WithContext.php
deleted file mode 100644
index d03670c..0000000
--- a/src/Commands/WithContext.php
+++ /dev/null
@@ -1,149 +0,0 @@
-getPath()) || $this->option('force')) {
- return false;
- }
-
- $question = new QuestionHelper();
-
- \assert($this->output instanceof OutputInterface);
- \assert($this->input instanceof InputInterface);
-
- return ! $question->ask(
- $this->input,
- $this->output,
- new ConfirmationQuestion(
- \sprintf(
- 'Workflow with given name [%s] exists. Some files can be overwritten. Would you like to continue?',
- $context->getBaseClass()
- )
- )
- );
- }
-
- public function getContext(): Context
- {
- \assert($this->container instanceof ContainerInterface);
-
- $config = $this->container->get(TemporalConfig::class);
- \assert($config instanceof TemporalConfig);
-
- $dirs = $this->container->get(DirectoriesInterface::class);
- \assert($dirs instanceof DirectoriesInterface);
-
- $name = $this->getNameInput();
- $namespace = $this->getNamespaceFromClass($name) ?? $config->getDefaultNamespace();
- $className = $this->qualifyClass($name, $namespace);
- $namespace = $namespace.'\\'.$className;
-
- $context = (new Context(
- $dirs->get('app').'src/Workflow/'.$className.'/',
- $namespace,
- $className,
- ))
- ->withActivityMethods(Utils::parseMethods((array)$this->option('activity')))
- ->withMethodParameters(Utils::parseParameters((array)$this->option('param')))
- ->withHandlerMethod($this->option('method') ?? 'handle')
- ->withSignalMethods(Utils::parseMethods((array)$this->option('signal')))
- ->withQueryMethods(Utils::parseMethods((array)$this->option('query')));
-
- if ($this->option('with-handler') ?? false) {
- $context = $context->withHandler();
- }
-
- if ($this->option('with-activity') ?? false) {
- $context = $context->withActivity();
- }
-
- if ($this->option('scheduled') ?? false) {
- $context = $context->withCronSchedule();
- }
-
- return $context;
- }
-
- protected function getPath(string $namespace, string $appDir): string
- {
- if (\str_starts_with($namespace, 'App')) {
- $namespace = \str_replace('App', 'src', $namespace);
- }
-
- return $appDir.\str_replace('\\', '/', $namespace).'/';
- }
-
- private function getNameInput(): string
- {
- return \trim($this->argument('name'));
- }
-
- private function getNamespaceFromClass(string $name): ?string
- {
- $namespace = \trim(\implode('\\', \array_slice(\explode('\\', $name), 0, -1)), '\\');
-
- return ! empty($namespace) ? $namespace : null;
- }
-
- private function qualifyClass(string $name, string $namespace): string
- {
- $name = \str_replace('/', '\\', $name);
- $name = \str_replace(['-', '_', '.'], ' ', $name);
- $name = \str_replace(' ', '', $name);
- if (\str_starts_with($name, $namespace)) {
- $name = \str_replace($namespace, '', $name);
- }
-
- $name = \ltrim($name, '\\/');
-
- return \ucwords($name);
- }
-}
diff --git a/src/Config/TemporalConfig.php b/src/Config/TemporalConfig.php
index 3a84343..78a28b4 100644
--- a/src/Config/TemporalConfig.php
+++ b/src/Config/TemporalConfig.php
@@ -14,7 +14,7 @@ final class TemporalConfig extends InjectableConfig
protected array $config = [
'address' => 'localhost:7233',
- 'namespace' => 'App\\Workflow',
+ 'namespace' => 'App\\Endpoint\\Temporal\\Workflow',
'temporalNamespace' => 'default',
'defaultWorker' => WorkerFactoryInterface::DEFAULT_TASK_QUEUE,
'workers' => [],
diff --git a/src/Exception/PresetNotFoundException.php b/src/Exception/PresetNotFoundException.php
deleted file mode 100644
index c6b9501..0000000
--- a/src/Exception/PresetNotFoundException.php
+++ /dev/null
@@ -1,10 +0,0 @@
-getClass());
- $class->addImplement($context->getClassInterfaceWithNamespace());
-
- $method = $class->addMethod('__construct')->setPublic();
-
- $method->addPromotedParameter('logger')
- ->setPrivate()
- ->setType(LoggerInterface::class);
-
- foreach ($context->getActivityMethods() as $method) {
- $class->addMember($method);
- $method
- ->addBody(
- \sprintf(
- '$this->logger->info(\'%s\', func_get_args());',
- 'Something special happens here.',
- )
- )
- ->addBody("\nreturn 'Success';");
- }
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(LoggerInterface::class),
- $context
- );
- }
-}
diff --git a/src/Generator/ActivityInterfaceGenerator.php b/src/Generator/ActivityInterfaceGenerator.php
deleted file mode 100644
index 50573a4..0000000
--- a/src/Generator/ActivityInterfaceGenerator.php
+++ /dev/null
@@ -1,34 +0,0 @@
-getClass(), $namespace);
- $class->addAttribute(ActivityInterface::class, ['prefix' => $context->getBaseClass('.')]);
-
- foreach ($context->getActivityMethods() as $method) {
- $class->addMember($method);
- $method
- ->setBody('')
- ->addAttribute(ActivityMethod::class);
- }
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(ActivityInterface::class)
- ->addUse(ActivityMethod::class),
- $context
- );
- }
-}
diff --git a/src/Generator/Context.php b/src/Generator/Context.php
deleted file mode 100644
index 63368eb..0000000
--- a/src/Generator/Context.php
+++ /dev/null
@@ -1,287 +0,0 @@
- */
- private array $activityMethods = [];
- /** @var array */
- private array $signalMethods = [];
- /** @var array */
- private array $queryMethods = [];
- /** @var array */
- private array $handlerParameters = [];
- private string $classPostfix = '';
-
- public function __construct(
- private readonly string $directory,
- private readonly string $namespace,
- private readonly string $baseClass,
- ) {
- }
-
- public function withClassPostfix(string $postfix): self
- {
- $this->classPostfix = \str_ends_with($this->baseClass, 'Workflow')
- ? \str_replace('Workflow', '', $postfix)
- : $postfix;
-
- return $this;
- }
-
- public function withCronSchedule(): self
- {
- $this->scheduled = true;
-
- return $this;
- }
-
- /**
- * @param Parameter[] $parameters
- */
- public function withMethodParameters(array $parameters): self
- {
- $this->handlerParameters = $parameters;
-
- return $this;
- }
-
- /**
- * @param Method[] $methods
- */
- public function withSignalMethods(array $methods): self
- {
- $this->signalMethods = $methods;
-
- return $this;
- }
-
- /**
- * @param Method[] $methods
- */
- public function withQueryMethods(array $methods): self
- {
- $this->queryMethods = $methods;
-
- return $this;
- }
-
- /**
- * @param non-empty-string $name
- */
- public function withHandlerMethod(string $name): self
- {
- $this->handlerMethod = $name;
-
- return $this;
- }
-
- public function withActivity(): self
- {
- $this->withActivity = true;
-
- return $this;
- }
-
- /**
- * @param Method[] $methods
- */
- public function withActivityMethods(array $methods): self
- {
- $this->activityMethods = $methods;
-
- return $this;
- }
-
- public function withHandler(): self
- {
- $this->withHandler = true;
-
- return $this;
- }
-
- /**
- * Get the namespace
- */
- public function getNamespace(): string
- {
- return $this->namespace;
- }
-
- /**
- * Get base class name without the namespace
- */
- public function getBaseClass(string $postfix = ''): string
- {
- return $this->baseClass.$postfix;
- }
-
- /**
- * Get base class interface without the namespace
- */
- public function getBaseClassInterface(string $postfix = ''): string
- {
- return $this->getBaseClass($postfix).self::INTERFACE;
- }
-
- /**
- * Get base class interface with the namespace
- */
- public function getBaseClassInterfaceWithNamespace(string $postfix = ''): string
- {
- return $this->getNamespace().'\\'.$this->getBaseClassInterface($postfix);
- }
-
- /**
- * Get current class name without the namespace
- */
- public function getClass(string $postfix = ''): string
- {
- if ($this->classPostfix !== '' && str_ends_with($this->baseClass, $this->classPostfix)) {
- return $this->getBaseClass($postfix);
- }
-
- return $this->baseClass.$this->classPostfix.$postfix;
- }
-
- /**
- * Get current class name with the namespace
- */
- public function getClassWithNamespace(string $postfix = ''): string
- {
- return $this->getNamespace().'\\'.$this->getClass($postfix);
- }
-
- /**
- * Get current class interface without the namespace
- */
- public function getClassInterface(string $postfix = ''): string
- {
- return $this->getClass($postfix).self::INTERFACE;
- }
-
- /**
- * Get current class interface with the namespace
- */
- public function getClassInterfaceWithNamespace(string $postfix = ''): string
- {
- return $this->getNamespace().'\\'.$this->getClassInterface($postfix);
- }
-
- public function getPath(): string
- {
- return $this->directory;
- }
-
- /**
- * Get current class file full path
- */
- public function getClassPath(): string
- {
- return $this->directory.$this->getClass().'.php';
- }
-
- /**
- * Get required query methods
- * @return Method[]
- */
- public function getSignalMethods(): array
- {
- return \array_map(fn($method) => clone $method, $this->signalMethods);
- }
-
- /**
- * Get required query methods
- * @return Method[]
- */
- public function getQueryMethods(): array
- {
- return \array_map(fn($method) => clone $method, $this->queryMethods);
- }
-
- /**
- * Check if workflow should be scheduled by cron expression
- */
- public function isScheduled(): bool
- {
- return $this->scheduled;
- }
-
- /**
- * Check if workflow should have activity classes
- */
- public function hasActivity(): bool
- {
- return $this->withActivity;
- }
-
- /**
- * Check if activity has defined methods
- */
- public function hasActivityMethods(): bool
- {
- return $this->activityMethods !== [];
- }
-
- /**
- * Get activity methods
- * @return Method[]
- */
- public function getActivityMethods(): array
- {
- if (! $this->hasActivityMethods()) {
- return [$this->handlerMethod => $this->getHandlerMethod()];
- }
-
- return \array_map(fn($method) => clone $method, $this->activityMethods);
- }
-
- /**
- * Check if workflow should have handler classes
- */
- public function hasHandler(): bool
- {
- return $this->withHandler;
- }
-
- /**
- * Check if default handler method is changed
- */
- public function isHandlerMethodNameChanged(): bool
- {
- return $this->handlerMethod !== self::HANDLER_METHOD;
- }
-
- /**
- * Get workflow handler method
- */
- public function getHandlerMethod(): Method
- {
- return (new Method($this->handlerMethod))
- ->setPublic()
- ->setReturnType('\Generator')
- ->setParameters($this->handlerParameters);
- }
-
-
- /**
- * Get workflow handler method name
- */
- public function getHandlerMethodName(): string
- {
- return $this->handlerMethod;
- }
-}
diff --git a/src/Generator/FileGeneratorInterface.php b/src/Generator/FileGeneratorInterface.php
deleted file mode 100644
index b97aa38..0000000
--- a/src/Generator/FileGeneratorInterface.php
+++ /dev/null
@@ -1,12 +0,0 @@
-writeln('Generating workflow files...');
-
- foreach ($generators as $name => $generator) {
- $c = clone $context;
-
- $generator->generate(
- $c->withClassPostfix($name),
- new PhpNamespace($c->getNamespace())
- )->print($this->files);
-
- $output->writeln(\sprintf(
- 'Class [%s] successfully generated.',
- $c->getClassWithNamespace()
- ));
- }
- }
-}
diff --git a/src/Generator/HandlerGenerator.php b/src/Generator/HandlerGenerator.php
deleted file mode 100644
index 92b8024..0000000
--- a/src/Generator/HandlerGenerator.php
+++ /dev/null
@@ -1,132 +0,0 @@
-getClass());
- $class->addImplement($context->getClassInterfaceWithNamespace());
-
- $constructor = $class
- ->addMethod('__construct')
- ->setPublic();
-
- $constructor->addPromotedParameter('manager')
- ->setPrivate()
- ->setType(WorkflowManagerInterface::class);
-
- $constructor->addPromotedParameter('logger')
- ->setPrivate()
- ->setType(LoggerInterface::class);
-
- $class->addMember($handlerMethod = $context->getHandlerMethod());
- $handlerMethod->setReturnType(RunningWorkflow::class);
-
- $handlerMethod->addBody($this->generateWorkflowInitialization($context));
- $handlerMethod->addBody($this->generateWorkflowSettingBody($context));
- $handlerMethod->addBody($this->generateRunScriptBody($context));
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(RunningWorkflow::class)
- ->addUse(WorkflowExecutionAlreadyStartedException::class)
- ->addUse(WorkflowIdReusePolicy::class)
- ->addUse(LoggerInterface::class)
- ->addUse(WorkflowManagerInterface::class),
- $context
- );
- }
-
- private function generateWorkflowInitialization(Context $context): string
- {
- $workflowClassName = $context->getBaseClass('WorkflowInterface');
-
- if ($context->isScheduled()) {
- return \sprintf(
- <<<'BODY'
-$workflow = $this->manager
- ->createScheduled(
- %s::class,
- '%s'
- );
-BODY
- ,
- $workflowClassName,
- '* * * * *'
- );
- }
-
- return \sprintf(
- <<<'BODY'
-$workflow = $this->manager
- ->create(%s::class);
-BODY
- ,
- $workflowClassName
- );
- }
-
- private function generateWorkflowSettingBody(Context $context): string
- {
- return <<<'BODY'
-// $workflow->assignId(
-// 'operation-id',
-// WorkflowIdReusePolicy::WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY
-// );
-
-// $workflow->withWorkflowRunTimeout(\Carbon\CarbonInterval::minutes(10))
-// ->withWorkflowTaskTimeout(\Carbon\CarbonInterval::minute())
-// ->withWorkflowExecutionTimeout(\Carbon\CarbonInterval::minutes(5));
-
-// $workflow->maxRetryAttempts(5)
-// ->backoffRetryCoefficient(1.5)
-// ->initialRetryInterval(\Carbon\CarbonInterval::seconds(5))
-// ->maxRetryInterval(\Carbon\CarbonInterval::seconds(20));
-BODY
- ;
- }
-
- /**
- * @param Context $context
- * @return string
- */
- private function generateRunScriptBody(Context $context): string
- {
- $runArgs = Utils::buildMethodArgs($context->getHandlerMethod()->getParameters());
-
- return \sprintf(
- <<<'BODY'
-try {
- $run = $workflow->run(%s);
-
- $this->logger->info('Workflow [%s] has been run', [
- 'id' => $run->getExecution()->getID()
- ]);
-
- return $run;
-} catch (WorkflowExecutionAlreadyStartedException $e) {
- $this->logger->error('Workflow has been already started.', [
- 'name' => $workflow->getWorkflowType()
- ]);
-
- throw $e;
-}
-BODY,
- $runArgs,
- $context->getBaseClass()
- );
- }
-}
diff --git a/src/Generator/HandlerInterfaceGenerator.php b/src/Generator/HandlerInterfaceGenerator.php
deleted file mode 100644
index c39eda6..0000000
--- a/src/Generator/HandlerInterfaceGenerator.php
+++ /dev/null
@@ -1,26 +0,0 @@
-getClass(), $namespace);
-
- $class->addMember($handler = $context->getHandlerMethod());
- $handler->setReturnType(RunningWorkflow::class);
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(RunningWorkflow::class),
- $context
- );
- }
-}
diff --git a/src/Generator/PhpCodePrinter.php b/src/Generator/PhpCodePrinter.php
deleted file mode 100644
index a81be96..0000000
--- a/src/Generator/PhpCodePrinter.php
+++ /dev/null
@@ -1,34 +0,0 @@
-addNamespace($this->namespace);
- $file->setStrictTypes();
-
- $printer = new PsrPrinter;
-
- $files->write(
- filename: $this->context->getClassPath(),
- data: $printer->printFile($file),
- ensureDirectory: true
- );
- }
-}
diff --git a/src/Generator/Utils.php b/src/Generator/Utils.php
deleted file mode 100644
index be1efc8..0000000
--- a/src/Generator/Utils.php
+++ /dev/null
@@ -1,159 +0,0 @@
- $type) {
- $method->addParameter($parameter)->setType($type);
- }
- }
-
- public static function generateWorkflowSignalMethods(array $signalMethods, ClassType $class): void
- {
- foreach ($signalMethods as $method) {
- $params = null;
- if (\str_contains($method, ',')) {
- /** @psalm-suppress PossiblyUndefinedArrayOffset */
- [$method, $params] = \explode(',', $method, 2);
- }
-
- $method = $class->addMethod($method)
- ->setPublic()
- ->setReturnType('void');
-
- if ($params) {
- static::addParameters(static::parseParameters(explode(',', $params)), $method);
- }
-
- if ($class->isInterface()) {
- $method->addAttribute(SignalMethod::class);
- } else {
- $method->addBody('// Do something special.');
- }
- }
- }
-
- public static function generateWorkflowQueryMethods(array $queryMethods, ClassType $class): void
- {
- foreach ($queryMethods as $method => $type) {
- $method = $class->addMethod($method)
- ->setPublic()
- ->setReturnType($type);
-
- if ($class->isInterface()) {
- $method->addAttribute(QueryMethod::class);
- } else {
- $method->addBody('// Query something special.');
- }
- }
- }
-
- /**
- * @param string[] $methods
- * @return Method[]
- */
- public static function parseMethods(array $methods): array
- {
- $result = [];
-
- foreach ($methods as $method) {
- $params = '';
- if (\str_contains($method, ',')) {
- /** @psalm-suppress PossiblyUndefinedArrayOffset */
- [$method, $params] = \explode(',', $method, 2);
- }
-
- if (\str_contains($method, ':')) {
- /** @psalm-suppress PossiblyUndefinedArrayOffset */
- [$method, $type] = \explode(':', $method, 2);
- }
-
- $type ??= 'void';
-
- $result[$method] = (new Method($method))
- ->setPublic()
- ->setReturnType($type);
-
- $result[$method]->setParameters(self::parseParameters(\explode(',', $params)));
- }
-
- return $result;
- }
-
- /**
- * @param string[] $parameters
- * @return Parameter[]
- */
- public static function parseParameters(array $parameters): array
- {
- $params = [];
-
- foreach ($parameters as $param) {
- $type = null;
- if (\str_contains($param, ':')) {
- /** @psalm-suppress PossiblyUndefinedArrayOffset */
- [$param, $type] = \explode(':', $param, 2);
- }
-
- if (empty($param)) {
- continue;
- }
-
- $type ??= 'string';
- $params[$param] = (new Parameter($param))->setType($type);
- }
-
- return $params;
- }
-
- public static function buildMethodArgs(array $args): string
- {
- return \implode(', ', \array_map(fn($param) => '$'.$param, \array_keys($args)));
- }
-
- public static function initializeActivityProperty(ClassType $class, Context $context): void
- {
- $activityClass = $context->getBaseClassInterface('Activity');
- $activityName = $context->getBaseClass().'.handle';
-
- $class->addProperty('activity')
- ->setPrivate()
- ->setType(ActivityProxy::class)
- ->addComment(
- $context->hasActivity()
- ? \sprintf('@var %s|%s', 'ActivityProxy', $activityClass)
- : \sprintf('@var %s', 'ActivityProxy')
- );
-
- if ($class->hasMethod('__construct')) {
- $constructor = $class->getMethod('__construct');
- } else {
- $constructor = $class->addMethod('__construct')->setPublic();
- }
-
- $constructor->addBody(
- \sprintf(
- <<<'BODY'
-$this->activity = Workflow::newActivityStub(
- %s,
- ActivityOptions::new()
- ->withScheduleToCloseTimeout(CarbonInterval::seconds(10))
-);
-BODY,
- $context->hasActivity() ? $activityClass.'::class' : "'$activityName'"
- )
- );
- }
-}
diff --git a/src/Generator/WorkflowGenerator.php b/src/Generator/WorkflowGenerator.php
deleted file mode 100644
index 9951f72..0000000
--- a/src/Generator/WorkflowGenerator.php
+++ /dev/null
@@ -1,69 +0,0 @@
-getClass());
- $class->addImplement($context->getClassInterfaceWithNamespace());
-
- Utils::initializeActivityProperty($class, $context);
-
- $class->addMember($handlerMethod = $context->getHandlerMethod());
-
- if (\count($context->getActivityMethods()) === 1) {
- foreach ($context->getActivityMethods() as $method) {
- $handlerMethod->addBody(
- \sprintf(
- 'return yield $this->activity->%s(%s);',
- $method->getName(),
- Utils::buildMethodArgs($method->getParameters())
- )
- );
- }
- } else {
- foreach ($context->getActivityMethods() as $method) {
- $handlerMethod->addBody('$result = [];');
-
- $handlerMethod->addBody(
- \sprintf(
- '$result[] = yield $this->activity->%s(%s);',
- $method->getName(),
- Utils::buildMethodArgs($method->getParameters())
- )
- );
-
- $handlerMethod->addBody('return $result;');
- }
- }
-
- foreach ($context->getSignalMethods() as $method) {
- $class->addMember($method->addBody('// Signal about something special.'));
- }
-
- foreach ($context->getQueryMethods() as $method) {
- $class->addMember($method->addBody('// Query something special.'));
- }
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(CarbonInterval::class)
- ->addUse(ActivityOptions::class)
- ->addUse(ActivityProxy::class)
- ->addUse(Workflow::class),
- $context
- );
- }
-}
diff --git a/src/Generator/WorkflowInterfaceGenerator.php b/src/Generator/WorkflowInterfaceGenerator.php
deleted file mode 100644
index cae4994..0000000
--- a/src/Generator/WorkflowInterfaceGenerator.php
+++ /dev/null
@@ -1,44 +0,0 @@
-getClass();
-
- $class = new \Nette\PhpGenerator\InterfaceType($className, $namespace);
-
- $class->addAttribute(WorkflowInterface::class);
-
- $class->addMember($method = $context->getHandlerMethod());
- $method->setBody('')->addAttribute(WorkflowMethod::class);
-
- foreach ($context->getSignalMethods() as $method) {
- $class->addMember($method->setBody('')->addAttribute(SignalMethod::class));
- }
-
- foreach ($context->getQueryMethods() as $method) {
- $class->addMember($method->setBody('')->addAttribute(QueryMethod::class));
- }
-
- return new PhpCodePrinter(
- $namespace
- ->add($class)
- ->addUse(QueryMethod::class)
- ->addUse(SignalMethod::class)
- ->addUse(WorkflowInterface::class)
- ->addUse(WorkflowMethod::class),
- $context
- );
- }
-}
diff --git a/src/Preset/PresetInterface.php b/src/Preset/PresetInterface.php
deleted file mode 100644
index 735bcc2..0000000
--- a/src/Preset/PresetInterface.php
+++ /dev/null
@@ -1,23 +0,0 @@
-presets[$name] = $preset;
- }
-
- public function findByName(string $name): PresetInterface
- {
- if (! isset($this->presets[$name])) {
- throw new PresetNotFoundException(
- \sprintf(
- 'Preset with given name [%s] is not defined.',
- $name
- )
- );
- }
-
- return $this->presets[$name];
- }
-
- public function getList(): array
- {
- return $this->presets;
- }
-}
diff --git a/src/Preset/PresetRegistryInterface.php b/src/Preset/PresetRegistryInterface.php
deleted file mode 100644
index aa79412..0000000
--- a/src/Preset/PresetRegistryInterface.php
+++ /dev/null
@@ -1,27 +0,0 @@
-
- */
- public function getList(): array;
-
- /**
- * Find an exists preset by name
- * @throws PresetNotFoundException
- */
- public function findByName(string $name): PresetInterface;
-}
diff --git a/src/Preset/WorkflowPreset.php b/src/Preset/WorkflowPreset.php
deleted file mode 100644
index 258d376..0000000
--- a/src/Preset/WorkflowPreset.php
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace->addUse(ActivityInterface::class);
+ $this->namespace->addUse(ActivityMethod::class);
+ $this->namespace->addUse(PromiseInterface::class);
+
+ $classAttributeArgs = [];
+ if ($this->activityName !== null) {
+ $classAttributeArgs['name'] = $this->activityName;
+ }
+
+ $this->class->addAttribute(ActivityInterface::class, $classAttributeArgs);
+ }
+
+ public function assignWorker(string $worker): void
+ {
+ $this->namespace->addUse(AssignWorker::class);
+ $this->class->addAttribute(AssignWorker::class, ['name' => $worker]);
+ }
+
+ public function addMethod(string $name, string $returnType): void
+ {
+ $this->class
+ ->addMethod($name)
+ ->setPublic()
+ ->addAttribute(ActivityMethod::class, ['name' => $name])
+ ->setReturnType($returnType)
+ ->addComment('@return PromiseInterface<' . $returnType . '>')
+ ->setBody('// TODO: Implement activity method');
+ }
+}
diff --git a/src/Scaffolder/Declaration/WorkflowDeclaration.php b/src/Scaffolder/Declaration/WorkflowDeclaration.php
new file mode 100644
index 0000000..93b7784
--- /dev/null
+++ b/src/Scaffolder/Declaration/WorkflowDeclaration.php
@@ -0,0 +1,76 @@
+namespace->addUse(WorkflowInterface::class);
+ $this->namespace->addUse(WorkflowMethod::class);
+
+ $this->class->addAttribute(WorkflowInterface::class);
+
+ $methodAttributeArgs = [];
+ if ($this->workflowName !== null) {
+ $methodAttributeArgs['name'] = $this->workflowName;
+ }
+
+ $this->class
+ ->addMethod('handle')
+ ->setPublic()
+ ->setComment('Handle workflow')
+ ->addAttribute(WorkflowMethod::class, $methodAttributeArgs)
+ ->setBody('// TODO: Implement handle method');
+ }
+
+ public function assignWorker(string $worker): void
+ {
+ $this->namespace->addUse(AssignWorker::class);
+ $this->class->addAttribute(AssignWorker::class, ['name' => $worker]);
+ }
+
+ public function addQueryMethod(string $name, string $returnType): void
+ {
+ $this->namespace->addUse(QueryMethod::class);
+ $this->class
+ ->addMethod($name)
+ ->setPublic()
+ ->addAttribute(QueryMethod::class)
+ ->setReturnType($returnType)
+ ->setBody('// TODO: Implement query method');
+ }
+
+ public function addSignalMethod(string $name): void
+ {
+ $this->namespace->addUse(SignalMethod::class);
+ $this->class
+ ->addMethod($name)
+ ->setPublic()
+ ->addAttribute(SignalMethod::class)
+ ->setReturnType('void')
+ ->setBody('// TODO: Implement signal method');
+ }
+}
diff --git a/src/Workflow/RunningWorkflow.php b/src/Workflow/RunningWorkflow.php
deleted file mode 100644
index 1323c2a..0000000
--- a/src/Workflow/RunningWorkflow.php
+++ /dev/null
@@ -1,20 +0,0 @@
-workflow, $name], $arguments);
- }
-}
diff --git a/src/Workflow/Workflow.php b/src/Workflow/Workflow.php
deleted file mode 100644
index 48ef8f7..0000000
--- a/src/Workflow/Workflow.php
+++ /dev/null
@@ -1,168 +0,0 @@
- $class
- */
- public function __construct(
- private readonly WorkflowClientInterface $client,
- private WorkflowOptions $options,
- private readonly string $class,
- private readonly string $type,
- ) {
- }
-
- public function getId(): ?string
- {
- return $this->options->workflowId;
- }
-
- public function backoffRetryCoefficient(float $coefficient): self
- {
- $this->retryOptions = $this->getRetryOptions()
- ->withBackoffCoefficient($coefficient);
-
- return $this;
- }
-
- public function maxRetryAttempts(int $attempts): self
- {
- $this->retryOptions = $this->getRetryOptions()
- ->withMaximumAttempts($attempts);
-
- return $this;
- }
-
- /**
- * @param DateIntervalValue|null $interval
- */
- public function maxRetryInterval($interval): self
- {
- $this->retryOptions = $this->getRetryOptions()
- ->withMaximumInterval($interval);
-
- return $this;
- }
-
- /**
- * @param DateIntervalValue|null $interval
- */
- public function initialRetryInterval($interval): self
- {
- $this->retryOptions = $this->getRetryOptions()
- ->withInitialInterval($interval);
-
- return $this;
- }
-
- /**
- * Workflow id to use when starting. If not specified a UUID is generated.
- * Note that it is dangerous as in case of client side retries no
- * deduplication will happen based on the generated id. So prefer assigning
- * business meaningful ids if possible.
- */
- public function assignId(string $id, ?int $policy = null): self
- {
- if ($policy !== null) {
- $this->withWorkflowIdReusePolicy($policy);
- }
-
- return $this->withWorkflowId($id);
- }
-
- /**
- * Sends signal on start.
- * @param mixed ...$args
- */
- public function withSignal(string $name, ...$args): self
- {
- $this->signal = new WorkflowSignal($name, $args);
-
- return $this;
- }
-
- /**
- * Starts untyped and typed workflow stubs in async mode.
- * @param mixed ...$args
- */
- public function run(...$args): RunningWorkflow
- {
- if ($this->retryOptions && ! $this->options->retryOptions) {
- $this->withRetryOptions($this->retryOptions);
- }
-
- $workflow = $this->createStub();
-
- if ($this->signal) {
- $run = $this->client->startWithSignal(
- workflow: $workflow,
- signal: $this->signal->getName(),
- signalArgs: $this->signal->getArgs(),
- startArgs: $args
- );
- } else {
- $run = $this->client->start($workflow, ...$args);
- }
-
- return new RunningWorkflow(
- $this->client->newUntypedRunningWorkflowStub(
- $run->getExecution()->getID(),
- $run->getExecution()->getRunID(),
- $this->type
- )
- );
- }
-
- public function __call(string $name, array $arguments)
- {
- if (str_starts_with($name, 'with')) {
- if (method_exists($this->options, $name)) {
- $this->options = call_user_func_array([$this->options, $name], $arguments);
-
- return $this;
- }
- }
-
- if (method_exists($this->class, $name)) {
- return call_user_func_array([$this->createStub(), $name], $arguments);
- }
-
- throw new \BadMethodCallException(\sprintf('Method [%s] doesn\'t exist.', $name));
- }
-
- /**
- * @return T
- */
- private function createStub(): WorkflowProxy
- {
- return $this->client->newWorkflowStub($this->class, $this->options);
- }
-
- private function getRetryOptions(): RetryOptions
- {
- if ($this->retryOptions) {
- return $this->retryOptions;
- }
-
- return $this->retryOptions = new RetryOptions();
- }
-}
diff --git a/src/Workflow/WorkflowManager.php b/src/Workflow/WorkflowManager.php
deleted file mode 100644
index 8f03f77..0000000
--- a/src/Workflow/WorkflowManager.php
+++ /dev/null
@@ -1,93 +0,0 @@
-client,
- $this->createOptions($id),
- $class,
- $this->getTypeFromWorkflowClass($class)
- );
- }
-
- public function createScheduled(string $class, string $expression, ?string $id = null): Workflow
- {
- return $this->create($class, $id)
- ->withCronSchedule($expression);
- }
-
- public function getById(
- string $id,
- ?string $class = null,
- ): RunningWorkflow {
- $type = $class !== null ? $this->getTypeFromWorkflowClass($class) : null;
-
- return new RunningWorkflow(
- $this->client->newUntypedRunningWorkflowStub(
- workflowID: $id,
- workflowType: $type
- )
- );
- }
-
- private function createOptions(?string $id): WorkflowOptions
- {
- $options = new WorkflowOptions();
-
- if ($id !== null) {
- $options = $options->withWorkflowId($id);
- }
-
- if ($this->defaultWorkflowExecutionTimeout !== null) {
- $options = $options->withWorkflowExecutionTimeout(
- $this->defaultWorkflowExecutionTimeout
- );
- }
-
- if ($this->defaultWorkflowRunTimeout !== null) {
- $options = $options->withWorkflowRunTimeout(
- $this->defaultWorkflowRunTimeout
- );
- }
-
- if ($this->defaultWorkflowTaskTimeout !== null) {
- $options = $options->withWorkflowTaskTimeout(
- $this->defaultWorkflowTaskTimeout
- );
- }
-
- return $options;
- }
-
- /**
- * @param class-string $class
- * @throws \ReflectionException
- */
- private function getTypeFromWorkflowClass(string $class): string
- {
- return $this->reader->fromClass($class)->getID();
- }
-}
diff --git a/src/Workflow/WorkflowSignal.php b/src/Workflow/WorkflowSignal.php
deleted file mode 100644
index 3cec02f..0000000
--- a/src/Workflow/WorkflowSignal.php
+++ /dev/null
@@ -1,24 +0,0 @@
-name;
- }
-
- public function getArgs(): array
- {
- return $this->args;
- }
-}
diff --git a/src/WorkflowManagerInterface.php b/src/WorkflowManagerInterface.php
deleted file mode 100644
index d0702b8..0000000
--- a/src/WorkflowManagerInterface.php
+++ /dev/null
@@ -1,44 +0,0 @@
- $class
- * @return RunningWorkflow|T|WorkflowStubInterface
- */
- public function getById(
- string $id,
- ?string $class = null,
- ): RunningWorkflow;
-
- /**
- * @psalm-template T of object
- * @param class-string $class
- * @return T|Workflow|WorkflowOptions
- */
- public function create(
- string $class,
- ?string $id = null
- ): Workflow;
-
- /**
- * @psalm-template T of object
- * @param class-string $class
- * @return T|Workflow|WorkflowOptions
- */
- public function createScheduled(
- string $class,
- string $expression,
- ?string $id = null
- ): Workflow;
-}
diff --git a/src/WorkflowPresetLocator.php b/src/WorkflowPresetLocator.php
deleted file mode 100644
index c2d2fbe..0000000
--- a/src/WorkflowPresetLocator.php
+++ /dev/null
@@ -1,41 +0,0 @@
-classes->getClasses() as $class) {
- if ($attr = $this->reader->firstClassMetadata($class, WorkflowPreset::class)) {
- if (! $class->implementsInterface(PresetInterface::class)) {
- continue;
- }
-
- $preset = $this->factory->make($class->getName());
- \assert($preset instanceof PresetInterface);
-
- $presets[$attr->name] = $preset;
- }
- }
-
- return $presets;
- }
-}
diff --git a/src/WorkflowPresetLocatorInterface.php b/src/WorkflowPresetLocatorInterface.php
deleted file mode 100644
index 1a77384..0000000
--- a/src/WorkflowPresetLocatorInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- */
- public function getPresets(): array;
-}
diff --git a/tests/src/Bootloader/PrototypeBootloaderTest.php b/tests/src/Bootloader/PrototypeBootloaderTest.php
index 33fef54..0d082e7 100644
--- a/tests/src/Bootloader/PrototypeBootloaderTest.php
+++ b/tests/src/Bootloader/PrototypeBootloaderTest.php
@@ -25,6 +25,5 @@ public function testBindProperties(string $expected, string $property): void
public function propertiesDataProvider(): \Traversable
{
yield [WorkflowClientInterface::class, 'workflow'];
- yield [WorkflowManagerInterface::class, 'workflowManager'];
}
}
diff --git a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php
index 9aa756e..f3e5604 100644
--- a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php
+++ b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php
@@ -4,22 +4,15 @@
namespace Spiral\TemporalBridge\Tests\Bootloader;
-use Spiral\Attributes\ReaderInterface;
use Spiral\TemporalBridge\Bootloader\TemporalBridgeBootloader;
use Spiral\TemporalBridge\Config\TemporalConfig;
use Spiral\Config\ConfigManager;
use Spiral\Config\LoaderInterface;
use Spiral\TemporalBridge\DeclarationLocator;
use Spiral\TemporalBridge\DeclarationLocatorInterface;
-use Spiral\TemporalBridge\Preset\PresetRegistry;
-use Spiral\TemporalBridge\Preset\PresetRegistryInterface;
use Spiral\TemporalBridge\Tests\TestCase;
use Spiral\TemporalBridge\WorkersRegistry;
use Spiral\TemporalBridge\WorkersRegistryInterface;
-use Spiral\TemporalBridge\Workflow\WorkflowManager;
-use Spiral\TemporalBridge\WorkflowManagerInterface;
-use Spiral\TemporalBridge\WorkflowPresetLocator;
-use Spiral\TemporalBridge\WorkflowPresetLocatorInterface;
use Temporal\Client\WorkflowClient;
use Temporal\Client\WorkflowClientInterface;
use Temporal\DataConverter\DataConverter;
@@ -30,24 +23,6 @@
class TemporalBridgeBootloaderTest extends TestCase
{
- public function testWorkflowPresetLocator()
- {
- $this->assertContainerBoundAsSingleton(
- WorkflowPresetLocatorInterface::class,
- WorkflowPresetLocator::class
- );
- }
-
- public function testWorkflowManager()
- {
- $this->mockContainer(ReaderInterface::class);
-
- $this->assertContainerBoundAsSingleton(
- WorkflowManagerInterface::class,
- WorkflowManager::class
- );
- }
-
public function testWorkerFactory()
{
$this->assertContainerBoundAsSingleton(
@@ -80,14 +55,6 @@ public function testWorkflowClient()
);
}
- public function testPresetRegistry()
- {
- $this->assertContainerBoundAsSingleton(
- PresetRegistryInterface::class,
- PresetRegistry::class
- );
- }
-
public function testWorkersRegistry(): void
{
$this->assertContainerBoundAsSingleton(
diff --git a/tests/src/Commands/MakePresetCommandTest.php b/tests/src/Commands/MakePresetCommandTest.php
deleted file mode 100644
index ffa10da..0000000
--- a/tests/src/Commands/MakePresetCommandTest.php
+++ /dev/null
@@ -1,64 +0,0 @@
-expectException(PresetNotFoundException::class);
- $this->expectExceptionMessage('Preset with given name [foo] is not defined.');
-
- $this->runCommand('temporal:make-preset', ['preset' => 'foo', 'name' => ' bar']);
- }
-
- public function testPresetWithoutGeneratorsShouldShowErrorMessage(): void
- {
- $registry = $this->mockContainer(PresetRegistryInterface::class);
- $preset = $this->mockContainer(PresetInterface::class);
-
- $registry->shouldReceive('findByName')->with('foo')->andReturn($preset);
-
- $preset->shouldReceive('init')->once();
- $preset->shouldReceive('generators')->once()->andReturn([]);
-
- $this->assertConsoleCommandOutputContainsStrings('temporal:make-preset', [
- 'preset' => 'foo', 'name' => ' bar'
- ], [
- 'Generators for preset [foo] are not found.'
- ]);
- }
-
- public function testPresetShouldGenerateFiles(): void
- {
- $registry = $this->mockContainer(PresetRegistryInterface::class);
- $preset = $this->mockContainer(PresetInterface::class);
- $generator = $this->mockContainer(FileGeneratorInterface::class);
- $printer = $this->mockContainer(PhpCodePrinter::class);
-
- $registry->shouldReceive('findByName')->with('foo')->andReturn($preset);
-
- $preset->shouldReceive('init')->once();
- $preset->shouldReceive('generators')->once()->andReturn([
- 'Baz' => $generator
- ]);
- $generator->shouldReceive('generate')->andReturn($printer);
- $printer->shouldReceive('print');
-
- $this->assertConsoleCommandOutputContainsStrings('temporal:make-preset', [
- 'preset' => 'foo', 'name' => ' bar'
- ], [
- 'Generating workflow files...',
- 'Class [App\Workflow\Bar\BarBaz] successfully generated.'
- ]);
- }
-}
diff --git a/tests/src/Commands/PresetListCommandTest.php b/tests/src/Commands/PresetListCommandTest.php
deleted file mode 100644
index 5f8236a..0000000
--- a/tests/src/Commands/PresetListCommandTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-assertConsoleCommandOutputContainsStrings('temporal:presets', [], [
- 'No available Workflow presets found.'
- ]);
- }
-
- public function testPresetsShouldBeFound()
- {
- $registry = $this->mockContainer(PresetRegistryInterface::class);
- $preset = $this->mockContainer(PresetInterface::class);
-
- $registry->shouldReceive('getList')->once()->andReturn([
- 'foo' => $preset
- ]);
-
- $preset->shouldReceive('getDescription')->once()->andReturn('First preset description');
-
- $this->assertConsoleCommandOutputContainsStrings('temporal:presets', [], [
- '| name | description |',
- '| foo | First preset description |'
- ]);
- }
-}
diff --git a/tests/src/Commands/Scaffolder/ActivityCommandTest.php b/tests/src/Commands/Scaffolder/ActivityCommandTest.php
new file mode 100644
index 0000000..280b91b
--- /dev/null
+++ b/tests/src/Commands/Scaffolder/ActivityCommandTest.php
@@ -0,0 +1,187 @@
+files = $this->mockContainer(FilesInterface::class);
+ }
+
+ public function testGenerate(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Activity/PaymentActivity.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:activity', [
+ 'name' => 'Payment',
+ ]);
+ }
+
+ public function testGenerateWithAssignedWorker(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Activity/PaymentActivity.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:activity', [
+ 'name' => 'Payment',
+ '--worker' => 'scanner_service',
+ ]);
+ }
+
+ public function testGenerateWithActivityName(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Activity/PaymentActivity.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:activity', [
+ 'name' => 'Payment',
+ '--activity-name' => 'payment',
+ ]);
+ }
+
+ public function testGenerateWithMethods(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Activity/PaymentActivity.php'));
+ $this->assertSame(
+ <<<'PHP'
+
+ */
+ #[ActivityMethod(name: 'pay')]
+ public function pay(): mixed
+ {
+ // TODO: Implement activity method
+ }
+
+ /**
+ * @return PromiseInterface
+ */
+ #[ActivityMethod(name: 'refund')]
+ public function refund(): void
+ {
+ // TODO: Implement activity method
+ }
+
+ /**
+ * @return PromiseInterface
+ */
+ #[ActivityMethod(name: 'getPaymentStatus')]
+ public function getPaymentStatus(): bool
+ {
+ // TODO: Implement activity method
+ }
+}
+
+PHP,
+ $body,
+ );
+ return true;
+ });
+
+ $this->runCommand('create:activity', [
+ 'name' => 'Payment',
+ '--method' => [
+ 'pay',
+ 'refund:void',
+ 'getPaymentStatus:bool',
+ ]
+ ]);
+ }
+}
diff --git a/tests/src/Commands/Scaffolder/WorkflowCommandTest.php b/tests/src/Commands/Scaffolder/WorkflowCommandTest.php
new file mode 100644
index 0000000..1a86f08
--- /dev/null
+++ b/tests/src/Commands/Scaffolder/WorkflowCommandTest.php
@@ -0,0 +1,265 @@
+files = $this->mockContainer(FilesInterface::class);
+ }
+
+ public function testGenerate(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Workflow/PaymentWorkflow.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:workflow', [
+ 'name' => 'Payment',
+ ]);
+ }
+
+ public function testGenerateWithWorkflowName(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Workflow/PaymentWorkflow.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:workflow', [
+ 'name' => 'Payment',
+ '--workflow-name' => 'PaymentWorkflow',
+ ]);
+ }
+
+ public function testGenerateWithWorker(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Workflow/PaymentWorkflow.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:workflow', [
+ 'name' => 'Payment',
+ '--worker' => 'test',
+ ]);
+ }
+
+ public function testGenerateWithQueryMethods(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Workflow/PaymentWorkflow.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:workflow', [
+ 'name' => 'Payment',
+ '--query-method' => [
+ 'getPayment:string',
+ 'getTotal:int',
+ 'getLastTransaction',
+ ],
+ ]);
+ }
+
+ public function testGenerateWithSignalMethods(): void
+ {
+ $this->files->shouldReceive('exists')->andReturnFalse();
+ $this->files->shouldReceive('write')->once()->withArgs(function (string $path, string $body) {
+ $this->assertTrue(\str_ends_with($path, '/app/src/Endpoint/Temporal/Workflow/PaymentWorkflow.php'));
+ $this->assertSame(
+ <<<'PHP'
+runCommand('create:workflow', [
+ 'name' => 'Payment',
+ '--signal-method' => [
+ 'pay',
+ 'cancel',
+ ],
+ ]);
+ }
+}
diff --git a/tests/src/Config/TemporalConfigTest.php b/tests/src/Config/TemporalConfigTest.php
index 6f56142..60068e2 100644
--- a/tests/src/Config/TemporalConfigTest.php
+++ b/tests/src/Config/TemporalConfigTest.php
@@ -24,7 +24,7 @@ public function testGetsDefaultNamespaceIfItNotSet(): void
{
$config = new TemporalConfig([]);
- $this->assertSame('App\\Workflow', $config->getDefaultNamespace());
+ $this->assertSame('App\\Endpoint\\Temporal\\Workflow', $config->getDefaultNamespace());
}
public function testGetsDefaultTemporalNamespaceIfItNotSet(): void
diff --git a/tests/src/Generator/ContextTest.php b/tests/src/Generator/ContextTest.php
deleted file mode 100644
index c626c09..0000000
--- a/tests/src/Generator/ContextTest.php
+++ /dev/null
@@ -1,234 +0,0 @@
-context = new Context('src/app/', 'App\\Foo', 'Bar');
- }
-
- public function testWithCronSchedule(): void
- {
- $this->assertFalse($this->context->isScheduled());
-
- $this->assertTrue($this->context->withCronSchedule()->isScheduled());
- }
-
- public function testWithActivity(): void
- {
- $this->assertFalse($this->context->hasActivity());
-
- $this->assertTrue($this->context->withActivity()->hasActivity());
- }
-
- public function testWithHandler(): void
- {
- $this->assertFalse($this->context->hasHandler());
-
- $this->assertTrue($this->context->withHandler()->hasHandler());
- }
-
- public function testGetsNamespace(): void
- {
- $this->assertSame(
- 'App\\Foo',
- $this->context->getNamespace()
- );
- }
-
- public function testGetsPath(): void
- {
- $this->assertSame(
- 'src/app/',
- $this->context->getPath()
- );
- }
-
- public function testGetsBaseClass(): void
- {
- $this->assertSame(
- 'Bar',
- $this->context->getBaseClass()
- );
-
- $this->assertSame(
- 'BarBaz',
- $this->context->getBaseClass('Baz')
- );
- }
-
- public function testGetsClassPath(): void
- {
- $this->assertSame(
- 'src/app/Bar.php',
- $this->context->getClassPath()
- );
- }
-
- public function testGetsBaseClassInterface(): void
- {
- $this->assertSame(
- 'BarInterface',
- $this->context->getBaseClassInterface()
- );
-
- $this->assertSame(
- 'BarBazInterface',
- $this->context->getBaseClassInterface('Baz')
- );
- }
-
- public function testGetsBaseClassInterfaceWithNamespace(): void
- {
- $this->assertSame(
- 'App\Foo\BarInterface',
- $this->context->getBaseClassInterfaceWithNamespace()
- );
-
- $this->assertSame(
- 'App\Foo\BarBazInterface',
- $this->context->getBaseClassInterfaceWithNamespace('Baz')
- );
- }
-
- public function testGetsClass(): void
- {
- $this->assertSame(
- 'Bar',
- $this->context->getClass()
- );
-
- $this->assertSame(
- 'BarBaz',
- $this->context->withClassPostfix('Baz')->getClass()
- );
-
- $this->assertSame(
- 'Bar',
- $this->context->withClassPostfix('Bar')->getClass()
- );
-
- $this->assertSame(
- 'BarBazFoo',
- $this->context->withClassPostfix('Baz')->getClass('Foo')
- );
- }
-
- public function testGetsClassInterface(): void
- {
- $this->assertSame(
- 'BarInterface',
- $this->context->getClassInterface()
- );
-
- $this->assertSame(
- 'BarBazInterface',
- $this->context->withClassPostfix('Baz')->getClassInterface()
- );
-
- $this->assertSame(
- 'BarInterface',
- $this->context->withClassPostfix('Bar')->getClassInterface()
- );
-
- $this->assertSame(
- 'BarBazFooInterface',
- $this->context->withClassPostfix('Baz')->getClassInterface('Foo')
- );
- }
-
- public function testGetsClassInterfaceWithNamespace(): void
- {
- $this->assertSame(
- 'App\Foo\BarInterface',
- $this->context->getClassInterfaceWithNamespace()
- );
-
- $this->assertSame(
- 'App\Foo\BarBazInterface',
- $this->context->withClassPostfix('Baz')->getClassInterfaceWithNamespace()
- );
-
- $this->assertSame(
- 'App\Foo\BarInterface',
- $this->context->withClassPostfix('Bar')->getClassInterfaceWithNamespace()
- );
-
- $this->assertSame(
- 'App\Foo\BarBazFooInterface',
- $this->context->withClassPostfix('Baz')->getClassInterfaceWithNamespace('Foo')
- );
- }
-
- public function testGetsClassWithNamespace(): void
- {
- $this->assertSame(
- 'App\Foo\Bar',
- $this->context->getClassWithNamespace()
- );
-
- $this->assertSame(
- 'App\Foo\BarFoo',
- $this->context->getClassWithNamespace('Foo')
- );
-
- $this->assertSame(
- 'App\Foo\BarBazFoo',
- $this->context->withClassPostfix('Baz')->getClassWithNamespace('Foo')
- );
- }
-
- public function testGetsHandlerMethodName(): void
- {
- $this->assertSame(
- 'handle',
- $this->context->getHandlerMethodName()
- );
-
- $this->assertFalse(
- $this->context->isHandlerMethodNameChanged()
- );
-
- $this->assertSame(
- 'foo',
- $this->context->withHandlerMethod('foo')->getHandlerMethodName()
- );
-
- $this->assertTrue(
- $this->context->isHandlerMethodNameChanged()
- );
- }
-
- public function testGetsHandlerMethod(): void
- {
- $method = $this->context->getHandlerMethod();
-
- $this->assertTrue($method->isPublic());
-
- $this->assertSame(
- '\Generator',
- $method->getReturnType()
- );
-
- $this->assertSame(
- 'handle',
- $method->getName()
- );
-
- $this->assertSame(
- 'foo',
- $this->context->withHandlerMethod('foo')->getHandlerMethod()->getName()
- );
- }
-}
diff --git a/tests/src/Generator/PhpCodePrinterTest.php b/tests/src/Generator/PhpCodePrinterTest.php
deleted file mode 100644
index 37e4155..0000000
--- a/tests/src/Generator/PhpCodePrinterTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-addClass('Baz');
-
- $printer = new PhpCodePrinter(
- $namespace,
- new Context('src/app/', 'App//Foo', 'Bar')
- );
-
- $files = $this->mockContainer(FilesInterface::class);
-
- $files->shouldReceive('write')->once()->withSomeOfArgs('src/app/Bar.php', <<print($files);
- }
-}
diff --git a/tests/src/Generator/WorkflowTypesTest.php b/tests/src/Generator/WorkflowTypesTest.php
deleted file mode 100644
index 8731035..0000000
--- a/tests/src/Generator/WorkflowTypesTest.php
+++ /dev/null
@@ -1,85 +0,0 @@
-dir = $this->getDirectoryByAlias('app').'src/Workflow/';
- }
-
- public function testMakesWorkflowWithoutActivityAndHandler()
- {
- $this->runCommand('temporal:make-workflow', [
- 'name' => 'PingSite',
- ]);
-
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflow.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflowInterface.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteActivity.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteActivityInterface.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteHandler.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteHandlerInterface.php');
- }
-
- public function testMakesWorkflowWithActivityWithoutHandler()
- {
- $this->runCommand('temporal:make-workflow', [
- 'name' => 'PingSite',
- '--with-activity' => true,
- ]);
-
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflow.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflowInterface.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteActivity.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteActivityInterface.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteHandler.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteHandlerInterface.php');
- }
-
- public function testMakesWorkflowWithActivityAndHandler()
- {
- $this->runCommand('temporal:make-workflow', [
- 'name' => 'PingSite',
- '--with-activity' => true,
- '--with-handler' => true,
- ]);
-
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflow.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflowInterface.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteActivity.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteActivityInterface.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteHandler.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteHandlerInterface.php');
- }
-
- public function testMakesWorkflowWithoutActivityWithHandler()
- {
- $this->runCommand('temporal:make-workflow', [
- 'name' => 'PingSite',
- '--with-handler' => true,
- ]);
-
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflow.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteWorkflowInterface.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteActivity.php');
- $this->assertFileDoesNotExist($this->dir.'PingSite/PingSiteActivityInterface.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteHandler.php');
- $this->assertFileExists($this->dir.'PingSite/PingSiteHandlerInterface.php');
- }
-
- protected function tearDown(): void
- {
- $this->cleanupDirectories($this->dir);
-
- parent::tearDown();
- }
-}
diff --git a/tests/src/Preset/PresetRegistryTest.php b/tests/src/Preset/PresetRegistryTest.php
deleted file mode 100644
index c498c17..0000000
--- a/tests/src/Preset/PresetRegistryTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-assertCount(0, $registry->getList());
-
- $registry->register('foo', $preset = \Mockery::mock(PresetInterface::class));
-
- $this->assertCount(1, $registry->getList());
-
- $this->assertSame($preset, $registry->findByName('foo'));
- }
-
- public function testNotFoundPresetShouldThrowAnException(): void
- {
- $this->expectException(PresetNotFoundException::class);
- $this->expectExceptionMessage('Preset with given name [foo] is not defined.');
-
- $registry = new PresetRegistry();
-
- $registry->findByName('foo');
- }
-}
diff --git a/tests/src/UtilsTest.php b/tests/src/UtilsTest.php
deleted file mode 100644
index 79f8bbf..0000000
--- a/tests/src/UtilsTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-assertSame('userId', $parsed['userId']->getName());
- $this->assertSame('string', $parsed['userId']->getType());
-
- $this->assertSame('name', $parsed['name']->getName());
- $this->assertSame('string', $parsed['name']->getType());
-
- $this->assertSame('exit', $parsed['exit']->getName());
- $this->assertSame('bool', $parsed['exit']->getType());
- }
-
- public function testParseMethods(): void
- {
- $methods = [
- 'exit',
- 'handler:string',
- 'book:bool,name:string,exit:bool',
- ];
-
- $parsed = Utils::parseMethods($methods);
-
- $this->assertSame('exit', $parsed['exit']->getName());
- $this->assertSame('void', $parsed['exit']->getReturnType());
- $this->assertSame([], $parsed['exit']->getParameters());
-
- $this->assertSame('handler', $parsed['handler']->getName());
- $this->assertSame('string', $parsed['handler']->getReturnType());
- $this->assertSame([], $parsed['handler']->getParameters());
-
- $this->assertSame('book', $parsed['book']->getName());
- $this->assertSame('bool', $parsed['book']->getReturnType());
- $this->assertCount(2, $parsed['book']->getParameters());
-
- $this->assertSame('name', $parsed['book']->getParameters()['name']->getName());
- $this->assertSame('string', $parsed['book']->getParameters()['name']->getType());
-
- $this->assertSame('exit', $parsed['book']->getParameters()['exit']->getName());
- $this->assertSame('bool', $parsed['book']->getParameters()['exit']->getType());
- }
-}
diff --git a/tests/src/Workflow/WorkflowManagerTest.php b/tests/src/Workflow/WorkflowManagerTest.php
deleted file mode 100644
index f2789f7..0000000
--- a/tests/src/Workflow/WorkflowManagerTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-manager = new WorkflowManager(
- $this->client = m::mock(WorkflowClientInterface::class),
- $this->reader = m::mock(WorkflowReader::class),
- );
- }
-
- public function testCreatesWorkflowWithoutId(): void
- {
- $class = new \ReflectionClass(SimpleWorkflow::class);
-
- $this->reader->shouldReceive('fromClass')
- ->with('foo')
- ->andReturn(new WorkflowPrototype('foo', $class->getMethod('handle'), $class));
-
- $this->assertInstanceOf(Workflow::class, $workflow = $this->manager->create('foo'));
- $this->assertNotEmpty($workflow->getId());
- }
-
- public function testCreatesWorkflowWithId(): void
- {
- $class = new \ReflectionClass(SimpleWorkflow::class);
-
- $this->reader->shouldReceive('fromClass')
- ->with('foo')
- ->andReturn(new WorkflowPrototype('foo', $class->getMethod('handle'), $class));
-
- $this->assertInstanceOf(Workflow::class, $workflow = $this->manager->create('foo', 'foo-id'));
- $this->assertSame('foo-id', $workflow->getId());
- }
-}