diff --git a/CHANGELOG.md b/CHANGELOG.md index 34164066..82cb3e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Latest ------ ## Changes +* [#312](https://github.com/cleverage/process-bundle/issues/312) Add read-only interfaces for the process manager and the registries, implemented by the existing classes and autowired by their interface: `ProcessManagerInterface` (`execute()`), `ProcessConfigurationRegistryInterface` (`getProcessConfiguration()`, `getProcessConfigurations()`, `hasProcessConfiguration()`), `TransformerRegistryInterface` (`getTransformer()`, `getTransformers()`, `hasTransformer()`) and `TaskRegistryInterface` (`getTask()`). Type your services on them: the classes will be `final` in v6.0 (the services of the bundle will then be typed on the interfaces). Update documentation, add tests. * [#310](https://github.com/cleverage/process-bundle/issues/310) Process configuration tree: a task `error_strategy` other than `skip` or `stop` is deprecated (notice when the container is compiled; it was accepted and the process failed with "Unknown error strategy" when the task failed), it will be rejected in v6.0. The process `public` key is a boolean node: a non-boolean value is rejected when the container is compiled, instead of a `TypeError` when the configuration is built. Describe the nodes of the process, task and generic transformer configurations (`config:dump-reference clever_age_process`). Update documentation, add tests. * [#309](https://github.com/cleverage/process-bundle/issues/309) Composer: `ext-intl` is no longer required, it is suggested: it is only needed by the `slugify` transformer (`SlugifyTransformer`), which is replaced by a service failing with an explicit message when the extension is missing (`UnavailableServicesCompilerPass`). Update documentation, add tests. * [#305](https://github.com/cleverage/process-bundle/issues/305) Bundle best practices, residues: the generic transformers are no longer autowired (explicit arguments). `ProcessHelpCommand` receives the `TaskRegistry` instead of the service container (passing a container is deprecated). Fetching from the service container a task of the application made public by the `TaskInterface` autoconfiguration is deprecated (`container.private` tag, new internal `PublicTaskDeprecationCompilerPass`); the tasks made public by the application itself are not concerned. Trigger the missing deprecation notices: `CheckSerializerCompilerPass`, `errors` task configuration key (use `error_outputs`). `TaskConfiguration::getErrors()` triggers a single notice on PHP 8.4+. `CleverAgeProcessBundle` is marked `@final since 5.4`. Update documentation, add tests. diff --git a/config/services/manager.yaml b/config/services/manager.yaml index a1fe6cfd..c11d9fd7 100644 --- a/config/services/manager.yaml +++ b/config/services/manager.yaml @@ -16,6 +16,8 @@ services: CleverAge\ProcessBundle\Manager\ProcessManager: alias: cleverage_process.manager.process + CleverAge\ProcessBundle\Manager\ProcessManagerInterface: + alias: cleverage_process.manager.process cleverage_process.context.contextual_option_resolver: class: CleverAge\ProcessBundle\Context\ContextualOptionResolver diff --git a/config/services/registry.yaml b/config/services/registry.yaml index 0db42234..73c10514 100644 --- a/config/services/registry.yaml +++ b/config/services/registry.yaml @@ -8,6 +8,8 @@ services: - ~ CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry: alias: cleverage_process.registry.process_configuration + CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistryInterface: + alias: cleverage_process.registry.process_configuration cleverage_process.registry.transformer: class: CleverAge\ProcessBundle\Registry\TransformerRegistry @@ -16,6 +18,8 @@ services: - ~ # Service locator of the transformers by code, see TransformerLocatorCompilerPass CleverAge\ProcessBundle\Registry\TransformerRegistry: alias: cleverage_process.registry.transformer + CleverAge\ProcessBundle\Registry\TransformerRegistryInterface: + alias: cleverage_process.registry.transformer cleverage_process.registry.task: class: CleverAge\ProcessBundle\Registry\TaskRegistry @@ -25,3 +29,5 @@ services: - '@service_container' # Deprecated fallback, removed in v6.0 CleverAge\ProcessBundle\Registry\TaskRegistry: alias: cleverage_process.registry.task + CleverAge\ProcessBundle\Registry\TaskRegistryInterface: + alias: cleverage_process.registry.task diff --git a/docs/04-advanced_workflow.md b/docs/04-advanced_workflow.md index 0dac8136..2e6720c8 100644 --- a/docs/04-advanced_workflow.md +++ b/docs/04-advanced_workflow.md @@ -29,8 +29,11 @@ the process code, the task code and the original message. The original exception ### Executing a process from PHP -The process manager service (`cleverage_process.manager.process`, private) can be autowired by its class, -`CleverAge\ProcessBundle\Manager\ProcessManager`, or injected explicitly: +The process manager service (`cleverage_process.manager.process`, private) can be autowired by its interface, +`CleverAge\ProcessBundle\Manager\ProcessManagerInterface` (or by its class, `ProcessManager`), or injected +explicitly. Type your services on the interface: the class will be `final` in v6.0 (the services of the bundle will +then be typed on the interfaces, so that they can be decorated). The registries have their interface too: `ProcessConfigurationRegistryInterface`, +`TransformerRegistryInterface` and `TaskRegistryInterface` (namespace `CleverAge\ProcessBundle\Registry`). ```yaml # config/services.yaml diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index ba9ce711..7e3bba10 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -42,7 +42,7 @@ * * @final since 5.4 */ -class ProcessManager implements ResetInterface +class ProcessManager implements ProcessManagerInterface, ResetInterface { protected const EXECUTE_PROCESS = 1; diff --git a/src/Manager/ProcessManagerInterface.php b/src/Manager/ProcessManagerInterface.php new file mode 100644 index 00000000..234782a5 --- /dev/null +++ b/src/Manager/ProcessManagerInterface.php @@ -0,0 +1,34 @@ + $context + * + * @throws MissingProcessException when the process does not exist + * @throws ProcessFailedException when a task fails with the "stop" error strategy + */ + public function execute(string $processCode, mixed $input = null, array $context = []): mixed; +} diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 848cea51..915fa392 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -24,10 +24,10 @@ * * @final since 5.4 */ -class ProcessConfigurationRegistry +class ProcessConfigurationRegistry implements ProcessConfigurationRegistryInterface { /** - * @var ProcessConfiguration[] + * @var array */ protected array $processConfigurations = []; @@ -53,7 +53,7 @@ public function getProcessConfiguration(string $processCode): ProcessConfigurati } /** - * @return ProcessConfiguration[] + * @return array */ public function getProcessConfigurations(): array { diff --git a/src/Registry/ProcessConfigurationRegistryInterface.php b/src/Registry/ProcessConfigurationRegistryInterface.php new file mode 100644 index 00000000..d727d8cd --- /dev/null +++ b/src/Registry/ProcessConfigurationRegistryInterface.php @@ -0,0 +1,39 @@ + indexed by process code + * + * @throws InvalidProcessConfigurationException when a process configuration is not valid + */ + public function getProcessConfigurations(): array; + + public function hasProcessConfiguration(string $processCode): bool; +} diff --git a/src/Registry/TaskRegistry.php b/src/Registry/TaskRegistry.php index ba000ab3..dc04656d 100644 --- a/src/Registry/TaskRegistry.php +++ b/src/Registry/TaskRegistry.php @@ -24,7 +24,7 @@ * (see TaskLocatorCompilerPass). The fallback container is only used, with a deprecation, for services that are not * in the locator (e.g. a process configuration added at runtime). */ -final class TaskRegistry +final class TaskRegistry implements TaskRegistryInterface { public function __construct( protected ContainerInterface $locator, diff --git a/src/Registry/TaskRegistryInterface.php b/src/Registry/TaskRegistryInterface.php new file mode 100644 index 00000000..227758e7 --- /dev/null +++ b/src/Registry/TaskRegistryInterface.php @@ -0,0 +1,28 @@ + indexed by code + */ + public function getTransformers(): array; + + /** + * @throws MissingTransformerException when the transformer does not exist + */ + public function getTransformer(string $code): TransformerInterface; + + public function hasTransformer(string $code): bool; +} diff --git a/tests/DependencyInjection/CleverAgeProcessExtensionTest.php b/tests/DependencyInjection/CleverAgeProcessExtensionTest.php index a0f5d545..b94004ec 100644 --- a/tests/DependencyInjection/CleverAgeProcessExtensionTest.php +++ b/tests/DependencyInjection/CleverAgeProcessExtensionTest.php @@ -19,9 +19,13 @@ use CleverAge\ProcessBundle\DependencyInjection\CleverAgeProcessExtension; use CleverAge\ProcessBundle\DependencyInjection\Configuration; use CleverAge\ProcessBundle\Manager\ProcessManager; +use CleverAge\ProcessBundle\Manager\ProcessManagerInterface; use CleverAge\ProcessBundle\Model\ProcessStopCheckerInterface; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; +use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistryInterface; +use CleverAge\ProcessBundle\Registry\TaskRegistryInterface; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use CleverAge\ProcessBundle\Registry\TransformerRegistryInterface; use CleverAge\ProcessBundle\Task\DummyTask; use CleverAge\ProcessBundle\Tests\Fixtures\AttributedTask; use CleverAge\ProcessBundle\Tests\Fixtures\AttributedTransformer; @@ -91,6 +95,24 @@ public function testServicesCanBeAutowiredByClassName(): void } } + public function testServicesCanBeAutowiredByInterface(): void + { + $container = new ContainerBuilder(); + (new CleverAgeProcessExtension())->load([], $container); + + foreach ([ + ProcessManagerInterface::class => 'cleverage_process.manager.process', + ProcessConfigurationRegistryInterface::class => 'cleverage_process.registry.process_configuration', + TransformerRegistryInterface::class => 'cleverage_process.registry.transformer', + TaskRegistryInterface::class => 'cleverage_process.registry.task', + ] as $interface => $id) { + self::assertSame($id, (string) $container->getAlias($interface)); + $class = $container->getDefinition($id)->getClass(); + self::assertIsString($class); + self::assertTrue(is_a($class, $interface, true), $class); + } + } + public function testTasksAndTransformersAreAutoconfigured(): void { $container = new ContainerBuilder();