From d02e0d10a8fd2d8b95d866fda7561843589b724a Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Wed, 23 Jan 2019 10:11:00 +0100 Subject: [PATCH 001/304] Add hash transformer --- .../tests/transfomer/hash_transformer.yml | 25 +++++++++ Tests/Transformer/HashTransformerTest.php | 31 +++++++++++ Transformer/HashTransformer.php | 51 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 Resources/tests/transfomer/hash_transformer.yml create mode 100644 Tests/Transformer/HashTransformerTest.php create mode 100644 Transformer/HashTransformer.php diff --git a/Resources/tests/transfomer/hash_transformer.yml b/Resources/tests/transfomer/hash_transformer.yml new file mode 100644 index 00000000..d69baa04 --- /dev/null +++ b/Resources/tests/transfomer/hash_transformer.yml @@ -0,0 +1,25 @@ +clever_age_process: + configurations: + test.hash_transformer.md5: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + hash: + algo: 'md5' + + test.hash_transformer.sha512: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + hash: + algo: 'sha512' diff --git a/Tests/Transformer/HashTransformerTest.php b/Tests/Transformer/HashTransformerTest.php new file mode 100644 index 00000000..4164c452 --- /dev/null +++ b/Tests/Transformer/HashTransformerTest.php @@ -0,0 +1,31 @@ +processManager->execute('test.hash_transformer.md5', 'This is a string'); + self::assertEquals('41fb5b5ae4d57c5ee528adb00e5e8e74', $result); + } + + /** + * Assert a string can be hash in sha512 + */ + public function testSha512Hash() + { + $result = $this->processManager->execute('test.hash_transformer.sha512', 'This is a string'); + self::assertEquals('f4d54d32e3523357ff023903eaba2721e8c8cfc7702663782cb3e52faf2c56c002cc3096b5f2b6df870be665d0040e9963590eb02d03d166e52999cd1c430db1', $result); + } +} diff --git a/Transformer/HashTransformer.php b/Transformer/HashTransformer.php new file mode 100644 index 00000000..f8aedd15 --- /dev/null +++ b/Transformer/HashTransformer.php @@ -0,0 +1,51 @@ + + */ +class HashTransformer implements ConfigurableTransformerInterface +{ + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('algo'); + $resolver->setAllowedValues('algo', hash_algos()); + $resolver->setAllowedTypes('algo', 'string'); + + $resolver->setDefined('raw_output'); + $resolver->setDefault('raw_output', false); + } + + /** + * {@inheritDoc} + * @throws \UnexpectedValueException + */ + public function transform($value, array $options = []) + { + return hash($options['algo'], $value, $options['raw_output']); + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'hash'; + } +} From e85e544896f97038eab3efb92e15cf84a52cc7aa Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Wed, 23 Jan 2019 16:16:43 +0100 Subject: [PATCH 002/304] Add type setter transformer --- .../transfomer/type_setter_transformer.yml | 37 ++++++++++ .../Transformer/TypeSetterTransformerTest.php | 40 +++++++++++ Transformer/TypeSetterTransformer.php | 69 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 Resources/tests/transfomer/type_setter_transformer.yml create mode 100644 Tests/Transformer/TypeSetterTransformerTest.php create mode 100644 Transformer/TypeSetterTransformer.php diff --git a/Resources/tests/transfomer/type_setter_transformer.yml b/Resources/tests/transfomer/type_setter_transformer.yml new file mode 100644 index 00000000..2de02bd6 --- /dev/null +++ b/Resources/tests/transfomer/type_setter_transformer.yml @@ -0,0 +1,37 @@ +clever_age_process: + configurations: + test.type_setter_transformer.int_to_int: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + type_setter: + type: 'integer' + + test.type_setter_transformer.string_to_int: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + type_setter: + type: 'integer' + + test.type_setter_transformer.int_to_string: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + type_setter: + type: 'string' diff --git a/Tests/Transformer/TypeSetterTransformerTest.php b/Tests/Transformer/TypeSetterTransformerTest.php new file mode 100644 index 00000000..6c8043f8 --- /dev/null +++ b/Tests/Transformer/TypeSetterTransformerTest.php @@ -0,0 +1,40 @@ +processManager->execute('test.type_setter_transformer.int_to_int', 1); + self::assertSame(1, $result); + } + + /** + * Assert string to int convertion + */ + public function testStringToInt() + { + $result = $this->processManager->execute('test.type_setter_transformer.string_to_int', '1'); + self::assertSame(1, $result); + } + + /** + * Assert int to string convertion + */ + public function testIntToString() + { + $result = $this->processManager->execute('test.type_setter_transformer.int_to_string', 1); + self::assertSame('1', $result); + } + +} diff --git a/Transformer/TypeSetterTransformer.php b/Transformer/TypeSetterTransformer.php new file mode 100644 index 00000000..d217d506 --- /dev/null +++ b/Transformer/TypeSetterTransformer.php @@ -0,0 +1,69 @@ + + */ +class TypeSetterTransformer implements ConfigurableTransformerInterface +{ + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('type'); + $resolver->setAllowedValues( + 'type', + [ + 'boolean', + 'bool', + 'integer', + 'int', + 'float', + 'double', + 'string', + 'array', + 'object', + 'null', + ] + ); + $resolver->setAllowedTypes('type', 'string'); + } + + /** + * {@inheritDoc} + * @throws \UnexpectedValueException + */ + public function transform($value, array $options = []) + { + $return = settype($value, $options['type']); + + if (true === $return) { + return $value; + } + + throw new TransformerException("Failed to change value type in {$options['type']}"); + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'type_setter'; + } +} From 78e7bfb2793e62e9a57e6559e0f457a44d185f31 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 10 Dec 2018 15:24:33 +0100 Subject: [PATCH 003/304] Removed global symfony/symfony dependency in favor of a version more compatible with sf4 (more granular requirements) --- composer.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bbd6ad35..8b3b287d 100644 --- a/composer.json +++ b/composer.json @@ -39,11 +39,21 @@ "require": { "php": ">=7.1", "ext-json": "*", - "symfony/symfony": "~3.0|~4.0", + + "symfony/framework-bundle": "~3.0|~4.0", "doctrine/orm": "~2.5", "doctrine/doctrine-bundle": "~1.6", "symfony/expression-language": "~3.0|~4.0", "symfony/monolog-bundle": "~3.3", + "symfony/console": "~3.0|~4.0", + "symfony/options-resolver": "~3.0|~4.0", + "symfony/process": "~3.0|~4.0", + "symfony/property-access": "~3.0|~4.0", + "symfony/serializer": "~3.0|~4.0", + "symfony/swiftmailer-bundle": "~3.0|~4.0", + "symfony/validator": "~3.0|~4.0", + "symfony/yaml": "~3.0|~4.0", + "sidus/base-bundle": "~1.0" }, "require-dev": { From cdbb6f9a16b55b31f847bd52d751fa682e91aabd Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 10 Dec 2018 15:30:08 +0100 Subject: [PATCH 004/304] Added Sf4 composer package type for bundles See https://symfony.com/doc/current/bundles/best_practices.html#installation --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8b3b287d..ea1f2f27 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "export" ], "homepage": "https://github.com/cleverage/process-bundle", - "type": "library", + "type": "symfony-bundle", "license": "MIT", "authors": [ { From a2be6cc4ed448dae3fb7c24627c68a17a662c750 Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Wed, 23 Jan 2019 16:20:50 +0100 Subject: [PATCH 005/304] Fix compatibility with SF4 of AbstractProcessTest --- Tests/AbstractProcessTest.php | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 1b3ade7b..ffe936c7 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -10,20 +10,17 @@ namespace CleverAge\ProcessBundle\Tests; +use CleverAge\ProcessBundle\EventListener\DataQueueEventListener; use CleverAge\ProcessBundle\Manager\ProcessManager; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\DependencyInjection\ContainerInterface; -use CleverAge\ProcessBundle\EventListener\DataQueueEventListener; /** * Provide all necessary setup to test a process */ abstract class AbstractProcessTest extends KernelTestCase { - /** @var ContainerInterface */ - protected $container; /** @var ProcessManager */ protected $processManager; @@ -36,16 +33,8 @@ abstract class AbstractProcessTest extends KernelTestCase */ protected function setUp() { - $kernel = static::bootKernel( - [ - 'environment' => 'test', - 'debug' => true, - ] - ); - - $this->container = $kernel->getContainer(); - $this->processManager = $this->container->get(ProcessManager::class); - $this->processConfigurationRegistry = $this->container->get(ProcessConfigurationRegistry::class); + $this->processManager = static::$container->get(ProcessManager::class); + $this->processConfigurationRegistry = static::$container->get(ProcessConfigurationRegistry::class); } /** @@ -58,7 +47,7 @@ protected function setUp() */ protected function assertDataQueue(array $expected, string $processName, bool $checkTask = true) { - $dataQueueListener = $this->container->get(DataQueueEventListener::class); + $dataQueueListener = static::$container->get(DataQueueEventListener::class); $actualQueue = $dataQueueListener->getQueue($processName); self::assertEquals(\count($expected), \count($actualQueue), 'Event count does not match'); From 12c360a69692678dc094e7e185af35141b3284b5 Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Tue, 5 Feb 2019 15:31:43 +0100 Subject: [PATCH 006/304] Load Doctrine tasks only if Doctrine is installed --- .../Doctrine/Task}/Database/DatabaseReaderTask.php | 4 ++-- .../Doctrine/Task}/Database/DatabaseUpdaterTask.php | 4 ++-- .../Task/EntityManager}/AbstractDoctrineQueryTask.php | 2 +- .../Task/EntityManager}/AbstractDoctrineTask.php | 2 +- .../Task/EntityManager}/ClearEntityManagerTask.php | 2 +- .../Task/EntityManager}/DoctrineBatchWriterTask.php | 5 +---- .../Task/EntityManager}/DoctrineDetacherTask.php | 3 +-- .../Task/EntityManager}/DoctrineReaderTask.php | 2 +- .../Task/EntityManager}/DoctrineRemoverTask.php | 4 +--- .../Task/EntityManager}/DoctrineWriterTask.php | 3 ++- .../Task/EntityManager}/PurgeDoctrineCacheTask.php | 6 +++++- DependencyInjection/CleverAgeProcessExtension.php | 11 +++++++++-- Documentation/reference/tasks/doctrine_reader_task.md | 2 +- Documentation/reference/tasks/doctrine_writer_task.md | 2 +- README.md | 2 +- Resources/config/services-doctrine/task.yml | 8 ++++++++ Resources/migration/move_doctrine_to_addon.sh | 4 ++++ composer.json | 6 ++++-- 18 files changed, 46 insertions(+), 26 deletions(-) rename {Task => Addon/Doctrine/Task}/Database/DatabaseReaderTask.php (98%) rename {Task => Addon/Doctrine/Task}/Database/DatabaseUpdaterTask.php (96%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/AbstractDoctrineQueryTask.php (98%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/AbstractDoctrineTask.php (96%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/ClearEntityManagerTask.php (92%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/DoctrineBatchWriterTask.php (92%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/DoctrineDetacherTask.php (91%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/DoctrineReaderTask.php (98%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/DoctrineRemoverTask.php (87%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/DoctrineWriterTask.php (94%) rename {Task/Doctrine => Addon/Doctrine/Task/EntityManager}/PurgeDoctrineCacheTask.php (94%) create mode 100644 Resources/config/services-doctrine/task.yml create mode 100644 Resources/migration/move_doctrine_to_addon.sh diff --git a/Task/Database/DatabaseReaderTask.php b/Addon/Doctrine/Task/Database/DatabaseReaderTask.php similarity index 98% rename from Task/Database/DatabaseReaderTask.php rename to Addon/Doctrine/Task/Database/DatabaseReaderTask.php index dab23c00..831cd279 100644 --- a/Task/Database/DatabaseReaderTask.php +++ b/Addon/Doctrine/Task/Database/DatabaseReaderTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Database; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\Database; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\FinalizableTaskInterface; @@ -134,7 +134,7 @@ public function finalize(ProcessState $state) * @throws \InvalidArgumentException * @throws \Doctrine\DBAL\DBALException * - * @return \Doctrine\DBAL\Driver\Statement + * @return \Doctrine\DBAL\Driver\ResultStatement */ protected function initializeStatement(ProcessState $state) { diff --git a/Task/Database/DatabaseUpdaterTask.php b/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php similarity index 96% rename from Task/Database/DatabaseUpdaterTask.php rename to Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php index bffd517b..5e840810 100644 --- a/Task/Database/DatabaseUpdaterTask.php +++ b/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Database; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\Database; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; @@ -63,7 +63,7 @@ public function execute(ProcessState $state) * @throws \InvalidArgumentException * @throws \Doctrine\DBAL\DBALException * - * @return \Doctrine\DBAL\Driver\Statement + * @return \Doctrine\DBAL\Driver\ResultStatement */ protected function initializeStatement(ProcessState $state) { diff --git a/Task/Doctrine/AbstractDoctrineQueryTask.php b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php similarity index 98% rename from Task/Doctrine/AbstractDoctrineQueryTask.php rename to Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php index d7217a6a..62b72dd6 100644 --- a/Task/Doctrine/AbstractDoctrineQueryTask.php +++ b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use Doctrine\ORM\EntityRepository; use Psr\Log\LogLevel; diff --git a/Task/Doctrine/AbstractDoctrineTask.php b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php similarity index 96% rename from Task/Doctrine/AbstractDoctrineTask.php rename to Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php index b528bbd3..47aac7e2 100644 --- a/Task/Doctrine/AbstractDoctrineTask.php +++ b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; diff --git a/Task/Doctrine/ClearEntityManagerTask.php b/Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php similarity index 92% rename from Task/Doctrine/ClearEntityManagerTask.php rename to Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php index 918ed66c..e21055e4 100644 --- a/Task/Doctrine/ClearEntityManagerTask.php +++ b/Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\ProcessState; diff --git a/Task/Doctrine/DoctrineBatchWriterTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php similarity index 92% rename from Task/Doctrine/DoctrineBatchWriterTask.php rename to Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php index 58e789b9..e82365d9 100644 --- a/Task/Doctrine/DoctrineBatchWriterTask.php +++ b/Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\FlushableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; @@ -32,7 +32,6 @@ class DoctrineBatchWriterTask extends AbstractDoctrineTask implements FlushableT * * @throws \Doctrine\ORM\ORMInvalidArgumentException * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \InvalidArgumentException */ public function flush(ProcessState $state) @@ -81,8 +80,6 @@ protected function configureOptions(OptionsResolver $resolver) * @param ProcessState $state * * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \UnexpectedValueException */ protected function writeBatch(ProcessState $state): void { diff --git a/Task/Doctrine/DoctrineDetacherTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php similarity index 91% rename from Task/Doctrine/DoctrineDetacherTask.php rename to Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php index 56b90197..cb5e0920 100644 --- a/Task/Doctrine/DoctrineDetacherTask.php +++ b/Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\ProcessState; use Doctrine\Common\Util\ClassUtils; @@ -27,7 +27,6 @@ class DoctrineDetacherTask extends AbstractDoctrineTask * * @throws \UnexpectedValueException * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \InvalidArgumentException */ public function execute(ProcessState $state) diff --git a/Task/Doctrine/DoctrineReaderTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php similarity index 98% rename from Task/Doctrine/DoctrineReaderTask.php rename to Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php index 32db3d28..b728119a 100644 --- a/Task/Doctrine/DoctrineReaderTask.php +++ b/Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; diff --git a/Task/Doctrine/DoctrineRemoverTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php similarity index 87% rename from Task/Doctrine/DoctrineRemoverTask.php rename to Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php index d5e4661d..4ea848c1 100644 --- a/Task/Doctrine/DoctrineRemoverTask.php +++ b/Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\ProcessState; use Doctrine\Common\Util\ClassUtils; @@ -27,9 +27,7 @@ class DoctrineRemoverTask extends AbstractDoctrineTask * * @throws \UnexpectedValueException * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \InvalidArgumentException - * @throws \Doctrine\ORM\ORMException */ public function execute(ProcessState $state) { diff --git a/Task/Doctrine/DoctrineWriterTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php similarity index 94% rename from Task/Doctrine/DoctrineWriterTask.php rename to Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php index e2dc26f7..93c68267 100644 --- a/Task/Doctrine/DoctrineWriterTask.php +++ b/Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\ProcessState; use Doctrine\Common\Util\ClassUtils; @@ -28,6 +28,7 @@ class DoctrineWriterTask extends AbstractDoctrineTask * @param ProcessState $state * * @throws \Doctrine\ORM\ORMException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface */ public function execute(ProcessState $state) { diff --git a/Task/Doctrine/PurgeDoctrineCacheTask.php b/Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php similarity index 94% rename from Task/Doctrine/PurgeDoctrineCacheTask.php rename to Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php index 47bd6d75..64d9e92b 100644 --- a/Task/Doctrine/PurgeDoctrineCacheTask.php +++ b/Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\Doctrine; +namespace CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; @@ -47,6 +47,8 @@ public function __construct(ManagerRegistry $doctrine) /** * @param ProcessState $state + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface */ public function execute(ProcessState $state) { @@ -65,6 +67,8 @@ public function execute(ProcessState $state) /** * @param EntityManagerInterface $entityManager * @param ProcessState $state + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface */ protected function purgeEntityManagerCache(EntityManagerInterface $entityManager, ProcessState $state): void { diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 14ad299f..04acbe4a 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -10,14 +10,15 @@ namespace CleverAge\ProcessBundle\DependencyInjection; +use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; +use Sidus\BaseBundle\DependencyInjection\Loader\ServiceLoader; use Sidus\BaseBundle\DependencyInjection\SidusBaseExtension; use Symfony\Component\DependencyInjection\ContainerBuilder; -use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; /** * This is the class that loads and manages your bundle configuration. * - * @see http://symfony.com/doc/current/cookbook/bundles/extension.html + * @see http://symfony.com/doc/current/cookbook/bundles/extension.html * * @author Valentin Clavreul * @author Vincent Chalnot @@ -34,6 +35,12 @@ public function load(array $configs, ContainerBuilder $container) { parent::load($configs, $container); + $loader = new ServiceLoader($container); + if (class_exists('\Doctrine\ORM\Version')) { + $serviceFolderPath = __DIR__.'/../Resources/config/services-doctrine'; + $loader->loadFiles($serviceFolderPath); + } + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Documentation/reference/tasks/doctrine_reader_task.md b/Documentation/reference/tasks/doctrine_reader_task.md index ce8b463c..8af89771 100644 --- a/Documentation/reference/tasks/doctrine_reader_task.md +++ b/Documentation/reference/tasks/doctrine_reader_task.md @@ -6,7 +6,7 @@ Reads data from a Doctrine Repository. Task reference -------------- -* **Service**: `CleverAge\ProcessBundle\Task\Doctrine\DoctrineReaderTask` +* **Service**: `CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineReaderTask` * **Iterable task** Accepted inputs diff --git a/Documentation/reference/tasks/doctrine_writer_task.md b/Documentation/reference/tasks/doctrine_writer_task.md index 2437c6e9..1b20916b 100644 --- a/Documentation/reference/tasks/doctrine_writer_task.md +++ b/Documentation/reference/tasks/doctrine_writer_task.md @@ -6,7 +6,7 @@ Write a Doctrine entity to the database. Task reference -------------- -* **Service**: `CleverAge\ProcessBundle\Task\Doctrine\DoctrineWriterTask` +* **Service**: `CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineWriterTask` Accepted inputs --------------- diff --git a/README.md b/README.md index e8a01a81..36485500 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ clever_age_process: entry_point: read tasks: read: - service: '@CleverAge\ProcessBundle\Task\Doctrine\DoctrineReaderTask' + service: '@CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineReaderTask' options: class_name: MyNamespace\FooBarBundle\Entity\Data outputs: [normalize] diff --git a/Resources/config/services-doctrine/task.yml b/Resources/config/services-doctrine/task.yml new file mode 100644 index 00000000..79e45e28 --- /dev/null +++ b/Resources/config/services-doctrine/task.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Addon\Doctrine\Task\: + resource: '../../../Addon/Doctrine/Task/*' + autowire: true + public: true + shared: false + tags: + - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/migration/move_doctrine_to_addon.sh b/Resources/migration/move_doctrine_to_addon.sh new file mode 100644 index 00000000..f1dcafdb --- /dev/null +++ b/Resources/migration/move_doctrine_to_addon.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Database/CleverAge\\ProcessBundle\\Addon\\Doctrine\\Task\\Database/g' {} \; +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Doctrine/CleverAge\\ProcessBundle\\Addon\\Doctrine\\Task\\EntityManager/g' {} \; diff --git a/composer.json b/composer.json index ea1f2f27..11f78218 100644 --- a/composer.json +++ b/composer.json @@ -41,8 +41,6 @@ "ext-json": "*", "symfony/framework-bundle": "~3.0|~4.0", - "doctrine/orm": "~2.5", - "doctrine/doctrine-bundle": "~1.6", "symfony/expression-language": "~3.0|~4.0", "symfony/monolog-bundle": "~3.3", "symfony/console": "~3.0|~4.0", @@ -58,5 +56,9 @@ }, "require-dev": { "phpunit/phpunit": "~6.4" + }, + "suggest": { + "doctrine/orm": "~2.5", + "doctrine/doctrine-bundle": "~1.6" } } From 9b967a26e6ef8fb852ef892828889130b41921ee Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Tue, 5 Feb 2019 15:54:30 +0100 Subject: [PATCH 007/304] Load Flysystem task only if OneupFlysystemBundle is enabled --- {Task/File => Addon/Flysystem/Task}/FileFetchTask.php | 8 ++------ DependencyInjection/CleverAgeProcessExtension.php | 7 +++++++ Resources/config/services-flysystem/task.yml | 8 ++++++++ Resources/migration/move_flysystem_to_addon.sh | 3 +++ composer.json | 3 ++- 5 files changed, 22 insertions(+), 7 deletions(-) rename {Task/File => Addon/Flysystem/Task}/FileFetchTask.php (97%) create mode 100644 Resources/config/services-flysystem/task.yml create mode 100644 Resources/migration/move_flysystem_to_addon.sh diff --git a/Task/File/FileFetchTask.php b/Addon/Flysystem/Task/FileFetchTask.php similarity index 97% rename from Task/File/FileFetchTask.php rename to Addon/Flysystem/Task/FileFetchTask.php index e33b7793..b2dbcdc7 100644 --- a/Task/File/FileFetchTask.php +++ b/Addon/Flysystem/Task/FileFetchTask.php @@ -1,14 +1,10 @@ getParameter('kernel.bundles'); + if (class_exists('\Doctrine\ORM\Version')) { $serviceFolderPath = __DIR__.'/../Resources/config/services-doctrine'; $loader->loadFiles($serviceFolderPath); } + if (array_key_exists('OneupFlysystemBundle', $bundles)) { + $serviceFolderPath = __DIR__.'/Resources/config/services-flysystem'; + $loader->loadFiles($serviceFolderPath); + } + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Resources/config/services-flysystem/task.yml b/Resources/config/services-flysystem/task.yml new file mode 100644 index 00000000..cf3ab04d --- /dev/null +++ b/Resources/config/services-flysystem/task.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Addon\Flysystem\Task\: + resource: '../../../Addon/Flysystem/Task/*' + autowire: true + public: true + shared: false + tags: + - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/migration/move_flysystem_to_addon.sh b/Resources/migration/move_flysystem_to_addon.sh new file mode 100644 index 00000000..c194a301 --- /dev/null +++ b/Resources/migration/move_flysystem_to_addon.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\File\\FileFetchTask/CleverAge\\ProcessBundle\\Addon\\Flysystem\\Task\\FileFetchTask/g' {} \; diff --git a/composer.json b/composer.json index 11f78218..d4b96042 100644 --- a/composer.json +++ b/composer.json @@ -59,6 +59,7 @@ }, "suggest": { "doctrine/orm": "~2.5", - "doctrine/doctrine-bundle": "~1.6" + "doctrine/doctrine-bundle": "~1.6", + "oneup/flysystem-bundle": "~1.13" } } From 5f683439cac3bf96c32806b89d3b54ea02d4ff8f Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Tue, 5 Feb 2019 12:18:46 +0100 Subject: [PATCH 008/304] Add optional soap request task and transformer --- CleverAgeProcessBundle.php | 11 + .../CleverAgeProcessExtension.php | 6 + Resources/config/services-soap/services.yml | 3 + Resources/config/services-soap/task.yml | 8 + .../config/services-soap/transformer.yml | 8 + Soap/Client/Client.php | 287 ++++++++++++++++++ Soap/Client/ClientInterface.php | 92 ++++++ Soap/Exception/MissingClientException.php | 33 ++ Soap/Registry.php | 70 +++++ Soap/Task/RequestTask.php | 102 +++++++ Soap/Transformer/RequestTransformer.php | 86 ++++++ composer.json | 1 + 12 files changed, 707 insertions(+) create mode 100644 Resources/config/services-soap/services.yml create mode 100644 Resources/config/services-soap/task.yml create mode 100644 Resources/config/services-soap/transformer.yml create mode 100644 Soap/Client/Client.php create mode 100644 Soap/Client/ClientInterface.php create mode 100644 Soap/Exception/MissingClientException.php create mode 100644 Soap/Registry.php create mode 100644 Soap/Task/RequestTask.php create mode 100644 Soap/Transformer/RequestTransformer.php diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index f78bb79a..dad3d6cd 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -12,6 +12,7 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use CleverAge\ProcessBundle\Soap\Registry as SoapRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -35,5 +36,15 @@ public function build(ContainerBuilder $container) 'addTransformer' ) ); + + if (extension_loaded('soap')) { + $container->addCompilerPass( + new RegistryCompilerPass( + SoapRegistry::class, + 'cleverage.soap.client', + 'addClient' + ) + ); + } } } diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 8480971a..0cd62eb5 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -22,6 +22,7 @@ * * @author Valentin Clavreul * @author Vincent Chalnot + * @author Madeline Veyrenc */ class CleverAgeProcessExtension extends SidusBaseExtension { @@ -48,6 +49,11 @@ public function load(array $configs, ContainerBuilder $container) $loader->loadFiles($serviceFolderPath); } + if (extension_loaded('soap')) { + $serviceFolderPath = __DIR__.'/../Resources/config/services-soap'; + $loader->loadFiles($serviceFolderPath); + } + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Resources/config/services-soap/services.yml b/Resources/config/services-soap/services.yml new file mode 100644 index 00000000..3cd7d7ff --- /dev/null +++ b/Resources/config/services-soap/services.yml @@ -0,0 +1,3 @@ +services: + CleverAge\ProcessBundle\Soap\Registry: + public: false diff --git a/Resources/config/services-soap/task.yml b/Resources/config/services-soap/task.yml new file mode 100644 index 00000000..83693495 --- /dev/null +++ b/Resources/config/services-soap/task.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Soap\Task\: + resource: '../../../Soap/Task/*' + autowire: true + public: true + shared: false + tags: + - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-soap/transformer.yml b/Resources/config/services-soap/transformer.yml new file mode 100644 index 00000000..e4fd4271 --- /dev/null +++ b/Resources/config/services-soap/transformer.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Soap\Transformer\: + resource: '../../../Soap/Transformer/*' + autowire: true + public: false + tags: + - { name: cleverage.transformer } + - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Soap/Client/Client.php b/Soap/Client/Client.php new file mode 100644 index 00000000..976b058f --- /dev/null +++ b/Soap/Client/Client.php @@ -0,0 +1,287 @@ + + */ +class Client implements ClientInterface +{ + /** @var string */ + private $code; + + /** @var string */ + private $wsdl; + + /** @var array */ + private $options = []; + + /** @var LoggerInterface */ + private $logger; + + /** @var \SoapClient */ + private $soapClient; + + /** @var string */ + private $lastRequest; + + /** @var string */ + private $lastRequestHeaders; + + /** @var string */ + private $lastResponse; + + /** @var string */ + private $lastResponseHeaders; + + /** + * Client constructor. + * + * @param LoggerInterface $logger + * @param string $code + * @param string $wsdl + * @param array $options + */ + public function __construct(LoggerInterface $logger, string $code, string $wsdl, array $options) + { + $this->logger = $logger; + $this->code = $code; + $this->wsdl = $wsdl; + $this->options = $options; + } + + /** + * @return LoggerInterface + */ + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + /** + * {@inheritdoc} + * @throws \UnexpectedValueException + */ + public function getCode(): string + { + if (!$this->code) { + throw new \UnexpectedValueException('Client code is not defined'); + } + + return $this->code; + } + + /** + * {@inheritdoc} + */ + public function getWsdl(): ?string + { + return $this->wsdl; + } + + /** + * {@inheritdoc} + */ + public function setWsdl(?string $wsdl): void + { + $this->wsdl = $wsdl; + } + + /** + * {@inheritdoc} + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * {@inheritdoc} + */ + public function setOptions(array $options): void + { + $this->options = $options; + } + + /** + * @return \SoapClient|null + */ + public function getSoapClient(): ?\SoapClient + { + return $this->soapClient; + } + + /** + * @param \SoapClient $soapClient + */ + public function setSoapClient(\SoapClient $soapClient): void + { + $this->soapClient = $soapClient; + } + + /** + * @return string + */ + public function getLastRequest(): string + { + return $this->lastRequest; + } + + /** + * @param string $lastRequest + */ + public function setLastRequest(string $lastRequest): void + { + $this->lastRequest = $lastRequest; + } + + /** + * @return string + */ + public function getLastRequestHeaders(): string + { + return $this->lastRequestHeaders; + } + + /** + * @param string $lastRequestHeaders + */ + public function setLastRequestHeaders(string $lastRequestHeaders): void + { + $this->lastRequestHeaders = $lastRequestHeaders; + } + + /** + * @return string + */ + public function getLastResponse(): string + { + return $this->lastResponse; + } + + /** + * @param string $lastResponse + */ + public function setLastResponse(string $lastResponse): void + { + $this->lastResponse = $lastResponse; + } + + /** + * @return string + */ + public function getLastResponseHeaders(): string + { + return $this->lastResponseHeaders; + } + + /** + * @param string $lastResponseHeaders + */ + public function setLastResponseHeaders(string $lastResponseHeaders): void + { + $this->lastResponseHeaders = $lastResponseHeaders; + } + + /** + * {@inheritdoc} + */ + public function call(string $method, array $input = []) + { + $this->initializeSoapClient(); + + $callMethod = sprintf('soapCall%s', ucfirst($method)); + if (method_exists($this, $callMethod)) { + return $this->$callMethod($input); + } + + $this->getLogger()->notice( + sprintf("Soap call '%s' on '%s'", $method, $this->getWsdl()) + ); + + return $this->doSoapCall($method, $input); + } + + /** + * @param string $method + * @param array $input + * + * @return bool|mixed + */ + protected function doSoapCall(string $method, array $input = []) + { + if (!$this->getSoapClient()) { + throw new \InvalidArgumentException('Soap client is not initialized'); + } + try { + $result = $this->getSoapClient()->__soapCall($method, [$input]); + } /** @noinspection PhpRedundantCatchClauseInspection */ catch (\SoapFault $e) { + $this->getLastRequestTrace(); + $this->getLogger()->alert( + sprintf("Soap call '%s' on '%s' failed : %s", $method, $this->getWsdl(), $e->getMessage()), + $this->getLastRequestTraceArray() + ); + + return false; + } + + $this->getLastRequestTrace(); + + if (array_key_exists('trace', $this->getOptions()) && $this->getOptions()['trace']) { + $this->getLogger()->debug( + sprintf("Trace of soap call '%s' on '%s'", $method, $this->getWsdl()), + $this->getLastRequestTraceArray() + ); + } + + return $result; + } + + /** + * Initialize \SoapClient object + * + * @return void + */ + protected function initializeSoapClient(): void + { + if (!$this->getSoapClient()) { + $options = array_merge($this->getOptions(), ['trace' => true]); + $this->setSoapClient(new \SoapClient($this->getWsdl(), $options)); + } + } + + protected function getLastRequestTrace(): void + { + if ($this->getSoapClient()) { + $this->setLastRequest($this->getSoapClient()->__getLastRequest()); + $this->setLastRequestHeaders($this->getSoapClient()->__getLastRequestHeaders()); + $this->setLastResponse($this->getSoapClient()->__getLastResponse()); + $this->setLastResponseHeaders($this->getSoapClient()->__getLastResponseHeaders()); + } + } + + /** + * @return array + */ + protected function getLastRequestTraceArray(): array + { + return [ + 'LastRequest' => $this->getLastRequest(), + 'LastRequestHeaders' => $this->getLastRequestHeaders(), + 'LastResponse' => $this->getLastResponse(), + 'LastResponseHeaders' => $this->getLastResponseHeaders(), + ]; + } +} diff --git a/Soap/Client/ClientInterface.php b/Soap/Client/ClientInterface.php new file mode 100644 index 00000000..40d20d6a --- /dev/null +++ b/Soap/Client/ClientInterface.php @@ -0,0 +1,92 @@ + + */ +interface ClientInterface +{ + /** + * Return the code of the client used in client registry. + * + * @return string + */ + public function getCode(): string; + + /** + * Return the URI of the WSDL file or NULL if working in non-WSDL mode. + * + * @return string + */ + public function getWsdl(): ?string; + + /** + * Set the URI of the WSDL file or NULL if working in non-WSDL mode. + * + * @param string $wsdl + * + * @return void + */ + public function setWsdl(?string $wsdl): void; + + /** + * Return the Soap client options + * + * @see http://php.net/manual/en/soapclient.soapclient.php + * + * @return array + */ + public function getOptions(): array; + + /** + * Set the Soap client options + * + * @see http://php.net/manual/en/soapclient.soapclient.php + * + * @param array $options + * + * @return void + */ + public function setOptions(array $options): void; + + /** + * @return string + */ + public function getLastRequest(): string; + + /** + * @return string + */ + public function getLastRequestHeaders(): string; + + /** + * @return string + */ + public function getLastResponse(): string; + + /** + * @return string + */ + public function getLastResponseHeaders(): string; + + /** + * Call Soap method + * + * @param string $method + * @param array $input + * + * @return mixed + */ + public function call(string $method, array $input = []); +} diff --git a/Soap/Exception/MissingClientException.php b/Soap/Exception/MissingClientException.php new file mode 100644 index 00000000..30ac78f3 --- /dev/null +++ b/Soap/Exception/MissingClientException.php @@ -0,0 +1,33 @@ + + */ +class MissingClientException extends \UnexpectedValueException implements ProcessExceptionInterface +{ + /** + * @param string $code + * + * @return MissingClientException + */ + public static function create($code) + { + $errorStr = "No Soap client with code : {$code}"; + + return new self($errorStr); + } +} diff --git a/Soap/Registry.php b/Soap/Registry.php new file mode 100644 index 00000000..e9168988 --- /dev/null +++ b/Soap/Registry.php @@ -0,0 +1,70 @@ + + */ +class Registry +{ + /** @var ClientInterface[] */ + private $clients = []; + + /** + * @param ClientInterface $client + */ + public function addClient(ClientInterface $client): void + { + if (array_key_exists($client->getCode(), $this->getClients())) { + throw new \UnexpectedValueException("Client {$client->getCode()} is already defined"); + } + $this->clients[$client->getCode()] = $client; + } + + /** + * @return ClientInterface[] + */ + public function getClients(): array + { + return $this->clients; + } + + /** + * @param string $code + * + * @throws MissingClientException + * + * @return ClientInterface + */ + public function getClient($code): ClientInterface + { + if (!$this->hasClient($code)) { + throw MissingClientException::create($code); + } + + return $this->getClients()[$code]; + } + + /** + * @param string $code + * + * @return bool + */ + public function hasClient($code): bool + { + return array_key_exists($code, $this->getClients()); + } +} diff --git a/Soap/Task/RequestTask.php b/Soap/Task/RequestTask.php new file mode 100644 index 00000000..867fc96d --- /dev/null +++ b/Soap/Task/RequestTask.php @@ -0,0 +1,102 @@ + + */ +class RequestTask extends AbstractConfigurableTask +{ + + /** @var LoggerInterface */ + protected $logger; + + /** @var Registry */ + protected $registry; + + /** + * SoapClientTask constructor. + * + * @param LoggerInterface $logger + * @param Registry $registry + */ + public function __construct(LoggerInterface $logger, Registry $registry) + { + $this->logger = $logger; + $this->registry = $registry; + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function execute(ProcessState $state) + { + $options = $this->getOptions($state); + + $client = $this->registry->getClient($options['client']); + + $input = $state->getInput() ?: []; + + $result = $client->call($options['method'], $input); + + // Handle empty results + if (false === $result) { + $logContext = [ + 'options' => $options, + 'last_request' => $client->getLastRequest(), + 'last_request_headers' => $client->getLastRequestHeaders(), + 'last_response' => $client->getLastResponse(), + 'last_response_headers' => $client->getLastResponseHeaders(), + ]; + + $state->setErrorOutput($result); + + $this->logger->error('Empty resultset for query', $logContext); + + if ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { + $state->setSkipped(true); + } elseif ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { + $state->setStopped(true); + } + } + + $state->setOutput($result); + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'client', + 'method', + ] + ); + $resolver->setAllowedTypes('client', ['string']); + $resolver->setAllowedTypes('method', ['string']); + } +} diff --git a/Soap/Transformer/RequestTransformer.php b/Soap/Transformer/RequestTransformer.php new file mode 100644 index 00000000..9f1d6bac --- /dev/null +++ b/Soap/Transformer/RequestTransformer.php @@ -0,0 +1,86 @@ + + */ +class RequestTransformer implements ConfigurableTransformerInterface +{ + /** @var Registry */ + protected $registry; + + /** + * RequestTransformer constructor. + * + * @param Registry $registry + */ + public function __construct(Registry $registry) + { + $this->registry = $registry; + } + + + /** + * {@inheritdoc} + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws \RuntimeException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function transform($value, array $options = []) + { + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + $options = $resolver->resolve($options); + + $client = $this->registry->getClient($options['client']); + + return $client->call($options['method'], $value); + } + + /** + * Returns the unique code to identify the transformer + * + * @return string + */ + public function getCode() + { + return 'soap_request'; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'client', + 'method', + ] + ); + $resolver->setAllowedTypes('client', ['string']); + $resolver->setAllowedTypes('method', ['string']); + } +} diff --git a/composer.json b/composer.json index d4b96042..fcaa007d 100644 --- a/composer.json +++ b/composer.json @@ -58,6 +58,7 @@ "phpunit/phpunit": "~6.4" }, "suggest": { + "ext-soap": "*", "doctrine/orm": "~2.5", "doctrine/doctrine-bundle": "~1.6", "oneup/flysystem-bundle": "~1.13" From 7aa9262b846ee2cd404b0e0fca6d012b706fd3db Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Tue, 5 Feb 2019 16:50:36 +0100 Subject: [PATCH 009/304] Add create method in Exception instead of overriding constructor --- Configuration/ProcessConfiguration.php | 2 +- Exception/MissingProcessException.php | 8 ++++++-- Exception/MissingTaskConfigurationException.php | 8 ++++++-- Exception/MissingTransformerException.php | 8 ++++++-- Registry/ProcessConfigurationRegistry.php | 2 +- Registry/TransformerRegistry.php | 2 +- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index a585c116..51c07898 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -176,7 +176,7 @@ public function getTaskConfigurations(): array public function getTaskConfiguration(string $taskCode): TaskConfiguration { if (!array_key_exists($taskCode, $this->taskConfigurations)) { - throw new MissingTaskConfigurationException($taskCode); + throw MissingTaskConfigurationException::create($taskCode); } return $this->taskConfigurations[$taskCode]; diff --git a/Exception/MissingProcessException.php b/Exception/MissingProcessException.php index c691d786..252b1fa5 100644 --- a/Exception/MissingProcessException.php +++ b/Exception/MissingProcessException.php @@ -20,9 +20,13 @@ class MissingProcessException extends \UnexpectedValueException implements Proce { /** * @param string $code + * + * @return MissingProcessException */ - public function __construct($code) + public static function create($code) { - parent::__construct("No process with code : {$code}"); + $errorStr = "No process with code : {$code}"; + + return new self($errorStr); } } diff --git a/Exception/MissingTaskConfigurationException.php b/Exception/MissingTaskConfigurationException.php index b4c67ef3..b1d7c53f 100644 --- a/Exception/MissingTaskConfigurationException.php +++ b/Exception/MissingTaskConfigurationException.php @@ -20,9 +20,13 @@ class MissingTaskConfigurationException extends \UnexpectedValueException implem { /** * @param string $code + * + * @return MissingTaskConfigurationException */ - public function __construct($code) + public static function create($code) { - parent::__construct("No task configuration with code : {$code}"); + $errorStr = "No task configuration with code : {$code}"; + + return new self($errorStr); } } diff --git a/Exception/MissingTransformerException.php b/Exception/MissingTransformerException.php index bbb7c1e7..471ee456 100644 --- a/Exception/MissingTransformerException.php +++ b/Exception/MissingTransformerException.php @@ -20,9 +20,13 @@ class MissingTransformerException extends \UnexpectedValueException implements P { /** * @param string $code + * + * @return MissingTransformerException */ - public function __construct($code) + public static function create($code) { - parent::__construct("No transformer with code : {$code}"); + $errorStr = "No transformer with code : {$code}"; + + return new self($errorStr); } } diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 8239dac8..d8e1b365 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -113,7 +113,7 @@ public function __construct(array $rawConfiguration, string $defaultErrorStrateg public function getProcessConfiguration(string $processCode): ProcessConfiguration { if (!$this->hasProcessConfiguration($processCode)) { - throw new MissingProcessException($processCode); + throw MissingProcessException::create($processCode); } return $this->processConfigurations[$processCode]; diff --git a/Registry/TransformerRegistry.php b/Registry/TransformerRegistry.php index c12466ae..8e85904c 100644 --- a/Registry/TransformerRegistry.php +++ b/Registry/TransformerRegistry.php @@ -53,7 +53,7 @@ public function getTransformers() public function getTransformer($code) { if (!$this->hasTransformer($code)) { - throw new MissingTransformerException($code); + throw MissingTransformerException::create($code); } return $this->transformers[$code]; From c5a3f5587b87ce3b722de7cf726a94b0f1931a9f Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Thu, 7 Feb 2019 10:40:32 +0100 Subject: [PATCH 010/304] Moving Soap directory in Addon --- {Soap => Addon/Soap}/Client/Client.php | 2 +- {Soap => Addon/Soap}/Client/ClientInterface.php | 2 +- {Soap => Addon/Soap}/Exception/MissingClientException.php | 2 +- {Soap => Addon/Soap}/Registry.php | 6 +++--- {Soap => Addon/Soap}/Task/RequestTask.php | 4 ++-- {Soap => Addon/Soap}/Transformer/RequestTransformer.php | 4 ++-- CleverAgeProcessBundle.php | 2 +- Resources/config/services-soap/services.yml | 2 +- Resources/config/services-soap/task.yml | 4 ++-- Resources/config/services-soap/transformer.yml | 4 ++-- 10 files changed, 16 insertions(+), 16 deletions(-) rename {Soap => Addon/Soap}/Client/Client.php (99%) rename {Soap => Addon/Soap}/Client/ClientInterface.php (97%) rename {Soap => Addon/Soap}/Exception/MissingClientException.php (93%) rename {Soap => Addon/Soap}/Registry.php (88%) rename {Soap => Addon/Soap}/Task/RequestTask.php (96%) rename {Soap => Addon/Soap}/Transformer/RequestTransformer.php (95%) diff --git a/Soap/Client/Client.php b/Addon/Soap/Client/Client.php similarity index 99% rename from Soap/Client/Client.php rename to Addon/Soap/Client/Client.php index 976b058f..723396e4 100644 --- a/Soap/Client/Client.php +++ b/Addon/Soap/Client/Client.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap\Client; +namespace CleverAge\ProcessBundle\Addon\Soap\Client; use Psr\Log\LoggerInterface; diff --git a/Soap/Client/ClientInterface.php b/Addon/Soap/Client/ClientInterface.php similarity index 97% rename from Soap/Client/ClientInterface.php rename to Addon/Soap/Client/ClientInterface.php index 40d20d6a..da40aa5e 100644 --- a/Soap/Client/ClientInterface.php +++ b/Addon/Soap/Client/ClientInterface.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap\Client; +namespace CleverAge\ProcessBundle\Addon\Soap\Client; /** * Interface ClientInterface diff --git a/Soap/Exception/MissingClientException.php b/Addon/Soap/Exception/MissingClientException.php similarity index 93% rename from Soap/Exception/MissingClientException.php rename to Addon/Soap/Exception/MissingClientException.php index 30ac78f3..1347ffe6 100644 --- a/Soap/Exception/MissingClientException.php +++ b/Addon/Soap/Exception/MissingClientException.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap\Exception; +namespace CleverAge\ProcessBundle\Addon\Soap\Exception; use CleverAge\ProcessBundle\Exception\ProcessExceptionInterface; diff --git a/Soap/Registry.php b/Addon/Soap/Registry.php similarity index 88% rename from Soap/Registry.php rename to Addon/Soap/Registry.php index e9168988..35b0a096 100644 --- a/Soap/Registry.php +++ b/Addon/Soap/Registry.php @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap; +namespace CleverAge\ProcessBundle\Addon\Soap; -use CleverAge\ProcessBundle\Soap\Client\ClientInterface; -use CleverAge\ProcessBundle\Soap\Exception\MissingClientException; +use CleverAge\ProcessBundle\Addon\Soap\Client\ClientInterface; +use CleverAge\ProcessBundle\Addon\Soap\Exception\MissingClientException; /** * Holds all tagged soap client services diff --git a/Soap/Task/RequestTask.php b/Addon/Soap/Task/RequestTask.php similarity index 96% rename from Soap/Task/RequestTask.php rename to Addon/Soap/Task/RequestTask.php index 867fc96d..cee94562 100644 --- a/Soap/Task/RequestTask.php +++ b/Addon/Soap/Task/RequestTask.php @@ -8,12 +8,12 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap\Task; +namespace CleverAge\ProcessBundle\Addon\Soap\Task; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use CleverAge\ProcessBundle\Soap\Registry; +use CleverAge\ProcessBundle\Addon\Soap\Registry; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/Soap/Transformer/RequestTransformer.php b/Addon/Soap/Transformer/RequestTransformer.php similarity index 95% rename from Soap/Transformer/RequestTransformer.php rename to Addon/Soap/Transformer/RequestTransformer.php index 9f1d6bac..49b633dc 100644 --- a/Soap/Transformer/RequestTransformer.php +++ b/Addon/Soap/Transformer/RequestTransformer.php @@ -8,9 +8,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Soap\Transformer; +namespace CleverAge\ProcessBundle\Addon\Soap\Transformer; -use CleverAge\ProcessBundle\Soap\Registry; +use CleverAge\ProcessBundle\Addon\Soap\Registry; use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index dad3d6cd..f4cc1118 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -10,9 +10,9 @@ namespace CleverAge\ProcessBundle; +use CleverAge\ProcessBundle\Addon\Soap\Registry as SoapRegistry; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use CleverAge\ProcessBundle\Soap\Registry as SoapRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; diff --git a/Resources/config/services-soap/services.yml b/Resources/config/services-soap/services.yml index 3cd7d7ff..b5671af0 100644 --- a/Resources/config/services-soap/services.yml +++ b/Resources/config/services-soap/services.yml @@ -1,3 +1,3 @@ services: - CleverAge\ProcessBundle\Soap\Registry: + CleverAge\ProcessBundle\Addon\Soap\Registry: public: false diff --git a/Resources/config/services-soap/task.yml b/Resources/config/services-soap/task.yml index 83693495..23996050 100644 --- a/Resources/config/services-soap/task.yml +++ b/Resources/config/services-soap/task.yml @@ -1,6 +1,6 @@ services: - CleverAge\ProcessBundle\Soap\Task\: - resource: '../../../Soap/Task/*' + CleverAge\ProcessBundle\Addon\Soap\Task\: + resource: '../../../Addon/Soap/Task/*' autowire: true public: true shared: false diff --git a/Resources/config/services-soap/transformer.yml b/Resources/config/services-soap/transformer.yml index e4fd4271..a0a61274 100644 --- a/Resources/config/services-soap/transformer.yml +++ b/Resources/config/services-soap/transformer.yml @@ -1,6 +1,6 @@ services: - CleverAge\ProcessBundle\Soap\Transformer\: - resource: '../../../Soap/Transformer/*' + CleverAge\ProcessBundle\Addon\Soap\Transformer\: + resource: '../../../Addon/Soap/Transformer/*' autowire: true public: false tags: From bcfb5893e4313506b435df7cba1210f71950d58b Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Thu, 7 Feb 2019 10:41:40 +0100 Subject: [PATCH 011/304] WSDL is nullable --- Addon/Soap/Client/Client.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Addon/Soap/Client/Client.php b/Addon/Soap/Client/Client.php index 723396e4..46e822f5 100644 --- a/Addon/Soap/Client/Client.php +++ b/Addon/Soap/Client/Client.php @@ -22,7 +22,7 @@ class Client implements ClientInterface /** @var string */ private $code; - /** @var string */ + /** @var string|null */ private $wsdl; /** @var array */ @@ -51,10 +51,10 @@ class Client implements ClientInterface * * @param LoggerInterface $logger * @param string $code - * @param string $wsdl + * @param string|null $wsdl * @param array $options */ - public function __construct(LoggerInterface $logger, string $code, string $wsdl, array $options) + public function __construct(LoggerInterface $logger, string $code, ?string $wsdl, array $options) { $this->logger = $logger; $this->code = $code; From d94a02e9cf5dc57d4cb9abbfb0148825431ee6c5 Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Thu, 7 Feb 2019 10:42:25 +0100 Subject: [PATCH 012/304] Attriute is overrided in constructor --- Addon/Soap/Client/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Addon/Soap/Client/Client.php b/Addon/Soap/Client/Client.php index 46e822f5..c3e80b4f 100644 --- a/Addon/Soap/Client/Client.php +++ b/Addon/Soap/Client/Client.php @@ -26,7 +26,7 @@ class Client implements ClientInterface private $wsdl; /** @var array */ - private $options = []; + private $options; /** @var LoggerInterface */ private $logger; From 3b10a3e0c0ae39a2d35e7e4639cc7af4a7d3fa06 Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Thu, 7 Feb 2019 16:22:58 +0100 Subject: [PATCH 013/304] Add Rest task and transformer --- Addon/Rest/Client/Client.php | 262 ++++++++++++++++++ Addon/Rest/Client/ClientInterface.php | 51 ++++ .../Rest/Exception/MissingClientException.php | 31 +++ Addon/Rest/Exception/RestException.php | 21 ++ Addon/Rest/Exception/RestRequestException.php | 21 ++ Addon/Rest/Registry.php | 66 +++++ Addon/Rest/Task/RequestTask.php | 122 ++++++++ Addon/Rest/Transformer/RequestTransformer.php | 130 +++++++++ CleverAgeProcessBundle.php | 14 + .../CleverAgeProcessExtension.php | 5 + Resources/config/services-rest/services.yml | 3 + Resources/config/services-rest/task.yml | 8 + .../config/services-rest/transformer.yml | 8 + composer.json | 3 +- 14 files changed, 744 insertions(+), 1 deletion(-) create mode 100644 Addon/Rest/Client/Client.php create mode 100644 Addon/Rest/Client/ClientInterface.php create mode 100644 Addon/Rest/Exception/MissingClientException.php create mode 100644 Addon/Rest/Exception/RestException.php create mode 100644 Addon/Rest/Exception/RestRequestException.php create mode 100644 Addon/Rest/Registry.php create mode 100644 Addon/Rest/Task/RequestTask.php create mode 100644 Addon/Rest/Transformer/RequestTransformer.php create mode 100644 Resources/config/services-rest/services.yml create mode 100644 Resources/config/services-rest/task.yml create mode 100644 Resources/config/services-rest/transformer.yml diff --git a/Addon/Rest/Client/Client.php b/Addon/Rest/Client/Client.php new file mode 100644 index 00000000..df1cd2fa --- /dev/null +++ b/Addon/Rest/Client/Client.php @@ -0,0 +1,262 @@ + + */ +class Client implements ClientInterface +{ + /** @var LoggerInterface */ + private $logger; + + /** @var string */ + private $code; + + /** @var string */ + private $uri; + + /** + * Shopify constructor. + * + * @param LoggerInterface $logger + * @param string $code + * @param string $uri + */ + public function __construct(LoggerInterface $logger, string $code, string $uri) + { + $this->logger = $logger; + $this->code = $code; + $this->uri = $uri; + } + + /** + * @return LoggerInterface + */ + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + /** + * @return string + */ + public function getCode(): string + { + return $this->code; + } + + /** + * @return string + */ + public function geUri(): string + { + return $this->uri; + } + + /** + * @param string $uri + */ + public function setUri(string $uri): void + { + $this->uri = $uri; + } + + /** + * @param array $options + * + * @return Response + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws \InvalidArgumentException + * @throws \Httpful\Exception\ConnectionErrorException + * @throws RestRequestException + * @throws \Exception + */ + public function call(array $options = []): Response + { + $options = $this->getOptions($options); + + $request = $this->initializeRequest($options); + $this->setRequestQueryParameters($request, $options); + $this->setRequestHeader($request, $options); + + return $request->send(); + } + + /** + * @param OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + */ + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + 'url', + ] + ); + + $resolver->setDefault('method', 'GET'); + $resolver->setDefault('url_parameters', []); + $resolver->setDefault('query_parameters', []); + $resolver->setDefault('headers', []); + $resolver->setDefault('sends', 'json'); + $resolver->setDefault('expects', 'json'); + + $resolver->setAllowedTypes('url', ['string']); + $resolver->setAllowedTypes('method', ['string']); + $resolver->setAllowedTypes('sends', ['string']); + $resolver->setAllowedTypes('expects', ['string']); + $resolver->setAllowedTypes('url_parameters', ['array']); + $resolver->setAllowedTypes('query_parameters', ['array']); + $resolver->setAllowedTypes('headers', ['array']); + } + + /** + * @param array $options + * + * @return array + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + */ + protected function getOptions(array $options = []): array + { + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + + return $resolver->resolve($options); + } + + /** + * @param array $options + * + * @return Request + * + * @throws RestRequestException + */ + protected function initializeRequest(array $options = []): Request + { + if (!in_array( + $options['method'], + [Http::HEAD, Http::GET, Http::POST, Http::PUT, Http::DELETE, Http::OPTIONS, Http::TRACE, Http::PATCH], + true + )) { + throw new RestRequestException(sprintf('%s is not an HTTP method', $options['method'])); + } + $request = Request::init($options['method']); + $request->sends($options['sends']); + $request->expects($options['expects']); + + return $request; + } + + /** + * @param Request $request + * @param array $options + * + * + * @throws \Exception + */ + protected function setRequestQueryParameters(Request $request, array $options = []): void + { + $uri = $this->constructUri($options); + if (Http::GET === $options['method']) { + if (is_array($options['query_parameters'])) { + $parametersString = http_build_query($options['query_parameters']); + } else { + $parametersString = (string) $options['query_parameters']; + } + $uri .= strpos($uri, '?') ? '&' : '?'; + $uri .= $parametersString; + } elseif ($options['query_parameters']) { + $request->body($options['query_parameters']); + } + + $uri = $this->replaceParametersInUri($uri, $options); + $request->uri($uri); + } + + /** + * @param Request $request + * @param array $options + * + * + */ + protected function setRequestHeader(Request $request, array $options = []): void + { + if ($options['headers']) { + $request->addHeaders($options['headers']); + } + } + + /** + * @return string + */ + protected function getApiUrl(): string + { + return sprintf('%s', $this->geUri()); + } + + /** + * @param array $options + * + * @return string + */ + protected function constructUri(array $options): string + { + $uri = ltrim($options['url'], '/'); + + return sprintf('%s/%s', $this->getApiUrl(), $uri); + } + + /** + * @param string $uri + * @param array $options + * + * @return string + * + */ + protected function replaceParametersInUri(string $uri, array $options = []): string + { + if (array_key_exists('url_parameters', $options) + && $options['url_parameters']) { + + $search = array_keys($options['url_parameters']); + array_walk( + $search, + function (&$item) { + $item = '{'.$item.'}'; + } + ); + $replace = array_values($options['url_parameters']); + + $uri = str_replace($search, $replace, $uri); + } + + return $uri; + } +} diff --git a/Addon/Rest/Client/ClientInterface.php b/Addon/Rest/Client/ClientInterface.php new file mode 100644 index 00000000..cc49f588 --- /dev/null +++ b/Addon/Rest/Client/ClientInterface.php @@ -0,0 +1,51 @@ + + */ +interface ClientInterface +{ + /** + * Return the code of the client used in client registry. + * + * @return string + */ + public function getCode(): string; + + /** + * Return the URI + * + * @return string + */ + public function geUri(): string; + + /** + * Set the URI + * + * @param string $uri + * + * @return void + */ + public function setUri(string $uri): void; + + /** + * @param array $options + * + * @return \Httpful\Response + */ + public function call(array $options = []): Response; +} diff --git a/Addon/Rest/Exception/MissingClientException.php b/Addon/Rest/Exception/MissingClientException.php new file mode 100644 index 00000000..9d21e480 --- /dev/null +++ b/Addon/Rest/Exception/MissingClientException.php @@ -0,0 +1,31 @@ + + */ +class MissingClientException extends RestException +{ + /** + * @param string $code + * + * @return MissingClientException + */ + public static function create($code) + { + $errorStr = "No rest client with code : {$code}"; + + return new self($errorStr); + } +} diff --git a/Addon/Rest/Exception/RestException.php b/Addon/Rest/Exception/RestException.php new file mode 100644 index 00000000..bbf37ec5 --- /dev/null +++ b/Addon/Rest/Exception/RestException.php @@ -0,0 +1,21 @@ + + */ +class RestException extends \Exception +{ + +} diff --git a/Addon/Rest/Exception/RestRequestException.php b/Addon/Rest/Exception/RestRequestException.php new file mode 100644 index 00000000..e1ae1bca --- /dev/null +++ b/Addon/Rest/Exception/RestRequestException.php @@ -0,0 +1,21 @@ + + */ +class RestRequestException extends RestException +{ + +} diff --git a/Addon/Rest/Registry.php b/Addon/Rest/Registry.php new file mode 100644 index 00000000..4ecb27eb --- /dev/null +++ b/Addon/Rest/Registry.php @@ -0,0 +1,66 @@ + + */ +class Registry +{ + /** @var ClientInterface[] */ + private $clients = []; + + /** + * @param ClientInterface $client + */ + public function addClient(ClientInterface $client): void + { + if (array_key_exists($client->getCode(), $this->getClients())) { + throw new \UnexpectedValueException("Client {$client->getCode()} is already defined"); + } + $this->clients[$client->getCode()] = $client; + } + + /** + * @return ClientInterface[] + */ + public function getClients(): array + { + return $this->clients; + } + + /** + * @param string $code + * + * @throws MissingClientException + * + * @return ClientInterface + */ + public function getClient($code): ClientInterface + { + if (!$this->hasClient($code)) { + throw MissingClientException::create($code); + } + + return $this->getClients()[$code]; + } + + /** + * @param string $code + * + * @return bool + */ + public function hasClient($code): bool + { + return array_key_exists($code, $this->getClients()); + } +} diff --git a/Addon/Rest/Task/RequestTask.php b/Addon/Rest/Task/RequestTask.php new file mode 100644 index 00000000..7944db70 --- /dev/null +++ b/Addon/Rest/Task/RequestTask.php @@ -0,0 +1,122 @@ + + */ +class RequestTask extends AbstractConfigurableTask +{ + + /** @var LoggerInterface */ + protected $logger; + + /** @var Registry */ + protected $registry; + + /** + * RequestTask constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger, Registry $registry) + { + $this->logger = $logger; + $this->registry = $registry; + } + + /** + * {@inheritdoc} + * @param ProcessState $state + * + * @throws \CleverAge\ProcessBundle\Addon\Rest\Exception\MissingClientException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function execute(ProcessState $state) + { + $options = $this->getOptions($state); + + $client = $this->registry->getClient($options['client']); + + $requestOptions = [ + 'url' => $options['url'], + 'headers' => $options['headers'], + 'url_parameters' => $options['url_parameters'], + 'query_parameters' => $options['query_parameters'], + 'sends' => $options['sends'], + 'expects' => $options['expects'], + ]; + + $input = $state->getInput() ?: []; + $requestOptions = array_merge($requestOptions, $input); + $result = $client->call($requestOptions); + + // Handle empty results + if (!\in_array($result->code, $options['valid_response_code'], false)) { + $this->logger->error( + 'REST request failed', + [ + 'client' => $options['client'], + 'options' => $options, + 'raw_headers' => $result->raw_headers, + 'raw_body' => $result->raw_body, + ] + ); + $state->setErrorOutput($result->body); + + if ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { + $state->setSkipped(true); + } elseif ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { + $state->setStopped(true); + } + + return; + } + + $state->setOutput($result->body); + } + + /** + * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'client', + 'url', + 'method', + ] + ); + $resolver->setDefault('headers', []); + $resolver->setDefault('url_parameters', []); + $resolver->setDefault('query_parameters', []); + $resolver->setDefault('sends', 'json'); + $resolver->setDefault('expects', 'json'); + $resolver->setDefault('valid_response_code', [200]); + $resolver->setAllowedTypes('client', ['string']); + $resolver->setAllowedTypes('url', ['string']); + $resolver->setAllowedTypes('method', ['string']); + $resolver->setAllowedTypes('valid_response_code', ['array']); + } +} diff --git a/Addon/Rest/Transformer/RequestTransformer.php b/Addon/Rest/Transformer/RequestTransformer.php new file mode 100644 index 00000000..737bb66b --- /dev/null +++ b/Addon/Rest/Transformer/RequestTransformer.php @@ -0,0 +1,130 @@ + + */ +class RequestTransformer implements ConfigurableTransformerInterface +{ + + /** @var LoggerInterface */ + protected $logger; + + /** @var Registry */ + protected $registry; + + /** + * RequestTransformer constructor. + * + * @param Registry $registry + */ + public function __construct(LoggerInterface $logger, Registry $registry) + { + $this->logger = $logger; + $this->registry = $registry; + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws \RuntimeException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws \CleverAge\ProcessBundle\Addon\Rest\Exception\MissingClientException + */ + public function transform($value, array $options = []) + { + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + $options = $resolver->resolve($options); + + $client = $this->registry->getClient($options['client']); + + $requestOptions = [ + 'url' => $options['url'], + 'headers' => $options['headers'], + 'url_parameters' => $options['url_parameters'], + 'query_parameters' => $options['query_parameters'], + 'sends' => $options['sends'], + 'expects' => $options['expects'], + ]; + + $input = $value ?: []; + $requestOptions = array_merge($requestOptions, $input); + $result = $client->call($requestOptions); + + // Handle empty results + if (!\in_array($result->code, $options['valid_response_code'], false)) { + $this->logger->error( + 'REST request failed', + [ + 'client' => $options['client'], + 'options' => $options, + 'raw_headers' => $result->raw_headers, + 'raw_body' => $result->raw_body, + ] + ); + + throw new TransformerException('REST request failed'); + } + + return $result->body; + } + + /** + * Returns the unique code to identify the transformer + * + * @return string + */ + public function getCode() + { + return 'rest_request'; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'client', + 'url', + 'method', + ] + ); + $resolver->setDefault('headers', []); + $resolver->setDefault('url_parameters', []); + $resolver->setDefault('query_parameters', []); + $resolver->setDefault('sends', 'json'); + $resolver->setDefault('expects', 'json'); + $resolver->setDefault('valid_response_code', [200]); + $resolver->setAllowedTypes('client', ['string']); + $resolver->setAllowedTypes('url', ['string']); + $resolver->setAllowedTypes('method', ['string']); + $resolver->setAllowedTypes('valid_response_code', ['array']); + } +} diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index f4cc1118..536ff1d5 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle; +use CleverAge\ProcessBundle\Addon\Rest\Registry as RestRegistry; use CleverAge\ProcessBundle\Addon\Soap\Registry as SoapRegistry; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; @@ -17,8 +18,11 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; /** + * Class CleverAgeProcessBundle + * * @author Valentin Clavreul * @author Vincent Chalnot + * @author Madeline Veyrenc */ class CleverAgeProcessBundle extends Bundle { @@ -46,5 +50,15 @@ public function build(ContainerBuilder $container) ) ); } + + if (class_exists('\Httpful\Request')) { + $container->addCompilerPass( + new RegistryCompilerPass( + RestRegistry::class, + 'cleverage.rest.client', + 'addClient' + ) + ); + } } } diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 0cd62eb5..50169225 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -54,6 +54,11 @@ public function load(array $configs, ContainerBuilder $container) $loader->loadFiles($serviceFolderPath); } + if (class_exists('\Httpful\Request')) { + $serviceFolderPath = __DIR__.'/../Resources/config/services-rest'; + $loader->loadFiles($serviceFolderPath); + } + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Resources/config/services-rest/services.yml b/Resources/config/services-rest/services.yml new file mode 100644 index 00000000..2367cef4 --- /dev/null +++ b/Resources/config/services-rest/services.yml @@ -0,0 +1,3 @@ +services: + CleverAge\ProcessBundle\Addon\Rest\Registry: + public: false diff --git a/Resources/config/services-rest/task.yml b/Resources/config/services-rest/task.yml new file mode 100644 index 00000000..54474d84 --- /dev/null +++ b/Resources/config/services-rest/task.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Addon\Rest\Task\: + resource: '../../../Addon/Rest/Task/*' + autowire: true + public: true + shared: false + tags: + - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-rest/transformer.yml b/Resources/config/services-rest/transformer.yml new file mode 100644 index 00000000..6433c91e --- /dev/null +++ b/Resources/config/services-rest/transformer.yml @@ -0,0 +1,8 @@ +services: + CleverAge\ProcessBundle\Addon\Rest\Transformer\: + resource: '../../../Addon/Rest/Transformer/*' + autowire: true + public: false + tags: + - { name: cleverage.transformer } + - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/composer.json b/composer.json index fcaa007d..e27c4972 100644 --- a/composer.json +++ b/composer.json @@ -61,6 +61,7 @@ "ext-soap": "*", "doctrine/orm": "~2.5", "doctrine/doctrine-bundle": "~1.6", - "oneup/flysystem-bundle": "~1.13" + "oneup/flysystem-bundle": "~1.13", + "nategood/httpful": "~0.2.20" } } From 1dd732fcf76747eb695cfa7e696407f210cbb394 Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Fri, 8 Feb 2019 17:08:39 +0100 Subject: [PATCH 014/304] Booting kernel on test setup --- Tests/AbstractProcessTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index ffe936c7..7e024a1d 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -33,6 +33,8 @@ abstract class AbstractProcessTest extends KernelTestCase */ protected function setUp() { + static::bootKernel(); + $this->processManager = static::$container->get(ProcessManager::class); $this->processConfigurationRegistry = static::$container->get(ProcessConfigurationRegistry::class); } From a5e76f9b8e2f1fc830d26b2deb53d7b42be9613e Mon Sep 17 00:00:00 2001 From: Madeline VEYRENC Date: Fri, 8 Feb 2019 15:56:49 +0100 Subject: [PATCH 015/304] Add tasks and transformers for cache manupulation --- .../Task/Database/DatabaseUpdaterTask.php | 5 +- CleverAgeProcessBundle.php | 5 + .../Compiler/CachePoolPass.php | 54 +++++ Documentation/reference/addons/cache.md | 33 +++ Registry/ProcessConfigurationRegistry.php | 2 +- Resources/config/services/task.yml | 5 + Resources/config/services/transformer.yml | 5 + Resources/tests/task/cache_deleter_task.yml | 65 ++++++ Resources/tests/task/cache_getter_task.yml | 86 ++++++++ Resources/tests/task/cache_setter_task.yml | 65 ++++++ .../transfomer/cache_deleter_transformer.yml | 94 ++++++++ .../transfomer/cache_getter_transformer.yml | 118 +++++++++++ .../transfomer/cache_setter_transformer.yml | 94 ++++++++ Task/Cache/AbstractCacheTask.php | 200 ++++++++++++++++++ Task/Cache/DeleterTask.php | 33 +++ Task/Cache/GetterTask.php | 36 ++++ Task/Cache/SetterTask.php | 35 +++ Tests/Task/Cache/DeleterTaskTest.php | 125 +++++++++++ Tests/Task/Cache/GetterTaskTest.php | 107 ++++++++++ Tests/Task/Cache/SetterTaskTest.php | 124 +++++++++++ .../Cache/DeleterTransformerTest.php | 128 +++++++++++ .../Cache/GetterTransformerTest.php | 118 +++++++++++ .../Cache/SetterTransformerTest.php | 126 +++++++++++ .../Cache/AbstractCacheTransformer.php | 200 ++++++++++++++++++ Transformer/Cache/DeleterTransformer.php | 38 ++++ Transformer/Cache/GetterTransformer.php | 63 ++++++ Transformer/Cache/SetterTransformer.php | 40 ++++ Transformer/TransformerTrait.php | 18 +- 28 files changed, 2015 insertions(+), 7 deletions(-) create mode 100644 DependencyInjection/Compiler/CachePoolPass.php create mode 100644 Documentation/reference/addons/cache.md create mode 100644 Resources/tests/task/cache_deleter_task.yml create mode 100644 Resources/tests/task/cache_getter_task.yml create mode 100644 Resources/tests/task/cache_setter_task.yml create mode 100644 Resources/tests/transfomer/cache_deleter_transformer.yml create mode 100644 Resources/tests/transfomer/cache_getter_transformer.yml create mode 100644 Resources/tests/transfomer/cache_setter_transformer.yml create mode 100644 Task/Cache/AbstractCacheTask.php create mode 100644 Task/Cache/DeleterTask.php create mode 100644 Task/Cache/GetterTask.php create mode 100644 Task/Cache/SetterTask.php create mode 100644 Tests/Task/Cache/DeleterTaskTest.php create mode 100644 Tests/Task/Cache/GetterTaskTest.php create mode 100644 Tests/Task/Cache/SetterTaskTest.php create mode 100644 Tests/Transformer/Cache/DeleterTransformerTest.php create mode 100644 Tests/Transformer/Cache/GetterTransformerTest.php create mode 100644 Tests/Transformer/Cache/SetterTransformerTest.php create mode 100644 Transformer/Cache/AbstractCacheTransformer.php create mode 100644 Transformer/Cache/DeleterTransformer.php create mode 100644 Transformer/Cache/GetterTransformer.php create mode 100644 Transformer/Cache/SetterTransformer.php diff --git a/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php b/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php index 5e840810..26dbbd59 100644 --- a/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php +++ b/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php @@ -69,7 +69,10 @@ protected function initializeStatement(ProcessState $state) { $connection = $this->getConnection($state); - return $connection->executeQuery($this->getOption($state, 'sql')); + $input = $state->getInput(); + $params = is_array($input) ? $input : []; + + return $connection->executeQuery($this->getOption($state, 'sql'), $params); } /** diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index 536ff1d5..34d43783 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -12,6 +12,7 @@ use CleverAge\ProcessBundle\Addon\Rest\Registry as RestRegistry; use CleverAge\ProcessBundle\Addon\Soap\Registry as SoapRegistry; +use CleverAge\ProcessBundle\DependencyInjection\Compiler\CachePoolPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -60,5 +61,9 @@ public function build(ContainerBuilder $container) ) ); } + +// $container->addCompilerPass( +// new CachePoolPass() +// ); } } diff --git a/DependencyInjection/Compiler/CachePoolPass.php b/DependencyInjection/Compiler/CachePoolPass.php new file mode 100644 index 00000000..3b38aec6 --- /dev/null +++ b/DependencyInjection/Compiler/CachePoolPass.php @@ -0,0 +1,54 @@ + + */ +class CachePoolPass implements CompilerPassInterface +{ + /** + * Inject tagged services into defined registry + * + * @api + * + * @param ContainerBuilder $container + * + * @throws InvalidArgumentException + * @throws \UnexpectedValueException + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException + * @throws \Exception + */ + public function process(ContainerBuilder $container) + { + $name = 'cache.app.cleverage_process'; + $pool = [ + 'adapter' => 'cache.app', + 'public' => true, + ]; + $definition = new ChildDefinition($pool['adapter']); + $container->registerAliasForArgument($name, CacheInterface::class); + $container->registerAliasForArgument($name, CacheItemPoolInterface::class); + $definition->setPublic($pool['public']); + + $definition->addTag('cache.pool'); + $container->setDefinition($name, $definition); + } +} diff --git a/Documentation/reference/addons/cache.md b/Documentation/reference/addons/cache.md new file mode 100644 index 00000000..facc4d43 --- /dev/null +++ b/Documentation/reference/addons/cache.md @@ -0,0 +1,33 @@ +Cache addon +=========== + +Contains tasks and transformers to handle cache. + +Activation +---------- + +Activated if cache pool `cleverage_process` is defined. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\ArrayFilterTransformer` +* **Transformer code**: `array_filter` + +Accepted inputs +--------------- + +`array` or `\Iterable` + +Possible outputs +---------------- + +`array` containing only filtered data + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `condition` | `array` | | `[]` | See [ConditionTrait](TODO) | +____ diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index d8e1b365..106f9e0a 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -27,7 +27,7 @@ class ProcessConfigurationRegistry protected $processConfigurations = []; /** - * @param array $rawConfiguration + * @param array $rawConfiguration * @param string $defaultErrorStrategy */ public function __construct(array $rawConfiguration, string $defaultErrorStrategy) diff --git a/Resources/config/services/task.yml b/Resources/config/services/task.yml index 61e64bf7..04eed02e 100644 --- a/Resources/config/services/task.yml +++ b/Resources/config/services/task.yml @@ -6,3 +6,8 @@ services: shared: false tags: - { name: monolog.logger, channel: cleverage_process_task } + + CleverAge\ProcessBundle\Task\Cache\: + resource: '../../../Task/Cache\*' + arguments: + $cache: '@cache.app' diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml index a058d18c..a88f4f5b 100644 --- a/Resources/config/services/transformer.yml +++ b/Resources/config/services/transformer.yml @@ -6,3 +6,8 @@ services: tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } + + CleverAge\ProcessBundle\Transformer\Cache\: + resource: '../../../Transformer/Cache\*' + arguments: + $cache: '@cache.app' diff --git a/Resources/tests/task/cache_deleter_task.yml b/Resources/tests/task/cache_deleter_task.yml new file mode 100644 index 00000000..7ce7165a --- /dev/null +++ b/Resources/tests/task/cache_deleter_task.yml @@ -0,0 +1,65 @@ +clever_age_process: + configurations: + test.cache_deleter_task.delete_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' + options: + key: + constant: 'DeleterTaskTest_testDeleteExistingCache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_task.delete_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' + options: + key: + constant: 'DeleterTaskTest_testDeleteMissingCache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_task.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' + options: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_task.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' + options: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/task/cache_getter_task.yml b/Resources/tests/task/cache_getter_task.yml new file mode 100644 index 00000000..3bd06b5e --- /dev/null +++ b/Resources/tests/task/cache_getter_task.yml @@ -0,0 +1,86 @@ +clever_age_process: + configurations: + test.cache_getter_task.get_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' + options: + key: + constant: 'GetterTaskTest_testGetExistingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_task.get_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' + options: + key: + constant: 'GetterTaskTest_testGetMissingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_task.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' + options: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_task.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' + options: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/task/cache_setter_task.yml b/Resources/tests/task/cache_setter_task.yml new file mode 100644 index 00000000..77fdba8c --- /dev/null +++ b/Resources/tests/task/cache_setter_task.yml @@ -0,0 +1,65 @@ +clever_age_process: + configurations: + test.cache_setter_task.set_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' + options: + key: + constant: 'SetterTaskTest_testSetExistingCache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_task.set_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' + options: + key: + constant: 'SetterTaskTest_testSetMissingCache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_task.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' + options: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_task.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' + options: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_deleter_transformer.yml b/Resources/tests/transfomer/cache_deleter_transformer.yml new file mode 100644 index 00000000..33a7a7db --- /dev/null +++ b/Resources/tests/transfomer/cache_deleter_transformer.yml @@ -0,0 +1,94 @@ +clever_age_process: + configurations: + test.cache_deleter_transformer.delete_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_deleter: + key: + constant: 'DeleterTransformerTest_testDeleteExistingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_transformer.delete_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_deleter: + key: + constant: 'DeleterTransformerTest_testDeleteMissingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_transformer.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_deleter: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_deleter_transformer.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_deleter: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_getter_transformer.yml b/Resources/tests/transfomer/cache_getter_transformer.yml new file mode 100644 index 00000000..01dc8347 --- /dev/null +++ b/Resources/tests/transfomer/cache_getter_transformer.yml @@ -0,0 +1,118 @@ +clever_age_process: + configurations: + test.cache_getter_transformer.get_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_getter: + key: + constant: 'GetterTransformerTest_testGetExistingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_transformer.get_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_getter: + key: + constant: 'GetterTransformerTest_testGetMissingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_transformer.ignore_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_getter: + key: + constant: 'GetterTransformerTest_testIgnoreMissingCache' + ignore_not_hit: true + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_transformer.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_getter: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_getter_transformer.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_getter: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_setter_transformer.yml b/Resources/tests/transfomer/cache_setter_transformer.yml new file mode 100644 index 00000000..13ea5442 --- /dev/null +++ b/Resources/tests/transfomer/cache_setter_transformer.yml @@ -0,0 +1,94 @@ +clever_age_process: + configurations: + test.cache_setter_transformer.set_existing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_setter: + key: + constant: 'SetterTransformerTest_testSetExistingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_transformer.set_missing_cache: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_setter: + key: + constant: 'SetterTransformerTest_testSetMissingCache' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_transformer.transform_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_setter: + key: + transformers: + implode: + separator: '_' + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.cache_setter_transformer.bad_cache_key: + entry_point: get_cache + end_point: dummy + tasks: + get_cache: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + cache_setter: + key: ~ + outputs: [dummy] + error_outputs: [missing_cache] + + missing_cache: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: 'missing cache' + outputs: [dummy] + + dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Task/Cache/AbstractCacheTask.php b/Task/Cache/AbstractCacheTask.php new file mode 100644 index 00000000..d8fc8db5 --- /dev/null +++ b/Task/Cache/AbstractCacheTask.php @@ -0,0 +1,200 @@ + + */ +abstract class AbstractCacheTask extends AbstractConfigurableTask +{ + use TransformerTrait; + + /** @var LoggerInterface */ + private $logger; + + /** @var PropertyAccessorInterface */ + private $accessor; + + /** @var CacheItemPoolInterface */ + private $cache; + + /** + * SetterTask constructor. + * + * @param LoggerInterface $logger + * @param PropertyAccessorInterface $accessor + * @param CacheItemPoolInterface $cache + * @param TransformerRegistry $transformerRegistry + */ + public function __construct( + LoggerInterface $logger, + PropertyAccessorInterface $accessor, + CacheItemPoolInterface $cache, + TransformerRegistry $transformerRegistry + ) { + $this->logger = $logger; + $this->accessor = $accessor; + $this->cache = $cache; + $this->transformerRegistry = $transformerRegistry; + } + + /** + * @return LoggerInterface + */ + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + /** + * @return PropertyAccessorInterface + */ + public function getAccessor(): PropertyAccessorInterface + { + return $this->accessor; + } + + /** + * @return CacheItemPoolInterface + */ + public function getCache(): CacheItemPoolInterface + { + return $this->cache; + } + + /** + * @param OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'key', + ] + ); + $resolver->setAllowedTypes('key', ['array', 'null']); + + /** @noinspection PhpUnusedParameterInspection */ + $resolver->setNormalizer( + 'key', + function (Options $options, $value) { + $mappingResolver = new OptionsResolver(); + $this->configureMappingOptions($mappingResolver); + + return $mappingResolver->resolve( + $value ?? [] + ); + } + ); + } + + /** + * @param OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + protected function configureMappingOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'code' => null, // Source property + 'constant' => null, + ] + ); + $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); + + $this->configureTransformersOptions($resolver); + } + + /** + * @param ProcessState $state + * + * @return string + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + protected function getKeyCache(ProcessState $state) + { + $options = $this->getOptions($state); + $input = $state->getInput(); + $key = $options['key']; + $keyValue = null; + + if (null !== $key['constant']) { + $keyValue = $key['constant']; + } elseif (null !== $key['code']) { + $sourceProperty = $key['code']; + if (\is_array($sourceProperty)) { + $keyValue = []; + /** @var array $sourceProperty */ + foreach ($sourceProperty as $destKey => $srcKey) { + try { + $keyValue[$destKey] = $this->getAccessor()->getValue($input, $srcKey); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'srcKey' => $srcKey, + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + try { + $keyValue = $this->getAccessor()->getValue($input, $sourceProperty); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + $keyValue = $input; + } + + try { + $keyValue = $this->applyTransformers($key['transformers'], $keyValue); + } catch (TransformerException $exception) { + $exception->setTargetProperty('key'); + $this->logger->debug( + 'Transformation exception', + [ + 'message' => $exception->getPrevious()->getMessage(), + 'file' => $exception->getPrevious()->getFile(), + 'line' => $exception->getPrevious()->getLine(), + 'trace' => $exception->getPrevious()->getTraceAsString(), + ] + ); + + throw $exception; + } + + return $keyValue; + } +} diff --git a/Task/Cache/DeleterTask.php b/Task/Cache/DeleterTask.php new file mode 100644 index 00000000..a260a800 --- /dev/null +++ b/Task/Cache/DeleterTask.php @@ -0,0 +1,33 @@ + + */ +class DeleterTask extends AbstractCacheTask +{ + /** + * @param ProcessState $state + * + * @throws \Psr\Cache\InvalidArgumentException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function execute(ProcessState $state) + { + $keyValue = $this->getKeyCache($state); + $input = $state->getInput(); + + $this->getCache()->deleteItem($keyValue); + + $state->setOutput($input); + } +} diff --git a/Task/Cache/GetterTask.php b/Task/Cache/GetterTask.php new file mode 100644 index 00000000..6790cbf5 --- /dev/null +++ b/Task/Cache/GetterTask.php @@ -0,0 +1,36 @@ + + */ +class GetterTask extends AbstractCacheTask +{ + /** + * @param ProcessState $state + * + * @throws \Psr\Cache\InvalidArgumentException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function execute(ProcessState $state) + { + $keyValue = $this->getKeyCache($state); + $cacheItem = $this->getCache()->getItem($keyValue); + + if (!$cacheItem->isHit()) { + $state->setErrorOutput($state->getInput()); + $state->setSkipped(true); + } + + $state->setOutput($cacheItem->get()); + } +} diff --git a/Task/Cache/SetterTask.php b/Task/Cache/SetterTask.php new file mode 100644 index 00000000..2735413c --- /dev/null +++ b/Task/Cache/SetterTask.php @@ -0,0 +1,35 @@ + + */ +class SetterTask extends AbstractCacheTask +{ + /** + * @param ProcessState $state + * + * @throws \Psr\Cache\InvalidArgumentException + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + public function execute(ProcessState $state) + { + $keyValue = $this->getKeyCache($state); + $input = $state->getInput(); + + $cacheItem = $this->getCache()->getItem($keyValue); + $cacheItem->set($input); + $this->getCache()->save($cacheItem); + + $state->setOutput($input); + } +} diff --git a/Tests/Task/Cache/DeleterTaskTest.php b/Tests/Task/Cache/DeleterTaskTest.php new file mode 100644 index 00000000..fe15a768 --- /dev/null +++ b/Tests/Task/Cache/DeleterTaskTest.php @@ -0,0 +1,125 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('DeleterTaskTest_testDeleteExistingCache'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $this->processManager->execute('test.cache_deleter_task.delete_existing_cache', $input); + + self::assertFalse($this->cache->hasItem('DeleterTaskTest_testDeleteExistingCache')); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testDeleteMissingCache() + { + if ($this->cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $this->processManager->execute('test.cache_deleter_task.delete_missing_cache', $input); + + self::assertFalse($this->cache->hasItem('DeleterTaskTest_testDeleteMissingCache')); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['DeleterTaskTest', 'testTransformCacheKey']; + + $cacheItem = $this->cache->getItem('DeleterTaskTest_testTransformCacheKey'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $this->processManager->execute('test.cache_deleter_task.transform_cache_key', $input); + + self::assertFalse($this->cache->hasItem('DeleterTaskTest_testTransformCacheKey')); + + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['DeleterTaskTest', 'testBadCacheKey']; + + $result = $this->processManager->execute('test.cache_deleter_task.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Tests/Task/Cache/GetterTaskTest.php b/Tests/Task/Cache/GetterTaskTest.php new file mode 100644 index 00000000..a926c2e3 --- /dev/null +++ b/Tests/Task/Cache/GetterTaskTest.php @@ -0,0 +1,107 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('GetterTaskTest_testGetExistingCache'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_task.get_existing_cache'); + self::assertEquals($input, $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testGetMissingCache() + { + if ($this->cache) { + $result = $this->processManager->execute('test.cache_getter_task.get_missing_cache'); + self::assertEquals('missing cache', $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['GetterTaskTest', 'testTransformCacheKey']; + + $cacheItem = $this->cache->getItem('GetterTaskTest_testTransformCacheKey'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_task.transform_cache_key', $input); + self::assertEquals($input, $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['GetterTaskTest', 'testBadCacheKey']; + + $cacheItem = $this->cache->getItem('GetterTaskTest_testBadCacheKey'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_task.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Tests/Task/Cache/SetterTaskTest.php b/Tests/Task/Cache/SetterTaskTest.php new file mode 100644 index 00000000..e08bd868 --- /dev/null +++ b/Tests/Task/Cache/SetterTaskTest.php @@ -0,0 +1,124 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('SetterTaskTest_testSetExistingCache'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $this->processManager->execute('test.cache_setter_task.set_existing_cache', $input); + + $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetExistingCache'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testSetMissingCache() + { + if ($this->cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $result = $this->processManager->execute('test.cache_setter_task.set_missing_cache', $input); + self::assertEquals($input, $result); + + $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetMissingCache'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['SetterTaskTest', 'testTransformCacheKey']; + + $result = $this->processManager->execute('test.cache_setter_task.transform_cache_key', $input); + + $resultCacheItem = $this->cache->getItem('SetterTaskTest_testTransformCacheKey'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['SetterTransformerTest', 'testBadCacheKey']; + + $result = $this->processManager->execute('test.cache_setter_task.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Tests/Transformer/Cache/DeleterTransformerTest.php b/Tests/Transformer/Cache/DeleterTransformerTest.php new file mode 100644 index 00000000..59cf0155 --- /dev/null +++ b/Tests/Transformer/Cache/DeleterTransformerTest.php @@ -0,0 +1,128 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('DeleterTransformerTest_testDeleteExistingCache'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_deleter_transformer.delete_existing_cache', $input); + self::assertEquals($input, $result); + + self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testDeleteExistingCache')); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testDeleteMissingCache() + { + if ($this->cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $result = $this->processManager->execute('test.cache_deleter_transformer.delete_missing_cache', $input); + self::assertEquals($input, $result); + + self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testDeleteMissingCache')); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['DeleterTransformerTest', 'testTransformCacheKey']; + + $cacheItem = $this->cache->getItem('DeleterTransformerTest_testTransformCacheKey'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_deleter_transformer.transform_cache_key', $input); + self::assertEquals($input, $result); + + self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testTransformCacheKey')); + + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['DeleterTransformerTest', 'testBadCacheKey']; + + $result = $this->processManager->execute('test.cache_deleter_transformer.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Tests/Transformer/Cache/GetterTransformerTest.php b/Tests/Transformer/Cache/GetterTransformerTest.php new file mode 100644 index 00000000..082c6f8b --- /dev/null +++ b/Tests/Transformer/Cache/GetterTransformerTest.php @@ -0,0 +1,118 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('GetterTransformerTest_testGetExistingCache'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_transformer.get_existing_cache'); + self::assertEquals($input, $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testGetMissingCache() + { + if ($this->cache) { + $result = $this->processManager->execute('test.cache_getter_transformer.get_missing_cache'); + self::assertEquals('missing cache', $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testIgnoreMissingCache() + { + if ($this->cache) { + $result = $this->processManager->execute('test.cache_getter_transformer.ignore_missing_cache'); + self::assertNull($result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['GetterTransformerTest', 'testTransformCacheKey']; + + $cacheItem = $this->cache->getItem('GetterTransformerTest_testTransformCacheKey'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_transformer.transform_cache_key', $input); + self::assertEquals($input, $result); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['GetterTransformerTest', 'testBadCacheKey']; + + $cacheItem = $this->cache->getItem('GetterTransformerTest_testBadCacheKey'); + $cacheItem->set($input); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_getter_transformer.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Tests/Transformer/Cache/SetterTransformerTest.php b/Tests/Transformer/Cache/SetterTransformerTest.php new file mode 100644 index 00000000..424f15e7 --- /dev/null +++ b/Tests/Transformer/Cache/SetterTransformerTest.php @@ -0,0 +1,126 @@ +cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $cacheItem = $this->cache->getItem('SetterTransformerTest_testSetExistingCache'); + $cacheItem->set([]); + $this->cache->save($cacheItem); + + $result = $this->processManager->execute('test.cache_setter_transformer.set_existing_cache', $input); + self::assertEquals($input, $result); + + $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetExistingCache'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testSetMissingCache() + { + if ($this->cache) { + $input = [ + [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1b', + 'key2' => 'value2b', + 'key3' => ['something'], + ], + [ + 'key1' => 'value1c', + 'key2' => 'value2c', + 'key3' => [], + ], + ]; + + $result = $this->processManager->execute('test.cache_setter_transformer.set_missing_cache', $input); + self::assertEquals($input, $result); + + $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetMissingCache'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testTransformCacheKey() + { + if ($this->cache) { + $input = ['SetterTransformerTest', 'testTransformCacheKey']; + + $result = $this->processManager->execute('test.cache_setter_transformer.transform_cache_key', $input); + self::assertEquals($input, $result); + + $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testTransformCacheKey'); + self::assertEquals($input, $resultCacheItem->get()); + } + } + + /** + * @throws \Psr\Cache\InvalidArgumentException + */ + public function testBadCacheKey() + { + if ($this->cache) { + $input = ['SetterTransformerTest', 'testBadCacheKey']; + + $result = $this->processManager->execute('test.cache_setter_transformer.bad_cache_key', $input); + self::assertEquals('missing cache', $result); + } + } + + protected function setUp() + { + parent::setUp(); + + if (static::$kernel->getContainer()->has('cache.app')) { + $this->cache = static::$kernel->getContainer()->get('cache.app'); + } + } +} diff --git a/Transformer/Cache/AbstractCacheTransformer.php b/Transformer/Cache/AbstractCacheTransformer.php new file mode 100644 index 00000000..54e02bf2 --- /dev/null +++ b/Transformer/Cache/AbstractCacheTransformer.php @@ -0,0 +1,200 @@ + + */ +abstract class AbstractCacheTransformer implements ConfigurableTransformerInterface +{ + use TransformerTrait; + + /** @var LoggerInterface */ + private $logger; + + /** @var PropertyAccessorInterface */ + private $accessor; + + /** @var CacheItemPoolInterface */ + private $cache; + + /** + * SetterTask constructor. + * + * @param LoggerInterface $logger + * @param PropertyAccessorInterface $accessor + * @param CacheItemPoolInterface $cache + * @param TransformerRegistry $transformerRegistry + */ + public function __construct( + LoggerInterface $logger, + PropertyAccessorInterface $accessor, + CacheItemPoolInterface $cache, + TransformerRegistry $transformerRegistry + ) { + $this->logger = $logger; + $this->accessor = $accessor; + $this->cache = $cache; + $this->transformerRegistry = $transformerRegistry; + } + + /** + * @return LoggerInterface + */ + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + /** + * @return PropertyAccessorInterface + */ + public function getAccessor(): PropertyAccessorInterface + { + return $this->accessor; + } + + /** + * @return CacheItemPoolInterface + */ + public function getCache(): CacheItemPoolInterface + { + return $this->cache; + } + + /** + * @param OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'key', + ] + ); + $resolver->setAllowedTypes('key', ['array', 'null']); + + /** @noinspection PhpUnusedParameterInspection */ + $resolver->setNormalizer( + 'key', + function (Options $options, $value) { + $mappingResolver = new OptionsResolver(); + $this->configureMappingOptions($mappingResolver); + + return $mappingResolver->resolve( + $value ?? [] + ); + } + ); + } + + /** + * @param OptionsResolver $resolver + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + protected function configureMappingOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'code' => null, // Source property + 'constant' => null, + ] + ); + $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); + + $this->configureTransformersOptions($resolver); + } + + /** + * @param array $options + * + * @return string + */ + protected function getKeyCache($value, array $options = []) + { + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + $options = $resolver->resolve($options); + + $input = $value; + $key = $options['key']; + $keyValue = null; + + if (null !== $key['constant']) { + $keyValue = $key['constant']; + } elseif (null !== $key['code']) { + $sourceProperty = $key['code']; + if (\is_array($sourceProperty)) { + $keyValue = []; + /** @var array $sourceProperty */ + foreach ($sourceProperty as $destKey => $srcKey) { + try { + $keyValue[$destKey] = $this->getAccessor()->getValue($input, $srcKey); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'srcKey' => $srcKey, + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + try { + $keyValue = $this->getAccessor()->getValue($input, $sourceProperty); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + $keyValue = $input; + } + + try { + $keyValue = $this->applyTransformers($key['transformers'], $keyValue); + } catch (TransformerException $exception) { + $exception->setTargetProperty('key'); + $this->logger->debug( + 'Transformation exception', + [ + 'message' => $exception->getPrevious()->getMessage(), + 'file' => $exception->getPrevious()->getFile(), + 'line' => $exception->getPrevious()->getLine(), + 'trace' => $exception->getPrevious()->getTraceAsString(), + ] + ); + + throw $exception; + } + + return $keyValue; + } +} diff --git a/Transformer/Cache/DeleterTransformer.php b/Transformer/Cache/DeleterTransformer.php new file mode 100644 index 00000000..06df6e4b --- /dev/null +++ b/Transformer/Cache/DeleterTransformer.php @@ -0,0 +1,38 @@ + + */ +class DeleterTransformer extends AbstractCacheTransformer +{ + /** + * {@inheritDoc} + * + * @throws \UnexpectedValueException + * @throws \Psr\Cache\InvalidArgumentException + */ + public function transform($value, array $options = []) + { + $keyValue = $this->getKeyCache($value, $options); + + $this->getCache()->deleteItem($keyValue); + + return $value; + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'cache_deleter'; + } +} diff --git a/Transformer/Cache/GetterTransformer.php b/Transformer/Cache/GetterTransformer.php new file mode 100644 index 00000000..1a727973 --- /dev/null +++ b/Transformer/Cache/GetterTransformer.php @@ -0,0 +1,63 @@ + + */ +class GetterTransformer extends AbstractCacheTransformer +{ + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + + $resolver->setDefaults( + [ + 'ignore_not_hit' => false, + ] + ); + $resolver->setAllowedTypes('ignore_not_hit', ['boolean']); + } + + /** + * {@inheritDoc} + * + * @throws \UnexpectedValueException + * @throws \Psr\Cache\InvalidArgumentException + */ + public function transform($value, array $options = []) + { + $keyValue = $this->getKeyCache($value, $options); + $cacheItem = $this->getCache()->getItem($keyValue); + + if (!$cacheItem->isHit()) { + if ($options['ignore_not_hit']) { + return null; + } + + throw new TransformerException($keyValue, 0, 'Cache not hit'); + } + + return $cacheItem->get(); + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'cache_getter'; + } +} diff --git a/Transformer/Cache/SetterTransformer.php b/Transformer/Cache/SetterTransformer.php new file mode 100644 index 00000000..c2e61ad3 --- /dev/null +++ b/Transformer/Cache/SetterTransformer.php @@ -0,0 +1,40 @@ + + */ +class SetterTransformer extends AbstractCacheTransformer +{ + /** + * {@inheritDoc} + * + * @throws \UnexpectedValueException + * @throws \Psr\Cache\InvalidArgumentException + */ + public function transform($value, array $options = []) + { + $keyValue = $this->getKeyCache($value, $options); + + $cacheItem = $this->getCache()->getItem($keyValue); + $cacheItem->set($value); + $this->getCache()->save($cacheItem); + + return $value; + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'cache_setter'; + } +} diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index e8e624a0..bf92c386 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -18,7 +18,6 @@ /** * Trait TransformerTrait * - * @package CleverAge\ProcessBundle\Transformer * @author Madeline Veyrenc */ trait TransformerTrait @@ -27,6 +26,14 @@ trait TransformerTrait /** @var TransformerRegistry */ protected $transformerRegistry; + /** + * @return TransformerRegistry + */ + public function getTransformerRegistry(): TransformerRegistry + { + return $this->transformerRegistry; + } + /** * @param array $transformers * @param mixed $value @@ -41,7 +48,7 @@ protected function applyTransformers(array $transformers, $value) foreach ($transformers as $transformerCode => $transformerOptions) { try { $transformerCode = $this->getCleanedTransfomerCode($transformerCode); - $transformer = $this->transformerRegistry->getTransformer($transformerCode); + $transformer = $this->getTransformerRegistry()->getTransformer($transformerCode); $value = $transformer->transform( $value, $transformerOptions ?: [] @@ -77,7 +84,7 @@ protected function getCleanedTransfomerCode(string $transformerCode) { $match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts); - if (1 === $match && $this->transformerRegistry->hasTransformer($parts[1])) { + if (1 === $match && $this->getTransformerRegistry()->hasTransformer($parts[1])) { return $parts[1]; } @@ -86,6 +93,7 @@ protected function getCleanedTransfomerCode(string $transformerCode) /** * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver + * * @throws \CleverAge\ProcessBundle\Exception\MissingTransformerException * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException @@ -107,7 +115,7 @@ function (Options $options, $transformers) { foreach ($transformers as $transformerCode => &$transformerOptions) { $transformerOptionsResolver = new OptionsResolver(); $transformerCode = $this->getCleanedTransfomerCode($transformerCode); - $transformer = $this->transformerRegistry->getTransformer($transformerCode); + $transformer = $this->getTransformerRegistry()->getTransformer($transformerCode); if ($transformer instanceof ConfigurableTransformerInterface) { $transformer->configureOptions($transformerOptionsResolver); $transformerOptions = $transformerOptionsResolver->resolve( @@ -121,4 +129,4 @@ function (Options $options, $transformers) { ); } -} \ No newline at end of file +} From 73059e8e79bb1d3475ecd92bc839ca0be62e76f0 Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Mon, 11 Feb 2019 15:02:21 +0100 Subject: [PATCH 016/304] Add transformer on value caching --- Resources/tests/task/cache_setter_task.yml | 10 ++ .../transfomer/cache_setter_transformer.yml | 10 ++ Task/Cache/AbstractCacheTask.php | 83 +---------------- Task/Cache/SetterTask.php | 35 ++++++- Task/TransformerTask.php | 3 - Tests/Task/Cache/SetterTaskTest.php | 6 +- .../Cache/SetterTransformerTest.php | 4 +- .../Cache/AbstractCacheTransformer.php | 84 +---------------- Transformer/Cache/SetterTransformer.php | 41 +++++++- Transformer/MappingTransformer.php | 6 -- Transformer/TransformerTrait.php | 93 ++++++++++++++++++- 11 files changed, 193 insertions(+), 182 deletions(-) diff --git a/Resources/tests/task/cache_setter_task.yml b/Resources/tests/task/cache_setter_task.yml index 77fdba8c..340272d7 100644 --- a/Resources/tests/task/cache_setter_task.yml +++ b/Resources/tests/task/cache_setter_task.yml @@ -9,6 +9,10 @@ clever_age_process: options: key: constant: 'SetterTaskTest_testSetExistingCache' + value: + transformers: + property_accessor: + property_path: '[0]' outputs: [dummy] dummy: @@ -23,6 +27,10 @@ clever_age_process: options: key: constant: 'SetterTaskTest_testSetMissingCache' + value: + transformers: + property_accessor: + property_path: '[0]' outputs: [dummy] dummy: @@ -39,6 +47,7 @@ clever_age_process: transformers: implode: separator: '_' + value: ~ outputs: [dummy] dummy: @@ -52,6 +61,7 @@ clever_age_process: service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' options: key: ~ + value: ~ outputs: [dummy] error_outputs: [missing_cache] diff --git a/Resources/tests/transfomer/cache_setter_transformer.yml b/Resources/tests/transfomer/cache_setter_transformer.yml index 13ea5442..54b25988 100644 --- a/Resources/tests/transfomer/cache_setter_transformer.yml +++ b/Resources/tests/transfomer/cache_setter_transformer.yml @@ -11,6 +11,10 @@ clever_age_process: cache_setter: key: constant: 'SetterTransformerTest_testSetExistingCache' + value: + transformers: + property_accessor: + property_path: '[0]' outputs: [dummy] error_outputs: [missing_cache] @@ -34,6 +38,10 @@ clever_age_process: cache_setter: key: constant: 'SetterTransformerTest_testSetMissingCache' + value: + transformers: + property_accessor: + property_path: '[0]' outputs: [dummy] error_outputs: [missing_cache] @@ -59,6 +67,7 @@ clever_age_process: transformers: implode: separator: '_' + value: ~ outputs: [dummy] error_outputs: [missing_cache] @@ -81,6 +90,7 @@ clever_age_process: transformers: cache_setter: key: ~ + value: ~ outputs: [dummy] error_outputs: [missing_cache] diff --git a/Task/Cache/AbstractCacheTask.php b/Task/Cache/AbstractCacheTask.php index d8fc8db5..6ca0ddb1 100644 --- a/Task/Cache/AbstractCacheTask.php +++ b/Task/Cache/AbstractCacheTask.php @@ -6,7 +6,6 @@ namespace CleverAge\ProcessBundle\Task\Cache; -use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Registry\TransformerRegistry; @@ -26,12 +25,6 @@ abstract class AbstractCacheTask extends AbstractConfigurableTask { use TransformerTrait; - /** @var LoggerInterface */ - private $logger; - - /** @var PropertyAccessorInterface */ - private $accessor; - /** @var CacheItemPoolInterface */ private $cache; @@ -55,22 +48,6 @@ public function __construct( $this->transformerRegistry = $transformerRegistry; } - /** - * @return LoggerInterface - */ - public function getLogger(): LoggerInterface - { - return $this->logger; - } - - /** - * @return PropertyAccessorInterface - */ - public function getAccessor(): PropertyAccessorInterface - { - return $this->accessor; - } - /** * @return CacheItemPoolInterface */ @@ -136,65 +113,7 @@ protected function configureMappingOptions(OptionsResolver $resolver) protected function getKeyCache(ProcessState $state) { $options = $this->getOptions($state); - $input = $state->getInput(); - $key = $options['key']; - $keyValue = null; - - if (null !== $key['constant']) { - $keyValue = $key['constant']; - } elseif (null !== $key['code']) { - $sourceProperty = $key['code']; - if (\is_array($sourceProperty)) { - $keyValue = []; - /** @var array $sourceProperty */ - foreach ($sourceProperty as $destKey => $srcKey) { - try { - $keyValue[$destKey] = $this->getAccessor()->getValue($input, $srcKey); - } catch (\RuntimeException $missingPropertyError) { - $this->getLogger()->debug( - 'Mapping exception', - [ - 'srcKey' => $srcKey, - 'message' => $missingPropertyError->getMessage(), - ] - ); - throw $missingPropertyError; - } - } - } else { - try { - $keyValue = $this->getAccessor()->getValue($input, $sourceProperty); - } catch (\RuntimeException $missingPropertyError) { - $this->getLogger()->debug( - 'Mapping exception', - [ - 'message' => $missingPropertyError->getMessage(), - ] - ); - throw $missingPropertyError; - } - } - } else { - $keyValue = $input; - } - - try { - $keyValue = $this->applyTransformers($key['transformers'], $keyValue); - } catch (TransformerException $exception) { - $exception->setTargetProperty('key'); - $this->logger->debug( - 'Transformation exception', - [ - 'message' => $exception->getPrevious()->getMessage(), - 'file' => $exception->getPrevious()->getFile(), - 'line' => $exception->getPrevious()->getLine(), - 'trace' => $exception->getPrevious()->getTraceAsString(), - ] - ); - - throw $exception; - } - return $keyValue; + return $this->transformValue($state->getInput(), $options['key']); } } diff --git a/Task/Cache/SetterTask.php b/Task/Cache/SetterTask.php index 2735413c..330c8657 100644 --- a/Task/Cache/SetterTask.php +++ b/Task/Cache/SetterTask.php @@ -7,6 +7,8 @@ namespace CleverAge\ProcessBundle\Task\Cache; use CleverAge\ProcessBundle\Model\ProcessState; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Class SetterTask @@ -27,9 +29,40 @@ public function execute(ProcessState $state) $input = $state->getInput(); $cacheItem = $this->getCache()->getItem($keyValue); - $cacheItem->set($input); + $cachedValue = $this->transformValue($input, $this->getOption($state, 'value')); + $cacheItem->set($cachedValue); $this->getCache()->save($cacheItem); $state->setOutput($input); } + + /** + * {@inheritdoc} + */ + protected function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + + $resolver->setRequired( + [ + 'value', + ] + ); + $resolver->setAllowedTypes('value', ['array', 'null']); + + /** @noinspection PhpUnusedParameterInspection */ + $resolver->setNormalizer( + 'value', + function (Options $options, $value) { + $mappingResolver = new OptionsResolver(); + $this->configureMappingOptions($mappingResolver); + + return $mappingResolver->resolve( + $value ?? [] + ); + } + ); + + return $resolver; + } } diff --git a/Task/TransformerTask.php b/Task/TransformerTask.php index a6aa5919..48d50f65 100644 --- a/Task/TransformerTask.php +++ b/Task/TransformerTask.php @@ -30,9 +30,6 @@ class TransformerTask extends AbstractConfigurableTask { use TransformerTrait; - /** @var LoggerInterface */ - protected $logger; - /** @var TransformerInterface */ protected $transformer; diff --git a/Tests/Task/Cache/SetterTaskTest.php b/Tests/Task/Cache/SetterTaskTest.php index e08bd868..d3519d63 100644 --- a/Tests/Task/Cache/SetterTaskTest.php +++ b/Tests/Task/Cache/SetterTaskTest.php @@ -49,7 +49,7 @@ public function testSetExistingCache() $this->processManager->execute('test.cache_setter_task.set_existing_cache', $input); $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetExistingCache'); - self::assertEquals($input, $resultCacheItem->get()); + self::assertEquals($input[0], $resultCacheItem->get()); } } @@ -81,7 +81,7 @@ public function testSetMissingCache() self::assertEquals($input, $result); $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetMissingCache'); - self::assertEquals($input, $resultCacheItem->get()); + self::assertEquals($input[0], $resultCacheItem->get()); } } @@ -93,7 +93,7 @@ public function testTransformCacheKey() if ($this->cache) { $input = ['SetterTaskTest', 'testTransformCacheKey']; - $result = $this->processManager->execute('test.cache_setter_task.transform_cache_key', $input); + $this->processManager->execute('test.cache_setter_task.transform_cache_key', $input); $resultCacheItem = $this->cache->getItem('SetterTaskTest_testTransformCacheKey'); self::assertEquals($input, $resultCacheItem->get()); diff --git a/Tests/Transformer/Cache/SetterTransformerTest.php b/Tests/Transformer/Cache/SetterTransformerTest.php index 424f15e7..0d5f92d9 100644 --- a/Tests/Transformer/Cache/SetterTransformerTest.php +++ b/Tests/Transformer/Cache/SetterTransformerTest.php @@ -50,7 +50,7 @@ public function testSetExistingCache() self::assertEquals($input, $result); $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetExistingCache'); - self::assertEquals($input, $resultCacheItem->get()); + self::assertEquals($input[0], $resultCacheItem->get()); } } @@ -82,7 +82,7 @@ public function testSetMissingCache() self::assertEquals($input, $result); $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetMissingCache'); - self::assertEquals($input, $resultCacheItem->get()); + self::assertEquals($input[0], $resultCacheItem->get()); } } diff --git a/Transformer/Cache/AbstractCacheTransformer.php b/Transformer/Cache/AbstractCacheTransformer.php index 54e02bf2..52c564ac 100644 --- a/Transformer/Cache/AbstractCacheTransformer.php +++ b/Transformer/Cache/AbstractCacheTransformer.php @@ -6,7 +6,6 @@ namespace CleverAge\ProcessBundle\Transformer\Cache; -use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use CleverAge\ProcessBundle\Transformer\TransformerTrait; @@ -25,12 +24,6 @@ abstract class AbstractCacheTransformer implements ConfigurableTransformerInterf { use TransformerTrait; - /** @var LoggerInterface */ - private $logger; - - /** @var PropertyAccessorInterface */ - private $accessor; - /** @var CacheItemPoolInterface */ private $cache; @@ -54,22 +47,6 @@ public function __construct( $this->transformerRegistry = $transformerRegistry; } - /** - * @return LoggerInterface - */ - public function getLogger(): LoggerInterface - { - return $this->logger; - } - - /** - * @return PropertyAccessorInterface - */ - public function getAccessor(): PropertyAccessorInterface - { - return $this->accessor; - } - /** * @return CacheItemPoolInterface */ @@ -136,65 +113,6 @@ protected function getKeyCache($value, array $options = []) $this->configureOptions($resolver); $options = $resolver->resolve($options); - $input = $value; - $key = $options['key']; - $keyValue = null; - - if (null !== $key['constant']) { - $keyValue = $key['constant']; - } elseif (null !== $key['code']) { - $sourceProperty = $key['code']; - if (\is_array($sourceProperty)) { - $keyValue = []; - /** @var array $sourceProperty */ - foreach ($sourceProperty as $destKey => $srcKey) { - try { - $keyValue[$destKey] = $this->getAccessor()->getValue($input, $srcKey); - } catch (\RuntimeException $missingPropertyError) { - $this->getLogger()->debug( - 'Mapping exception', - [ - 'srcKey' => $srcKey, - 'message' => $missingPropertyError->getMessage(), - ] - ); - throw $missingPropertyError; - } - } - } else { - try { - $keyValue = $this->getAccessor()->getValue($input, $sourceProperty); - } catch (\RuntimeException $missingPropertyError) { - $this->getLogger()->debug( - 'Mapping exception', - [ - 'message' => $missingPropertyError->getMessage(), - ] - ); - throw $missingPropertyError; - } - } - } else { - $keyValue = $input; - } - - try { - $keyValue = $this->applyTransformers($key['transformers'], $keyValue); - } catch (TransformerException $exception) { - $exception->setTargetProperty('key'); - $this->logger->debug( - 'Transformation exception', - [ - 'message' => $exception->getPrevious()->getMessage(), - 'file' => $exception->getPrevious()->getFile(), - 'line' => $exception->getPrevious()->getLine(), - 'trace' => $exception->getPrevious()->getTraceAsString(), - ] - ); - - throw $exception; - } - - return $keyValue; + return $this->transformValue($value, $options['key']); } } diff --git a/Transformer/Cache/SetterTransformer.php b/Transformer/Cache/SetterTransformer.php index c2e61ad3..be316f23 100644 --- a/Transformer/Cache/SetterTransformer.php +++ b/Transformer/Cache/SetterTransformer.php @@ -6,6 +6,9 @@ namespace CleverAge\ProcessBundle\Transformer\Cache; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + /** * Class SetterTransformer * @@ -24,7 +27,11 @@ public function transform($value, array $options = []) $keyValue = $this->getKeyCache($value, $options); $cacheItem = $this->getCache()->getItem($keyValue); - $cacheItem->set($value); + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + $options = $resolver->resolve($options); + $cachedValue = $this->transformValue($value, $options['value']); + $cacheItem->set($cachedValue); $this->getCache()->save($cacheItem); return $value; @@ -37,4 +44,36 @@ public function getCode() { return 'cache_setter'; } + + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + + $resolver->setRequired( + [ + 'value', + ] + ); + $resolver->setAllowedTypes('value', ['array', 'null']); + + /** @noinspection PhpUnusedParameterInspection */ + $resolver->setNormalizer( + 'value', + function (Options $options, $value) { + $mappingResolver = new OptionsResolver(); + $this->configureMappingOptions($mappingResolver); + + return $mappingResolver->resolve( + $value ?? [] + ); + } + ); + + return $resolver; + } + + } diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 3072c5ea..0db9c64f 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -28,12 +28,6 @@ class MappingTransformer implements ConfigurableTransformerInterface { use TransformerTrait; - /** @var LoggerInterface */ - protected $logger; - - /** @var PropertyAccessorInterface */ - protected $accessor; - /** * @param TransformerRegistry $transformerRegistry * @param LoggerInterface $logger diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index bf92c386..14382c8e 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -12,8 +12,10 @@ use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Trait TransformerTrait @@ -22,9 +24,30 @@ */ trait TransformerTrait { + /** @var LoggerInterface */ + private $logger; + + /** @var PropertyAccessorInterface */ + private $accessor; /** @var TransformerRegistry */ - protected $transformerRegistry; + private $transformerRegistry; + + /** + * @return LoggerInterface + */ + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + /** + * @return PropertyAccessorInterface + */ + public function getAccessor(): PropertyAccessorInterface + { + return $this->accessor; + } /** * @return TransformerRegistry @@ -91,6 +114,74 @@ protected function getCleanedTransfomerCode(string $transformerCode) return $transformerCode; } + /** + * @param mixed $value + * @param array $options + * + * @return mixed + */ + protected function transformValue($value, array $options = []) + { + $transformedValue = null; + + if (null !== $options['constant']) { + $transformedValue = $options['constant']; + } elseif (null !== $options['code']) { + $sourceProperty = $options['code']; + if (\is_array($sourceProperty)) { + $transformedValue = []; + /** @var array $sourceProperty */ + foreach ($sourceProperty as $destKey => $srcKey) { + try { + $transformedValue[$destKey] = $this->getAccessor()->getValue($value, $srcKey); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'srcKey' => $srcKey, + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + try { + $transformedValue = $this->getAccessor()->getValue($value, $sourceProperty); + } catch (\RuntimeException $missingPropertyError) { + $this->getLogger()->debug( + 'Mapping exception', + [ + 'message' => $missingPropertyError->getMessage(), + ] + ); + throw $missingPropertyError; + } + } + } else { + $transformedValue = $value; + } + + try { + $transformedValue = $this->applyTransformers($options['transformers'], $transformedValue); + } catch (TransformerException $exception) { + $exception->setTargetProperty('key'); + $this->logger->debug( + 'Transformation exception', + [ + 'message' => $exception->getPrevious()->getMessage(), + 'file' => $exception->getPrevious()->getFile(), + 'line' => $exception->getPrevious()->getLine(), + 'trace' => $exception->getPrevious()->getTraceAsString(), + ] + ); + + throw $exception; + } + + return $transformedValue; + } + /** * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver * From 932546238823757385945bc0897f2cc716ceb1d2 Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Tue, 12 Feb 2019 09:36:42 +0100 Subject: [PATCH 017/304] Fix error output detection --- Manager/ProcessManager.php | 2 +- Model/ProcessState.php | 11 ++++++++--- Resources/tests/process/exception_management.yml | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 5dbb7888..02024d04 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -405,7 +405,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e $state->setException($exception); if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { $state->setSkipped(true); - if (null === $state->getErrorOutput()) { + if (!$state->hasErrorOutput()) { $state->setErrorOutput($state->getInput()); } } elseif ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { diff --git a/Model/ProcessState.php b/Model/ProcessState.php index d152c88e..542271ad 100644 --- a/Model/ProcessState.php +++ b/Model/ProcessState.php @@ -46,6 +46,9 @@ class ProcessState /** @var mixed */ protected $errorOutput; + /** @var boolean */ + protected $hasErrorOutput = false; + /** @var bool */ protected $stopped = false; @@ -118,9 +121,10 @@ public function reset($cleanInput) $this->setOutput(null); $this->setSkipped(false); $this->setException(null); - $this->setErrorOutput(null); + $this->errorOutput = null; + $this->hasErrorOutput = false; - if($cleanInput) { + if ($cleanInput) { $this->setInput(null); $this->setPreviousState(null); } @@ -239,6 +243,7 @@ public function getErrorOutput() */ public function setErrorOutput($errorOutput) { + $this->hasErrorOutput = true; $this->errorOutput = $errorOutput; } @@ -247,7 +252,7 @@ public function setErrorOutput($errorOutput) */ public function hasErrorOutput() { - return null !== $this->errorOutput; + return $this->hasErrorOutput; } /** diff --git a/Resources/tests/process/exception_management.yml b/Resources/tests/process/exception_management.yml index ef7329db..1d60a8f6 100644 --- a/Resources/tests/process/exception_management.yml +++ b/Resources/tests/process/exception_management.yml @@ -23,7 +23,7 @@ clever_age_process: implode: separator: '' outputs: [aggregator] - errors: [error_aggregator] + error_outputs: [error_aggregator] aggregator: service: '@CleverAge\ProcessBundle\Task\AggregateIterableTask' From 3f12896601560b0767f9b34aab460f766196b4f6 Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Tue, 12 Feb 2019 09:37:05 +0100 Subject: [PATCH 018/304] Set error output if filter not match --- Task/FilterTask.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Task/FilterTask.php b/Task/FilterTask.php index a7464bcc..ffe4ebc7 100644 --- a/Task/FilterTask.php +++ b/Task/FilterTask.php @@ -48,6 +48,7 @@ public function execute(ProcessState $state) { $input = $state->getInput(); if (!$this->checkCondition($input, $this->getOptions($state))) { + $state->setErrorOutput($input); $state->setSkipped(true); return; From e51b11e3b8297a9b20459fe1d7f15b2d28c37ef5 Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Tue, 12 Feb 2019 14:11:02 +0100 Subject: [PATCH 019/304] Catching exception on request --- Addon/Rest/Client/Client.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Addon/Rest/Client/Client.php b/Addon/Rest/Client/Client.php index df1cd2fa..64c97619 100644 --- a/Addon/Rest/Client/Client.php +++ b/Addon/Rest/Client/Client.php @@ -99,7 +99,18 @@ public function call(array $options = []): Response $this->setRequestQueryParameters($request, $options); $this->setRequestHeader($request, $options); - return $request->send(); + try { + return $request->send(); + } catch (\Exception $e) { + $this->logger->error( + 'Rest request failed', + [ + 'url' => $request->uri, + 'error' => $e->getMessage(), + ] + ); + throw new RestRequestException('Rest request failed', 0, $e); + } } /** From 9aeec9e25c0312a83c56bef25ca58fcb83d5865f Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Tue, 12 Feb 2019 14:11:26 +0100 Subject: [PATCH 020/304] rawurlencode url parameters --- Addon/Rest/Client/Client.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Addon/Rest/Client/Client.php b/Addon/Rest/Client/Client.php index 64c97619..f1396d26 100644 --- a/Addon/Rest/Client/Client.php +++ b/Addon/Rest/Client/Client.php @@ -264,6 +264,12 @@ function (&$item) { } ); $replace = array_values($options['url_parameters']); + array_walk( + $replace, + function (&$item) { + $item = rawurlencode($item); + } + ); $uri = str_replace($search, $replace, $uri); } From 184e86fe4c32d4db2e36b40e7b4615152c51c3f4 Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Wed, 13 Feb 2019 01:06:49 +0100 Subject: [PATCH 021/304] Send request in isolate method --- Addon/Rest/Client/Client.php | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/Addon/Rest/Client/Client.php b/Addon/Rest/Client/Client.php index f1396d26..3e86d38c 100644 --- a/Addon/Rest/Client/Client.php +++ b/Addon/Rest/Client/Client.php @@ -87,7 +87,6 @@ public function setUri(string $uri): void * @throws \Symfony\Component\OptionsResolver\Exception\AccessException * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \InvalidArgumentException - * @throws \Httpful\Exception\ConnectionErrorException * @throws RestRequestException * @throws \Exception */ @@ -98,19 +97,7 @@ public function call(array $options = []): Response $request = $this->initializeRequest($options); $this->setRequestQueryParameters($request, $options); $this->setRequestHeader($request, $options); - - try { - return $request->send(); - } catch (\Exception $e) { - $this->logger->error( - 'Rest request failed', - [ - 'url' => $request->uri, - 'error' => $e->getMessage(), - ] - ); - throw new RestRequestException('Rest request failed', 0, $e); - } + return $this->sendRequest($request, $options); } /** @@ -224,6 +211,30 @@ protected function setRequestHeader(Request $request, array $options = []): void } } + /** + * @param Request $request + * @param array $options + * + * @return Response|null + * + * @throws RestRequestException + */ + protected function sendRequest(Request $request, array $options = []): ?Response + { + try { + return $request->send(); + } catch (\Exception $e) { + $this->logger->error( + 'Rest request failed', + [ + 'url' => $request->uri, + 'error' => $e->getMessage(), + ] + ); + throw new RestRequestException('Rest request failed', 0, $e); + } + } + /** * @return string */ From 443597e66b11f5b1e2afaf671ad01e3ce905d54b Mon Sep 17 00:00:00 2001 From: Madeline Veyrenc Date: Wed, 13 Feb 2019 01:07:00 +0100 Subject: [PATCH 022/304] Fix copyright --- Addon/Flysystem/Task/FileFetchTask.php | 12 ++++++++---- Addon/Rest/Client/Client.php | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Addon/Flysystem/Task/FileFetchTask.php b/Addon/Flysystem/Task/FileFetchTask.php index b2dbcdc7..5327da3b 100644 --- a/Addon/Flysystem/Task/FileFetchTask.php +++ b/Addon/Flysystem/Task/FileFetchTask.php @@ -1,8 +1,12 @@ Date: Wed, 13 Feb 2019 08:09:39 +0100 Subject: [PATCH 023/304] Update copyright --- .../Task/Database/DatabaseReaderTask.php | 16 ++++++++-------- .../Task/Database/DatabaseUpdaterTask.php | 4 ++-- .../EntityManager/AbstractDoctrineQueryTask.php | 16 ++++++++-------- .../Task/EntityManager/AbstractDoctrineTask.php | 16 ++++++++-------- .../EntityManager/ClearEntityManagerTask.php | 16 ++++++++-------- .../EntityManager/DoctrineBatchWriterTask.php | 16 ++++++++-------- .../Task/EntityManager/DoctrineDetacherTask.php | 16 ++++++++-------- .../Task/EntityManager/DoctrineReaderTask.php | 16 ++++++++-------- .../Task/EntityManager/DoctrineRemoverTask.php | 16 ++++++++-------- .../Task/EntityManager/DoctrineWriterTask.php | 16 ++++++++-------- .../EntityManager/PurgeDoctrineCacheTask.php | 16 ++++++++-------- Addon/Flysystem/Task/FileFetchTask.php | 16 ++++++++-------- Addon/Rest/Client/Client.php | 16 ++++++++-------- Addon/Rest/Client/ClientInterface.php | 16 ++++++++-------- Addon/Rest/Exception/MissingClientException.php | 16 ++++++++-------- Addon/Rest/Exception/RestException.php | 16 ++++++++-------- Addon/Rest/Exception/RestRequestException.php | 16 ++++++++-------- Addon/Rest/Registry.php | 4 ++++ Addon/Rest/Task/RequestTask.php | 16 ++++++++-------- Addon/Rest/Transformer/RequestTransformer.php | 16 ++++++++-------- Addon/Soap/Client/Client.php | 16 ++++++++-------- Addon/Soap/Client/ClientInterface.php | 16 ++++++++-------- Addon/Soap/Exception/MissingClientException.php | 16 ++++++++-------- Addon/Soap/Registry.php | 16 ++++++++-------- Addon/Soap/Task/RequestTask.php | 16 ++++++++-------- Addon/Soap/Transformer/RequestTransformer.php | 16 ++++++++-------- CleverAgeProcessBundle.php | 16 ++++++++-------- Command/ExecuteProcessCommand.php | 4 ++-- Command/ListProcessCommand.php | 16 ++++++++-------- Command/ProcessHelpCommand.php | 4 ++-- Configuration/ProcessConfiguration.php | 4 ++-- Configuration/TaskConfiguration.php | 4 ++-- Context/ContextualOptionResolver.php | 4 ++-- .../CleverAgeProcessExtension.php | 4 ++-- DependencyInjection/Compiler/CachePoolPass.php | 16 ++++++++-------- .../Compiler/RegistryCompilerPass.php | 4 ++-- DependencyInjection/Configuration.php | 4 ++-- Event/EventDispatcherTaskEvent.php | 4 ++-- EventListener/DataQueueEventListener.php | 4 ++-- Exception/CircularProcessException.php | 4 ++-- .../InvalidProcessConfigurationException.php | 4 ++-- Exception/MissingProcessException.php | 4 ++-- Exception/MissingTaskConfigurationException.php | 4 ++-- Exception/MissingTransformerException.php | 4 ++-- Exception/MultiBranchProcessException.php | 4 ++-- Exception/ProcessExceptionInterface.php | 4 ++-- Exception/TransformerException.php | 4 ++-- Filesystem/CsvFile.php | 4 ++-- Filesystem/CsvResource.php | 4 ++-- Filesystem/FileStreamInterface.php | 4 ++-- Logger/AbstractLogger.php | 8 ++++++++ Logger/AbstractProcessor.php | 4 ++-- Logger/ProcessLogger.php | 8 ++++++++ Logger/ProcessProcessor.php | 8 ++++++++ Logger/TaskLogger.php | 8 ++++++++ Logger/TaskProcessor.php | 8 ++++++++ Logger/TransformerProcessor.php | 8 ++++++++ Manager/ProcessManager.php | 4 ++-- Model/AbstractConfigurableTask.php | 16 ++++++++-------- Model/BlockingTaskInterface.php | 4 ++-- Model/FinalizableTaskInterface.php | 4 ++-- Model/FlushableTaskInterface.php | 4 ++-- Model/InitializableTaskInterface.php | 4 ++-- Model/IterableTaskInterface.php | 4 ++-- Model/ProcessHistory.php | 4 ++-- Model/ProcessState.php | 16 ++++++++-------- Model/TaskInterface.php | 4 ++-- Registry/ProcessConfigurationRegistry.php | 4 ++-- Registry/TransformerRegistry.php | 4 ++-- Task/AbstractIterableOutputTask.php | 4 ++-- Task/AggregateIterableTask.php | 4 ++-- Task/ArrayMergeTask.php | 4 ++-- Task/Cache/AbstractCacheTask.php | 4 ++++ Task/Cache/DeleterTask.php | 4 ++++ Task/Cache/GetterTask.php | 4 ++++ Task/Cache/SetterTask.php | 4 ++++ Task/ColumnAggregatorTask.php | 4 ++-- Task/ConstantIterableOutputTask.php | 4 ++-- Task/ConstantOutputTask.php | 4 ++-- Task/CounterTask.php | 4 ++-- Task/Debug/DebugTask.php | 4 ++-- Task/Debug/DieTask.php | 4 ++-- Task/Debug/ErrorForwarderTask.php | 4 ++-- Task/Debug/MemInfoDumpTask.php | 4 ++-- Task/DummyTask.php | 4 ++-- Task/Event/EventDispatcherTask.php | 4 ++-- Task/File/Csv/AbstractCsvResourceTask.php | 16 ++++++++-------- Task/File/Csv/AbstractCsvTask.php | 16 ++++++++-------- Task/File/Csv/CsvReaderTask.php | 16 ++++++++-------- Task/File/Csv/CsvSplitterTask.php | 4 ++-- Task/File/Csv/CsvWriterTask.php | 16 ++++++++-------- Task/File/Csv/InputCsvReaderTask.php | 4 ++-- Task/File/FileMoverTask.php | 4 ++-- Task/File/FileRemoverTask.php | 4 ++-- Task/File/FileWriterTask.php | 4 ++-- Task/File/FolderBrowserTask.php | 16 ++++++++-------- Task/File/YamlReaderTask.php | 4 ++-- Task/File/YamlWriterTask.php | 4 ++-- Task/FilterTask.php | 4 ++-- Task/InputAggregatorTask.php | 4 ++-- Task/InputIteratorTask.php | 4 ++-- Task/IterableBatchTask.php | 4 ++-- Task/ObjectUpdaterTask.php | 4 ++-- Task/Process/ProcessExecutorTask.php | 4 ++-- Task/Process/ProcessLauncherTask.php | 16 ++++++++-------- Task/PropertyGetterTask.php | 16 ++++++++-------- Task/PropertySetterTask.php | 16 ++++++++-------- Task/Reporting/AdvancedStatCounterTask.php | 4 ++-- Task/Reporting/LoggerTask.php | 4 ++-- Task/Reporting/StatCounterTask.php | 16 ++++++++-------- Task/RowAggregatorTask.php | 4 ++-- Task/Serialization/DenormalizerTask.php | 16 ++++++++-------- Task/Serialization/NormalizerTask.php | 16 ++++++++-------- Task/Serialization/SerializerTask.php | 4 ++-- Task/SimpleBatchTask.php | 4 ++-- Task/SkipEmptyTask.php | 4 ++-- Task/SplitJoinLineTask.php | 4 ++-- Task/StopTask.php | 4 ++-- Task/TransformerTask.php | 16 ++++++++-------- Task/Validation/ValidatorTask.php | 16 ++++++++-------- Tests/AbstractProcessTest.php | 4 ++-- Tests/BasicTest.php | 4 ++-- Tests/BlockingTaskTest.php | 4 ++-- Tests/CircularProcessTest.php | 4 ++-- Tests/ContextTest.php | 4 ++-- Tests/ExceptionManagementTest.php | 8 ++++++++ Tests/FlushableTaskTest.php | 4 ++-- Tests/IterableTaskTest.php | 4 ++-- Tests/MultiBranchProcessTest.php | 4 ++-- Tests/MultiWorkflowTest.php | 4 ++-- Tests/Task/Cache/DeleterTaskTest.php | 4 ++++ Tests/Task/Cache/GetterTaskTest.php | 4 ++++ Tests/Task/Cache/SetterTaskTest.php | 4 ++++ Tests/Task/ColumnAggregatorTaskTest.php | 8 ++++++++ Tests/Task/FilterTaskTest.php | 4 ++-- Tests/Task/ProcessExecutorTaskTest.php | 4 ++-- Tests/Task/StopTaskTest.php | 8 ++++++++ Tests/Task/TransformerTaskTest.php | 4 ++-- Tests/Task/ValidatorTaskTest.php | 4 ++-- Tests/Transformer/ArrayFilterTransformerTest.php | 4 ++-- .../Transformer/Cache/DeleterTransformerTest.php | 4 ++++ .../Transformer/Cache/GetterTransformerTest.php | 4 ++++ .../Transformer/Cache/SetterTransformerTest.php | 4 ++++ Tests/Transformer/CallbackTransformerTest.php | 4 ++-- Tests/Transformer/DateTransformersTest.php | 8 ++++++++ Tests/Transformer/HashTransformerTest.php | 8 ++++++++ Tests/Transformer/MappingTransformerTest.php | 8 ++++++++ Tests/Transformer/TypeSetterTransformerTest.php | 8 ++++++++ Tests/Transformer/UnsetTransformerTest.php | 8 ++++++++ Transformer/ArrayElementTransformer.php | 4 ++-- Transformer/ArrayFilterTransformer.php | 4 ++-- Transformer/ArrayFirstTransformer.php | 4 ++-- Transformer/ArrayLastTransformer.php | 4 ++-- Transformer/ArrayMapTransformer.php | 4 ++-- Transformer/Cache/AbstractCacheTransformer.php | 4 ++++ Transformer/Cache/DeleterTransformer.php | 4 ++++ Transformer/Cache/GetterTransformer.php | 4 ++++ Transformer/Cache/SetterTransformer.php | 4 ++++ Transformer/CallbackTransformer.php | 4 ++-- Transformer/ConditionTrait.php | 4 ++-- Transformer/ConfigurableTransformerInterface.php | 4 ++-- Transformer/ConvertValueTransformer.php | 4 ++-- Transformer/DateFormatTransformer.php | 4 ++-- Transformer/DateParserTransformer.php | 4 ++-- Transformer/DefaultTransformer.php | 4 ++-- Transformer/DenormalizeTransformer.php | 4 ++-- Transformer/EvaluatorTransformer.php | 4 ++-- Transformer/ExplodeTransformer.php | 4 ++-- Transformer/HashTransformer.php | 4 ++-- Transformer/ImplodeTransformer.php | 4 ++-- Transformer/MappingTransformer.php | 16 ++++++++-------- Transformer/NormalizeTransformer.php | 4 ++-- Transformer/PregFilterTransformer.php | 4 ++-- Transformer/PropertyAccessorTransformer.php | 4 ++-- .../RecursivePropertySetterTransformer.php | 16 ++++++++-------- Transformer/SlugifyTransformer.php | 4 ++-- Transformer/SprintfTransformer.php | 4 ++-- Transformer/TransformerInterface.php | 4 ++-- Transformer/TransformerTrait.php | 4 ++-- Transformer/TrimTransformer.php | 4 ++-- Transformer/TypeSetterTransformer.php | 4 ++-- Transformer/UnsetTransformer.php | 4 ++-- Transformer/WrapperTransformer.php | 4 ++-- 183 files changed, 744 insertions(+), 572 deletions(-) diff --git a/Addon/Doctrine/Task/Database/DatabaseReaderTask.php b/Addon/Doctrine/Task/Database/DatabaseReaderTask.php index 831cd279..ddfc5b0b 100644 --- a/Addon/Doctrine/Task/Database/DatabaseReaderTask.php +++ b/Addon/Doctrine/Task/Database/DatabaseReaderTask.php @@ -1,12 +1,12 @@ Date: Wed, 20 Feb 2019 16:05:13 +0100 Subject: [PATCH 024/304] Add doctrine entity manager cleaner --- .../EntityManager/DoctrineCleanerTask.php | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php new file mode 100644 index 00000000..d4b09e67 --- /dev/null +++ b/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php @@ -0,0 +1,44 @@ + + */ +class DoctrineCleanerTask extends AbstractDoctrineTask +{ + /** + * @param ProcessState $state + * + * @throws \UnexpectedValueException + * @throws \Doctrine\ORM\ORMInvalidArgumentException + * @throws \InvalidArgumentException + */ + public function execute(ProcessState $state) + { + $entity = $state->getInput(); + if (null === $entity) { + throw new \RuntimeException('DoctrineWriterTask does not allow null input'); + } + $class = ClassUtils::getClass($entity); + $entityManager = $this->doctrine->getManagerForClass($class); + if (!$entityManager instanceof EntityManagerInterface) { + throw new \UnexpectedValueException("No manager found for class {$class}"); + } + $entityManager->clear(); + } +} From 6d9e692afefed2a23037ca8d6da546a2cf6c9d9f Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 20 Mar 2019 17:16:53 +0100 Subject: [PATCH 025/304] Better error handling for error strategy: stop. Now outputing to error outputs all the time and stopping or skipping only after --- Manager/ProcessManager.php | 38 ++++++++++++++++++++++++-------------- Model/ProcessHistory.php | 8 ++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 6bb26907..5037c2d4 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -292,11 +292,8 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF $this->processExecution($taskConfiguration, $executionFlag); $this->handleState($state); - if ($state->isStopped()) { - return; - } - // An error feed cannot be blocked or skipped (except if the process has been stopped) + // An error feed cannot be blocked or skipped (even if the process has been stopped) if ($state->hasErrorOutput()) { foreach ($taskConfiguration->getErrorTasksConfigurations() as $errorTask) { $this->prepareNextProcess($taskConfiguration, $errorTask, true); @@ -310,6 +307,17 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF } } } + if ($state->isStopped()) { + if ($state->getException()) { + throw new \RuntimeException( + "Process {$state->getProcessConfiguration()->getCode()} has failed", + -1, + $state->getException() + ); + } + + return; + } // Run child items only if the state is not "skipped" and task is not blocking $task = $taskConfiguration->getTask(); @@ -401,15 +409,23 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e // Manage exception catching and setting the same if ($exception) { - $this->taskLogger->log($taskConfiguration->getLogLevel(), $exception->getMessage(), $state->getErrorContext()); + $this->taskLogger->log( + $taskConfiguration->getLogLevel(), + $exception->getMessage(), + $state->getErrorContext() + ); $state->setException($exception); + if (!$state->hasErrorOutput()) { + $state->setErrorOutput($state->getInput()); + } if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { $state->setSkipped(true); - if (!$state->hasErrorOutput()) { - $state->setErrorOutput($state->getInput()); - } } elseif ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { $state->stop($exception); + } else { + throw new \UnexpectedValueException( + "Unknown error strategy '{$taskConfiguration->getErrorStrategy()}'" + ); } } } @@ -527,12 +543,6 @@ protected function handleState(ProcessState $state): void $processHistory = $state->getProcessHistory(); if ($state->getException() && $state->isStopped()) { $processHistory->setFailed(); - - throw new \RuntimeException( - "Process {$state->getProcessConfiguration()->getCode()} has failed", - -1, - $state->getException() - ); } } diff --git a/Model/ProcessHistory.php b/Model/ProcessHistory.php index ee70ebbf..e38d6493 100644 --- a/Model/ProcessHistory.php +++ b/Model/ProcessHistory.php @@ -142,6 +142,14 @@ public function isStarted() return $this->state === self::STATE_STARTED; } + /** + * @return bool + */ + public function isFailed() + { + return $this->state === self::STATE_FAILED; + } + /** * Get process duration in seconds * From 65e5b019529210d863dcedfca863f04a30b471f4 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 1 Apr 2019 11:31:04 +0200 Subject: [PATCH 026/304] Allow console command to output data in a JSON file --- Command/ExecuteProcessCommand.php | 66 ++++++++++++++++- Filesystem/JsonStreamFile.php | 114 ++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 Filesystem/JsonStreamFile.php diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 485e7d73..7bb9d5c9 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Command; +use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -27,6 +28,12 @@ */ class ExecuteProcessCommand extends Command { + + const OUTPUT_STDOUT = '-'; + + const OUTPUT_FORMAT_DUMP = 'dump'; + const OUTPUT_FORMAT_JSON = 'json-stream'; + /** @var ProcessManager */ protected $processManager; @@ -57,6 +64,14 @@ protected function configure() $this->addOption('input', 'i', InputOption::VALUE_REQUIRED, 'Pass input data to the first task of the process'); $this->addOption('input-from-stdin', null, InputOption::VALUE_NONE, 'Read input data from stdin'); $this->addOption('context', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Contextual value', []); + $this->addOption('output', 'o', + InputOption::VALUE_REQUIRED, + 'Output path to dump data ("-" to use STDOUT with symfony dumper)', + self::OUTPUT_STDOUT); + $this->addOption('output-format', 't', + InputOption::VALUE_OPTIONAL, + 'Output format', + null); } /** @@ -84,10 +99,11 @@ protected function execute(InputInterface $input, OutputInterface $output) if (!$output->isQuiet()) { $output->writeln("Starting process '{$code}'..."); } + + // Execute each process $returnValue = $this->processManager->execute($code, $inputData, $context); - if ($output->isVeryVerbose() && class_exists(VarDumper::class)) { - VarDumper::dump($returnValue); // @todo remove this please - } + $this->handleOutputData($returnValue, $input, $output); + if (!$output->isQuiet()) { $output->writeln("Process '{$code}' executed successfully"); } @@ -121,4 +137,48 @@ protected function parseContextValues(InputInterface $input) return $context; } + + protected function handleOutputData($data, InputInterface $input, OutputInterface $output) + { + // Skip all if undefined + if (!$input->getOption('output-format')) { + return; + } + + $dataIsIterable = $data instanceof \iterable || \is_array($data); + + // Handle printing the output + if ($input->getOption('output') === self::OUTPUT_STDOUT) { + if ($output->isVeryVerbose()) { + if ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP && class_exists(VarDumper::class)) { + VarDumper::dump($data); // @todo remove this please + } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON && $dataIsIterable) { + foreach ($data as $item) { + $output->writeln(json_encode($item)); + } + } else { + throw new \InvalidArgumentException(sprintf( + "Cannot handle data output with format '%s' (iterable=%s)", + $input->getOption('output-format'), + $dataIsIterable + )); + } + } + } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON && $dataIsIterable) { + $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); + foreach ($data as $item) { + $outputFile->writeLine($item); + } + + if ($output->isVerbose()) { + $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); + } + } else { + throw new \InvalidArgumentException(sprintf( + "Cannot handle data output with format '%s' (iterable=%s)", + $input->getOption('output-format'), + $dataIsIterable + )); + } + } } diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php new file mode 100644 index 00000000..d0b5e178 --- /dev/null +++ b/Filesystem/JsonStreamFile.php @@ -0,0 +1,114 @@ +file = new \SplFileObject($filename, $mode); + } + + /** + * Warning! This method will rewind the file to the beginning before and after counting the lines! + * + * @throws \RuntimeException + * + * @return int + */ + public function getLineCount(): int + { + if (null === $this->lineCount) { + $this->rewind(); + $line = 0; + while (!$this->isEndOfFile()) { + ++$line; + $this->file->next(); + } + $this->rewind(); + + $this->lineCount = $line; + } + + return $this->lineCount; + } + + /** + * @return int + */ + public function getCurrentLine(): int + { + return $this->currentLine; + } + + /** + * @return bool + */ + public function isEndOfFile(): bool + { + return $this->file->eof(); + } + + /** + * Return an array containing current data and moving the file pointer + * + * @return array|null + */ + public function readLine(): ?array + { + if ($this->isEndOfFile()) { + return null; + } + + $rawLine = $this->file->fgets(); + $this->currentLine++; + + return json_decode($rawLine, true); + } + + /** + * @param $item + * + * @return int + */ + public function writeLine($item): int + { + if (!is_array($item) && !is_scalar($item)) { + throw new \InvalidArgumentException( + sprintf('%s only supports items of type scalar or array', __CLASS__) + ); + } + + $this->file->fwrite(json_encode($item) . PHP_EOL); + $this->currentLine++; + + return $this->currentLine; + } + + /** + * Rewind data to array + */ + public function rewind(): void + { + $this->file->rewind(); + $this->currentLine = 0; + } +} From 390d4f604cad854c36495fbab1ee413ae0530e00 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 1 Apr 2019 16:27:59 +0200 Subject: [PATCH 027/304] Use JSON file to buffer outputs from ProcessLauncher --- Command/ExecuteProcessCommand.php | 24 +- Filesystem/JsonStreamFile.php | 5 +- Model/SubprocessInstance.php | 207 ++++++++++++++++++ Task/File/JsonStream/JsonStreamReaderTask.php | 47 ++++ Task/Process/ProcessLauncherTask.php | 126 +++++------ 5 files changed, 326 insertions(+), 83 deletions(-) create mode 100644 Model/SubprocessInstance.php create mode 100644 Task/File/JsonStream/JsonStreamReaderTask.php diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 7bb9d5c9..0180730e 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -145,39 +145,31 @@ protected function handleOutputData($data, InputInterface $input, OutputInterfac return; } - $dataIsIterable = $data instanceof \iterable || \is_array($data); - // Handle printing the output if ($input->getOption('output') === self::OUTPUT_STDOUT) { if ($output->isVeryVerbose()) { if ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP && class_exists(VarDumper::class)) { VarDumper::dump($data); // @todo remove this please - } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON && $dataIsIterable) { - foreach ($data as $item) { - $output->writeln(json_encode($item)); - } + } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { + $output->writeln(json_encode($data)); } else { throw new \InvalidArgumentException(sprintf( - "Cannot handle data output with format '%s' (iterable=%s)", - $input->getOption('output-format'), - $dataIsIterable + "Cannot handle data output with format '%s'", + $input->getOption('output-format') )); } } - } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON && $dataIsIterable) { + } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); - foreach ($data as $item) { - $outputFile->writeLine($item); - } + $outputFile->writeLine($data); if ($output->isVerbose()) { $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { throw new \InvalidArgumentException(sprintf( - "Cannot handle data output with format '%s' (iterable=%s)", - $input->getOption('output-format'), - $dataIsIterable + "Cannot handle data output with format '%s'", + $input->getOption('output-format') )); } } diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php index d0b5e178..5e5c9aeb 100644 --- a/Filesystem/JsonStreamFile.php +++ b/Filesystem/JsonStreamFile.php @@ -25,6 +25,9 @@ class JsonStreamFile public function __construct(string $filename, $mode = 'rb') { $this->file = new \SplFileObject($filename, $mode); + + // Useful to skip empty trailing lines + $this->file->setFlags(\SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); } /** @@ -72,7 +75,7 @@ public function isEndOfFile(): bool * * @return array|null */ - public function readLine(): ?array + public function readLine() { if ($this->isEndOfFile()) { return null; diff --git a/Model/SubprocessInstance.php b/Model/SubprocessInstance.php new file mode 100644 index 00000000..db167370 --- /dev/null +++ b/Model/SubprocessInstance.php @@ -0,0 +1,207 @@ +processCode = $processCode; + $this->input = $input; + $this->context = $context; + + $resolver = new OptionsResolver(); + $this->configureOptions($resolver); + $this->options = $resolver->resolve($options); + + $this->consolePath = $kernel->getProjectDir() . '/bin/console'; + $this->environment = $kernel->getEnvironment(); + $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid() . '.json-stream'; // Todo use param ? + $this->logDir = $kernel->getLogDir() . '/process'; + } + + + /** + * Prepare the process before start + * + * @return $this + */ + public function buildProcess() + { + $pathFinder = new PhpExecutableFinder(); + + $arguments = [ + 'nohup', + $pathFinder->find(), + $this->consolePath, + '--env=' . $this->environment, + 'cleverage:process:execute', + '--input-from-stdin', + ]; + + $fs = new Filesystem(); + $fs->mkdir($this->logDir); + if (!$fs->exists($this->consolePath)) { + throw new \RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); + } + + if ($this->options[self::OPTION_JSON_BUFFERING]) { + $arguments = array_merge($arguments, [ + '--output=' . $this->bufferPath, + '--output-format=json-stream', + ]); + } + + if (!empty($this->context)) { + foreach ($this->context as $key => $value) { + $arguments[] = sprintf('--context=%s:%s', $key, $value); + } + } + + $arguments[] = $this->processCode; + + $this->process = new Process($arguments, null, null, $this->input); + $this->process->setCommandLine($this->process->getCommandLine()); + $this->process->inheritEnvironmentVariables(); + $this->process->enableOutput(); + + return $this; + } + + /** + * Start the process + * + * @return $this + */ + public function start() + { + $this->process->start(); + + return $this; + } + + /** + * Stop the process + * + * @param int $timeout + * + * @return $this + */ + public function stop($timeout = 10) + { + $this->process->stop($timeout); + + return $this; + } + + /** + * @return Process + */ + public function getProcess(): Process + { + return $this->process; + } + + /** + * @return string + */ + public function getProcessCode(): string + { + return $this->processCode; + } + + /** + * @return string|null + */ + public function getInput(): ?string + { + return $this->input; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @return array + */ + public function getContext(): array + { + return $this->context; + } + + /** + * @return string|null + */ + public function getResult(): ?string + { + $fs = new Filesystem(); + if ($this->process->isTerminated() && $fs->exists($this->bufferPath)) { + return $this->bufferPath; + } + + return null; + } + + /** + * Available options for process launcher + * + * @param OptionsResolver $resolver + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault(self::OPTION_JSON_BUFFERING, false); + $resolver->setAllowedTypes(self::OPTION_JSON_BUFFERING, 'bool'); + } +} diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/Task/File/JsonStream/JsonStreamReaderTask.php new file mode 100644 index 00000000..66d5305b --- /dev/null +++ b/Task/File/JsonStream/JsonStreamReaderTask.php @@ -0,0 +1,47 @@ +file === null) { + $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); + } + + $line = $this->file->readLine(); + if (isset($line)) { + $state->setOutput($line); + } else { + $state->setSkipped(true); + } + + } + + public function next(ProcessState $state) + { + $eof = $this->file->isEndOfFile(); + if ($eof) { + $this->file = null; + } + + return !$eof; + } + + protected function getFilePath(ProcessState $state) + { + return $state->getInput(); + } + + +} diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index 793a5614..2a7e852c 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -12,16 +12,15 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\FlushableTaskInterface; +use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; +use CleverAge\ProcessBundle\Model\SubprocessInstance; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Psr\Log\LoggerInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Process\PhpExecutableFinder; -use Symfony\Component\Process\Process; /** * Launch a new process for each input received, input must be a scalar, a resource or a \Traversable @@ -29,7 +28,7 @@ * @author Valentin Clavreul * @author Vincent Chalnot */ -class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableTaskInterface +class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { /** @var LoggerInterface */ protected $logger; @@ -40,9 +39,15 @@ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableT /** @var KernelInterface */ protected $kernel; - /** @var Process[] */ + /** @var SubprocessInstance[] */ protected $launchedProcesses = []; + /** @var \SplQueue */ + protected $finishedBuffers; + + /** @var bool */ + protected $flushMode = false; + /** * @param LoggerInterface $logger * @param ProcessConfigurationRegistry $processRegistry @@ -56,18 +61,14 @@ public function __construct( $this->logger = $logger; $this->processRegistry = $processRegistry; $this->kernel = $kernel; + + $this->finishedBuffers = new \SplQueue(); } /** * @param ProcessState $state * - * @throws \Symfony\Component\Process\Exception\LogicException - * @throws \Symfony\Component\Process\Exception\RuntimeException * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Symfony\Component\Filesystem\Exception\IOException - * @throws \InvalidArgumentException - * @throws \RuntimeException - * @throws \Symfony\Component\Process\Exception\InvalidArgumentException */ public function execute(ProcessState $state) { @@ -83,77 +84,65 @@ public function execute(ProcessState $state) $this->launchedProcesses[] = $process; $logContext = [ - 'input' => $process->getInput(), + 'input' => $process->getProcess()->getInput(), ]; - $this->logger->debug("Running command: {$process->getCommandLine()}", $logContext); + $this->logger->debug("Running command: {$process->getProcess()->getCommandLine()}", $logContext); sleep($options['sleep_interval_after_launch']); + + // Never return data during exec, only during flushes + $state->setSkipped(true); } /** * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Symfony\Component\Process\Exception\RuntimeException */ public function flush(ProcessState $state) { - while (\count($this->launchedProcesses) > 0) { - $this->handleProcesses($state); - sleep($this->getOption($state, 'sleep_on_finalize_interval')); + $this->flushMode = true; + if ($this->finishedBuffers->isEmpty()) { + $this->flushMode = false; + $state->setSkipped(true); + } else { + $state->setOutput($this->finishedBuffers->dequeue()); } - - $state->setSkipped(true); } /** * @param ProcessState $state * - * @throws \Symfony\Component\Process\Exception\LogicException - * @throws \Symfony\Component\Process\Exception\RuntimeException + * @return bool * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Symfony\Component\Filesystem\Exception\IOException - * @throws \InvalidArgumentException - * @throws \RuntimeException - * @throws \Symfony\Component\Process\Exception\InvalidArgumentException - * - * @return \Symfony\Component\Process\Process */ - protected function launchProcess(ProcessState $state) + public function next(ProcessState $state) { - $pathFinder = new PhpExecutableFinder(); - $consolePath = $this->kernel->getRootDir().'/../bin/console'; - $logDir = $this->kernel->getLogDir().'/process'; - $processCode = $this->getOption($state, 'process'); - $processOptions = $this->getOption($state, 'process_options'); - - $fs = new Filesystem(); - $fs->mkdir($logDir); - if (!$fs->exists($consolePath)) { - throw new \RuntimeException("Unable to resolve path to symfony console '{$consolePath}'"); + if (!$this->flushMode) { + return false; } - $arguments = [ - 'nohup', - $pathFinder->find(), - $consolePath, - '--env='.$this->kernel->getEnvironment(), - 'cleverage:process:execute', - '--input-from-stdin', - ]; + sleep($this->getOption($state, 'sleep_on_finalize_interval')); + $this->handleProcesses($state); - $arguments = array_merge($arguments, $processOptions); - $arguments[] = $processCode; + return count($this->launchedProcesses) > 0 || $this->finishedBuffers->count() > 0; + } - $process = new Process($arguments, null, null, $state->getInput()); - $process->setCommandLine($process->getCommandLine()); - $process->inheritEnvironmentVariables(); - $process->enableOutput(); - $process->start(); - return $process; + /** + * @param ProcessState $state + * + * @return SubprocessInstance + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + protected function launchProcess(ProcessState $state) + { + // TODO options & context + $subprocess = new SubprocessInstance($this->kernel, $this->getOption($state, 'process'), $state->getInput(), [], [ + SubprocessInstance::OPTION_JSON_BUFFERING => true, + ]); + $subprocess->buildProcess(); + + return $subprocess->start(); } /** @@ -164,26 +153,31 @@ protected function launchProcess(ProcessState $state) protected function handleProcesses(ProcessState $state) { foreach ($this->launchedProcesses as $key => $process) { - if (!$process->isTerminated()) { + if (!$process->getProcess()->isTerminated()) { // @todo handle incremental error output properly, specially for terminal where logs are lost - echo $process->getIncrementalErrorOutput(); + echo $process->getProcess()->getIncrementalErrorOutput(); continue; } $logContext = [ - 'cmd' => $process->getCommandLine(), - 'input' => $process->getInput(), - 'exit_code' => $process->getExitCode(), - 'exit_code_text' => $process->getExitCodeText(), + 'cmd' => $process->getProcess()->getCommandLine(), + 'input' => $process->getProcess()->getInput(), + 'exit_code' => $process->getProcess()->getExitCode(), + 'exit_code_text' => $process->getProcess()->getExitCodeText(), ]; $this->logger->debug('Command terminated', $logContext); unset($this->launchedProcesses[$key]); - if (0 !== $process->getExitCode()) { - $this->logger->critical($process->getErrorOutput(), $logContext); + if (0 !== $process->getProcess()->getExitCode()) { + $this->logger->critical($process->getProcess()->getErrorOutput(), $logContext); $this->killProcesses(); - throw new \RuntimeException("Sub-process has failed: {$process->getExitCodeText()}"); + throw new \RuntimeException("Sub-process has failed: {$process->getProcess()->getExitCodeText()}"); + } + + $result = $process->getResult(); + if (isset($result)) { + $this->finishedBuffers->enqueue($result); } } } From da257e0f673efe9716fd32a5195c2f2ce90a87b4 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 1 Apr 2019 18:12:27 +0200 Subject: [PATCH 028/304] Removed suboptimal log for big files (due to "getLineCount" parsing the whole file) --- Task/File/Csv/CsvSplitterTask.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index f82a9f30..29d05735 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -43,9 +43,6 @@ public function execute(ProcessState $state) $options['mode'] ); - if ($csv->getLineCount() > $options['max_lines']) { - $this->logger->debug("Found big CSV file ({$csv->getLineCount()} lines), splitting..."); - } $this->csv = $csv; } From 7631a26b4c5fa6ab70e701ae46ef2856ffe41333 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 1 Apr 2019 18:15:41 +0200 Subject: [PATCH 029/304] Better stat display (last update time is now the real last update time) --- Task/Reporting/AdvancedStatCounterTask.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Task/Reporting/AdvancedStatCounterTask.php b/Task/Reporting/AdvancedStatCounterTask.php index c9ececa3..3e1753ec 100644 --- a/Task/Reporting/AdvancedStatCounterTask.php +++ b/Task/Reporting/AdvancedStatCounterTask.php @@ -54,6 +54,7 @@ public function execute(ProcessState $state) $now = new \DateTime(); if (!$this->startedAt) { $this->startedAt = $now; + $this->lastUpdate = $now; } if ($this->preInitCounter < $this->getOption($state, 'skip_first')) { $this->preInitCounter++; @@ -61,7 +62,7 @@ public function execute(ProcessState $state) return; } - if ($this->lastUpdate && 0 === $this->counter % $this->getOption($state, 'show_every')) { + if ($this->counter > 0 && 0 === $this->counter % $this->getOption($state, 'show_every')) { $diff = $now->diff($this->lastUpdate); $fullText = "Last iteration {$diff->format('%H:%I:%S')} ago"; $items = $this->getOption($state, 'num_items') * $this->counter; @@ -73,12 +74,12 @@ public function execute(ProcessState $state) $fullText .= " - {$rate} items/s - {$items} items processed"; $fullText .= " in {$now->diff($this->startedAt)->format('%H:%I:%S')}"; + $this->lastUpdate = $now; $this->logger->info($fullText); } else { $state->setSkipped(true); } $this->counter++; - $this->lastUpdate = $now; } /** From ba3089c63dce12a698e376c520e5b1c259905376 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 1 Apr 2019 18:16:29 +0200 Subject: [PATCH 030/304] ProcessLauncherTask is now able to flush data asap --- Filesystem/JsonStreamFile.php | 6 --- Task/Process/ProcessLauncherTask.php | 66 ++++++++++++++++++---------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php index 5e5c9aeb..c2b8759e 100644 --- a/Filesystem/JsonStreamFile.php +++ b/Filesystem/JsonStreamFile.php @@ -94,12 +94,6 @@ public function readLine() */ public function writeLine($item): int { - if (!is_array($item) && !is_scalar($item)) { - throw new \InvalidArgumentException( - sprintf('%s only supports items of type scalar or array', __CLASS__) - ); - } - $this->file->fwrite(json_encode($item) . PHP_EOL); $this->currentLine++; diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index 2a7e852c..3e8a342c 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -74,25 +74,12 @@ public function execute(ProcessState $state) { $this->handleProcesses($state); // Handler processes first - $options = $this->getOptions($state); - while (\count($this->launchedProcesses) >= $options['max_processes']) { - $this->handleProcesses($state); - sleep($options['sleep_interval']); + if (!$this->flushMode) { + $this->handleInput($state); + $state->setSkipped(true); + } else { + $this->flush($state); } - - $process = $this->launchProcess($state); - $this->launchedProcesses[] = $process; - - $logContext = [ - 'input' => $process->getProcess()->getInput(), - ]; - - $this->logger->debug("Running command: {$process->getProcess()->getCommandLine()}", $logContext); - - sleep($options['sleep_interval_after_launch']); - - // Never return data during exec, only during flushes - $state->setSkipped(true); } /** @@ -117,16 +104,47 @@ public function flush(ProcessState $state) */ public function next(ProcessState $state) { - if (!$this->flushMode) { - return false; + // if there is some data waiting, handle it in priority + if ($this->finishedBuffers->count() > 0) { + $this->flushMode = true; + return true; + } + + // if we are in flush mode, we should wait for process to finish + if ($this->flushMode) { + return count($this->launchedProcesses) > 0; } sleep($this->getOption($state, 'sleep_on_finalize_interval')); $this->handleProcesses($state); - return count($this->launchedProcesses) > 0 || $this->finishedBuffers->count() > 0; + return false; } + /** + * @param ProcessState $state + * + * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + */ + protected function handleInput(ProcessState $state) + { + $options = $this->getOptions($state); + while (\count($this->launchedProcesses) >= $options['max_processes']) { + $this->handleProcesses($state); + sleep($options['sleep_interval']); + } + + $process = $this->launchProcess($state); + $this->launchedProcesses[] = $process; + + $logContext = [ + 'input' => $process->getProcess()->getInput(), + ]; + + $this->logger->debug("Running command: {$process->getProcess()->getCommandLine()}", $logContext); + + sleep($options['sleep_interval_after_launch']); + } /** * @param ProcessState $state @@ -216,9 +234,9 @@ function (Options $options, $value) { 'process_options' => [], ] ); - $resolver->setAllowedTypes('max_processes', ['integer']); - $resolver->setAllowedTypes('sleep_interval', ['integer']); - $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer']); + $resolver->setAllowedTypes('max_processes', ['integer', 'double']); + $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); + $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); $resolver->setAllowedTypes('process_options', ['array']); } From 7b8a500130552c1b05e440a6786ba7733e51b6b5 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 2 Apr 2019 12:28:35 +0200 Subject: [PATCH 031/304] Allow to change the name of transformer list option --- Transformer/TransformerTrait.php | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index e8e624a0..3c95c034 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -85,23 +85,16 @@ protected function getCleanedTransfomerCode(string $transformerCode) } /** - * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver - * @throws \CleverAge\ProcessBundle\Exception\MissingTransformerException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @param OptionsResolver $resolver + * @param string $optionName */ - protected function configureTransformersOptions(OptionsResolver $resolver) + protected function configureTransformersOptions(OptionsResolver $resolver, $optionName = 'transformers') { - $resolver->setDefault('transformers', []); - $resolver->setAllowedTypes('transformers', ['array']); + $resolver->setDefault($optionName, []); + $resolver->setAllowedTypes($optionName, ['array']); /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( // This logic is duplicated from the array_map transformer @todo fix me - 'transformers', + $optionName, function (Options $options, $transformers) { /** @var array $transformers */ foreach ($transformers as $transformerCode => &$transformerOptions) { @@ -121,4 +114,4 @@ function (Options $options, $transformers) { ); } -} \ No newline at end of file +} From c012e98eb4a04e630194e2f1ead8d2495aaf6740 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 2 Apr 2019 17:08:13 +0200 Subject: [PATCH 032/304] Transformer does now require correct option ahead of transformation (on behalf of user) Lots of small optimisation on TransformerTrait and most of Transformers --- Transformer/ArrayMapTransformer.php | 5 --- Transformer/CallbackTransformer.php | 6 ---- Transformer/ConvertValueTransformer.php | 5 --- Transformer/DateFormatTransformer.php | 1 + Transformer/DenormalizeTransformer.php | 21 ++--------- Transformer/EvaluatorTransformer.php | 36 ++++++++++++++----- Transformer/ExplodeTransformer.php | 6 ---- Transformer/MappingTransformer.php | 4 --- Transformer/NormalizeTransformer.php | 18 ++-------- Transformer/PregFilterTransformer.php | 6 ---- Transformer/PropertyAccessorTransformer.php | 5 --- .../RecursivePropertySetterTransformer.php | 6 ---- Transformer/SlugifyTransformer.php | 14 ++++---- Transformer/TransformerTrait.php | 27 ++++++++------ Transformer/TrimTransformer.php | 6 ---- Transformer/UnsetTransformer.php | 4 --- Transformer/WrapperTransformer.php | 5 --- 17 files changed, 56 insertions(+), 119 deletions(-) diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index 3715389f..04356f76 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -39,7 +39,6 @@ public function __construct(TransformerRegistry $transformerRegistry) * @param array $values * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \UnexpectedValueException * @throws \CleverAge\ProcessBundle\Exception\MissingTransformerException * @@ -51,10 +50,6 @@ public function transform($values, array $options = []) throw new \UnexpectedValueException('Input value must be an array or traversable'); } - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ - $options = $resolver->resolve($options); /** @var array $transformers */ $transformers = $options['transformers']; diff --git a/Transformer/CallbackTransformer.php b/Transformer/CallbackTransformer.php index f5b0fc7b..3cd14de3 100644 --- a/Transformer/CallbackTransformer.php +++ b/Transformer/CallbackTransformer.php @@ -28,16 +28,10 @@ class CallbackTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * * @return mixed $value */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - if (count($options['additional_parameters']) && !count($options['right_parameters'])) { $options['right_parameters'] = $options['additional_parameters']; diff --git a/Transformer/ConvertValueTransformer.php b/Transformer/ConvertValueTransformer.php index e708dac6..09b5be11 100644 --- a/Transformer/ConvertValueTransformer.php +++ b/Transformer/ConvertValueTransformer.php @@ -26,7 +26,6 @@ class ConvertValueTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \UnexpectedValueException * * @return mixed $value @@ -37,10 +36,6 @@ public function transform($value, array $options = []) return $value; } - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - if (!is_string($value) && !is_int($value)) { // If not a valid array index if (!$options['auto_cast']) { $type = gettype($value); diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 38bcd4a9..a7469edc 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -31,6 +31,7 @@ class DateFormatTransformer implements ConfigurableTransformerInterface * @param array $options * * @return mixed|string + * @throws \Exception */ public function transform($value, array $options = []) { diff --git a/Transformer/DenormalizeTransformer.php b/Transformer/DenormalizeTransformer.php index 32134645..53fc9a82 100644 --- a/Transformer/DenormalizeTransformer.php +++ b/Transformer/DenormalizeTransformer.php @@ -60,28 +60,11 @@ public function configureOptions(OptionsResolver $resolver) * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException - * @throws \Symfony\Component\Serializer\Exception\RuntimeException - * @throws \Symfony\Component\Serializer\Exception\LogicException - * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException - * @throws \Symfony\Component\Serializer\Exception\ExtraAttributesException - * @throws \Symfony\Component\Serializer\Exception\BadMethodCallException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @return mixed + * @return mixed|object + * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - return $this->denormalizer->denormalize( $value, $options['class'], diff --git a/Transformer/EvaluatorTransformer.php b/Transformer/EvaluatorTransformer.php index 6b2b61de..0f53470b 100644 --- a/Transformer/EvaluatorTransformer.php +++ b/Transformer/EvaluatorTransformer.php @@ -11,6 +11,8 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\ExpressionLanguage\ParsedExpression; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -20,6 +22,19 @@ */ class EvaluatorTransformer implements ConfigurableTransformerInterface { + + /** @var ExpressionLanguage */ + protected $language; + + /** + * EvaluatorTransformer constructor. + */ + public function __construct() + { + $this->language = new ExpressionLanguage(); + } + + /** * @param OptionsResolver $resolver * @@ -28,12 +43,23 @@ class EvaluatorTransformer implements ConfigurableTransformerInterface */ public function configureOptions(OptionsResolver $resolver) { + // Allow to cache the parsing by statically defining variables + $resolver->setDefault('variables', null); + $resolver->addAllowedTypes('variables', ['null', 'array']); + $resolver->setRequired( [ 'expression', ] ); - $resolver->setAllowedTypes('expression', ['string']); + $resolver->setAllowedTypes('expression', ['string', ParsedExpression::class]); + $resolver->setNormalizer('expression', function (Options $options, $expression) { + if (is_array($options['variables'])) { + return $this->language->parse($expression, $options['variables']); + } else { + return $expression; + } + }); } /** @@ -51,13 +77,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - $language = new ExpressionLanguage(); - - return $language->evaluate( + return $this->language->evaluate( $options['expression'], $value ); diff --git a/Transformer/ExplodeTransformer.php b/Transformer/ExplodeTransformer.php index e42f62ba..08a60547 100644 --- a/Transformer/ExplodeTransformer.php +++ b/Transformer/ExplodeTransformer.php @@ -26,16 +26,10 @@ class ExplodeTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * * @return mixed $value */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - if (null === $value || '' === $value) { return []; } diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 3072c5ea..901a3c01 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -61,10 +61,6 @@ public function __construct( */ public function transform($input, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - if (!empty($options['initial_value']) && $options['keep_input']) { throw new InvalidOptionsException( 'The options "initial_value" and "keep_input" can\'t be both enabled.' diff --git a/Transformer/NormalizeTransformer.php b/Transformer/NormalizeTransformer.php index 245baa50..2de16fc6 100644 --- a/Transformer/NormalizeTransformer.php +++ b/Transformer/NormalizeTransformer.php @@ -54,25 +54,11 @@ public function configureOptions(OptionsResolver $resolver) * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\Serializer\Exception\LogicException - * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException - * @throws \Symfony\Component\Serializer\Exception\CircularReferenceException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @return mixed + * @return array|bool|float|int|mixed|string + * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - return $this->normalizer->normalize( $value, $options['format'], diff --git a/Transformer/PregFilterTransformer.php b/Transformer/PregFilterTransformer.php index 01e2b3fd..9fa7e0d8 100644 --- a/Transformer/PregFilterTransformer.php +++ b/Transformer/PregFilterTransformer.php @@ -25,16 +25,10 @@ class PregFilterTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * * @return mixed $value */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - $pattern = $options['pattern']; $replacement = $options['replacement']; diff --git a/Transformer/PropertyAccessorTransformer.php b/Transformer/PropertyAccessorTransformer.php index 0f96bb4d..f1993c85 100644 --- a/Transformer/PropertyAccessorTransformer.php +++ b/Transformer/PropertyAccessorTransformer.php @@ -38,7 +38,6 @@ public function __construct(PropertyAccessorInterface $accessor) * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException * @throws \Symfony\Component\PropertyAccess\Exception\AccessException * @throws \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException @@ -47,10 +46,6 @@ public function __construct(PropertyAccessorInterface $accessor) */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ - $options = $resolver->resolve($options); if (null === $value && $options['ignore_null']) { return null; diff --git a/Transformer/RecursivePropertySetterTransformer.php b/Transformer/RecursivePropertySetterTransformer.php index faad1000..852322bd 100644 --- a/Transformer/RecursivePropertySetterTransformer.php +++ b/Transformer/RecursivePropertySetterTransformer.php @@ -40,7 +40,6 @@ public function __construct(PropertyAccessorInterface $accessor) * * @throws \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException * @throws \CleverAge\ProcessBundle\Exception\TransformerException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException * @throws \Symfony\Component\PropertyAccess\Exception\AccessException * @throws \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException @@ -49,11 +48,6 @@ public function __construct(PropertyAccessorInterface $accessor) */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ - $options = $resolver->resolve($options); - if (null === $value && $options['ignore_null']) { return null; } diff --git a/Transformer/SlugifyTransformer.php b/Transformer/SlugifyTransformer.php index c6075987..6d0d5496 100644 --- a/Transformer/SlugifyTransformer.php +++ b/Transformer/SlugifyTransformer.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Transformer; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -26,17 +27,12 @@ class SlugifyTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * * @return mixed $value */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - $transliterator = \Transliterator::create($options['transliterator']); + /** @var \Transliterator $transliterator */ + $transliterator = $options['transliterator']; $string = $transliterator->transliterate($value); return trim( @@ -73,5 +69,9 @@ public function configureOptions(OptionsResolver $resolver) 'separator' => '_', ] ); + + $resolver->setNormalizer('transliterator', function(Options $options, $value) { + return \Transliterator::create($value); + }); } } diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 3c95c034..0f9bbfb8 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -37,15 +37,15 @@ trait TransformerTrait */ protected function applyTransformers(array $transformers, $value) { + // Quick return for better perfs + if (empty($transformers)) { + return $value; + } + /** @noinspection ForeachSourceInspection */ - foreach ($transformers as $transformerCode => $transformerOptions) { + foreach ($transformers as $transformerCode => $transformerClosure) { try { - $transformerCode = $this->getCleanedTransfomerCode($transformerCode); - $transformer = $this->transformerRegistry->getTransformer($transformerCode); - $value = $transformer->transform( - $value, - $transformerOptions ?: [] - ); + $value = $transformerClosure($value); } catch (\Throwable $exception) { throw new TransformerException($transformerCode, 0, $exception); } @@ -96,10 +96,11 @@ protected function configureTransformersOptions(OptionsResolver $resolver, $opti $resolver->setNormalizer( // This logic is duplicated from the array_map transformer @todo fix me $optionName, function (Options $options, $transformers) { - /** @var array $transformers */ - foreach ($transformers as $transformerCode => &$transformerOptions) { + $transformerClosures = []; + + foreach ($transformers as $origTransformerCode => $transformerOptions) { $transformerOptionsResolver = new OptionsResolver(); - $transformerCode = $this->getCleanedTransfomerCode($transformerCode); + $transformerCode = $this->getCleanedTransfomerCode($origTransformerCode); $transformer = $this->transformerRegistry->getTransformer($transformerCode); if ($transformer instanceof ConfigurableTransformerInterface) { $transformer->configureOptions($transformerOptionsResolver); @@ -107,9 +108,13 @@ function (Options $options, $transformers) { $transformerOptions ?? [] ); } + + $transformerClosures[$origTransformerCode] = function ($value) use ($transformer, $transformerOptions) { + return $transformer->transform($value, $transformerOptions); + }; } - return $transformers; + return $transformerClosures; } ); } diff --git a/Transformer/TrimTransformer.php b/Transformer/TrimTransformer.php index f8fb75d6..1fe8ab28 100644 --- a/Transformer/TrimTransformer.php +++ b/Transformer/TrimTransformer.php @@ -26,16 +26,10 @@ class TrimTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * * @return mixed $value */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - return trim($value, $options['charlist']); } diff --git a/Transformer/UnsetTransformer.php b/Transformer/UnsetTransformer.php index 91a3e2bb..c994e0ac 100644 --- a/Transformer/UnsetTransformer.php +++ b/Transformer/UnsetTransformer.php @@ -34,10 +34,6 @@ public function __construct(PropertyAccessorInterface $accessor) */ public function transform($value, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - if (!\is_array($value)) { throw new \UnexpectedValueException('Given value must be an array'); } diff --git a/Transformer/WrapperTransformer.php b/Transformer/WrapperTransformer.php index 25468474..6b547bf8 100644 --- a/Transformer/WrapperTransformer.php +++ b/Transformer/WrapperTransformer.php @@ -26,17 +26,12 @@ class WrapperTransformer implements ConfigurableTransformerInterface * @param mixed $input * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface * @throws \Exception * * @return mixed $value */ public function transform($input, array $options = []) { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - return [$options['wrapper_key'] => $input]; } From 852db80e3ab9c3db2d5d552b7a29ef4c1c47d109 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 11 Apr 2019 10:19:41 +0200 Subject: [PATCH 033/304] [WIP - should be reviewed and tested] Fixed ProcessLauncher being stopped before end of every subprocesses --- Task/Process/ProcessLauncherTask.php | 52 +++++++++++++++++++++------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index 3e8a342c..145cb75d 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -72,13 +72,21 @@ public function __construct( */ public function execute(ProcessState $state) { + // TODO still not perfect, optimize and secure it $this->handleProcesses($state); // Handler processes first if (!$this->flushMode) { $this->handleInput($state); $state->setSkipped(true); + } elseif (!$this->finishedBuffers->isEmpty()) { + $state->setOutput($this->finishedBuffers->dequeue()); + + // After dequeue, stop flush + if ($this->finishedBuffers->isEmpty()) { + $this->flushMode = false; + } } else { - $this->flush($state); + $state->setSkipped(true); } } @@ -88,11 +96,15 @@ public function execute(ProcessState $state) public function flush(ProcessState $state) { $this->flushMode = true; - if ($this->finishedBuffers->isEmpty()) { - $this->flushMode = false; - $state->setSkipped(true); - } else { + if (!$this->finishedBuffers->isEmpty()) { $state->setOutput($this->finishedBuffers->dequeue()); + } else { + $state->setSkipped(true); + } + + // After dequeue, stop flush + if ($this->finishedBuffers->isEmpty() && !count($this->launchedProcesses)) { + $this->flushMode = false; } } @@ -104,9 +116,12 @@ public function flush(ProcessState $state) */ public function next(ProcessState $state) { + $this->handleProcesses($state); + // if there is some data waiting, handle it in priority if ($this->finishedBuffers->count() > 0) { $this->flushMode = true; + return true; } @@ -116,7 +131,6 @@ public function next(ProcessState $state) } sleep($this->getOption($state, 'sleep_on_finalize_interval')); - $this->handleProcesses($state); return false; } @@ -154,13 +168,16 @@ protected function handleInput(ProcessState $state) */ protected function launchProcess(ProcessState $state) { - // TODO options & context - $subprocess = new SubprocessInstance($this->kernel, $this->getOption($state, 'process'), $state->getInput(), [], [ - SubprocessInstance::OPTION_JSON_BUFFERING => true, - ]); - $subprocess->buildProcess(); + $subprocess = new SubprocessInstance($this->kernel, + $this->getOption($state, 'process'), + $state->getInput(), + $this->getOption($state, 'context'), + [ + SubprocessInstance::OPTION_JSON_BUFFERING => true, + ] + ); - return $subprocess->start(); + return $subprocess->buildProcess()->start(); } /** @@ -232,12 +249,23 @@ function (Options $options, $value) { 'sleep_interval_after_launch' => 1, 'sleep_on_finalize_interval' => 1, 'process_options' => [], + 'context' => [], ] ); $resolver->setAllowedTypes('max_processes', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); + $resolver->setAllowedTypes('context', ['array']); + $resolver->setAllowedTypes('process_options', ['array']); + $resolver->setNormalizer('process_options', function (Options $options, $value) { + if (!empty($value)) { + // Todo deprecation trigger + throw new \InvalidArgumentException("Deprecated option, please contact support for help"); + } + + return $value; + }); } /** From a631c93083b7b65d47334c1fb89c7663a33f6bf3 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 16 Apr 2019 16:48:16 +0200 Subject: [PATCH 034/304] Refactoring ArrayMap with transformer trait --- Transformer/ArrayMapTransformer.php | 50 ++++++----------------------- Transformer/TransformerTrait.php | 36 ++++++++++----------- 2 files changed, 27 insertions(+), 59 deletions(-) diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index 04356f76..23765de6 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -11,7 +11,6 @@ namespace CleverAge\ProcessBundle\Transformer; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -22,8 +21,7 @@ */ class ArrayMapTransformer implements ConfigurableTransformerInterface { - /** @var TransformerRegistry */ - protected $transformerRegistry; + use TransformerTrait; /** * @param TransformerRegistry $transformerRegistry @@ -40,7 +38,6 @@ public function __construct(TransformerRegistry $transformerRegistry) * @param array $options * * @throws \UnexpectedValueException - * @throws \CleverAge\ProcessBundle\Exception\MissingTransformerException * * @return mixed $value */ @@ -50,19 +47,10 @@ public function transform($values, array $options = []) throw new \UnexpectedValueException('Input value must be an array or traversable'); } - /** @var array $transformers */ - $transformers = $options['transformers']; - $results = []; /** @noinspection ForeachSourceInspection */ foreach ($values as $key => $item) { - foreach ($transformers as $transformerCode => $transformerOptions) { - if (null === $transformerOptions) { - $transformerOptions = []; - } - $transformer = $this->transformerRegistry->getTransformer($transformerCode); - $item = $transformer->transform($item, $transformerOptions); - } + $item = $this->applyTransformers($options['transformers'], $item); if (null === $item && $options['skip_null']) { continue; } @@ -84,40 +72,20 @@ public function getCode() /** * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { + $this->configureTransformersOptions($resolver); $resolver->setRequired( [ 'transformers', ] ); - $resolver->setAllowedTypes('transformers', ['array']); - $resolver->setDefaults([ - 'skip_null' => false, - ]); - $resolver->setAllowedTypes('skip_null', ['boolean']); - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'transformers', - function (Options $options, $transformers) { - /** @var array $transformers */ - foreach ($transformers as $transformerCode => &$transformerOptions) { - $transformerOptionsResolver = new OptionsResolver(); - /** @noinspection ExceptionsAnnotatingAndHandlingInspection */// @todo remove me sometimes - $transformer = $this->transformerRegistry->getTransformer($transformerCode); - if ($transformer instanceof ConfigurableTransformerInterface) { - $transformer->configureOptions($transformerOptionsResolver); - $transformerOptions = $transformerOptionsResolver->resolve( - $transformerOptions ?? [] - ); - } - } - - return $transformers; - } + $resolver->setDefaults( + [ + 'skip_null' => false, + ] ); + $resolver->setAllowedTypes('skip_null', ['boolean']); } } diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 0f9bbfb8..fcd1b387 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -10,20 +10,17 @@ namespace CleverAge\ProcessBundle\Transformer; +use CleverAge\ProcessBundle\Exception\MissingTransformerException; use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Trait TransformerTrait - * - * @package CleverAge\ProcessBundle\Transformer * @author Madeline Veyrenc */ trait TransformerTrait { - /** @var TransformerRegistry */ protected $transformerRegistry; @@ -31,7 +28,7 @@ trait TransformerTrait * @param array $transformers * @param mixed $value * - * @throws \CleverAge\ProcessBundle\Exception\TransformerException + * @throws TransformerException * * @return mixed */ @@ -59,19 +56,20 @@ protected function applyTransformers(array $transformers, $value) * keys This way you can chain multiple times the same transformer. Without this, it would silently call only the * 1st one. * + * @param string $transformerCode + * + * @throws MissingTransformerException + * + * @return string + * * @example - * transformers: - * callback#1: + * transformers: + * callback#1: * callback: array_filter - * callback#2: + * callback#2: * callback: array_reverse * * - * @param string $transformerCode - * - * @throws \CleverAge\ProcessBundle\Exception\MissingTransformerException - * - * @return string */ protected function getCleanedTransfomerCode(string $transformerCode) { @@ -92,10 +90,12 @@ protected function configureTransformersOptions(OptionsResolver $resolver, $opti { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( // This logic is duplicated from the array_map transformer @todo fix me + $resolver->setNormalizer( $optionName, - function (Options $options, $transformers) { + function (/** @noinspection PhpUnusedParameterInspection */ + Options $options, + $transformers + ) { $transformerClosures = []; foreach ($transformers as $origTransformerCode => $transformerOptions) { @@ -109,14 +109,14 @@ function (Options $options, $transformers) { ); } - $transformerClosures[$origTransformerCode] = function ($value) use ($transformer, $transformerOptions) { + $closure = static function ($value) use ($transformer, $transformerOptions) { return $transformer->transform($value, $transformerOptions); }; + $transformerClosures[$origTransformerCode] = $closure; } return $transformerClosures; } ); } - } From 5e0bd68b961c711d03e9e407118c9cb16cb763a1 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 24 Apr 2019 16:54:18 +0200 Subject: [PATCH 035/304] Major refactoring & coding style fixing --- CleverAgeProcessBundle.php | 4 +- Command/ExecuteProcessCommand.php | 64 ++++++---- Command/ListProcessCommand.php | 24 ++-- Command/ProcessHelpCommand.php | 120 +++++++++++------- Configuration/ProcessConfiguration.php | 21 ++- Configuration/TaskConfiguration.php | 8 +- Context/ContextualOptionResolver.php | 6 +- .../CleverAgeProcessExtension.php | 6 +- .../Compiler/RegistryCompilerPass.php | 11 +- DependencyInjection/Configuration.php | 4 +- Event/EventDispatcherTaskEvent.php | 4 +- EventListener/DataQueueEventListener.php | 4 +- Exception/CircularProcessException.php | 4 +- .../InvalidProcessConfigurationException.php | 4 +- Exception/MissingProcessException.php | 4 +- .../MissingTaskConfigurationException.php | 4 +- Exception/MissingTransformerException.php | 4 +- Exception/MultiBranchProcessException.php | 4 +- Exception/ProcessExceptionInterface.php | 4 +- Exception/TransformerException.php | 4 +- Filesystem/CsvFile.php | 4 +- Filesystem/CsvResource.php | 6 +- Filesystem/FileStreamInterface.php | 21 +-- Filesystem/JsonStreamFile.php | 26 ++-- Filesystem/SeekableFileInterface.php | 38 ++++++ Filesystem/StructuredFileInterface.php | 27 ++++ Filesystem/WritableFileInterface.php | 24 ++++ .../WritableStructuredFileInterface.php | 24 ++++ LICENSE | 2 +- Logger/AbstractLogger.php | 78 ++---------- Logger/AbstractProcessor.php | 4 +- Logger/ProcessLogger.php | 16 ++- Logger/ProcessProcessor.php | 10 +- Logger/TaskLogger.php | 10 +- Logger/TaskProcessor.php | 11 +- Logger/TransformerProcessor.php | 11 +- Manager/ProcessManager.php | 30 +++-- Model/AbstractConfigurableTask.php | 11 +- Model/BlockingTaskInterface.php | 4 +- Model/FinalizableTaskInterface.php | 4 +- Model/FlushableTaskInterface.php | 4 +- Model/InitializableTaskInterface.php | 4 +- Model/IterableTaskInterface.php | 4 +- Model/ProcessHistory.php | 4 +- Model/ProcessState.php | 88 ++++++------- Model/SubprocessInstance.php | 42 ++++-- Model/TaskInterface.php | 6 +- README.md | 2 +- Registry/ProcessConfigurationRegistry.php | 8 +- Registry/TransformerRegistry.php | 4 +- Resources/config/services/logger.yml | 10 +- Resources/tests/process/blocking_tasks.yml | 6 +- Resources/tests/process/iterable_process.yml | 16 +-- Resources/tests/task/validator_task.yml | 28 ++-- Task/AbstractIterableOutputTask.php | 7 +- Task/AggregateIterableTask.php | 7 +- Task/ArrayMergeTask.php | 25 ++-- Task/ColumnAggregatorTask.php | 6 +- Task/ConstantIterableOutputTask.php | 13 +- Task/ConstantOutputTask.php | 10 +- Task/CounterTask.php | 4 +- Task/Database/DatabaseReaderTask.php | 22 ++-- Task/Database/DatabaseUpdaterTask.php | 22 ++-- Task/Debug/DebugTask.php | 4 +- Task/Debug/DieTask.php | 4 +- Task/Debug/ErrorForwarderTask.php | 4 +- Task/Debug/MemInfoDumpTask.php | 4 +- Task/Doctrine/AbstractDoctrineQueryTask.php | 7 +- Task/Doctrine/AbstractDoctrineTask.php | 7 +- Task/Doctrine/ClearEntityManagerTask.php | 10 +- Task/Doctrine/DoctrineBatchWriterTask.php | 22 ++-- Task/Doctrine/DoctrineDetacherTask.php | 10 +- Task/Doctrine/DoctrineReaderTask.php | 7 +- Task/Doctrine/DoctrineRemoverTask.php | 13 +- Task/Doctrine/DoctrineWriterTask.php | 18 ++- Task/Doctrine/PurgeDoctrineCacheTask.php | 7 +- Task/DummyTask.php | 4 +- Task/Event/EventDispatcherTask.php | 13 +- Task/File/Csv/AbstractCsvResourceTask.php | 13 +- Task/File/Csv/AbstractCsvTask.php | 13 +- Task/File/Csv/CsvReaderTask.php | 17 ++- Task/File/Csv/CsvSplitterTask.php | 18 ++- Task/File/Csv/CsvWriterTask.php | 17 ++- Task/File/Csv/InputCsvReaderTask.php | 15 ++- Task/File/FileFetchTask.php | 27 ++-- Task/File/FileMoverTask.php | 16 ++- Task/File/FileRemoverTask.php | 7 +- Task/File/FileWriterTask.php | 16 ++- Task/File/FolderBrowserTask.php | 17 ++- Task/File/JsonStream/JsonStreamReaderTask.php | 19 ++- Task/File/YamlReaderTask.php | 18 ++- Task/File/YamlWriterTask.php | 16 ++- Task/FilterTask.php | 16 ++- Task/InputAggregatorTask.php | 32 +++-- Task/InputIteratorTask.php | 7 +- Task/IterableBatchTask.php | 10 +- Task/ObjectUpdaterTask.php | 4 +- Task/Process/ProcessExecutorTask.php | 10 +- Task/Process/ProcessLauncherTask.php | 44 ++++--- Task/PropertyGetterTask.php | 11 +- Task/PropertySetterTask.php | 11 +- Task/Reporting/AdvancedStatCounterTask.php | 15 ++- Task/Reporting/LoggerTask.php | 25 ++-- Task/Reporting/StatCounterTask.php | 4 +- Task/RowAggregatorTask.php | 14 +- Task/Serialization/DenormalizerTask.php | 31 +++-- Task/Serialization/NormalizerTask.php | 24 ++-- Task/Serialization/SerializerTask.php | 13 +- Task/SimpleBatchTask.php | 10 +- Task/SkipEmptyTask.php | 4 +- Task/SplitJoinLineTask.php | 4 +- Task/StopTask.php | 4 +- Task/TransformerTask.php | 45 ++++--- Task/Validation/ValidatorTask.php | 9 +- Tests/AbstractProcessTest.php | 6 +- Tests/BasicTest.php | 26 ++-- Tests/BlockingTaskTest.php | 10 +- Tests/CircularProcessTest.php | 4 +- Tests/ContextTest.php | 22 +++- Tests/ExceptionManagementTest.php | 34 +++-- Tests/FlushableTaskTest.php | 4 +- Tests/IterableTaskTest.php | 6 +- Tests/MultiBranchProcessTest.php | 93 ++++++++++---- Tests/MultiWorkflowTest.php | 59 +++++---- Tests/Task/ColumnAggregatorTaskTest.php | 46 ++++--- Tests/Task/FilterTaskTest.php | 5 +- Tests/Task/ProcessExecutorTaskTest.php | 5 +- Tests/Task/StopTaskTest.php | 18 ++- Tests/Task/TransformerTaskTest.php | 5 +- Tests/Task/ValidatorTaskTest.php | 9 +- .../ArrayFilterTransformerTest.php | 16 ++- Tests/Transformer/CallbackTransformerTest.php | 4 +- Tests/Transformer/DateTransformersTest.php | 20 ++- Tests/Transformer/MappingTransformerTest.php | 15 ++- Tests/Transformer/UnsetTransformerTest.php | 19 ++- Transformer/ArrayElementTransformer.php | 7 +- Transformer/ArrayFilterTransformer.php | 8 +- Transformer/ArrayFirstTransformer.php | 15 +-- Transformer/ArrayLastTransformer.php | 4 +- Transformer/ArrayMapTransformer.php | 4 +- Transformer/CallbackTransformer.php | 16 ++- Transformer/ConditionTrait.php | 26 ++-- .../ConfigurableTransformerInterface.php | 7 +- Transformer/ConvertValueTransformer.php | 7 +- Transformer/DateFormatTransformer.php | 16 ++- Transformer/DateParserTransformer.php | 10 +- Transformer/DefaultTransformer.php | 7 +- Transformer/DenormalizeTransformer.php | 13 +- Transformer/EvaluatorTransformer.php | 39 +++--- Transformer/ExplodeTransformer.php | 7 +- Transformer/ImplodeTransformer.php | 4 +- Transformer/MappingTransformer.php | 43 ++++--- Transformer/NormalizeTransformer.php | 13 +- Transformer/PregFilterTransformer.php | 7 +- Transformer/PropertyAccessorTransformer.php | 16 ++- .../RecursivePropertySetterTransformer.php | 27 ++-- Transformer/SlugifyTransformer.php | 16 ++- Transformer/SprintfTransformer.php | 4 +- Transformer/TransformerInterface.php | 4 +- Transformer/TransformerTrait.php | 7 +- Transformer/TrimTransformer.php | 7 +- Transformer/UnsetTransformer.php | 5 +- Transformer/WrapperTransformer.php | 7 +- composer.json | 2 +- 164 files changed, 1485 insertions(+), 1010 deletions(-) create mode 100644 Filesystem/SeekableFileInterface.php create mode 100644 Filesystem/StructuredFileInterface.php create mode 100644 Filesystem/WritableFileInterface.php create mode 100644 Filesystem/WritableStructuredFileInterface.php diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index f78bb79a..232a8046 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -1,8 +1,8 @@ -addOption('input', 'i', InputOption::VALUE_REQUIRED, 'Pass input data to the first task of the process'); $this->addOption('input-from-stdin', null, InputOption::VALUE_NONE, 'Read input data from stdin'); - $this->addOption('context', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Contextual value', []); - $this->addOption('output', 'o', + $this->addOption( + 'context', + 'c', + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Contextual value', + [] + ); + $this->addOption( + 'output', + 'o', InputOption::VALUE_REQUIRED, 'Output path to dump data ("-" to use STDOUT with symfony dumper)', - self::OUTPUT_STDOUT); - $this->addOption('output-format', 't', - InputOption::VALUE_OPTIONAL, - 'Output format', - null); + self::OUTPUT_STDOUT + ); + $this->addOption('output-format', 't', InputOption::VALUE_OPTIONAL, 'Output format'); } /** @@ -115,7 +122,7 @@ protected function execute(InputInterface $input, OutputInterface $output) /** * @param InputInterface $input * - * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + * @throws InvalidArgumentException * * @return array */ @@ -138,6 +145,11 @@ protected function parseContextValues(InputInterface $input) return $context; } + /** + * @param mixed $data + * @param InputInterface $input + * @param OutputInterface $output + */ protected function handleOutputData($data, InputInterface $input, OutputInterface $output) { // Skip all if undefined @@ -153,10 +165,12 @@ protected function handleOutputData($data, InputInterface $input, OutputInterfac } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { $output->writeln(json_encode($data)); } else { - throw new \InvalidArgumentException(sprintf( - "Cannot handle data output with format '%s'", - $input->getOption('output-format') - )); + throw new \InvalidArgumentException( + sprintf( + "Cannot handle data output with format '%s'", + $input->getOption('output-format') + ) + ); } } } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { @@ -167,10 +181,12 @@ protected function handleOutputData($data, InputInterface $input, OutputInterfac $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { - throw new \InvalidArgumentException(sprintf( - "Cannot handle data output with format '%s'", - $input->getOption('output-format') - )); + throw new \InvalidArgumentException( + sprintf( + "Cannot handle data output with format '%s'", + $input->getOption('output-format') + ) + ); } } } diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index 7337adc6..13811bcf 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -1,8 +1,8 @@ -writeln("There are {$publicCount} process configurations defined (and {$privateCount} private) :"); + $output->writeln( + "There are {$publicCount} process configurations defined (and {$privateCount} private) :" + ); $messages = []; foreach ($processConfigurations as $processConfiguration) { @@ -69,12 +73,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $message = " - {$processConfiguration->getCode()} with {$countTasks} tasks"; if ($processConfiguration->isPrivate()) { - $message .= " (private)"; + $message .= ' (private)'; } $messages[] = [ 'process' => $processConfiguration, - 'output' => $message, + 'output' => $message, ]; } } @@ -89,7 +93,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($processConfiguration->getDescription()) { $outputMessage = $this->padMessage($outputMessage, $maxMessageLength + 3); - $outputMessage .= "{$processConfiguration->getDescription()}"; + $outputMessage .= $processConfiguration->getDescription(); } $outputMessages[] = $outputMessage; @@ -147,8 +151,8 @@ public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b) /** * Filter callback to find max message length * - * @param ProcessConfiguration $a - * @param ProcessConfiguration $b + * @param int $max + * @param array $message * * @return int */ diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index 58d5be74..7c49eede 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -1,8 +1,8 @@ -getArgument('process_code'); $process = $this->processConfigRegistry->getProcessConfiguration($processCode); - $output->writeln("Process: "); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $processCode); + $output->writeln('Process: '); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); $output->writeln(''); if ($process->getDescription()) { - $output->writeln("Description:"); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $process->getDescription()); + $output->writeln('Description:'); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); $output->writeln(''); } if ($process->getHelp()) { - $output->writeln("Help:"); + $output->writeln('Help:'); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $helpLine); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$helpLine); } $output->writeln(''); } - $output->writeln("Tasks tree:"); + $output->writeln('Tasks tree:'); $branches = []; @@ -128,14 +134,17 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->resolveBranchOutput($branches, $nextTaskCode, $process, $output); // Remove the task from the remaining list - $remainingTasks = array_filter($remainingTasks, function ($task) use ($nextTaskCode) { - return $task != $nextTaskCode; - }); + $remainingTasks = array_filter( + $remainingTasks, + static function ($task) use ($nextTaskCode) { + return $task !== $nextTaskCode; + } + ); } $branches = array_filter($branches); if (!empty($branches)) { - $branchStr = '[' . implode(', ', $branches) . ']'; + $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } } @@ -160,9 +169,13 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ } // Check if task has all necessary ancestors in branches - $hasAllAncestors = array_reduce($task->getPreviousTasksConfigurations(), function ($result, TaskConfiguration $prevTask) use ($branches) { - return $result && \in_array($prevTask->getCode(), $branches); - }, true); + $hasAllAncestors = array_reduce( + $task->getPreviousTasksConfigurations(), + static function ($result, TaskConfiguration $prevTask) use ($branches) { + return $result && \in_array($prevTask->getCode(), $branches, true); + }, + true + ); if ($hasAllAncestors) { $taskCandidates[] = $taskCode; @@ -179,7 +192,7 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ $weight = 0; $task = $process->getTaskConfiguration($taskCandidate); foreach ($task->getPreviousTasksConfigurations() as $prevTask) { - $key = array_search($prevTask->getCode(), $branches); + $key = array_search($prevTask->getCode(), $branches, true); // Should never be non-numeric... if (!is_numeric($key)) { @@ -189,7 +202,7 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ } if (!empty($task->getPreviousTasksConfigurations())) { - $weight = $weight / \count($task->getPreviousTasksConfigurations()); + $weight /= \count($task->getPreviousTasksConfigurations()); } $taskWeights[$taskCandidate] = $weight; @@ -199,11 +212,14 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ $bestCandidate = key($taskWeights); $bestWeight = $taskWeights[$bestCandidate]; - $equalWeights = array_filter($taskWeights, function ($item) use ($bestWeight) { - return $item == $bestWeight; - }); + $equalWeights = array_filter( + $taskWeights, + static function ($item) use ($bestWeight) { + return $item == $bestWeight; + } + ); - if (count($equalWeights) == 1) { + if (1 === count($equalWeights)) { return $bestCandidate; } @@ -249,8 +265,12 @@ protected function getTaskChildrenCount(TaskConfiguration $task) * @param ProcessConfiguration $process * @param OutputInterface $output */ - protected function resolveBranchOutput(&$branches, $taskCode, ProcessConfiguration $process, OutputInterface $output) - { + protected function resolveBranchOutput( + &$branches, + $taskCode, + ProcessConfiguration $process, + OutputInterface $output + ) { $task = $process->getTaskConfiguration($taskCode); $branchesToMerge = []; $gapBranches = []; @@ -320,12 +340,12 @@ protected function resolveBranchOutput(&$branches, $taskCode, ProcessConfigurati $output, $branches, '', - function ($taskCode, $i) use ($branchesToMerge, $gapBranches, $origin) { + static function ($taskCode, $i) use ($branchesToMerge, $gapBranches, $origin) { return \in_array($i, $branchesToMerge, true) || \in_array($i, $gapBranches, true) || $i === $origin; }, - function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { + static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { if ($i === $origin) { return self::CHAR_RECEIVE; } @@ -371,7 +391,7 @@ function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { $output, $branches, $this->getTaskDescription($task), - function ($branchTask, $i) use ($taskCode) { + static function ($branchTask, $i) use ($taskCode) { return $branchTask === $taskCode; }, $nodeStr @@ -381,18 +401,20 @@ function ($branchTask, $i) use ($taskCode) { if ($output->isVerbose() && $task->getHelp()) { $helpLines = array_filter(explode("\n", $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE)."{$helpLine}"; $this->writeBranches($output, $branches, $helpMessage); } } // Check next tasks - $nextTasks = array_unique(array_map( - function (TaskConfiguration $task) { - return $task->getCode(); - }, - array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) - )); + $nextTasks = array_unique( + array_map( + static function (TaskConfiguration $task) { + return $task->getCode(); + }, + array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) + ) + ); if (\count($nextTasks) > 1) { $this->writeBranches($output, $branches); array_shift($nextTasks); @@ -427,10 +449,10 @@ function (TaskConfiguration $task) { $output, $branches, '', - function ($branchTask, $i) use ($origin, $final) { + static function ($branchTask, $i) use ($origin, $final) { return $i >= $origin && $i <= $final; }, - function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) { + static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) { if ($i === $origin) { return self::CHAR_RECEIVE; } @@ -510,8 +532,8 @@ protected function writeBranches(OutputInterface $output, $branches, $comment = /** * @param TaskConfiguration $task * - * @throws \Psr\Container\NotFoundExceptionInterface - * @throws \Psr\Container\ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws ContainerExceptionInterface * @throws \UnexpectedValueException * * @return string @@ -540,11 +562,11 @@ protected function getTaskDescription(TaskConfiguration $task) } if (\count($interfaces)) { - $description .= ' (' . implode(', ', $interfaces) . ')'; + $description .= ' ('.implode(', ', $interfaces).')'; } if (\count($subprocess)) { - $description .= ' {' . implode(', ', $subprocess) . '}'; + $description .= ' {'.implode(', ', $subprocess).'}'; } if ($task->getDescription()) { @@ -557,8 +579,8 @@ protected function getTaskDescription(TaskConfiguration $task) /** * @param TaskConfiguration $taskConfiguration * - * @throws \Psr\Container\NotFoundExceptionInterface - * @throws \Psr\Container\ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws ContainerExceptionInterface * @throws \UnexpectedValueException * * @return mixed diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index a585c116..f0ec7d9d 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -1,8 +1,8 @@ -code = $code; $this->taskConfigurations = $taskConfigurations; $this->options = $options; @@ -99,7 +98,7 @@ public function getOptions(): array } /** - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return TaskConfiguration|null */ @@ -113,7 +112,7 @@ public function getEntryPoint() } /** - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return TaskConfiguration|null */ @@ -169,7 +168,7 @@ public function getTaskConfigurations(): array /** * @param string $taskCode * - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return TaskConfiguration */ @@ -187,7 +186,7 @@ public function getTaskConfiguration(string $taskCode): TaskConfiguration * * If one task depend from another, it should come after * - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return array */ @@ -222,7 +221,7 @@ public function getDependencyGroups(): array * * If one task depend from another, it should come after * - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return array */ @@ -246,7 +245,7 @@ public function getMainTaskGroup(): array * Get the most important task (may be the entry or end task, or simply the first) * Used to check which tree should be used * - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return TaskConfiguration */ @@ -321,7 +320,7 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe * * @param array $dependencies * - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws MissingTaskConfigurationException * * @return array */ diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index a791e71c..b2b39ef3 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -1,8 +1,8 @@ - * @author Vincent Chalnot diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/DependencyInjection/Compiler/RegistryCompilerPass.php index a032bb46..03b796aa 100644 --- a/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -1,8 +1,8 @@ - * @author Vincent Chalnot */ -class CsvResource implements FileStreamInterface +class CsvResource implements WritableStructuredFileInterface, SeekableFileInterface { /** @var string */ protected $delimiter; diff --git a/Filesystem/FileStreamInterface.php b/Filesystem/FileStreamInterface.php index bc7199ce..5eca344d 100644 --- a/Filesystem/FileStreamInterface.php +++ b/Filesystem/FileStreamInterface.php @@ -1,8 +1,8 @@ -isEndOfFile()) { return null; @@ -88,13 +98,13 @@ public function readLine() } /** - * @param $item + * @param array $item * * @return int */ public function writeLine($item): int { - $this->file->fwrite(json_encode($item) . PHP_EOL); + $this->file->fwrite(json_encode($item).PHP_EOL); $this->currentLine++; return $this->currentLine; diff --git a/Filesystem/SeekableFileInterface.php b/Filesystem/SeekableFileInterface.php new file mode 100644 index 00000000..2cd00d9d --- /dev/null +++ b/Filesystem/SeekableFileInterface.php @@ -0,0 +1,38 @@ +logger->log($level, $message, $context); } - - /** - * {@inheritDoc} - */ - public function emergency($message, array $context = []) - { - $this->log(LogLevel::EMERGENCY, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function alert($message, array $context = []) - { - $this->log(LogLevel::ALERT, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function critical($message, array $context = []) - { - $this->log(LogLevel::CRITICAL, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function error($message, array $context = []) - { - $this->log(LogLevel::ERROR, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function warning($message, array $context = []) - { - $this->log(LogLevel::WARNING, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function notice($message, array $context = []) - { - $this->log(LogLevel::NOTICE, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function info($message, array $context = []) - { - $this->log(LogLevel::INFO, $message, $context); - } - - /** - * {@inheritDoc} - */ - public function debug($message, array $context = []) - { - $this->log(LogLevel::DEBUG, $message, $context); - } - } diff --git a/Logger/AbstractProcessor.php b/Logger/AbstractProcessor.php index 094aec9c..3c6be8c9 100644 --- a/Logger/AbstractProcessor.php +++ b/Logger/AbstractProcessor.php @@ -1,8 +1,8 @@ - + * @author Madeline Veyrenc */ class ProcessLogger extends AbstractLogger { - } diff --git a/Logger/ProcessProcessor.php b/Logger/ProcessProcessor.php index 1106aef2..fd292312 100644 --- a/Logger/ProcessProcessor.php +++ b/Logger/ProcessProcessor.php @@ -1,4 +1,12 @@ -getTask(); + if (null === $task) { + throw new \RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); + } $state = $taskConfiguration->getState(); try { @@ -401,7 +409,11 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e // Manage exception catching and setting the same if ($exception) { - $this->taskLogger->log($taskConfiguration->getLogLevel(), $exception->getMessage(), $state->getErrorContext()); + $this->taskLogger->log( + $taskConfiguration->getLogLevel(), + $exception->getMessage(), + $state->getErrorContext() + ); $state->setException($exception); if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { $state->setSkipped(true); @@ -472,7 +484,7 @@ protected function finalize(TaskConfiguration $taskConfiguration): void * * @throws \RuntimeException * @throws \InvalidArgumentException - * @throws \Doctrine\ORM\ORMInvalidArgumentException + * @throws ORMInvalidArgumentException * * @return ProcessHistory */ @@ -561,9 +573,9 @@ protected function endProcess(ProcessHistory $history): void * @param ProcessConfiguration $processConfiguration * * @throws \RuntimeException - * @throws \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException - * @throws \CleverAge\ProcessBundle\Exception\CircularProcessException - * @throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException + * @throws InvalidProcessConfigurationException + * @throws CircularProcessException + * @throws MissingTaskConfigurationException */ protected function checkProcess(ProcessConfiguration $processConfiguration): void { diff --git a/Model/AbstractConfigurableTask.php b/Model/AbstractConfigurableTask.php index 21d62397..4115b81a 100644 --- a/Model/AbstractConfigurableTask.php +++ b/Model/AbstractConfigurableTask.php @@ -1,8 +1,8 @@ -setPreviousState($this); @@ -113,14 +113,14 @@ public function duplicate() * * @param bool $cleanInput */ - public function reset($cleanInput) + public function reset($cleanInput): void { $this->setOutput(null); $this->setSkipped(false); - $this->setException(null); + $this->setException(); $this->setErrorOutput(null); - if($cleanInput) { + if ($cleanInput) { $this->setInput(null); $this->setPreviousState(null); } @@ -129,7 +129,7 @@ public function reset($cleanInput) /** * @return ProcessConfiguration */ - public function getProcessConfiguration() + public function getProcessConfiguration(): ProcessConfiguration { return $this->processConfiguration; } @@ -137,7 +137,7 @@ public function getProcessConfiguration() /** * @return ProcessHistory */ - public function getProcessHistory() + public function getProcessHistory(): ProcessHistory { return $this->processHistory; } @@ -153,7 +153,7 @@ public function getTaskConfiguration(): TaskConfiguration /** * @param TaskConfiguration $taskConfiguration */ - public function setTaskConfiguration(TaskConfiguration $taskConfiguration) + public function setTaskConfiguration(TaskConfiguration $taskConfiguration): void { $this->taskConfiguration = $taskConfiguration; } @@ -169,7 +169,7 @@ public function getInput() /** * @param mixed $input */ - public function setInput($input) + public function setInput($input): void { $this->input = $input; } @@ -185,15 +185,15 @@ public function getOutput() /** * @param mixed $output */ - public function setOutput($output) + public function setOutput($output): void { $this->output = $output; } /** - * @deprecated Use getErrorOutput instead - * * @return mixed + * + * @deprecated Use getErrorOutput instead */ public function getError() { @@ -203,11 +203,11 @@ public function getError() } /** - * @deprecated Use setErrorOutput instead - * * @param mixed $error + * + * @deprecated Use setErrorOutput instead */ - public function setError($error) + public function setError($error): void { @trigger_error('Deprecated method, use setErrorOutput instead', E_USER_DEPRECATED); @@ -215,11 +215,11 @@ public function setError($error) } /** - * @deprecated Use hasErrorOutput instead - * * @return bool + * + * @deprecated Use hasErrorOutput instead */ - public function hasError() + public function hasError(): bool { @trigger_error('Deprecated method, use hasErrorOutput instead', E_USER_DEPRECATED); @@ -237,7 +237,7 @@ public function getErrorOutput() /** * @param mixed $errorOutput */ - public function setErrorOutput($errorOutput) + public function setErrorOutput($errorOutput): void { $this->errorOutput = $errorOutput; } @@ -245,7 +245,7 @@ public function setErrorOutput($errorOutput) /** * @return bool */ - public function hasErrorOutput() + public function hasErrorOutput(): bool { return null !== $this->errorOutput; } @@ -253,7 +253,7 @@ public function hasErrorOutput() /** * @param \Throwable $e */ - public function stop(\Throwable $e = null) + public function stop(\Throwable $e = null): void { if ($e) { $this->setException($e); @@ -272,15 +272,15 @@ public function isStopped(): bool /** * @param boolean $stopped */ - public function setStopped(bool $stopped) + public function setStopped(bool $stopped): void { $this->stopped = $stopped; } /** - * @return \Throwable + * @return \Throwable|null */ - public function getException() + public function getException(): ?\Throwable { return $this->exception; } @@ -288,7 +288,7 @@ public function getException() /** * @param \Throwable|null $exception */ - public function setException(\Throwable $exception = null) + public function setException(\Throwable $exception = null): void { $this->exception = $exception; } @@ -296,7 +296,7 @@ public function setException(\Throwable $exception = null) /** * @return array */ - public function getErrorContext() + public function getErrorContext(): array { return $this->errorContext; } @@ -304,7 +304,7 @@ public function getErrorContext() /** * @param array $errorContext */ - public function setErrorContext(array $errorContext) + public function setErrorContext(array $errorContext): void { $this->errorContext = $errorContext; } @@ -313,7 +313,7 @@ public function setErrorContext(array $errorContext) * @param string|int $key * @param string|int|array $value */ - public function addErrorContextValue($key, $value) + public function addErrorContextValue($key, $value): void { $this->errorContext[$key] = $value; } @@ -321,7 +321,7 @@ public function addErrorContextValue($key, $value) /** * @param string|int $key */ - public function removeErrorContext($key) + public function removeErrorContext($key): void { unset($this->errorContext[$key]); } @@ -329,7 +329,7 @@ public function removeErrorContext($key) /** * @return int */ - public function getReturnCode() + public function getReturnCode(): int { if (null !== $this->returnCode) { return $this->returnCode; @@ -341,7 +341,7 @@ public function getReturnCode() /** * @param int $returnCode */ - public function setReturnCode(int $returnCode) + public function setReturnCode(int $returnCode): void { $this->returnCode = $returnCode; } @@ -349,7 +349,7 @@ public function setReturnCode(int $returnCode) /** * @return bool */ - public function isSkipped() + public function isSkipped(): bool { return $this->skipped; } @@ -357,15 +357,15 @@ public function isSkipped() /** * @param bool $skipped */ - public function setSkipped(bool $skipped) + public function setSkipped(bool $skipped): void { $this->skipped = $skipped; } /** - * @return ProcessState + * @return ProcessState|null */ - public function getPreviousState() + public function getPreviousState(): ?ProcessState { return $this->previousState; } @@ -373,7 +373,7 @@ public function getPreviousState() /** * @param ProcessState $previousState */ - public function setPreviousState($previousState) + public function setPreviousState($previousState): void { $this->previousState = $previousState; } @@ -391,7 +391,7 @@ public function getStatus(): string * * @throws \UnexpectedValueException */ - public function setStatus(string $status) + public function setStatus(string $status): void { if (!\in_array($status, self::STATUS, true)) { throw new \UnexpectedValueException("Unknown status {$status}"); @@ -403,7 +403,7 @@ public function setStatus(string $status) /** * @return bool */ - public function isResolved() + public function isResolved(): bool { return $this->status === self::STATUS_RESOLVED; } @@ -431,9 +431,9 @@ public function setContext(array $context): void } /** - * @return array + * @return array|null */ - public function getContextualizedOptions() + public function getContextualizedOptions(): ?array { if (!$this->contextualizedOptions) { $options = $this->getTaskConfiguration()->getOptions(); @@ -463,11 +463,11 @@ public function getContextualizedOption($code, $default = null) } /** - * @deprecated Use monolog processors instead - * * @return array + * + * @deprecated Use monolog processors instead */ - public function getLogContext() + public function getLogContext(): array { @trigger_error('Deprecated method, use monolog processors instead', E_USER_DEPRECATED); $context = [ diff --git a/Model/SubprocessInstance.php b/Model/SubprocessInstance.php index db167370..a980807b 100644 --- a/Model/SubprocessInstance.php +++ b/Model/SubprocessInstance.php @@ -1,5 +1,12 @@ -processCode = $processCode; $this->input = $input; $this->context = $context; @@ -61,10 +72,10 @@ public function __construct(KernelInterface $kernel, string $processCode, ?strin $this->configureOptions($resolver); $this->options = $resolver->resolve($options); - $this->consolePath = $kernel->getProjectDir() . '/bin/console'; + $this->consolePath = $kernel->getProjectDir().'/bin/console'; $this->environment = $kernel->getEnvironment(); - $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid() . '.json-stream'; // Todo use param ? - $this->logDir = $kernel->getLogDir() . '/process'; + $this->bufferPath = $kernel->getProjectDir().'/var/cdm_buffer_'.uniqid().'.json-stream'; // Todo use param ? + $this->logDir = $kernel->getLogDir().'/process'; } @@ -81,7 +92,7 @@ public function buildProcess() 'nohup', $pathFinder->find(), $this->consolePath, - '--env=' . $this->environment, + '--env='.$this->environment, 'cleverage:process:execute', '--input-from-stdin', ]; @@ -93,10 +104,13 @@ public function buildProcess() } if ($this->options[self::OPTION_JSON_BUFFERING]) { - $arguments = array_merge($arguments, [ - '--output=' . $this->bufferPath, - '--output-format=json-stream', - ]); + $arguments = array_merge( + $arguments, + [ + '--output='.$this->bufferPath, + '--output-format=json-stream', + ] + ); } if (!empty($this->context)) { diff --git a/Model/TaskInterface.php b/Model/TaskInterface.php index 9c19c491..1cfba4e7 100644 --- a/Model/TaskInterface.php +++ b/Model/TaskInterface.php @@ -1,8 +1,8 @@ - * @author Vincent Chalnot diff --git a/README.md b/README.md index e8a01a81..7638db0b 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Validate data from the input and pass it to the output ### Creating the class ```php -getOption($state, 'merge_function'); - if ($mergeFunction == 'array_merge') { - $this->mergedOutput = \array_merge($this->mergedOutput, $input); - } elseif ($mergeFunction == 'array_merge_recursive') { - $this->mergedOutput = \array_merge_recursive($this->mergedOutput, $input); - } elseif ($mergeFunction == 'array_replace') { - $this->mergedOutput = \array_replace($this->mergedOutput, $input); - } elseif ($mergeFunction == 'array_replace_recursive') { - $this->mergedOutput = \array_replace_recursive($this->mergedOutput, $input); - } else { + if (!\in_array($mergeFunction, self::MERGE_FUNC, true)) { throw new \InvalidArgumentException("Unknown merge function {$mergeFunction}"); } + $this->mergedOutput = $mergeFunction($this->mergedOutput, $input); } /** @@ -57,12 +53,13 @@ public function proceed(ProcessState $state) $state->setOutput($this->mergedOutput); } + /** + * @param OptionsResolver $resolver + */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('merge_function', 'array_merge'); $resolver->setAllowedTypes('merge_function', 'string'); - $resolver->setAllowedValues('merge_function', ['array_merge', 'array_merge_recursive', 'array_replace', 'array_replace_recursive']); + $resolver->setAllowedValues('merge_function', self::MERGE_FUNC); } - - } diff --git a/Task/ColumnAggregatorTask.php b/Task/ColumnAggregatorTask.php index 40c292b1..a5ae8254 100644 --- a/Task/ColumnAggregatorTask.php +++ b/Task/ColumnAggregatorTask.php @@ -1,8 +1,8 @@ - */ diff --git a/Task/ConstantIterableOutputTask.php b/Task/ConstantIterableOutputTask.php index 05c3bec7..09cb5df1 100644 --- a/Task/ConstantIterableOutputTask.php +++ b/Task/ConstantIterableOutputTask.php @@ -1,8 +1,8 @@ -setAllowedTypes('entity_manager', ['NULL', 'string', EntityManagerInterface::class]); $resolver->setNormalizer( 'entity_manager', - function (/** @noinspection PhpUnusedParameterInspection */ + function ( + /** @noinspection PhpUnusedParameterInspection */ Options $options, $value ) { diff --git a/Task/DummyTask.php b/Task/DummyTask.php index 92117569..f7b64e7d 100644 --- a/Task/DummyTask.php +++ b/Task/DummyTask.php @@ -1,8 +1,8 @@ -setNormalizer( 'file_path', - function (Options $options, $value) { + static function (Options $options, $value) { $value = strtr( $value, [ @@ -95,7 +98,7 @@ function (Options $options, $value) { * * @throws \UnexpectedValueException * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ExceptionInterface * * @return array */ diff --git a/Task/File/Csv/InputCsvReaderTask.php b/Task/File/Csv/InputCsvReaderTask.php index 4f2e6e48..d9aaa175 100644 --- a/Task/File/Csv/InputCsvReaderTask.php +++ b/Task/File/Csv/InputCsvReaderTask.php @@ -1,8 +1,8 @@ - 0) { + if ('' !== $basePath) { $basePath = rtrim($options['base_path'], '/').'/'; } diff --git a/Task/File/FileFetchTask.php b/Task/File/FileFetchTask.php index e33b7793..079dc1c0 100644 --- a/Task/File/FileFetchTask.php +++ b/Task/File/FileFetchTask.php @@ -1,8 +1,8 @@ -setNormalizer( 'folder_path', - function (Options $options, $value) { + static function (Options $options, $value) { if (!is_dir($value)) { throw new InvalidConfigurationException( "Folder path does not exists or is not a folder: '{$value}'" diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/Task/File/JsonStream/JsonStreamReaderTask.php index 66d5305b..e4af7cbc 100644 --- a/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/Task/File/JsonStream/JsonStreamReaderTask.php @@ -1,21 +1,32 @@ -file === null) { + if (null === $this->file) { $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); } diff --git a/Task/File/YamlReaderTask.php b/Task/File/YamlReaderTask.php index d0780272..8ad5ff59 100644 --- a/Task/File/YamlReaderTask.php +++ b/Task/File/YamlReaderTask.php @@ -1,8 +1,8 @@ -setAllowedTypes('file_path', ['string']); $resolver->setNormalizer( 'file_path', - function (Options $options, $value) { + static function (Options $options, $value) { if (!file_exists($value)) { throw new \UnexpectedValueException("File not found: {$value}"); } @@ -55,8 +59,8 @@ function (Options $options, $value) { * @param ProcessState $state * * @throws \InvalidArgumentException - * @throws \Symfony\Component\Yaml\Exception\ParseException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ParseException + * @throws ExceptionInterface * * @return \Iterator */ diff --git a/Task/File/YamlWriterTask.php b/Task/File/YamlWriterTask.php index c92cb5f7..21bad80c 100644 --- a/Task/File/YamlWriterTask.php +++ b/Task/File/YamlWriterTask.php @@ -1,8 +1,8 @@ -setRequired('input_codes'); - $resolver->setDefaults([ - 'clean_input_on_override' => true, - 'keep_inputs' => null, - ]); + $resolver->setDefaults( + [ + 'clean_input_on_override' => true, + 'keep_inputs' => null, + ] + ); $resolver->setAllowedTypes('input_codes', 'array'); $resolver->setAllowedTypes('clean_input_on_override', 'boolean'); $resolver->setAllowedTypes('keep_inputs', ['NULL', 'array']); @@ -94,7 +99,7 @@ protected function configureOptions(OptionsResolver $resolver) * * @param ProcessState $state * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ExceptionInterface * @throws \InvalidArgumentException * @throws \UnexpectedValueException * @@ -103,6 +108,9 @@ protected function configureOptions(OptionsResolver $resolver) protected function getInputCode(ProcessState $state) { $previousState = $state->getPreviousState(); + if (!$previousState) { + throw new \RuntimeException('No previous state for current task'); + } $previousTaskCode = $previousState->getTaskConfiguration()->getCode(); $inputCodes = $this->getOption($state, 'input_codes'); if (!array_key_exists($previousTaskCode, $inputCodes)) { @@ -117,7 +125,7 @@ protected function getInputCode(ProcessState $state) * * @param ProcessState $state * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ExceptionInterface * @throws \InvalidArgumentException * * @return bool diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index dea026d7..3eaba6ee 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -1,8 +1,8 @@ -kernel, + $subprocess = new SubprocessInstance( + $this->kernel, $this->getOption($state, 'process'), $state->getInput(), $this->getOption($state, 'context'), @@ -183,7 +188,7 @@ protected function launchProcess(ProcessState $state) /** * @param ProcessState $state * - * @throws \Symfony\Component\Process\Exception\RuntimeException + * @throws RuntimeException */ protected function handleProcesses(ProcessState $state) { @@ -220,9 +225,9 @@ protected function handleProcesses(ProcessState $state) /** * @param OptionsResolver $resolver * - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @throws AccessException + * @throws UndefinedOptionsException + * @throws InvalidConfigurationException */ protected function configureOptions(OptionsResolver $resolver) { @@ -258,14 +263,17 @@ function (Options $options, $value) { $resolver->setAllowedTypes('context', ['array']); $resolver->setAllowedTypes('process_options', ['array']); - $resolver->setNormalizer('process_options', function (Options $options, $value) { - if (!empty($value)) { - // Todo deprecation trigger - throw new \InvalidArgumentException("Deprecated option, please contact support for help"); - } + $resolver->setNormalizer( + 'process_options', + static function (Options $options, $value) { + if (!empty($value)) { + // Todo deprecation trigger + throw new \InvalidArgumentException('Deprecated option, please contact support for help'); + } - return $value; - }); + return $value; + } + ); } /** diff --git a/Task/PropertyGetterTask.php b/Task/PropertyGetterTask.php index 23907c67..3f7c5e66 100644 --- a/Task/PropertyGetterTask.php +++ b/Task/PropertyGetterTask.php @@ -1,8 +1,8 @@ -getOptions($state); if (!$this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { - throw new \UnexpectedValueException('Given value is not normalizable for format ' . $options['format']); + throw new \UnexpectedValueException('Given value is not normalizable for format '.$options['format']); } $normalizedData = $this->normalizer->normalize( @@ -61,8 +67,8 @@ public function execute(ProcessState $state) /** * @param OptionsResolver $resolver * - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @throws AccessException + * @throws UndefinedOptionsException */ protected function configureOptions(OptionsResolver $resolver) { diff --git a/Task/Serialization/SerializerTask.php b/Task/Serialization/SerializerTask.php index b77d6390..46dce5c6 100644 --- a/Task/Serialization/SerializerTask.php +++ b/Task/Serialization/SerializerTask.php @@ -1,9 +1,9 @@ -addAllowedTypes('constraints', ['NULL', 'array']); $resolver->setNormalizer( 'constraints', - function (Options $options, $constraints) { + static function (Options $options, $constraints) { if (null === $constraints) { return null; } diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 1b3ade7b..019fbb16 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -1,8 +1,8 @@ -container->get(DataQueueEventListener::class); $actualQueue = $dataQueueListener->getQueue($processName); - self::assertEquals(\count($expected), \count($actualQueue), 'Event count does not match'); + self::assertCount(\count($expected), $actualQueue, 'Event count does not match'); /** * @var int $key diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index 1d5bb8ab..93a497f4 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -1,8 +1,8 @@ -assertDataQueue( [ [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 1, ], [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 2, ], [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 3, ], - ], 'test.error_process'); + ], + 'test.error_process' + ); } /** @@ -68,21 +70,23 @@ public function testErrorProcessBlocking() $this->assertDataQueue( [ [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 1, ], [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 2, ], [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 3, ], [ - 'task' => 'aggregate', + 'task' => 'aggregate', 'value' => [1, 2, 3], ], - ], 'test.error_process_with_blocking'); + ], + 'test.error_process_with_blocking' + ); } } diff --git a/Tests/BlockingTaskTest.php b/Tests/BlockingTaskTest.php index 58d169c7..47805513 100644 --- a/Tests/BlockingTaskTest.php +++ b/Tests/BlockingTaskTest.php @@ -1,8 +1,8 @@ -assertDataQueue( [ [ - 'task' => 'aggregate', + 'task' => 'aggregate', 'value' => [1, 2, 3, 1, 2, 3, 1, 2, 3], ], - ], 'test.multiple_iteration_blocking'); + ], + 'test.multiple_iteration_blocking' + ); } /** diff --git a/Tests/CircularProcessTest.php b/Tests/CircularProcessTest.php index 00b5de7b..335c079b 100644 --- a/Tests/CircularProcessTest.php +++ b/Tests/CircularProcessTest.php @@ -1,8 +1,8 @@ -processManager->execute('test.context.multi_values', null, ['value1' => 'red', 'value2' => 'dead']); + $result = $this->processManager->execute( + 'test.context.multi_values', + null, + ['value1' => 'red', 'value2' => 'dead'] + ); self::assertEquals('red is dead', $result); } @@ -56,7 +60,11 @@ public function testContextMultiValue() */ public function testContextCannotMergeValue() { - $this->processManager->execute('test.context.merged_value', null, ['value' => ['another_key' => 'another_value']]); + $this->processManager->execute( + 'test.context.merged_value', + null, + ['value' => ['another_key' => 'another_value']] + ); } /** @@ -68,7 +76,11 @@ public function testComplexContext() self::assertEquals(['another_key' => 'another_value'], $result); - $result = $this->processManager->execute('test.context.sub_value', null, ['value' => ['another_key' => 'another_value']]); + $result = $this->processManager->execute( + 'test.context.sub_value', + null, + ['value' => ['another_key' => 'another_value']] + ); self::assertEquals(['key' => ['another_key' => 'another_value']], $result); } diff --git a/Tests/ExceptionManagementTest.php b/Tests/ExceptionManagementTest.php index 96d103c1..790052cd 100644 --- a/Tests/ExceptionManagementTest.php +++ b/Tests/ExceptionManagementTest.php @@ -1,4 +1,12 @@ -processManager->execute('test.exception_management.set_exception_in_the_middle'); - self::assertEquals([ - 'abc', - 'bcd', - 'cde', - 'def', - ], $result['success']); + self::assertEquals( + [ + 'abc', + 'bcd', + 'cde', + 'def', + ], + $result['success'] + ); - self::assertEquals([ - 1 - ], $result['errors']); + self::assertEquals( + [ + 1, + ], + $result['errors'] + ); } } diff --git a/Tests/FlushableTaskTest.php b/Tests/FlushableTaskTest.php index 9807bba1..552b1ca4 100644 --- a/Tests/FlushableTaskTest.php +++ b/Tests/FlushableTaskTest.php @@ -1,8 +1,8 @@ -processManager->execute('test.multi_branch_process_first'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data1', - 'value' => 'ok', + [ + 'task' => 'data1', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_first'); + 'test.multi_branch_process_first' + ); $this->processManager->execute('test.multi_branch_process_entry'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry'); + 'test.multi_branch_process_entry' + ); $this->processManager->execute('test.multi_branch_process_entry_reversed'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry'); + 'test.multi_branch_process_entry' + ); $this->processManager->execute('test.multi_branch_process_end'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_end'); + 'test.multi_branch_process_end' + ); $this->processManager->execute('test.multi_branch_process_entry_end'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry_end'); + 'test.multi_branch_process_entry_end' + ); } public function testMainGroupOrder() { $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_first'); - self::assertEquals(['data1', 'pushDataEvent1'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_first'); + self::assertEquals( + ['data1', 'pushDataEvent1'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_first' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry' + ); - $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry_reversed'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry_reversed'); + $process = $this->processConfigurationRegistry->getProcessConfiguration( + 'test.multi_branch_process_entry_reversed' + ); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry_reversed' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_end'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_end'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_end' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry_end'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry_end'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry_end' + ); } /** diff --git a/Tests/MultiWorkflowTest.php b/Tests/MultiWorkflowTest.php index 2ea0b10c..a77cb486 100644 --- a/Tests/MultiWorkflowTest.php +++ b/Tests/MultiWorkflowTest.php @@ -1,8 +1,8 @@ -processManager->execute('test.multi_workflow_process'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data', - 'value' => 1, - ], - [ - 'task' => 'data', - 'value' => 2, - ], - [ - 'task' => 'data', - 'value' => 3, - ], - [ - 'task' => 'aggregate', - 'value' => [1, 2, 3], - ], - [ - 'task' => 'aggregate2', - 'value' => [1, 2, 3], - ], - [ - 'task' => 'inputAggregate', - 'value' => [ - 'aggregate' => [1, 2, 3], - 'aggregate2' => [1, 2, 3], + [ + 'task' => 'data', + 'value' => 1, + ], + [ + 'task' => 'data', + 'value' => 2, + ], + [ + 'task' => 'data', + 'value' => 3, + ], + [ + 'task' => 'aggregate', + 'value' => [1, 2, 3], + ], + [ + 'task' => 'aggregate2', + 'value' => [1, 2, 3], + ], + [ + 'task' => 'inputAggregate', + 'value' => [ + 'aggregate' => [1, 2, 3], + 'aggregate2' => [1, 2, 3], + ], ], ], - ], 'test.multi_workflow_process'); + 'test.multi_workflow_process' + ); } } diff --git a/Tests/Task/ColumnAggregatorTaskTest.php b/Tests/Task/ColumnAggregatorTaskTest.php index 2be09222..89b859c2 100644 --- a/Tests/Task/ColumnAggregatorTaskTest.php +++ b/Tests/Task/ColumnAggregatorTaskTest.php @@ -1,8 +1,15 @@ - 'B', 'col2' => 'val4']; $input = [$input1, $input2, $input3, $input4]; - self::assertEquals([ - 'aggregateAny' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => $input, + self::assertEquals( + [ + 'aggregateAny' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => $input, + ], ], - ], - 'aggregateA' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => [$input1,$input3], + 'aggregateA' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => [$input1, $input3], + ], ], - ], - 'aggregateB' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => [$input2,$input4], + 'aggregateB' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => [$input2, $input4], + ], ], ], - ], $this->processManager->execute('test.column_aggregator_task.simple', $input)); + $this->processManager->execute('test.column_aggregator_task.simple', $input) + ); } } diff --git a/Tests/Task/FilterTaskTest.php b/Tests/Task/FilterTaskTest.php index 27b4c84c..1a430fde 100644 --- a/Tests/Task/FilterTaskTest.php +++ b/Tests/Task/FilterTaskTest.php @@ -1,8 +1,8 @@ -assertDataQueue( [ [ - 'task' => 'data', + 'task' => 'data', 'value' => 1, ], - ], 'test.task.stop_task.iterable_interruption'); + ], + 'test.task.stop_task.iterable_interruption' + ); } } diff --git a/Tests/Task/TransformerTaskTest.php b/Tests/Task/TransformerTaskTest.php index 9a07fe28..1f7f174f 100644 --- a/Tests/Task/TransformerTaskTest.php +++ b/Tests/Task/TransformerTaskTest.php @@ -1,8 +1,8 @@ - 42, - 'any_field' => 'hello', + 'int_field' => 42, + 'any_field' => 'hello', 'choice_field' => 'Some random value 1', ]; $result = $this->processManager->execute('test.validator_task', $input); diff --git a/Tests/Transformer/ArrayFilterTransformerTest.php b/Tests/Transformer/ArrayFilterTransformerTest.php index 3ecb88d5..8a98c6f8 100644 --- a/Tests/Transformer/ArrayFilterTransformerTest.php +++ b/Tests/Transformer/ArrayFilterTransformerTest.php @@ -1,8 +1,8 @@ -processManager->execute('test.array_filter_transformer.simple', $input); - $nativeResult = array_filter($input, function ($item) { - return isset($item['filter_value']) && $item['filter_value'] === 'X'; - }); + $nativeResult = array_filter( + $input, + static function ($item) { + return isset($item['filter_value']) && 'X' === $item['filter_value']; + } + ); // Note that to match native function, key are preserved $expectedResult = [ 0 => ['data' => 1, 'filter_value' => 'X'], - 3 => ['data' => 4, 'filter_value' => 'X'] + 3 => ['data' => 4, 'filter_value' => 'X'], ]; self::assertCount(2, $result); diff --git a/Tests/Transformer/CallbackTransformerTest.php b/Tests/Transformer/CallbackTransformerTest.php index 08194f93..433d4997 100644 --- a/Tests/Transformer/CallbackTransformerTest.php +++ b/Tests/Transformer/CallbackTransformerTest.php @@ -1,8 +1,8 @@ -processManager->execute('test.date_transformers.date_parser', '2001-01-01'); // There could be a 1s difference, depending on execution time... - $date->setTime(0,0); - $result->setTime(0,0); + $date->setTime(0, 0); + $result->setTime(0, 0); self::assertInstanceOf(\DateTime::class, $result); if ($result instanceof \DateTime) { @@ -50,6 +58,7 @@ public function testDateParser() /** * Assert that a date is not parsed if the format doesn't match + * * @expectedException \RuntimeException */ public function testDateParserError() @@ -62,7 +71,10 @@ public function testDateParserError() */ public function testDateParseFormat() { - $result = $this->processManager->execute('test.date_transformers.date_parse_format', '2001-01-01T00:00:00+00:00'); + $result = $this->processManager->execute( + 'test.date_transformers.date_parse_format', + '2001-01-01T00:00:00+00:00' + ); self::assertEquals('2001-01-01', $result); } } diff --git a/Tests/Transformer/MappingTransformerTest.php b/Tests/Transformer/MappingTransformerTest.php index af63aa91..b78cfede 100644 --- a/Tests/Transformer/MappingTransformerTest.php +++ b/Tests/Transformer/MappingTransformerTest.php @@ -1,4 +1,12 @@ -processManager->execute('test.mapping_transformer.multi_subtransformers', ['field' => [3, null, 4, 2]]); + $result = $this->processManager->execute( + 'test.mapping_transformer.multi_subtransformers', + ['field' => [3, null, 4, 2]] + ); self::assertEquals(['field2' => [2, 4, 3]], $result); } diff --git a/Tests/Transformer/UnsetTransformerTest.php b/Tests/Transformer/UnsetTransformerTest.php index bc9cdde7..527af018 100644 --- a/Tests/Transformer/UnsetTransformerTest.php +++ b/Tests/Transformer/UnsetTransformerTest.php @@ -1,8 +1,15 @@ - 1, + 'other' => 1, 'to_unset' => 1, - 'to_test' => 2, + 'to_test' => 2, ]; $result = $this->processManager->execute('test.unset_transformer.simple', $input); self::assertEquals(['other' => 1, 'to_test' => 2], $result); @@ -30,9 +37,9 @@ public function testSimpleUnset() public function testConditionalUnset() { $input = [ - 'other' => 1, + 'other' => 1, 'to_unset' => 1, - 'to_test' => 2, + 'to_test' => 2, ]; // Should unset diff --git a/Transformer/ArrayElementTransformer.php b/Transformer/ArrayElementTransformer.php index a78739b1..ec7fd1e9 100644 --- a/Transformer/ArrayElementTransformer.php +++ b/Transformer/ArrayElementTransformer.php @@ -1,8 +1,8 @@ -configureOptions($resolver); - $options = $resolver->resolve($options); - if ($options['allow_not_iterable'] && !is_iterable($value)) { return $value; } @@ -56,9 +53,9 @@ public function getCode() /** * @param OptionsResolver $resolver * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ExceptionInterface */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults( [ diff --git a/Transformer/ArrayLastTransformer.php b/Transformer/ArrayLastTransformer.php index 73c0be68..15668896 100644 --- a/Transformer/ArrayLastTransformer.php +++ b/Transformer/ArrayLastTransformer.php @@ -1,8 +1,8 @@ -setNormalizer( 'callback', - function (Options $options, $value) { + static function (Options $options, $value) { if (!\is_callable($value)) { throw new InvalidOptionsException( 'Callback option must be callable' @@ -93,9 +94,12 @@ function (Options $options, $value) { /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'additional_parameters', - function (Options $options, $value) { + static function (Options $options, $value) { if ($value) { - @trigger_error('The "additional_parameters" option is deprecated. Use "right_parameters" instead.', E_USER_DEPRECATED); + @trigger_error( + 'The "additional_parameters" option is deprecated. Use "right_parameters" instead.', + E_USER_DEPRECATED + ); } return $value; diff --git a/Transformer/ConditionTrait.php b/Transformer/ConditionTrait.php index e9b6bd89..f43b5d37 100644 --- a/Transformer/ConditionTrait.php +++ b/Transformer/ConditionTrait.php @@ -1,8 +1,8 @@ -setDefault($wrapperKey, []); $resolver->setAllowedTypes($wrapperKey, ['array']); - $resolver->setNormalizer($wrapperKey, function (OptionsResolver $options, $value) { - $conditionResolver = new OptionsResolver(); - $this->configureConditionOptions($conditionResolver); + $resolver->setNormalizer( + $wrapperKey, + function (OptionsResolver $options, $value) { + $conditionResolver = new OptionsResolver(); + $this->configureConditionOptions($conditionResolver); - return $conditionResolver->resolve($value); - }); + return $conditionResolver->resolve($value); + } + ); } /** @@ -117,9 +123,9 @@ protected function configureConditionOptions(OptionsResolver $resolver) * @param bool $shouldMatch * @param bool $regexpMode * - * @throws \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException - * @throws \Symfony\Component\PropertyAccess\Exception\AccessException - * @throws \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @throws UnexpectedTypeException + * @throws AccessException + * @throws InvalidArgumentException * * @return bool */ diff --git a/Transformer/ConfigurableTransformerInterface.php b/Transformer/ConfigurableTransformerInterface.php index 1d1dc931..f5ceba20 100644 --- a/Transformer/ConfigurableTransformerInterface.php +++ b/Transformer/ConfigurableTransformerInterface.php @@ -1,8 +1,8 @@ -setAllowedTypes('expression', ['string', ParsedExpression::class]); - $resolver->setNormalizer('expression', function (Options $options, $expression) { - if (is_array($options['variables'])) { - return $this->language->parse($expression, $options['variables']); - } else { + $resolver->setNormalizer( + 'expression', + function (Options $options, $expression) { + if (is_array($options['variables'])) { + return $this->language->parse($expression, $options['variables']); + } + return $expression; } - }); + ); } /** * @param mixed $value * @param array $options * - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException + * @throws UndefinedOptionsException + * @throws OptionDefinitionException + * @throws NoSuchOptionException + * @throws MissingOptionsException + * @throws InvalidOptionsException + * @throws AccessException * * @return string */ diff --git a/Transformer/ExplodeTransformer.php b/Transformer/ExplodeTransformer.php index 08a60547..a6d60d7f 100644 --- a/Transformer/ExplodeTransformer.php +++ b/Transformer/ExplodeTransformer.php @@ -1,8 +1,8 @@ -accessor->getValue($value, $options['iterator']); if (!is_iterable($iterable)) { - throw new TransformerException($options['iterator'], 0, 'Property not an iterable'); + throw new TransformerException($options['iterator']); } $protertiesToSet = []; @@ -69,7 +74,7 @@ public function transform($value, array $options = []) } else { $protertiesValue = $this->accessor->getValue($value, $propertyValuePath); if (null === $protertiesValue && !$options['ignore_null']) { - throw new TransformerException($propertyValuePath, 0, 'Property is null'); + throw new TransformerException($propertyValuePath); } } $protertiesToSet[$propertyName] = $protertiesValue; @@ -79,7 +84,7 @@ public function transform($value, array $options = []) foreach ($protertiesToSet as $protertyName => $propertyValue) { try { $this->accessor->setValue($item, $protertyName, $propertyValue); - } catch (\Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException $e) { + } catch (NoSuchPropertyException $e) { if ($item instanceof \stdClass) { $item = (object) array_merge((array) $item, [$protertyName => $propertyValue]); } else { @@ -105,7 +110,7 @@ public function getCode() /** * @param OptionsResolver $resolver * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface + * @throws ExceptionInterface */ public function configureOptions(OptionsResolver $resolver) { diff --git a/Transformer/SlugifyTransformer.php b/Transformer/SlugifyTransformer.php index 6d0d5496..017135cc 100644 --- a/Transformer/SlugifyTransformer.php +++ b/Transformer/SlugifyTransformer.php @@ -1,8 +1,8 @@ -setNormalizer('transliterator', function(Options $options, $value) { - return \Transliterator::create($value); - }); + $resolver->setNormalizer( + 'transliterator', + static function (Options $options, $value) { + return \Transliterator::create($value); + } + ); } } diff --git a/Transformer/SprintfTransformer.php b/Transformer/SprintfTransformer.php index 5a8791cf..e5e5e8e2 100644 --- a/Transformer/SprintfTransformer.php +++ b/Transformer/SprintfTransformer.php @@ -1,8 +1,8 @@ -setAllowedTypes($optionName, ['array']); $resolver->setNormalizer( $optionName, - function (/** @noinspection PhpUnusedParameterInspection */ + function ( + /** @noinspection PhpUnusedParameterInspection */ Options $options, $transformers ) { diff --git a/Transformer/TrimTransformer.php b/Transformer/TrimTransformer.php index 1fe8ab28..00575b7c 100644 --- a/Transformer/TrimTransformer.php +++ b/Transformer/TrimTransformer.php @@ -1,8 +1,8 @@ - Date: Wed, 24 Apr 2019 19:24:03 +0200 Subject: [PATCH 036/304] Moving all external dependencies to dedicated bundles --- .../Task/Database/DatabaseReaderTask.php | 219 ------------- .../Task/Database/DatabaseUpdaterTask.php | 111 ------- .../AbstractDoctrineQueryTask.php | 113 ------- .../EntityManager/AbstractDoctrineTask.php | 64 ---- .../EntityManager/ClearEntityManagerTask.php | 35 --- .../EntityManager/DoctrineBatchWriterTask.php | 111 ------- .../EntityManager/DoctrineCleanerTask.php | 44 --- .../EntityManager/DoctrineDetacherTask.php | 45 --- .../Task/EntityManager/DoctrineReaderTask.php | 123 -------- .../EntityManager/DoctrineRemoverTask.php | 43 --- .../Task/EntityManager/DoctrineWriterTask.php | 90 ------ .../EntityManager/PurgeDoctrineCacheTask.php | 131 -------- Addon/Flysystem/Task/FileFetchTask.php | 197 ------------ Addon/Rest/Client/Client.php | 294 ------------------ Addon/Rest/Client/ClientInterface.php | 51 --- .../Rest/Exception/MissingClientException.php | 31 -- Addon/Rest/Exception/RestException.php | 21 -- Addon/Rest/Exception/RestRequestException.php | 21 -- Addon/Rest/Registry.php | 70 ----- Addon/Rest/Task/RequestTask.php | 122 -------- Addon/Rest/Transformer/RequestTransformer.php | 130 -------- Addon/Soap/Client/Client.php | 287 ----------------- Addon/Soap/Client/ClientInterface.php | 92 ------ .../Soap/Exception/MissingClientException.php | 33 -- Addon/Soap/Registry.php | 70 ----- Addon/Soap/Task/RequestTask.php | 102 ------ Addon/Soap/Transformer/RequestTransformer.php | 86 ----- CleverAgeProcessBundle.php | 29 +- .../CleverAgeProcessExtension.php | 24 -- Documentation/01-quick_start.md | 2 +- .../reference/tasks/doctrine_reader_task.md | 35 --- .../reference/tasks/doctrine_writer_task.md | 28 -- Manager/ProcessManager.php | 8 - README.md | 5 +- Resources/config/services-doctrine/task.yml | 8 - Resources/config/services-flysystem/task.yml | 8 - Resources/config/services-rest/services.yml | 3 - Resources/config/services-rest/task.yml | 8 - .../config/services-rest/transformer.yml | 8 - Resources/config/services-soap/services.yml | 3 - Resources/config/services-soap/task.yml | 8 - .../config/services-soap/transformer.yml | 8 - Resources/migration/move_doctrine_to_addon.sh | 4 +- .../migration/move_flysystem_to_addon.sh | 2 +- composer.json | 10 +- 45 files changed, 11 insertions(+), 2926 deletions(-) delete mode 100644 Addon/Doctrine/Task/Database/DatabaseReaderTask.php delete mode 100644 Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php delete mode 100644 Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php delete mode 100644 Addon/Flysystem/Task/FileFetchTask.php delete mode 100644 Addon/Rest/Client/Client.php delete mode 100644 Addon/Rest/Client/ClientInterface.php delete mode 100644 Addon/Rest/Exception/MissingClientException.php delete mode 100644 Addon/Rest/Exception/RestException.php delete mode 100644 Addon/Rest/Exception/RestRequestException.php delete mode 100644 Addon/Rest/Registry.php delete mode 100644 Addon/Rest/Task/RequestTask.php delete mode 100644 Addon/Rest/Transformer/RequestTransformer.php delete mode 100644 Addon/Soap/Client/Client.php delete mode 100644 Addon/Soap/Client/ClientInterface.php delete mode 100644 Addon/Soap/Exception/MissingClientException.php delete mode 100644 Addon/Soap/Registry.php delete mode 100644 Addon/Soap/Task/RequestTask.php delete mode 100644 Addon/Soap/Transformer/RequestTransformer.php delete mode 100644 Documentation/reference/tasks/doctrine_reader_task.md delete mode 100644 Documentation/reference/tasks/doctrine_writer_task.md delete mode 100644 Resources/config/services-doctrine/task.yml delete mode 100644 Resources/config/services-flysystem/task.yml delete mode 100644 Resources/config/services-rest/services.yml delete mode 100644 Resources/config/services-rest/task.yml delete mode 100644 Resources/config/services-rest/transformer.yml delete mode 100644 Resources/config/services-soap/services.yml delete mode 100644 Resources/config/services-soap/task.yml delete mode 100644 Resources/config/services-soap/transformer.yml diff --git a/Addon/Doctrine/Task/Database/DatabaseReaderTask.php b/Addon/Doctrine/Task/Database/DatabaseReaderTask.php deleted file mode 100644 index ddfc5b0b..00000000 --- a/Addon/Doctrine/Task/Database/DatabaseReaderTask.php +++ /dev/null @@ -1,219 +0,0 @@ - - * @author Vincent Chalnot - */ -class DatabaseReaderTask extends AbstractConfigurableTask implements IterableTaskInterface, FinalizableTaskInterface -{ - /** @var LoggerInterface */ - protected $logger; - - /** @var ManagerRegistry */ - protected $doctrine; - - /** @var PDOStatement */ - protected $statement; - - /** @var array|mixed */ - protected $nextItem; - - /** - * @param LoggerInterface $logger - * @param ManagerRegistry $doctrine - */ - public function __construct(LoggerInterface $logger, ManagerRegistry $doctrine) - { - $this->logger = $logger; - $this->doctrine = $doctrine; - } - - /** - * Moves the internal pointer to the next element, - * return true if the task has a next element - * return false if the task has terminated it's iteration - * - * @param ProcessState $state - * - * @throws \LogicException - * - * @return bool - */ - public function next(ProcessState $state) - { - if (!$this->statement) { - return false; - } - - $this->nextItem = $this->statement->fetch(); - - return (bool) $this->nextItem; - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Doctrine\DBAL\DBALException - */ - public function execute(ProcessState $state) - { - $options = $this->getOptions($state); - if (!$this->statement) { - $this->statement = $this->initializeStatement($state); - } - - // Check if the next item has been stored by the next() call - if (null !== $this->nextItem) { - $result = $this->nextItem; - $this->nextItem = null; - } else { - $result = $this->statement->fetch(); - } - - // Handle empty results - if (false === $result) { - $logContext = ['options' => $options]; - $this->logger->log($options['empty_log_level'], 'Empty resultset for query', $logContext); - $state->setSkipped(true); - $this->statement = null; - - return; - } - - if (null !== $options['paginate']) { - $results = []; - $i = 0; - while (false !== $result && $i++ < $options['paginate']) { - $results[] = $result; - $result = $this->statement->fetch(); - } - $state->setOutput($results); - } else { - $state->setOutput($result); - } - } - - /** - * @param ProcessState $state - */ - public function finalize(ProcessState $state) - { - if ($this->statement) { - $this->statement->closeCursor(); - } - } - - /** - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - * @throws \Doctrine\DBAL\DBALException - * - * @return \Doctrine\DBAL\Driver\ResultStatement - */ - protected function initializeStatement(ProcessState $state) - { - $options = $this->getOptions($state); - $connection = $this->getConnection($state); - $sql = $options['sql']; - - if (null === $sql) { - $qb = $connection->createQueryBuilder(); - $qb - ->select('tbl.*') - ->from($options['table'], 'tbl'); - - if ($options['limit']) { - $qb->setMaxResults($options['limit']); - } - if ($options['offset']) { - $qb->setFirstResult($options['offset']); - } - - $sql = $qb->getSQL(); - } - - return $connection->executeQuery($sql); - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'table', - ] - ); - $resolver->setAllowedTypes('table', ['string']); - $resolver->setDefaults( - [ - 'connection' => null, - 'sql' => null, - 'limit' => null, - 'offset' => null, - 'paginate' => null, - 'empty_log_level' => LogLevel::WARNING, - ] - ); - $resolver->setAllowedTypes('connection', ['NULL', 'string']); - $resolver->setAllowedTypes('sql', ['NULL', 'string']); - $resolver->setAllowedTypes('paginate', ['NULL', 'int']); - $resolver->setAllowedTypes('limit', ['NULL', 'integer']); - $resolver->setAllowedTypes('offset', ['NULL', 'integer']); - $resolver->setAllowedValues( - 'empty_log_level', - [ - LogLevel::ALERT, - LogLevel::CRITICAL, - LogLevel::DEBUG, - LogLevel::EMERGENCY, - LogLevel::ERROR, - LogLevel::INFO, - LogLevel::NOTICE, - LogLevel::WARNING, - ] - ); - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @return \Doctrine\DBAL\Connection - */ - protected function getConnection(ProcessState $state) - { - /** @noinspection PhpIncompatibleReturnTypeInspection */ - - return $this->doctrine->getConnection($this->getOption($state, 'connection')); - } -} diff --git a/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php b/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php deleted file mode 100644 index ef375adf..00000000 --- a/Addon/Doctrine/Task/Database/DatabaseUpdaterTask.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @author Vincent Chalnot - */ -class DatabaseUpdaterTask extends AbstractConfigurableTask -{ - /** @var ManagerRegistry */ - protected $doctrine; - - /** @var LoggerInterface */ - protected $logger; - - /** - * @param ManagerRegistry $doctrine - * @param LoggerInterface $logger - */ - public function __construct(ManagerRegistry $doctrine, LoggerInterface $logger) - { - $this->doctrine = $doctrine; - $this->logger = $logger; - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Doctrine\DBAL\DBALException - */ - public function execute(ProcessState $state) - { - $statement = $this->initializeStatement($state); - - if (false === $statement->execute()) { - throw new \RuntimeException("Error while executing query: {$statement->errorInfo()}"); - } - } - - /** - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - * @throws \Doctrine\DBAL\DBALException - * - * @return \Doctrine\DBAL\Driver\ResultStatement - */ - protected function initializeStatement(ProcessState $state) - { - $connection = $this->getConnection($state); - - $input = $state->getInput(); - $params = is_array($input) ? $input : []; - - return $connection->executeQuery($this->getOption($state, 'sql'), $params); - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'sql', - ] - ); - $resolver->setAllowedTypes('sql', ['string']); - $resolver->setDefaults( - [ - 'connection' => null, - ] - ); - $resolver->setAllowedTypes('connection', ['NULL', 'string']); - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @return \Doctrine\DBAL\Connection - */ - protected function getConnection(ProcessState $state) - { - /** @noinspection PhpIncompatibleReturnTypeInspection */ - - return $this->doctrine->getConnection($this->getOption($state, 'connection')); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php deleted file mode 100644 index 3bee890a..00000000 --- a/Addon/Doctrine/Task/EntityManager/AbstractDoctrineQueryTask.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @author Vincent Chalnot - */ -abstract class AbstractDoctrineQueryTask extends AbstractDoctrineTask -{ - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - $resolver->setRequired( - [ - 'class_name', - ] - ); - $resolver->setAllowedTypes('class_name', ['string']); - $resolver->setDefaults( - [ - 'criteria' => [], - 'order_by' => [], - 'limit' => null, - 'offset' => null, - 'empty_log_level' => LogLevel::WARNING, - ] - ); - $resolver->setAllowedTypes('criteria', ['array']); - $resolver->setAllowedTypes('order_by', ['array']); - $resolver->setAllowedTypes('limit', ['NULL', 'integer']); - $resolver->setAllowedTypes('offset', ['NULL', 'integer']); - $resolver->setAllowedValues( - 'empty_log_level', - [ - LogLevel::ALERT, - LogLevel::CRITICAL, - LogLevel::DEBUG, - LogLevel::EMERGENCY, - LogLevel::ERROR, - LogLevel::INFO, - LogLevel::NOTICE, - LogLevel::WARNING, - ] - ); - } - - /** - * @param EntityRepository $repository - * @param array $criteria - * @param array $orderBy - * @param int $limit - * @param int $offset - * - * @throws \UnexpectedValueException - * - * @return \Doctrine\ORM\QueryBuilder - */ - protected function getQueryBuilder( - EntityRepository $repository, - array $criteria, - array $orderBy, - $limit = null, - $offset = null - ) { - $qb = $repository->createQueryBuilder('e'); - foreach ($criteria as $field => $value) { - if (preg_match('/[^a-zA-Z0-9]/', $field)) { - throw new \UnexpectedValueException("Forbidden field name '{$field}'"); - } - $parameterName = uniqid('param', false); - if (null === $value) { - $qb->andWhere("e.{$field} IS NULL"); - } else { - if (\is_array($value)) { - $qb->andWhere("e.{$field} IN (:{$parameterName})"); - } else { - $qb->andWhere("e.{$field} = :{$parameterName}"); - } - $qb->setParameter($parameterName, $value); - } - } - /** @noinspection ForeachSourceInspection */ - foreach ($orderBy as $field => $order) { - $qb->addOrderBy("e.{$field}", $order); - } - if (null !== $limit) { - $qb->setMaxResults($limit); - } - if (null !== $offset) { - $qb->setFirstResult($offset); - } - - return $qb; - } -} diff --git a/Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php b/Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php deleted file mode 100644 index ccd08516..00000000 --- a/Addon/Doctrine/Task/EntityManager/AbstractDoctrineTask.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @author Vincent Chalnot - */ -abstract class AbstractDoctrineTask extends AbstractConfigurableTask -{ - /** @var ManagerRegistry */ - protected $doctrine; - - /** - * @param ManagerRegistry $doctrine - */ - public function __construct(ManagerRegistry $doctrine) - { - $this->doctrine = $doctrine; - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'entity_manager' => null, - ] - ); - $resolver->setAllowedTypes('entity_manager', ['NULL', 'string']); - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @return EntityManagerInterface|ObjectManager - */ - protected function getManager(ProcessState $state) - { - return $this->doctrine->getManager($this->getOption($state, 'entity_manager')); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php b/Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php deleted file mode 100644 index 0d4f77f8..00000000 --- a/Addon/Doctrine/Task/EntityManager/ClearEntityManagerTask.php +++ /dev/null @@ -1,35 +0,0 @@ - - */ -class ClearEntityManagerTask extends AbstractDoctrineTask -{ - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) - { - $entityManager = $this->getManager($state); - $entityManager->clear(); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php deleted file mode 100644 index 8723654c..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineBatchWriterTask.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @author Vincent Chalnot - */ -class DoctrineBatchWriterTask extends AbstractDoctrineTask implements FlushableTaskInterface -{ - /** @var array */ - protected $batch = []; - - /** - * @param ProcessState $state - * - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - */ - public function flush(ProcessState $state) - { - $this->writeBatch($state); - } - - /** - * @param ProcessState $state - * - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) - { - $this->batch[] = $state->getInput(); - - if (\count($this->batch) >= $this->getOption($state, 'batch_count')) { - $this->writeBatch($state); - } else { - $state->setSkipped(true); - } - } - - /** - * @param OptionsResolver $resolver - * - * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - $resolver->setDefaults( - [ - 'batch_count' => 10, - ] - ); - $resolver->setAllowedTypes('batch_count', ['integer']); - } - - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - */ - protected function writeBatch(ProcessState $state): void - { - if (0 === \count($this->batch)) { - $state->setSkipped(true); - - return; - } - - // Support for multiple entity managers is overkill but might be necessary - $entityManagers = new \SplObjectStorage(); - foreach ($this->batch as $entity) { - $class = ClassUtils::getClass($entity); - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $entityManager->persist($entity); - $entityManagers->attach($entityManager); - } - - foreach ($entityManagers as $entityManager) { - $entityManager->flush(); - } - - $state->setOutput($this->batch); - $this->batch = []; - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php deleted file mode 100644 index d4b09e67..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineCleanerTask.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -class DoctrineCleanerTask extends AbstractDoctrineTask -{ - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) - { - $entity = $state->getInput(); - if (null === $entity) { - throw new \RuntimeException('DoctrineWriterTask does not allow null input'); - } - $class = ClassUtils::getClass($entity); - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $entityManager->clear(); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php deleted file mode 100644 index 11c9b231..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineDetacherTask.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @author Vincent Chalnot - */ -class DoctrineDetacherTask extends AbstractDoctrineTask -{ - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) - { - $entity = $state->getInput(); - if (null === $entity) { - throw new \RuntimeException('DoctrineWriterTask does not allow null input'); - } - $class = ClassUtils::getClass($entity); - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $entityManager->detach($entity); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php deleted file mode 100644 index 7ab9c9dd..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineReaderTask.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @author Vincent Chalnot - */ -class DoctrineReaderTask extends AbstractDoctrineQueryTask implements IterableTaskInterface -{ - /** @var LoggerInterface */ - protected $logger; - - /** @var IterableResult */ - protected $iterator; - - /** - * @param LoggerInterface $logger - * @param ManagerRegistry $doctrine - */ - public function __construct(LoggerInterface $logger, ManagerRegistry $doctrine) - { - $this->logger = $logger; - parent::__construct($doctrine); - } - - /** - * Moves the internal pointer to the next element, - * return true if the task has a next element - * return false if the task has terminated it's iteration - * - * @param ProcessState $state - * - * @throws \LogicException - * - * @return bool - */ - public function next(ProcessState $state) - { - if (!$this->iterator) { - return false; - } - $this->iterator->next(); - - return $this->iterator->valid(); - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \UnexpectedValueException - */ - public function execute(ProcessState $state) - { - $options = $this->getOptions($state); - if (!$this->iterator) { - $class = $options['class_name']; - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $repository = $entityManager->getRepository($class); - if (!$repository instanceof EntityRepository) { - throw new \UnexpectedValueException("No repository found for class {$class}"); - } - $this->initIterator($repository, $options); - } - - $result = $this->iterator->current(); - - // Handle empty results - if (false === $result) { - $logContext = ['options' => $options]; - $this->logger->log($options['empty_log_level'], 'Empty resultset for query', $logContext); - $state->setSkipped(true); - $this->iterator = null; - - return; - } - - $state->setOutput(reset($result)); - } - - /** - * @param EntityRepository $repository - * @param array $options - * - * @throws \UnexpectedValueException - */ - protected function initIterator(EntityRepository $repository, array $options) - { - $qb = $this->getQueryBuilder( - $repository, - $options['criteria'], - $options['order_by'], - $options['limit'], - $options['offset'] - ); - - $this->iterator = $qb->getQuery()->iterate(); - $this->iterator->next(); // Move to first element - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php deleted file mode 100644 index 70eed3bc..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineRemoverTask.php +++ /dev/null @@ -1,43 +0,0 @@ - - * @author Vincent Chalnot - */ -class DoctrineRemoverTask extends AbstractDoctrineTask -{ - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \Doctrine\ORM\ORMInvalidArgumentException - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) - { - $entity = $state->getInput(); - $class = ClassUtils::getClass($entity); - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $entityManager->remove($entity); - $entityManager->flush(); - } -} diff --git a/Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php b/Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php deleted file mode 100644 index 2a8183ab..00000000 --- a/Addon/Doctrine/Task/EntityManager/DoctrineWriterTask.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @author Vincent Chalnot - */ -class DoctrineWriterTask extends AbstractDoctrineTask -{ - /** - * @param ProcessState $state - * - * @throws \Doctrine\ORM\ORMException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $state->setOutput($this->writeEntity($state)); - } - - /** - * @param OptionsResolver $resolver - * - * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - $resolver->setDefaults( - [ - 'global_flush' => true, - ] - ); - $resolver->setAllowedTypes('global_flush', ['boolean']); - } - - /** - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \Doctrine\ORM\ORMException - * - * @return mixed - */ - protected function writeEntity(ProcessState $state) - { - $options = $this->getOptions($state); - $entity = $state->getInput(); - - if (null === $entity) { - throw new \RuntimeException('DoctrineWriterTask does not allow null input'); - } - $class = ClassUtils::getClass($entity); - $entityManager = $this->doctrine->getManagerForClass($class); - if (!$entityManager instanceof EntityManagerInterface) { - throw new \UnexpectedValueException("No manager found for class {$class}"); - } - $entityManager->persist($entity); - - if ($options['global_flush']) { - $entityManager->flush(); - } else { - if (!$entityManager instanceof EntityManager) { - throw new \UnexpectedValueException("Manager for class {$class} does not support unitary flush"); - } - $entityManager->flush($entity); - } - - return $entity; - } -} diff --git a/Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php b/Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php deleted file mode 100644 index 1fa58f9d..00000000 --- a/Addon/Doctrine/Task/EntityManager/PurgeDoctrineCacheTask.php +++ /dev/null @@ -1,131 +0,0 @@ - - */ -class PurgeDoctrineCacheTask extends AbstractConfigurableTask -{ - /** @var array */ - protected const METHOD_MAP = [ - 'query_cache' => 'getQueryCacheImpl', - 'result_cache' => 'getResultCacheImpl', - 'hydration_cache' => 'getHydrationCacheImpl', - 'metadata_cache' => 'getMetadataCacheImpl', - ]; - - /** @var ManagerRegistry */ - protected $doctrine; - - /** - * @param ManagerRegistry $doctrine - */ - public function __construct(ManagerRegistry $doctrine) - { - $this->doctrine = $doctrine; - } - - /** - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $entityManager = $this->getOption($state, 'entity_manager'); - if ($entityManager) { - $this->purgeEntityManagerCache($entityManager, $state); - } else { - foreach ($this->doctrine->getManagers() as $entityManager) { - if ($entityManager instanceof EntityManagerInterface) { - $this->purgeEntityManagerCache($entityManager, $state); - } - } - } - } - - /** - * @param EntityManagerInterface $entityManager - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - protected function purgeEntityManagerCache(EntityManagerInterface $entityManager, ProcessState $state): void - { - $options = $this->getOptions($state); - foreach (self::METHOD_MAP as $option => $method) { - if ($options[$option]) { - $this->purgeCache($entityManager->getConfiguration()->$method()); - } - } - } - - /** - * @param Cache $cache - */ - protected function purgeCache(Cache $cache = null): void - { - if ($cache instanceof FlushableCache) { - $cache->flushAll(); - } - } - - /** - * @param OptionsResolver $resolver - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'query_cache' => true, - 'result_cache' => true, - 'hydration_cache' => true, - 'metadata_cache' => false, - 'entity_manager' => null, // Purge all entity managers by default - ] - ); - $resolver->setAllowedTypes('query_cache', ['bool']); - $resolver->setAllowedTypes('result_cache', ['bool']); - $resolver->setAllowedTypes('hydration_cache', ['bool']); - $resolver->setAllowedTypes('entity_manager', ['NULL', 'string', EntityManagerInterface::class]); - $resolver->setNormalizer( - 'entity_manager', - function (/** @noinspection PhpUnusedParameterInspection */ - Options $options, - $value - ) { - if (null === $value) { - return null; - } - if (is_string($value)) { - $value = $this->doctrine->getManager($value); - } - if (!$value instanceof EntityManagerInterface) { - throw new \UnexpectedValueException('Unable to resolve entity manager'); - } - - return $value; - } - ); - } -} diff --git a/Addon/Flysystem/Task/FileFetchTask.php b/Addon/Flysystem/Task/FileFetchTask.php deleted file mode 100644 index 92482aa6..00000000 --- a/Addon/Flysystem/Task/FileFetchTask.php +++ /dev/null @@ -1,197 +0,0 @@ - - */ -class FileFetchTask extends AbstractConfigurableTask implements IterableTaskInterface -{ - - /** @var MountManager */ - protected $mountManager; - - /** @var FilesystemInterface */ - protected $sourceFS; - - /** @var FilesystemInterface */ - protected $destinationFS; - - /** @var array */ - protected $matchingFiles = []; - - /** - * @param MountManager|null $mountManager - */ - public function __construct(MountManager $mountManager = null) - { - $this->mountManager = $mountManager; - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \League\Flysystem\FilesystemNotFoundException - */ - public function initialize(ProcessState $state) - { - if (!$this->mountManager) { - throw new ServiceNotFoundException('MountManager service not found, you need to install FlySystemBundle'); - } - // Configure options - parent::initialize($state); - - $this->sourceFS = $this->mountManager->getFilesystem($this->getOption($state, 'source_filesystem')); - $this->destinationFS = $this->mountManager->getFilesystem($this->getOption($state, 'destination_filesystem')); - } - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \UnexpectedValueException - * @throws \League\Flysystem\FilesystemNotFoundException - * @throws \League\Flysystem\FileNotFoundException - */ - public function execute(ProcessState $state) - { - $this->findMatchingFiles($state); - - $file = current($this->matchingFiles); - if (!$file) { - $state->setSkipped(true); - - return; - } - - $this->doFileCopy($state, $file, $this->getOption($state, 'remove_source')); - $state->setOutput($file); - } - - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - * - * @return bool|mixed - */ - public function next(ProcessState $state) - { - $this->findMatchingFiles($state); - - return next($this->matchingFiles); - } - - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - protected function findMatchingFiles(ProcessState $state) - { - $filePattern = $this->getOption($state, 'file_pattern'); - if ($filePattern) { - foreach ($this->sourceFS->listContents('/') as $file) { - if ('file' === $file['type'] - && preg_match($filePattern, $file['path']) - && !\in_array($file['path'], $this->matchingFiles, true)) { - $this->matchingFiles[] = $file['path']; - } - } - } else { - $input = $state->getInput(); - if (!$input) { - throw new \UnexpectedValueException('No pattern neither input provided for the Task'); - } - if (\is_array($input)) { - foreach ($input as $file) { - if (!\in_array($file, $this->matchingFiles, true)) { - $this->matchingFiles[] = $file; - } - } - } elseif (!\in_array($input, $this->matchingFiles, true)) { - $this->matchingFiles[] = $input; - } - } - } - - /** - * @param ProcessState $state - * @param string $filename - * @param bool $removeSource - * - * @throws \League\Flysystem\FileNotFoundException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \League\Flysystem\FilesystemNotFoundException - * @throws \InvalidArgumentException - * - * @return mixed - */ - protected function doFileCopy(ProcessState $state, $filename, $removeSource) - { - $prefixFrom = $this->getOption($state, 'source_filesystem'); - $prefixTo = $this->getOption($state, 'destination_filesystem'); - - $buffer = $this->mountManager->getFilesystem($prefixFrom)->readStream($filename); - - if (false === $buffer) { - return false; - } - - $result = $this->mountManager->getFilesystem($prefixTo)->putStream($filename, $buffer); - - if (\is_resource($buffer)) { - fclose($buffer); - } - - if ($removeSource) { - $this->mountManager->delete(sprintf('%s://%s', $prefixFrom, $filename)); - } - - return $result ? $filename : null; - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired(['source_filesystem', 'destination_filesystem']); - $resolver->setAllowedTypes('source_filesystem', 'string'); - $resolver->setAllowedTypes('destination_filesystem', 'string'); - - $resolver->setDefault('file_pattern', null); - $resolver->setAllowedTypes('file_pattern', ['string', 'null']); - - $resolver->setDefault('remove_source', false); - $resolver->setAllowedTypes('remove_source', 'boolean'); - } -} diff --git a/Addon/Rest/Client/Client.php b/Addon/Rest/Client/Client.php deleted file mode 100644 index b08264d5..00000000 --- a/Addon/Rest/Client/Client.php +++ /dev/null @@ -1,294 +0,0 @@ - - */ -class Client implements ClientInterface -{ - /** @var LoggerInterface */ - private $logger; - - /** @var string */ - private $code; - - /** @var string */ - private $uri; - - /** - * Shopify constructor. - * - * @param LoggerInterface $logger - * @param string $code - * @param string $uri - */ - public function __construct(LoggerInterface $logger, string $code, string $uri) - { - $this->logger = $logger; - $this->code = $code; - $this->uri = $uri; - } - - /** - * @return LoggerInterface - */ - public function getLogger(): LoggerInterface - { - return $this->logger; - } - - /** - * @return string - */ - public function getCode(): string - { - return $this->code; - } - - /** - * @return string - */ - public function geUri(): string - { - return $this->uri; - } - - /** - * @param string $uri - */ - public function setUri(string $uri): void - { - $this->uri = $uri; - } - - /** - * @param array $options - * - * @return Response - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \InvalidArgumentException - * @throws RestRequestException - * @throws \Exception - */ - public function call(array $options = []): Response - { - $options = $this->getOptions($options); - - $request = $this->initializeRequest($options); - $this->setRequestQueryParameters($request, $options); - $this->setRequestHeader($request, $options); - return $this->sendRequest($request, $options); - } - - /** - * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function configureOptions(OptionsResolver $resolver): void - { - $resolver->setRequired( - [ - 'url', - ] - ); - - $resolver->setDefault('method', 'GET'); - $resolver->setDefault('url_parameters', []); - $resolver->setDefault('query_parameters', []); - $resolver->setDefault('headers', []); - $resolver->setDefault('sends', 'json'); - $resolver->setDefault('expects', 'json'); - - $resolver->setAllowedTypes('url', ['string']); - $resolver->setAllowedTypes('method', ['string']); - $resolver->setAllowedTypes('sends', ['string']); - $resolver->setAllowedTypes('expects', ['string']); - $resolver->setAllowedTypes('url_parameters', ['array']); - $resolver->setAllowedTypes('query_parameters', ['array']); - $resolver->setAllowedTypes('headers', ['array']); - } - - /** - * @param array $options - * - * @return array - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function getOptions(array $options = []): array - { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - - return $resolver->resolve($options); - } - - /** - * @param array $options - * - * @return Request - * - * @throws RestRequestException - */ - protected function initializeRequest(array $options = []): Request - { - if (!in_array( - $options['method'], - [Http::HEAD, Http::GET, Http::POST, Http::PUT, Http::DELETE, Http::OPTIONS, Http::TRACE, Http::PATCH], - true - )) { - throw new RestRequestException(sprintf('%s is not an HTTP method', $options['method'])); - } - $request = Request::init($options['method']); - $request->sends($options['sends']); - $request->expects($options['expects']); - - return $request; - } - - /** - * @param Request $request - * @param array $options - * - * - * @throws \Exception - */ - protected function setRequestQueryParameters(Request $request, array $options = []): void - { - $uri = $this->constructUri($options); - if (Http::GET === $options['method']) { - if (is_array($options['query_parameters'])) { - $parametersString = http_build_query($options['query_parameters']); - } else { - $parametersString = (string) $options['query_parameters']; - } - $uri .= strpos($uri, '?') ? '&' : '?'; - $uri .= $parametersString; - } elseif ($options['query_parameters']) { - $request->body($options['query_parameters']); - } - - $uri = $this->replaceParametersInUri($uri, $options); - $request->uri($uri); - } - - /** - * @param Request $request - * @param array $options - * - * - */ - protected function setRequestHeader(Request $request, array $options = []): void - { - if ($options['headers']) { - $request->addHeaders($options['headers']); - } - } - - /** - * @param Request $request - * @param array $options - * - * @return Response|null - * - * @throws RestRequestException - */ - protected function sendRequest(Request $request, array $options = []): ?Response - { - try { - return $request->send(); - } catch (\Exception $e) { - $this->logger->error( - 'Rest request failed', - [ - 'url' => $request->uri, - 'error' => $e->getMessage(), - ] - ); - throw new RestRequestException('Rest request failed', 0, $e); - } - } - - /** - * @return string - */ - protected function getApiUrl(): string - { - return sprintf('%s', $this->geUri()); - } - - /** - * @param array $options - * - * @return string - */ - protected function constructUri(array $options): string - { - $uri = ltrim($options['url'], '/'); - - return sprintf('%s/%s', $this->getApiUrl(), $uri); - } - - /** - * @param string $uri - * @param array $options - * - * @return string - * - */ - protected function replaceParametersInUri(string $uri, array $options = []): string - { - if (array_key_exists('url_parameters', $options) - && $options['url_parameters']) { - - $search = array_keys($options['url_parameters']); - array_walk( - $search, - function (&$item) { - $item = '{'.$item.'}'; - } - ); - $replace = array_values($options['url_parameters']); - array_walk( - $replace, - function (&$item) { - $item = rawurlencode($item); - } - ); - - $uri = str_replace($search, $replace, $uri); - } - - return $uri; - } -} diff --git a/Addon/Rest/Client/ClientInterface.php b/Addon/Rest/Client/ClientInterface.php deleted file mode 100644 index b0e18cfb..00000000 --- a/Addon/Rest/Client/ClientInterface.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ -interface ClientInterface -{ - /** - * Return the code of the client used in client registry. - * - * @return string - */ - public function getCode(): string; - - /** - * Return the URI - * - * @return string - */ - public function geUri(): string; - - /** - * Set the URI - * - * @param string $uri - * - * @return void - */ - public function setUri(string $uri): void; - - /** - * @param array $options - * - * @return \Httpful\Response - */ - public function call(array $options = []): Response; -} diff --git a/Addon/Rest/Exception/MissingClientException.php b/Addon/Rest/Exception/MissingClientException.php deleted file mode 100644 index 392ba304..00000000 --- a/Addon/Rest/Exception/MissingClientException.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -class MissingClientException extends RestException -{ - /** - * @param string $code - * - * @return MissingClientException - */ - public static function create($code) - { - $errorStr = "No rest client with code : {$code}"; - - return new self($errorStr); - } -} diff --git a/Addon/Rest/Exception/RestException.php b/Addon/Rest/Exception/RestException.php deleted file mode 100644 index e581fbe0..00000000 --- a/Addon/Rest/Exception/RestException.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class RestException extends \Exception -{ - -} diff --git a/Addon/Rest/Exception/RestRequestException.php b/Addon/Rest/Exception/RestRequestException.php deleted file mode 100644 index ec1d5fad..00000000 --- a/Addon/Rest/Exception/RestRequestException.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class RestRequestException extends RestException -{ - -} diff --git a/Addon/Rest/Registry.php b/Addon/Rest/Registry.php deleted file mode 100644 index ec9ee975..00000000 --- a/Addon/Rest/Registry.php +++ /dev/null @@ -1,70 +0,0 @@ - - */ -class Registry -{ - /** @var ClientInterface[] */ - private $clients = []; - - /** - * @param ClientInterface $client - */ - public function addClient(ClientInterface $client): void - { - if (array_key_exists($client->getCode(), $this->getClients())) { - throw new \UnexpectedValueException("Client {$client->getCode()} is already defined"); - } - $this->clients[$client->getCode()] = $client; - } - - /** - * @return ClientInterface[] - */ - public function getClients(): array - { - return $this->clients; - } - - /** - * @param string $code - * - * @throws MissingClientException - * - * @return ClientInterface - */ - public function getClient($code): ClientInterface - { - if (!$this->hasClient($code)) { - throw MissingClientException::create($code); - } - - return $this->getClients()[$code]; - } - - /** - * @param string $code - * - * @return bool - */ - public function hasClient($code): bool - { - return array_key_exists($code, $this->getClients()); - } -} diff --git a/Addon/Rest/Task/RequestTask.php b/Addon/Rest/Task/RequestTask.php deleted file mode 100644 index 5538a9ab..00000000 --- a/Addon/Rest/Task/RequestTask.php +++ /dev/null @@ -1,122 +0,0 @@ - - */ -class RequestTask extends AbstractConfigurableTask -{ - - /** @var LoggerInterface */ - protected $logger; - - /** @var Registry */ - protected $registry; - - /** - * RequestTask constructor. - * - * @param LoggerInterface $logger - */ - public function __construct(LoggerInterface $logger, Registry $registry) - { - $this->logger = $logger; - $this->registry = $registry; - } - - /** - * {@inheritdoc} - * @param ProcessState $state - * - * @throws \CleverAge\ProcessBundle\Addon\Rest\Exception\MissingClientException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $options = $this->getOptions($state); - - $client = $this->registry->getClient($options['client']); - - $requestOptions = [ - 'url' => $options['url'], - 'headers' => $options['headers'], - 'url_parameters' => $options['url_parameters'], - 'query_parameters' => $options['query_parameters'], - 'sends' => $options['sends'], - 'expects' => $options['expects'], - ]; - - $input = $state->getInput() ?: []; - $requestOptions = array_merge($requestOptions, $input); - $result = $client->call($requestOptions); - - // Handle empty results - if (!\in_array($result->code, $options['valid_response_code'], false)) { - $this->logger->error( - 'REST request failed', - [ - 'client' => $options['client'], - 'options' => $options, - 'raw_headers' => $result->raw_headers, - 'raw_body' => $result->raw_body, - ] - ); - $state->setErrorOutput($result->body); - - if ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { - $state->setSkipped(true); - } elseif ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { - $state->setStopped(true); - } - - return; - } - - $state->setOutput($result->body); - } - - /** - * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'client', - 'url', - 'method', - ] - ); - $resolver->setDefault('headers', []); - $resolver->setDefault('url_parameters', []); - $resolver->setDefault('query_parameters', []); - $resolver->setDefault('sends', 'json'); - $resolver->setDefault('expects', 'json'); - $resolver->setDefault('valid_response_code', [200]); - $resolver->setAllowedTypes('client', ['string']); - $resolver->setAllowedTypes('url', ['string']); - $resolver->setAllowedTypes('method', ['string']); - $resolver->setAllowedTypes('valid_response_code', ['array']); - } -} diff --git a/Addon/Rest/Transformer/RequestTransformer.php b/Addon/Rest/Transformer/RequestTransformer.php deleted file mode 100644 index 5b83ede3..00000000 --- a/Addon/Rest/Transformer/RequestTransformer.php +++ /dev/null @@ -1,130 +0,0 @@ - - */ -class RequestTransformer implements ConfigurableTransformerInterface -{ - - /** @var LoggerInterface */ - protected $logger; - - /** @var Registry */ - protected $registry; - - /** - * RequestTransformer constructor. - * - * @param Registry $registry - */ - public function __construct(LoggerInterface $logger, Registry $registry) - { - $this->logger = $logger; - $this->registry = $registry; - } - - /** - * {@inheritdoc} - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \RuntimeException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @throws \CleverAge\ProcessBundle\Addon\Rest\Exception\MissingClientException - */ - public function transform($value, array $options = []) - { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - $client = $this->registry->getClient($options['client']); - - $requestOptions = [ - 'url' => $options['url'], - 'headers' => $options['headers'], - 'url_parameters' => $options['url_parameters'], - 'query_parameters' => $options['query_parameters'], - 'sends' => $options['sends'], - 'expects' => $options['expects'], - ]; - - $input = $value ?: []; - $requestOptions = array_merge($requestOptions, $input); - $result = $client->call($requestOptions); - - // Handle empty results - if (!\in_array($result->code, $options['valid_response_code'], false)) { - $this->logger->error( - 'REST request failed', - [ - 'client' => $options['client'], - 'options' => $options, - 'raw_headers' => $result->raw_headers, - 'raw_body' => $result->raw_body, - ] - ); - - throw new TransformerException('REST request failed'); - } - - return $result->body; - } - - /** - * Returns the unique code to identify the transformer - * - * @return string - */ - public function getCode() - { - return 'rest_request'; - } - - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'client', - 'url', - 'method', - ] - ); - $resolver->setDefault('headers', []); - $resolver->setDefault('url_parameters', []); - $resolver->setDefault('query_parameters', []); - $resolver->setDefault('sends', 'json'); - $resolver->setDefault('expects', 'json'); - $resolver->setDefault('valid_response_code', [200]); - $resolver->setAllowedTypes('client', ['string']); - $resolver->setAllowedTypes('url', ['string']); - $resolver->setAllowedTypes('method', ['string']); - $resolver->setAllowedTypes('valid_response_code', ['array']); - } -} diff --git a/Addon/Soap/Client/Client.php b/Addon/Soap/Client/Client.php deleted file mode 100644 index 52e01552..00000000 --- a/Addon/Soap/Client/Client.php +++ /dev/null @@ -1,287 +0,0 @@ - - */ -class Client implements ClientInterface -{ - /** @var string */ - private $code; - - /** @var string|null */ - private $wsdl; - - /** @var array */ - private $options; - - /** @var LoggerInterface */ - private $logger; - - /** @var \SoapClient */ - private $soapClient; - - /** @var string */ - private $lastRequest; - - /** @var string */ - private $lastRequestHeaders; - - /** @var string */ - private $lastResponse; - - /** @var string */ - private $lastResponseHeaders; - - /** - * Client constructor. - * - * @param LoggerInterface $logger - * @param string $code - * @param string|null $wsdl - * @param array $options - */ - public function __construct(LoggerInterface $logger, string $code, ?string $wsdl, array $options) - { - $this->logger = $logger; - $this->code = $code; - $this->wsdl = $wsdl; - $this->options = $options; - } - - /** - * @return LoggerInterface - */ - public function getLogger(): LoggerInterface - { - return $this->logger; - } - - /** - * {@inheritdoc} - * @throws \UnexpectedValueException - */ - public function getCode(): string - { - if (!$this->code) { - throw new \UnexpectedValueException('Client code is not defined'); - } - - return $this->code; - } - - /** - * {@inheritdoc} - */ - public function getWsdl(): ?string - { - return $this->wsdl; - } - - /** - * {@inheritdoc} - */ - public function setWsdl(?string $wsdl): void - { - $this->wsdl = $wsdl; - } - - /** - * {@inheritdoc} - */ - public function getOptions(): array - { - return $this->options; - } - - /** - * {@inheritdoc} - */ - public function setOptions(array $options): void - { - $this->options = $options; - } - - /** - * @return \SoapClient|null - */ - public function getSoapClient(): ?\SoapClient - { - return $this->soapClient; - } - - /** - * @param \SoapClient $soapClient - */ - public function setSoapClient(\SoapClient $soapClient): void - { - $this->soapClient = $soapClient; - } - - /** - * @return string - */ - public function getLastRequest(): string - { - return $this->lastRequest; - } - - /** - * @param string $lastRequest - */ - public function setLastRequest(string $lastRequest): void - { - $this->lastRequest = $lastRequest; - } - - /** - * @return string - */ - public function getLastRequestHeaders(): string - { - return $this->lastRequestHeaders; - } - - /** - * @param string $lastRequestHeaders - */ - public function setLastRequestHeaders(string $lastRequestHeaders): void - { - $this->lastRequestHeaders = $lastRequestHeaders; - } - - /** - * @return string - */ - public function getLastResponse(): string - { - return $this->lastResponse; - } - - /** - * @param string $lastResponse - */ - public function setLastResponse(string $lastResponse): void - { - $this->lastResponse = $lastResponse; - } - - /** - * @return string - */ - public function getLastResponseHeaders(): string - { - return $this->lastResponseHeaders; - } - - /** - * @param string $lastResponseHeaders - */ - public function setLastResponseHeaders(string $lastResponseHeaders): void - { - $this->lastResponseHeaders = $lastResponseHeaders; - } - - /** - * {@inheritdoc} - */ - public function call(string $method, array $input = []) - { - $this->initializeSoapClient(); - - $callMethod = sprintf('soapCall%s', ucfirst($method)); - if (method_exists($this, $callMethod)) { - return $this->$callMethod($input); - } - - $this->getLogger()->notice( - sprintf("Soap call '%s' on '%s'", $method, $this->getWsdl()) - ); - - return $this->doSoapCall($method, $input); - } - - /** - * @param string $method - * @param array $input - * - * @return bool|mixed - */ - protected function doSoapCall(string $method, array $input = []) - { - if (!$this->getSoapClient()) { - throw new \InvalidArgumentException('Soap client is not initialized'); - } - try { - $result = $this->getSoapClient()->__soapCall($method, [$input]); - } /** @noinspection PhpRedundantCatchClauseInspection */ catch (\SoapFault $e) { - $this->getLastRequestTrace(); - $this->getLogger()->alert( - sprintf("Soap call '%s' on '%s' failed : %s", $method, $this->getWsdl(), $e->getMessage()), - $this->getLastRequestTraceArray() - ); - - return false; - } - - $this->getLastRequestTrace(); - - if (array_key_exists('trace', $this->getOptions()) && $this->getOptions()['trace']) { - $this->getLogger()->debug( - sprintf("Trace of soap call '%s' on '%s'", $method, $this->getWsdl()), - $this->getLastRequestTraceArray() - ); - } - - return $result; - } - - /** - * Initialize \SoapClient object - * - * @return void - */ - protected function initializeSoapClient(): void - { - if (!$this->getSoapClient()) { - $options = array_merge($this->getOptions(), ['trace' => true]); - $this->setSoapClient(new \SoapClient($this->getWsdl(), $options)); - } - } - - protected function getLastRequestTrace(): void - { - if ($this->getSoapClient()) { - $this->setLastRequest($this->getSoapClient()->__getLastRequest()); - $this->setLastRequestHeaders($this->getSoapClient()->__getLastRequestHeaders()); - $this->setLastResponse($this->getSoapClient()->__getLastResponse()); - $this->setLastResponseHeaders($this->getSoapClient()->__getLastResponseHeaders()); - } - } - - /** - * @return array - */ - protected function getLastRequestTraceArray(): array - { - return [ - 'LastRequest' => $this->getLastRequest(), - 'LastRequestHeaders' => $this->getLastRequestHeaders(), - 'LastResponse' => $this->getLastResponse(), - 'LastResponseHeaders' => $this->getLastResponseHeaders(), - ]; - } -} diff --git a/Addon/Soap/Client/ClientInterface.php b/Addon/Soap/Client/ClientInterface.php deleted file mode 100644 index 4874e988..00000000 --- a/Addon/Soap/Client/ClientInterface.php +++ /dev/null @@ -1,92 +0,0 @@ - - */ -interface ClientInterface -{ - /** - * Return the code of the client used in client registry. - * - * @return string - */ - public function getCode(): string; - - /** - * Return the URI of the WSDL file or NULL if working in non-WSDL mode. - * - * @return string - */ - public function getWsdl(): ?string; - - /** - * Set the URI of the WSDL file or NULL if working in non-WSDL mode. - * - * @param string $wsdl - * - * @return void - */ - public function setWsdl(?string $wsdl): void; - - /** - * Return the Soap client options - * - * @see http://php.net/manual/en/soapclient.soapclient.php - * - * @return array - */ - public function getOptions(): array; - - /** - * Set the Soap client options - * - * @see http://php.net/manual/en/soapclient.soapclient.php - * - * @param array $options - * - * @return void - */ - public function setOptions(array $options): void; - - /** - * @return string - */ - public function getLastRequest(): string; - - /** - * @return string - */ - public function getLastRequestHeaders(): string; - - /** - * @return string - */ - public function getLastResponse(): string; - - /** - * @return string - */ - public function getLastResponseHeaders(): string; - - /** - * Call Soap method - * - * @param string $method - * @param array $input - * - * @return mixed - */ - public function call(string $method, array $input = []); -} diff --git a/Addon/Soap/Exception/MissingClientException.php b/Addon/Soap/Exception/MissingClientException.php deleted file mode 100644 index 610e45e2..00000000 --- a/Addon/Soap/Exception/MissingClientException.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class MissingClientException extends \UnexpectedValueException implements ProcessExceptionInterface -{ - /** - * @param string $code - * - * @return MissingClientException - */ - public static function create($code) - { - $errorStr = "No Soap client with code : {$code}"; - - return new self($errorStr); - } -} diff --git a/Addon/Soap/Registry.php b/Addon/Soap/Registry.php deleted file mode 100644 index c8b10359..00000000 --- a/Addon/Soap/Registry.php +++ /dev/null @@ -1,70 +0,0 @@ - - */ -class Registry -{ - /** @var ClientInterface[] */ - private $clients = []; - - /** - * @param ClientInterface $client - */ - public function addClient(ClientInterface $client): void - { - if (array_key_exists($client->getCode(), $this->getClients())) { - throw new \UnexpectedValueException("Client {$client->getCode()} is already defined"); - } - $this->clients[$client->getCode()] = $client; - } - - /** - * @return ClientInterface[] - */ - public function getClients(): array - { - return $this->clients; - } - - /** - * @param string $code - * - * @throws MissingClientException - * - * @return ClientInterface - */ - public function getClient($code): ClientInterface - { - if (!$this->hasClient($code)) { - throw MissingClientException::create($code); - } - - return $this->getClients()[$code]; - } - - /** - * @param string $code - * - * @return bool - */ - public function hasClient($code): bool - { - return array_key_exists($code, $this->getClients()); - } -} diff --git a/Addon/Soap/Task/RequestTask.php b/Addon/Soap/Task/RequestTask.php deleted file mode 100644 index 940c88b9..00000000 --- a/Addon/Soap/Task/RequestTask.php +++ /dev/null @@ -1,102 +0,0 @@ - - */ -class RequestTask extends AbstractConfigurableTask -{ - - /** @var LoggerInterface */ - protected $logger; - - /** @var Registry */ - protected $registry; - - /** - * SoapClientTask constructor. - * - * @param LoggerInterface $logger - * @param Registry $registry - */ - public function __construct(LoggerInterface $logger, Registry $registry) - { - $this->logger = $logger; - $this->registry = $registry; - } - - /** - * {@inheritdoc} - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $options = $this->getOptions($state); - - $client = $this->registry->getClient($options['client']); - - $input = $state->getInput() ?: []; - - $result = $client->call($options['method'], $input); - - // Handle empty results - if (false === $result) { - $logContext = [ - 'options' => $options, - 'last_request' => $client->getLastRequest(), - 'last_request_headers' => $client->getLastRequestHeaders(), - 'last_response' => $client->getLastResponse(), - 'last_response_headers' => $client->getLastResponseHeaders(), - ]; - - $state->setErrorOutput($result); - - $this->logger->error('Empty resultset for query', $logContext); - - if ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { - $state->setSkipped(true); - } elseif ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { - $state->setStopped(true); - } - } - - $state->setOutput($result); - } - - /** - * {@inheritdoc} - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'client', - 'method', - ] - ); - $resolver->setAllowedTypes('client', ['string']); - $resolver->setAllowedTypes('method', ['string']); - } -} diff --git a/Addon/Soap/Transformer/RequestTransformer.php b/Addon/Soap/Transformer/RequestTransformer.php deleted file mode 100644 index 65afcfb8..00000000 --- a/Addon/Soap/Transformer/RequestTransformer.php +++ /dev/null @@ -1,86 +0,0 @@ - - */ -class RequestTransformer implements ConfigurableTransformerInterface -{ - /** @var Registry */ - protected $registry; - - /** - * RequestTransformer constructor. - * - * @param Registry $registry - */ - public function __construct(Registry $registry) - { - $this->registry = $registry; - } - - - /** - * {@inheritdoc} - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException - * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException - * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \RuntimeException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function transform($value, array $options = []) - { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - $client = $this->registry->getClient($options['client']); - - return $client->call($options['method'], $value); - } - - /** - * Returns the unique code to identify the transformer - * - * @return string - */ - public function getCode() - { - return 'soap_request'; - } - - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'client', - 'method', - ] - ); - $resolver->setAllowedTypes('client', ['string']); - $resolver->setAllowedTypes('method', ['string']); - } -} diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index 675db622..28da8497 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -10,9 +10,6 @@ namespace CleverAge\ProcessBundle; -use CleverAge\ProcessBundle\Addon\Rest\Registry as RestRegistry; -use CleverAge\ProcessBundle\Addon\Soap\Registry as SoapRegistry; -use CleverAge\ProcessBundle\DependencyInjection\Compiler\CachePoolPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -32,7 +29,7 @@ class CleverAgeProcessBundle extends Bundle * * @param ContainerBuilder $container */ - public function build(ContainerBuilder $container) + public function build(ContainerBuilder $container): void { $container->addCompilerPass( new RegistryCompilerPass( @@ -41,29 +38,5 @@ public function build(ContainerBuilder $container) 'addTransformer' ) ); - - if (extension_loaded('soap')) { - $container->addCompilerPass( - new RegistryCompilerPass( - SoapRegistry::class, - 'cleverage.soap.client', - 'addClient' - ) - ); - } - - if (class_exists('\Httpful\Request')) { - $container->addCompilerPass( - new RegistryCompilerPass( - RestRegistry::class, - 'cleverage.rest.client', - 'addClient' - ) - ); - } - -// $container->addCompilerPass( -// new CachePoolPass() -// ); } } diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index dfb937f1..f4a67e60 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -11,7 +11,6 @@ namespace CleverAge\ProcessBundle\DependencyInjection; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; -use Sidus\BaseBundle\DependencyInjection\Loader\ServiceLoader; use Sidus\BaseBundle\DependencyInjection\SidusBaseExtension; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -36,29 +35,6 @@ public function load(array $configs, ContainerBuilder $container) { parent::load($configs, $container); - $loader = new ServiceLoader($container); - $bundles = $container->getParameter('kernel.bundles'); - - if (class_exists('\Doctrine\ORM\Version')) { - $serviceFolderPath = __DIR__.'/../Resources/config/services-doctrine'; - $loader->loadFiles($serviceFolderPath); - } - - if (array_key_exists('OneupFlysystemBundle', $bundles)) { - $serviceFolderPath = __DIR__.'/Resources/config/services-flysystem'; - $loader->loadFiles($serviceFolderPath); - } - - if (extension_loaded('soap')) { - $serviceFolderPath = __DIR__.'/../Resources/config/services-soap'; - $loader->loadFiles($serviceFolderPath); - } - - if (class_exists('\Httpful\Request')) { - $serviceFolderPath = __DIR__.'/../Resources/config/services-rest'; - $loader->loadFiles($serviceFolderPath); - } - $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index 09b34956..a5dd83f6 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -18,7 +18,7 @@ The most common example is the ETL. It's a kind of application whose main purpos ## Installation -This bundle requires Symfony 3 and Doctrine. You can install it using composer: +This bundle requires Symfony 3. You can install it using composer: ```bash composer require cleverage/process-bundle diff --git a/Documentation/reference/tasks/doctrine_reader_task.md b/Documentation/reference/tasks/doctrine_reader_task.md deleted file mode 100644 index 8af89771..00000000 --- a/Documentation/reference/tasks/doctrine_reader_task.md +++ /dev/null @@ -1,35 +0,0 @@ -DoctrineReaderTask -================== - -Reads data from a Doctrine Repository. - -Task reference --------------- - -* **Service**: `CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineReaderTask` -* **Iterable task** - -Accepted inputs ---------------- - -Input is ignored - -Possible outputs ----------------- - -Iterate on an entity list returned by a Doctrine query. - -Options -------- - -All the criteria, order_by, limit and offset options behave like the [`EntityRepository::findBy`](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#by-simple-conditions) method. - -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `class_name` | `string` | **X** | | Class name of the entity | -| `criteria` | `array` | | `[]` | List of field => value to use while matching entities | -| `order_by` | `array` | | `[]` | List of field => direction | -| `limit` | `int` or `null` | | `null` | Result max count | -| `offset` | `int` or `null` | | `null` | Result first item offset | -| `entity_manager` | `string` or `null` | | `null` | Use another entity manager than the default | - diff --git a/Documentation/reference/tasks/doctrine_writer_task.md b/Documentation/reference/tasks/doctrine_writer_task.md deleted file mode 100644 index 1b20916b..00000000 --- a/Documentation/reference/tasks/doctrine_writer_task.md +++ /dev/null @@ -1,28 +0,0 @@ -DoctrineWriterTask -================== - -Write a Doctrine entity to the database. - -Task reference --------------- - -* **Service**: `CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineWriterTask` - -Accepted inputs ---------------- - -Any doctrine managed entity. - -Possible outputs ----------------- - -Re-output given entity. - -Options -------- - -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `entity_manager` | `string` or `null` | | `null` | Use another entity manager than the default | -| `global_flush` | `bool` | | `true` | Flush the whole entity manager after persist | - diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 5037c2d4..9ce5fa8d 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -25,7 +25,6 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\TaskInterface; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; -use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -49,9 +48,6 @@ class ProcessManager /** @var TaskLogger */ protected $taskLogger; - /** @var EntityManagerInterface */ - protected $entityManager; - /** @var ProcessConfigurationRegistry */ protected $processConfigurationRegistry; @@ -77,7 +73,6 @@ class ProcessManager * @param ContainerInterface $container * @param ProcessLogger $processLogger * @param TaskLogger $taskLogger - * @param EntityManagerInterface $entityManager * @param ProcessConfigurationRegistry $processConfigurationRegistry * @param ContextualOptionResolver $contextualOptionResolver */ @@ -85,14 +80,12 @@ public function __construct( ContainerInterface $container, ProcessLogger $processLogger, TaskLogger $taskLogger, - EntityManagerInterface $entityManager, ProcessConfigurationRegistry $processConfigurationRegistry, ContextualOptionResolver $contextualOptionResolver ) { $this->container = $container; $this->processLogger = $processLogger; $this->taskLogger = $taskLogger; - $this->entityManager = $entityManager; $this->processConfigurationRegistry = $processConfigurationRegistry; $this->contextualOptionResolver = $contextualOptionResolver; } @@ -488,7 +481,6 @@ protected function finalize(TaskConfiguration $taskConfiguration): void * * @throws \RuntimeException * @throws \InvalidArgumentException - * @throws \Doctrine\ORM\ORMInvalidArgumentException * * @return ProcessHistory */ diff --git a/README.md b/README.md index 36485500..784cbe39 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,6 @@ Basically, it will greatly ease the configuration of import and exports but can - [PropertyGetterTask](Documentation/reference/tasks/property_getter_task.md) - [PropertySetterTask](Documentation/reference/tasks/property_setter_task.md) - [TransformerTask](Documentation/reference/tasks/transformer_task.md) - - Entities - - [DoctrineReaderTask](Documentation/reference/tasks/doctrine_reader_task.md) - - [DoctrineWriterTask](Documentation/reference/tasks/doctrine_writer_task.md) - File/CSV - [CsvReaderTask](Documentation/reference/tasks/csv_reader_task.md) - [CsvWriterTask](Documentation/reference/tasks/csv_writer_task.md) @@ -161,7 +158,7 @@ clever_age_process: entry_point: read tasks: read: - service: '@CleverAge\ProcessBundle\Addon\Doctrine\Task\EntityManager\DoctrineReaderTask' + service: '@CleverAge\DoctrineProcessBundle\Task\EntityManager\DoctrineReaderTask' options: class_name: MyNamespace\FooBarBundle\Entity\Data outputs: [normalize] diff --git a/Resources/config/services-doctrine/task.yml b/Resources/config/services-doctrine/task.yml deleted file mode 100644 index 79e45e28..00000000 --- a/Resources/config/services-doctrine/task.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Doctrine\Task\: - resource: '../../../Addon/Doctrine/Task/*' - autowire: true - public: true - shared: false - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-flysystem/task.yml b/Resources/config/services-flysystem/task.yml deleted file mode 100644 index cf3ab04d..00000000 --- a/Resources/config/services-flysystem/task.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Flysystem\Task\: - resource: '../../../Addon/Flysystem/Task/*' - autowire: true - public: true - shared: false - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-rest/services.yml b/Resources/config/services-rest/services.yml deleted file mode 100644 index 2367cef4..00000000 --- a/Resources/config/services-rest/services.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Rest\Registry: - public: false diff --git a/Resources/config/services-rest/task.yml b/Resources/config/services-rest/task.yml deleted file mode 100644 index 54474d84..00000000 --- a/Resources/config/services-rest/task.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Rest\Task\: - resource: '../../../Addon/Rest/Task/*' - autowire: true - public: true - shared: false - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-rest/transformer.yml b/Resources/config/services-rest/transformer.yml deleted file mode 100644 index 6433c91e..00000000 --- a/Resources/config/services-rest/transformer.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Rest\Transformer\: - resource: '../../../Addon/Rest/Transformer/*' - autowire: true - public: false - tags: - - { name: cleverage.transformer } - - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Resources/config/services-soap/services.yml b/Resources/config/services-soap/services.yml deleted file mode 100644 index b5671af0..00000000 --- a/Resources/config/services-soap/services.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Soap\Registry: - public: false diff --git a/Resources/config/services-soap/task.yml b/Resources/config/services-soap/task.yml deleted file mode 100644 index 23996050..00000000 --- a/Resources/config/services-soap/task.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Soap\Task\: - resource: '../../../Addon/Soap/Task/*' - autowire: true - public: true - shared: false - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services-soap/transformer.yml b/Resources/config/services-soap/transformer.yml deleted file mode 100644 index a0a61274..00000000 --- a/Resources/config/services-soap/transformer.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\ProcessBundle\Addon\Soap\Transformer\: - resource: '../../../Addon/Soap/Transformer/*' - autowire: true - public: false - tags: - - { name: cleverage.transformer } - - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Resources/migration/move_doctrine_to_addon.sh b/Resources/migration/move_doctrine_to_addon.sh index f1dcafdb..8440915e 100644 --- a/Resources/migration/move_doctrine_to_addon.sh +++ b/Resources/migration/move_doctrine_to_addon.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Database/CleverAge\\ProcessBundle\\Addon\\Doctrine\\Task\\Database/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Doctrine/CleverAge\\ProcessBundle\\Addon\\Doctrine\\Task\\EntityManager/g' {} \; +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Database/CleverAge\\DoctrineProcessBundle\\Task\\Database/g' {} \; +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Doctrine/CleverAge\\DoctrineProcessBundle\\Task\\EntityManager/g' {} \; diff --git a/Resources/migration/move_flysystem_to_addon.sh b/Resources/migration/move_flysystem_to_addon.sh index c194a301..5dc78064 100644 --- a/Resources/migration/move_flysystem_to_addon.sh +++ b/Resources/migration/move_flysystem_to_addon.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\File\\FileFetchTask/CleverAge\\ProcessBundle\\Addon\\Flysystem\\Task\\FileFetchTask/g' {} \; +find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\File\\FileFetchTask/CleverAge\\FlysystemProcessBundle\\Task\\FileFetchTask/g' {} \; diff --git a/composer.json b/composer.json index e27c4972..7e2a57b2 100644 --- a/composer.json +++ b/composer.json @@ -58,10 +58,10 @@ "phpunit/phpunit": "~6.4" }, "suggest": { - "ext-soap": "*", - "doctrine/orm": "~2.5", - "doctrine/doctrine-bundle": "~1.6", - "oneup/flysystem-bundle": "~1.13", - "nategood/httpful": "~0.2.20" + "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", + "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", + "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", + "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", + "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle" } } From 3c5d6cbafbcd48686ea88988476d5b9b025d97bd Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 24 Apr 2019 19:28:52 +0200 Subject: [PATCH 037/304] Fixing comment style for licence and massive autoformat --- CleverAgeProcessBundle.php | 4 +- Command/ExecuteProcessCommand.php | 14 ++- Command/ListProcessCommand.php | 10 +- Command/ProcessHelpCommand.php | 68 ++++++++------ Configuration/ProcessConfiguration.php | 7 +- Configuration/TaskConfiguration.php | 8 +- Context/ContextualOptionResolver.php | 4 +- .../CleverAgeProcessExtension.php | 4 +- .../Compiler/CachePoolPass.php | 8 +- .../Compiler/RegistryCompilerPass.php | 8 +- DependencyInjection/Configuration.php | 4 +- Event/EventDispatcherTaskEvent.php | 4 +- EventListener/DataQueueEventListener.php | 4 +- Exception/CircularProcessException.php | 4 +- .../InvalidProcessConfigurationException.php | 4 +- Exception/MissingProcessException.php | 4 +- .../MissingTaskConfigurationException.php | 4 +- Exception/MissingTransformerException.php | 4 +- Exception/MultiBranchProcessException.php | 4 +- Exception/ProcessExceptionInterface.php | 4 +- Exception/TransformerException.php | 4 +- Filesystem/CsvFile.php | 4 +- Filesystem/CsvResource.php | 4 +- Filesystem/FileStreamInterface.php | 4 +- Logger/AbstractLogger.php | 4 +- Logger/AbstractProcessor.php | 4 +- Logger/ProcessLogger.php | 4 +- Logger/ProcessProcessor.php | 4 +- Logger/TaskLogger.php | 4 +- Logger/TaskProcessor.php | 5 +- Logger/TransformerProcessor.php | 5 +- Manager/ProcessManager.php | 4 +- Model/AbstractConfigurableTask.php | 4 +- Model/BlockingTaskInterface.php | 4 +- Model/FinalizableTaskInterface.php | 4 +- Model/FlushableTaskInterface.php | 4 +- Model/InitializableTaskInterface.php | 4 +- Model/IterableTaskInterface.php | 4 +- Model/ProcessHistory.php | 4 +- Model/ProcessState.php | 13 +-- Model/TaskInterface.php | 6 +- Registry/ProcessConfigurationRegistry.php | 4 +- Registry/TransformerRegistry.php | 4 +- Task/AbstractIterableOutputTask.php | 4 +- Task/AggregateIterableTask.php | 4 +- Task/ArrayMergeTask.php | 9 +- Task/Cache/AbstractCacheTask.php | 6 +- Task/Cache/DeleterTask.php | 4 +- Task/Cache/GetterTask.php | 4 +- Task/Cache/SetterTask.php | 4 +- Task/ColumnAggregatorTask.php | 6 +- Task/ConstantIterableOutputTask.php | 4 +- Task/ConstantOutputTask.php | 4 +- Task/CounterTask.php | 4 +- Task/Debug/DebugTask.php | 4 +- Task/Debug/DieTask.php | 4 +- Task/Debug/ErrorForwarderTask.php | 4 +- Task/Debug/MemInfoDumpTask.php | 4 +- Task/DummyTask.php | 4 +- Task/Event/EventDispatcherTask.php | 4 +- Task/File/Csv/AbstractCsvResourceTask.php | 4 +- Task/File/Csv/AbstractCsvTask.php | 4 +- Task/File/Csv/CsvReaderTask.php | 4 +- Task/File/Csv/CsvSplitterTask.php | 4 +- Task/File/Csv/CsvWriterTask.php | 6 +- Task/File/Csv/InputCsvReaderTask.php | 4 +- Task/File/FileMoverTask.php | 4 +- Task/File/FileRemoverTask.php | 4 +- Task/File/FileWriterTask.php | 4 +- Task/File/FolderBrowserTask.php | 4 +- Task/File/YamlReaderTask.php | 4 +- Task/File/YamlWriterTask.php | 4 +- Task/FilterTask.php | 4 +- Task/InputAggregatorTask.php | 16 ++-- Task/InputIteratorTask.php | 4 +- Task/IterableBatchTask.php | 4 +- Task/ObjectUpdaterTask.php | 4 +- Task/Process/ProcessExecutorTask.php | 4 +- Task/Process/ProcessLauncherTask.php | 4 +- Task/PropertyGetterTask.php | 4 +- Task/PropertySetterTask.php | 4 +- Task/Reporting/AdvancedStatCounterTask.php | 4 +- Task/Reporting/LoggerTask.php | 4 +- Task/Reporting/StatCounterTask.php | 4 +- Task/RowAggregatorTask.php | 4 +- Task/Serialization/DenormalizerTask.php | 4 +- Task/Serialization/NormalizerTask.php | 6 +- Task/Serialization/SerializerTask.php | 2 +- Task/SimpleBatchTask.php | 4 +- Task/SkipEmptyTask.php | 4 +- Task/SplitJoinLineTask.php | 4 +- Task/StopTask.php | 4 +- Task/TransformerTask.php | 4 +- Task/Validation/ValidatorTask.php | 4 +- Tests/AbstractProcessTest.php | 4 +- Tests/BasicTest.php | 26 +++--- Tests/BlockingTaskTest.php | 10 +- Tests/CircularProcessTest.php | 4 +- Tests/ContextTest.php | 22 ++++- Tests/ExceptionManagementTest.php | 28 +++--- Tests/FlushableTaskTest.php | 4 +- Tests/IterableTaskTest.php | 4 +- Tests/MultiBranchProcessTest.php | 93 +++++++++++++------ Tests/MultiWorkflowTest.php | 59 ++++++------ Tests/Task/Cache/DeleterTaskTest.php | 4 +- Tests/Task/Cache/GetterTaskTest.php | 4 +- Tests/Task/Cache/SetterTaskTest.php | 4 +- Tests/Task/ColumnAggregatorTaskTest.php | 39 ++++---- Tests/Task/FilterTaskTest.php | 4 +- Tests/Task/ProcessExecutorTaskTest.php | 4 +- Tests/Task/StopTaskTest.php | 10 +- Tests/Task/TransformerTaskTest.php | 4 +- Tests/Task/ValidatorTaskTest.php | 8 +- .../ArrayFilterTransformerTest.php | 15 +-- .../Cache/DeleterTransformerTest.php | 4 +- .../Cache/GetterTransformerTest.php | 4 +- .../Cache/SetterTransformerTest.php | 4 +- Tests/Transformer/CallbackTransformerTest.php | 4 +- Tests/Transformer/DateTransformersTest.php | 14 ++- Tests/Transformer/HashTransformerTest.php | 9 +- Tests/Transformer/MappingTransformerTest.php | 9 +- .../Transformer/TypeSetterTransformerTest.php | 4 +- Tests/Transformer/UnsetTransformerTest.php | 12 +-- Transformer/ArrayElementTransformer.php | 4 +- Transformer/ArrayFilterTransformer.php | 5 +- Transformer/ArrayFirstTransformer.php | 4 +- Transformer/ArrayLastTransformer.php | 4 +- Transformer/ArrayMapTransformer.php | 12 ++- .../Cache/AbstractCacheTransformer.php | 4 +- Transformer/Cache/DeleterTransformer.php | 4 +- Transformer/Cache/GetterTransformer.php | 4 +- Transformer/Cache/SetterTransformer.php | 4 +- Transformer/CallbackTransformer.php | 9 +- Transformer/ConditionTrait.php | 17 ++-- .../ConfigurableTransformerInterface.php | 4 +- Transformer/ConvertValueTransformer.php | 4 +- Transformer/DateFormatTransformer.php | 8 +- Transformer/DateParserTransformer.php | 4 +- Transformer/DefaultTransformer.php | 4 +- Transformer/DenormalizeTransformer.php | 4 +- Transformer/EvaluatorTransformer.php | 4 +- Transformer/ExplodeTransformer.php | 4 +- Transformer/HashTransformer.php | 4 +- Transformer/ImplodeTransformer.php | 4 +- Transformer/MappingTransformer.php | 4 +- Transformer/NormalizeTransformer.php | 4 +- Transformer/PregFilterTransformer.php | 4 +- Transformer/PropertyAccessorTransformer.php | 4 +- .../RecursivePropertySetterTransformer.php | 4 +- Transformer/SlugifyTransformer.php | 4 +- Transformer/SprintfTransformer.php | 4 +- Transformer/TransformerInterface.php | 4 +- Transformer/TransformerTrait.php | 20 ++-- Transformer/TrimTransformer.php | 4 +- Transformer/TypeSetterTransformer.php | 4 +- Transformer/UnsetTransformer.php | 4 +- Transformer/WrapperTransformer.php | 4 +- 157 files changed, 613 insertions(+), 491 deletions(-) diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index 28da8497..478e9eae 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -1,5 +1,5 @@ -addOption('input', 'i', InputOption::VALUE_REQUIRED, 'Pass input data to the first task of the process'); $this->addOption('input-from-stdin', null, InputOption::VALUE_NONE, 'Read input data from stdin'); - $this->addOption('context', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Contextual value', []); + $this->addOption( + 'context', + 'c', + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Contextual value', + [] + ); } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @throws \Exception diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index a4904f91..6f7cfc03 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -1,5 +1,5 @@ -writeln("There are {$publicCount} process configurations defined (and {$privateCount} private) :"); + $output->writeln( + "There are {$publicCount} process configurations defined (and {$privateCount} private) :" + ); $messages = []; foreach ($processConfigurations as $processConfiguration) { @@ -74,7 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $messages[] = [ 'process' => $processConfiguration, - 'output' => $message, + 'output' => $message, ]; } } diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index d69240e5..777c90ab 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -1,5 +1,5 @@ -processConfigRegistry->getProcessConfiguration($processCode); $output->writeln("Process: "); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $processCode); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); $output->writeln(''); if ($process->getDescription()) { $output->writeln("Description:"); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $process->getDescription()); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); $output->writeln(''); } @@ -109,7 +109,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln("Help:"); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $helpLine); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$helpLine); } $output->writeln(''); } @@ -128,14 +128,17 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->resolveBranchOutput($branches, $nextTaskCode, $process, $output); // Remove the task from the remaining list - $remainingTasks = array_filter($remainingTasks, function ($task) use ($nextTaskCode) { - return $task != $nextTaskCode; - }); + $remainingTasks = array_filter( + $remainingTasks, + function ($task) use ($nextTaskCode) { + return $task != $nextTaskCode; + } + ); } $branches = array_filter($branches); if (!empty($branches)) { - $branchStr = '[' . implode(', ', $branches) . ']'; + $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } } @@ -160,9 +163,13 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ } // Check if task has all necessary ancestors in branches - $hasAllAncestors = array_reduce($task->getPreviousTasksConfigurations(), function ($result, TaskConfiguration $prevTask) use ($branches) { - return $result && \in_array($prevTask->getCode(), $branches); - }, true); + $hasAllAncestors = array_reduce( + $task->getPreviousTasksConfigurations(), + function ($result, TaskConfiguration $prevTask) use ($branches) { + return $result && \in_array($prevTask->getCode(), $branches); + }, + true + ); if ($hasAllAncestors) { $taskCandidates[] = $taskCode; @@ -199,9 +206,12 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ $bestCandidate = key($taskWeights); $bestWeight = $taskWeights[$bestCandidate]; - $equalWeights = array_filter($taskWeights, function ($item) use ($bestWeight) { - return $item == $bestWeight; - }); + $equalWeights = array_filter( + $taskWeights, + function ($item) use ($bestWeight) { + return $item == $bestWeight; + } + ); if (count($equalWeights) == 1) { return $bestCandidate; @@ -249,8 +259,12 @@ protected function getTaskChildrenCount(TaskConfiguration $task) * @param ProcessConfiguration $process * @param OutputInterface $output */ - protected function resolveBranchOutput(&$branches, $taskCode, ProcessConfiguration $process, OutputInterface $output) - { + protected function resolveBranchOutput( + &$branches, + $taskCode, + ProcessConfiguration $process, + OutputInterface $output + ) { $task = $process->getTaskConfiguration($taskCode); $branchesToMerge = []; $gapBranches = []; @@ -381,18 +395,20 @@ function ($branchTask, $i) use ($taskCode) { if ($output->isVerbose() && $task->getHelp()) { $helpLines = array_filter(explode("\n", $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE)."{$helpLine}"; $this->writeBranches($output, $branches, $helpMessage); } } // Check next tasks - $nextTasks = array_unique(array_map( - function (TaskConfiguration $task) { - return $task->getCode(); - }, - array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) - )); + $nextTasks = array_unique( + array_map( + function (TaskConfiguration $task) { + return $task->getCode(); + }, + array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) + ) + ); if (\count($nextTasks) > 1) { $this->writeBranches($output, $branches); array_shift($nextTasks); @@ -540,11 +556,11 @@ protected function getTaskDescription(TaskConfiguration $task) } if (\count($interfaces)) { - $description .= ' (' . implode(', ', $interfaces) . ')'; + $description .= ' ('.implode(', ', $interfaces).')'; } if (\count($subprocess)) { - $description .= ' {' . implode(', ', $subprocess) . '}'; + $description .= ' {'.implode(', ', $subprocess).'}'; } if ($task->getDescription()) { diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index dccddbe2..1931c388 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -1,5 +1,5 @@ -code = $code; $this->taskConfigurations = $taskConfigurations; $this->options = $options; diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index 509dac3c..b2b39ef3 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -1,5 +1,5 @@ - * @author Vincent Chalnot diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 79b1e7a2..2f2a358c 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -1,5 +1,5 @@ -setDefault('merge_function', 'array_merge'); $resolver->setAllowedTypes('merge_function', 'string'); - $resolver->setAllowedValues('merge_function', ['array_merge', 'array_merge_recursive', 'array_replace', 'array_replace_recursive']); + $resolver->setAllowedValues( + 'merge_function', + ['array_merge', 'array_merge_recursive', 'array_replace', 'array_replace_recursive'] + ); } diff --git a/Task/Cache/AbstractCacheTask.php b/Task/Cache/AbstractCacheTask.php index c9451371..87dd2635 100644 --- a/Task/Cache/AbstractCacheTask.php +++ b/Task/Cache/AbstractCacheTask.php @@ -1,5 +1,5 @@ - */ diff --git a/Task/ConstantIterableOutputTask.php b/Task/ConstantIterableOutputTask.php index 21542b9d..22c20ac9 100644 --- a/Task/ConstantIterableOutputTask.php +++ b/Task/ConstantIterableOutputTask.php @@ -1,5 +1,5 @@ -format('Ymd'), (new \DateTime())->format('Ymd_His'), - uniqid() + uniqid(), ], $value ); diff --git a/Task/File/Csv/InputCsvReaderTask.php b/Task/File/Csv/InputCsvReaderTask.php index 82596f76..661c7438 100644 --- a/Task/File/Csv/InputCsvReaderTask.php +++ b/Task/File/Csv/InputCsvReaderTask.php @@ -1,5 +1,5 @@ -setRequired('input_codes'); - $resolver->setDefaults([ - 'clean_input_on_override' => true, - 'keep_inputs' => null, - ]); + $resolver->setDefaults( + [ + 'clean_input_on_override' => true, + 'keep_inputs' => null, + ] + ); $resolver->setAllowedTypes('input_codes', 'array'); $resolver->setAllowedTypes('clean_input_on_override', 'boolean'); $resolver->setAllowedTypes('keep_inputs', ['NULL', 'array']); diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index e0078599..163e415c 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -1,5 +1,5 @@ -getOptions($state); if (!$this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { - throw new \UnexpectedValueException('Given value is not normalizable for format ' . $options['format']); + throw new \UnexpectedValueException('Given value is not normalizable for format '.$options['format']); } $normalizedData = $this->normalizer->normalize( diff --git a/Task/Serialization/SerializerTask.php b/Task/Serialization/SerializerTask.php index ffd93a3f..3dcb93e1 100644 --- a/Task/Serialization/SerializerTask.php +++ b/Task/Serialization/SerializerTask.php @@ -1,6 +1,6 @@ assertDataQueue( [ [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 1, ], [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 2, ], [ - 'task' => 'doNothing', + 'task' => 'doNothing', 'value' => 3, ], - ], 'test.error_process'); + ], + 'test.error_process' + ); } /** @@ -68,21 +70,23 @@ public function testErrorProcessBlocking() $this->assertDataQueue( [ [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 1, ], [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 2, ], [ - 'task' => 'doNothing2', + 'task' => 'doNothing2', 'value' => 3, ], [ - 'task' => 'aggregate', + 'task' => 'aggregate', 'value' => [1, 2, 3], ], - ], 'test.error_process_with_blocking'); + ], + 'test.error_process_with_blocking' + ); } } diff --git a/Tests/BlockingTaskTest.php b/Tests/BlockingTaskTest.php index 29c11d72..47805513 100644 --- a/Tests/BlockingTaskTest.php +++ b/Tests/BlockingTaskTest.php @@ -1,5 +1,5 @@ -assertDataQueue( [ [ - 'task' => 'aggregate', + 'task' => 'aggregate', 'value' => [1, 2, 3, 1, 2, 3, 1, 2, 3], ], - ], 'test.multiple_iteration_blocking'); + ], + 'test.multiple_iteration_blocking' + ); } /** diff --git a/Tests/CircularProcessTest.php b/Tests/CircularProcessTest.php index 2883875b..335c079b 100644 --- a/Tests/CircularProcessTest.php +++ b/Tests/CircularProcessTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.context.multi_values', null, ['value1' => 'red', 'value2' => 'dead']); + $result = $this->processManager->execute( + 'test.context.multi_values', + null, + ['value1' => 'red', 'value2' => 'dead'] + ); self::assertEquals('red is dead', $result); } @@ -56,7 +60,11 @@ public function testContextMultiValue() */ public function testContextCannotMergeValue() { - $this->processManager->execute('test.context.merged_value', null, ['value' => ['another_key' => 'another_value']]); + $this->processManager->execute( + 'test.context.merged_value', + null, + ['value' => ['another_key' => 'another_value']] + ); } /** @@ -68,7 +76,11 @@ public function testComplexContext() self::assertEquals(['another_key' => 'another_value'], $result); - $result = $this->processManager->execute('test.context.sub_value', null, ['value' => ['another_key' => 'another_value']]); + $result = $this->processManager->execute( + 'test.context.sub_value', + null, + ['value' => ['another_key' => 'another_value']] + ); self::assertEquals(['key' => ['another_key' => 'another_value']], $result); } diff --git a/Tests/ExceptionManagementTest.php b/Tests/ExceptionManagementTest.php index 15543ce7..790052cd 100644 --- a/Tests/ExceptionManagementTest.php +++ b/Tests/ExceptionManagementTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.exception_management.set_exception_in_the_middle'); - self::assertEquals([ - 'abc', - 'bcd', - 'cde', - 'def', - ], $result['success']); + self::assertEquals( + [ + 'abc', + 'bcd', + 'cde', + 'def', + ], + $result['success'] + ); - self::assertEquals([ - 1 - ], $result['errors']); + self::assertEquals( + [ + 1, + ], + $result['errors'] + ); } } diff --git a/Tests/FlushableTaskTest.php b/Tests/FlushableTaskTest.php index f66799aa..552b1ca4 100644 --- a/Tests/FlushableTaskTest.php +++ b/Tests/FlushableTaskTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.multi_branch_process_first'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data1', - 'value' => 'ok', + [ + 'task' => 'data1', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_first'); + 'test.multi_branch_process_first' + ); $this->processManager->execute('test.multi_branch_process_entry'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry'); + 'test.multi_branch_process_entry' + ); $this->processManager->execute('test.multi_branch_process_entry_reversed'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry'); + 'test.multi_branch_process_entry' + ); $this->processManager->execute('test.multi_branch_process_end'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_end'); + 'test.multi_branch_process_end' + ); $this->processManager->execute('test.multi_branch_process_entry_end'); - $this->assertDataQueue([ + $this->assertDataQueue( [ - 'task' => 'data2', - 'value' => 'ok', + [ + 'task' => 'data2', + 'value' => 'ok', + ], ], - ], 'test.multi_branch_process_entry_end'); + 'test.multi_branch_process_entry_end' + ); } public function testMainGroupOrder() { $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_first'); - self::assertEquals(['data1', 'pushDataEvent1'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_first'); + self::assertEquals( + ['data1', 'pushDataEvent1'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_first' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry' + ); - $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry_reversed'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry_reversed'); + $process = $this->processConfigurationRegistry->getProcessConfiguration( + 'test.multi_branch_process_entry_reversed' + ); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry_reversed' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_end'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_end'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_end' + ); $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_entry_end'); - self::assertEquals(['data2', 'pushDataEvent2'], $process->getMainTaskGroup(),'Failed testing task order with process test.multi_branch_process_entry_end'); + self::assertEquals( + ['data2', 'pushDataEvent2'], + $process->getMainTaskGroup(), + 'Failed testing task order with process test.multi_branch_process_entry_end' + ); } /** diff --git a/Tests/MultiWorkflowTest.php b/Tests/MultiWorkflowTest.php index eb147f96..a77cb486 100644 --- a/Tests/MultiWorkflowTest.php +++ b/Tests/MultiWorkflowTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.multi_workflow_process'); - $this->assertDataQueue([ - [ - 'task' => 'data', - 'value' => 1, - ], - [ - 'task' => 'data', - 'value' => 2, - ], - [ - 'task' => 'data', - 'value' => 3, - ], - [ - 'task' => 'aggregate', - 'value' => [1, 2, 3], - ], - [ - 'task' => 'aggregate2', - 'value' => [1, 2, 3], - ], + $this->assertDataQueue( [ - 'task' => 'inputAggregate', - 'value' => [ - 'aggregate' => [1, 2, 3], - 'aggregate2' => [1, 2, 3], + [ + 'task' => 'data', + 'value' => 1, + ], + [ + 'task' => 'data', + 'value' => 2, + ], + [ + 'task' => 'data', + 'value' => 3, + ], + [ + 'task' => 'aggregate', + 'value' => [1, 2, 3], + ], + [ + 'task' => 'aggregate2', + 'value' => [1, 2, 3], + ], + [ + 'task' => 'inputAggregate', + 'value' => [ + 'aggregate' => [1, 2, 3], + 'aggregate2' => [1, 2, 3], + ], ], ], - ], 'test.multi_workflow_process'); + 'test.multi_workflow_process' + ); } } diff --git a/Tests/Task/Cache/DeleterTaskTest.php b/Tests/Task/Cache/DeleterTaskTest.php index 0bda84be..25265ef7 100644 --- a/Tests/Task/Cache/DeleterTaskTest.php +++ b/Tests/Task/Cache/DeleterTaskTest.php @@ -1,5 +1,5 @@ - 'B', 'col2' => 'val4']; $input = [$input1, $input2, $input3, $input4]; - self::assertEquals([ - 'aggregateAny' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => $input, + self::assertEquals( + [ + 'aggregateAny' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => $input, + ], ], - ], - 'aggregateA' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => [$input1,$input3], + 'aggregateA' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => [$input1, $input3], + ], ], - ], - 'aggregateB' => [ - 'col1' => [ - 'column' => 'col1', - 'values' => [$input2,$input4], + 'aggregateB' => [ + 'col1' => [ + 'column' => 'col1', + 'values' => [$input2, $input4], + ], ], ], - ], $this->processManager->execute('test.column_aggregator_task.simple', $input)); + $this->processManager->execute('test.column_aggregator_task.simple', $input) + ); } } diff --git a/Tests/Task/FilterTaskTest.php b/Tests/Task/FilterTaskTest.php index 12ed4455..a7a70bf6 100644 --- a/Tests/Task/FilterTaskTest.php +++ b/Tests/Task/FilterTaskTest.php @@ -1,5 +1,5 @@ -assertDataQueue( [ [ - 'task' => 'data', + 'task' => 'data', 'value' => 1, ], - ], 'test.task.stop_task.iterable_interruption'); + ], + 'test.task.stop_task.iterable_interruption' + ); } } diff --git a/Tests/Task/TransformerTaskTest.php b/Tests/Task/TransformerTaskTest.php index 4888b35b..de557f54 100644 --- a/Tests/Task/TransformerTaskTest.php +++ b/Tests/Task/TransformerTaskTest.php @@ -1,5 +1,5 @@ - 42, - 'any_field' => 'hello', + 'int_field' => 42, + 'any_field' => 'hello', 'choice_field' => 'Some random value 1', ]; $result = $this->processManager->execute('test.validator_task', $input); diff --git a/Tests/Transformer/ArrayFilterTransformerTest.php b/Tests/Transformer/ArrayFilterTransformerTest.php index b2bfed12..825e1584 100644 --- a/Tests/Transformer/ArrayFilterTransformerTest.php +++ b/Tests/Transformer/ArrayFilterTransformerTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.array_filter_transformer.simple', $input); - $nativeResult = array_filter($input, function ($item) { - return isset($item['filter_value']) && $item['filter_value'] === 'X'; - }); + $nativeResult = array_filter( + $input, + function ($item) { + return isset($item['filter_value']) && $item['filter_value'] === 'X'; + } + ); // Note that to match native function, key are preserved $expectedResult = [ 0 => ['data' => 1, 'filter_value' => 'X'], - 3 => ['data' => 4, 'filter_value' => 'X'] + 3 => ['data' => 4, 'filter_value' => 'X'], ]; self::assertCount(2, $result); diff --git a/Tests/Transformer/Cache/DeleterTransformerTest.php b/Tests/Transformer/Cache/DeleterTransformerTest.php index be2ae977..50da784c 100644 --- a/Tests/Transformer/Cache/DeleterTransformerTest.php +++ b/Tests/Transformer/Cache/DeleterTransformerTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.date_transformers.date_parser', '2001-01-01'); // There could be a 1s difference, depending on execution time... - $date->setTime(0,0); - $result->setTime(0,0); + $date->setTime(0, 0); + $result->setTime(0, 0); self::assertInstanceOf(\DateTime::class, $result); if ($result instanceof \DateTime) { @@ -58,6 +58,7 @@ public function testDateParser() /** * Assert that a date is not parsed if the format doesn't match + * * @expectedException \RuntimeException */ public function testDateParserError() @@ -70,7 +71,10 @@ public function testDateParserError() */ public function testDateParseFormat() { - $result = $this->processManager->execute('test.date_transformers.date_parse_format', '2001-01-01T00:00:00+00:00'); + $result = $this->processManager->execute( + 'test.date_transformers.date_parse_format', + '2001-01-01T00:00:00+00:00' + ); self::assertEquals('2001-01-01', $result); } } diff --git a/Tests/Transformer/HashTransformerTest.php b/Tests/Transformer/HashTransformerTest.php index 19b656c4..ea3f7bfa 100644 --- a/Tests/Transformer/HashTransformerTest.php +++ b/Tests/Transformer/HashTransformerTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.hash_transformer.sha512', 'This is a string'); - self::assertEquals('f4d54d32e3523357ff023903eaba2721e8c8cfc7702663782cb3e52faf2c56c002cc3096b5f2b6df870be665d0040e9963590eb02d03d166e52999cd1c430db1', $result); + self::assertEquals( + 'f4d54d32e3523357ff023903eaba2721e8c8cfc7702663782cb3e52faf2c56c002cc3096b5f2b6df870be665d0040e9963590eb02d03d166e52999cd1c430db1', + $result + ); } } diff --git a/Tests/Transformer/MappingTransformerTest.php b/Tests/Transformer/MappingTransformerTest.php index 8f90b676..b78cfede 100644 --- a/Tests/Transformer/MappingTransformerTest.php +++ b/Tests/Transformer/MappingTransformerTest.php @@ -1,5 +1,5 @@ -processManager->execute('test.mapping_transformer.multi_subtransformers', ['field' => [3, null, 4, 2]]); + $result = $this->processManager->execute( + 'test.mapping_transformer.multi_subtransformers', + ['field' => [3, null, 4, 2]] + ); self::assertEquals(['field2' => [2, 4, 3]], $result); } diff --git a/Tests/Transformer/TypeSetterTransformerTest.php b/Tests/Transformer/TypeSetterTransformerTest.php index 518a5eac..00899813 100644 --- a/Tests/Transformer/TypeSetterTransformerTest.php +++ b/Tests/Transformer/TypeSetterTransformerTest.php @@ -1,5 +1,5 @@ - 1, + 'other' => 1, 'to_unset' => 1, - 'to_test' => 2, + 'to_test' => 2, ]; $result = $this->processManager->execute('test.unset_transformer.simple', $input); self::assertEquals(['other' => 1, 'to_test' => 2], $result); @@ -38,9 +38,9 @@ public function testSimpleUnset() public function testConditionalUnset() { $input = [ - 'other' => 1, + 'other' => 1, 'to_unset' => 1, - 'to_test' => 2, + 'to_test' => 2, ]; // Should unset diff --git a/Transformer/ArrayElementTransformer.php b/Transformer/ArrayElementTransformer.php index dd2ea384..cd89cb37 100644 --- a/Transformer/ArrayElementTransformer.php +++ b/Transformer/ArrayElementTransformer.php @@ -1,5 +1,5 @@ -setAllowedTypes('transformers', ['array']); - $resolver->setDefaults([ - 'skip_null' => false, - ]); + $resolver->setDefaults( + [ + 'skip_null' => false, + ] + ); $resolver->setAllowedTypes('skip_null', ['boolean']); /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( diff --git a/Transformer/Cache/AbstractCacheTransformer.php b/Transformer/Cache/AbstractCacheTransformer.php index 9e0b1071..87161cd0 100644 --- a/Transformer/Cache/AbstractCacheTransformer.php +++ b/Transformer/Cache/AbstractCacheTransformer.php @@ -1,5 +1,5 @@ -setDefault($wrapperKey, []); $resolver->setAllowedTypes($wrapperKey, ['array']); - $resolver->setNormalizer($wrapperKey, function (OptionsResolver $options, $value) { - $conditionResolver = new OptionsResolver(); - $this->configureConditionOptions($conditionResolver); + $resolver->setNormalizer( + $wrapperKey, + function (OptionsResolver $options, $value) { + $conditionResolver = new OptionsResolver(); + $this->configureConditionOptions($conditionResolver); - return $conditionResolver->resolve($value); - }); + return $conditionResolver->resolve($value); + } + ); } /** diff --git a/Transformer/ConfigurableTransformerInterface.php b/Transformer/ConfigurableTransformerInterface.php index dcb55d0b..19c4f4b4 100644 --- a/Transformer/ConfigurableTransformerInterface.php +++ b/Transformer/ConfigurableTransformerInterface.php @@ -1,5 +1,5 @@ - Date: Wed, 24 Apr 2019 20:35:38 +0200 Subject: [PATCH 038/304] Removing dependency to swiftmailer --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 2879fe16..9cb59464 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,6 @@ "symfony/process": "~3.0|~4.0", "symfony/property-access": "~3.0|~4.0", "symfony/serializer": "~3.0|~4.0", - "symfony/swiftmailer-bundle": "~3.0|~4.0", "symfony/validator": "~3.0|~4.0", "symfony/yaml": "~3.0|~4.0", "sidus/base-bundle": "~1.0" From 8c79416f3effeb511d27a68139cd2f8017f823f7 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Thu, 25 Apr 2019 11:43:31 +0200 Subject: [PATCH 039/304] Removing cache-related tasks and transformers, moving them to separate bundle --- .../Compiler/CachePoolPass.php | 54 ------- Documentation/reference/addons/cache.md | 33 ----- Resources/config/services/task.yml | 5 - Resources/config/services/transformer.yml | 5 - Resources/tests/task/cache_deleter_task.yml | 65 --------- Resources/tests/task/cache_getter_task.yml | 86 ------------ Resources/tests/task/cache_setter_task.yml | 75 ---------- .../transfomer/cache_deleter_transformer.yml | 94 ------------- .../transfomer/cache_getter_transformer.yml | 118 ---------------- .../transfomer/cache_setter_transformer.yml | 104 -------------- Task/Cache/AbstractCacheTask.php | 123 ---------------- Task/Cache/DeleterTask.php | 37 ----- Task/Cache/GetterTask.php | 40 ------ Task/Cache/SetterTask.php | 72 ---------- Tests/BasicTest.php | 3 +- Tests/CircularProcessTest.php | 3 +- Tests/MultiBranchProcessTest.php | 3 +- Tests/Task/Cache/DeleterTaskTest.php | 129 ----------------- Tests/Task/Cache/GetterTaskTest.php | 111 --------------- Tests/Task/Cache/SetterTaskTest.php | 128 ----------------- .../Cache/DeleterTransformerTest.php | 132 ------------------ .../Cache/GetterTransformerTest.php | 122 ---------------- .../Cache/SetterTransformerTest.php | 130 ----------------- .../Cache/AbstractCacheTransformer.php | 122 ---------------- Transformer/Cache/DeleterTransformer.php | 42 ------ Transformer/Cache/GetterTransformer.php | 67 --------- Transformer/Cache/SetterTransformer.php | 83 ----------- 27 files changed, 6 insertions(+), 1980 deletions(-) delete mode 100644 DependencyInjection/Compiler/CachePoolPass.php delete mode 100644 Documentation/reference/addons/cache.md delete mode 100644 Resources/tests/task/cache_deleter_task.yml delete mode 100644 Resources/tests/task/cache_getter_task.yml delete mode 100644 Resources/tests/task/cache_setter_task.yml delete mode 100644 Resources/tests/transfomer/cache_deleter_transformer.yml delete mode 100644 Resources/tests/transfomer/cache_getter_transformer.yml delete mode 100644 Resources/tests/transfomer/cache_setter_transformer.yml delete mode 100644 Task/Cache/AbstractCacheTask.php delete mode 100644 Task/Cache/DeleterTask.php delete mode 100644 Task/Cache/GetterTask.php delete mode 100644 Task/Cache/SetterTask.php delete mode 100644 Tests/Task/Cache/DeleterTaskTest.php delete mode 100644 Tests/Task/Cache/GetterTaskTest.php delete mode 100644 Tests/Task/Cache/SetterTaskTest.php delete mode 100644 Tests/Transformer/Cache/DeleterTransformerTest.php delete mode 100644 Tests/Transformer/Cache/GetterTransformerTest.php delete mode 100644 Tests/Transformer/Cache/SetterTransformerTest.php delete mode 100644 Transformer/Cache/AbstractCacheTransformer.php delete mode 100644 Transformer/Cache/DeleterTransformer.php delete mode 100644 Transformer/Cache/GetterTransformer.php delete mode 100644 Transformer/Cache/SetterTransformer.php diff --git a/DependencyInjection/Compiler/CachePoolPass.php b/DependencyInjection/Compiler/CachePoolPass.php deleted file mode 100644 index ab872418..00000000 --- a/DependencyInjection/Compiler/CachePoolPass.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -class CachePoolPass implements CompilerPassInterface -{ - /** - * Inject tagged services into defined registry - * - * @param ContainerBuilder $container - * - * @throws InvalidArgumentException - * @throws \UnexpectedValueException - * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException - * @throws \Exception - * @api - * - */ - public function process(ContainerBuilder $container) - { - $name = 'cache.app.cleverage_process'; - $pool = [ - 'adapter' => 'cache.app', - 'public' => true, - ]; - $definition = new ChildDefinition($pool['adapter']); - $container->registerAliasForArgument($name, CacheInterface::class); - $container->registerAliasForArgument($name, CacheItemPoolInterface::class); - $definition->setPublic($pool['public']); - - $definition->addTag('cache.pool'); - $container->setDefinition($name, $definition); - } -} diff --git a/Documentation/reference/addons/cache.md b/Documentation/reference/addons/cache.md deleted file mode 100644 index facc4d43..00000000 --- a/Documentation/reference/addons/cache.md +++ /dev/null @@ -1,33 +0,0 @@ -Cache addon -=========== - -Contains tasks and transformers to handle cache. - -Activation ----------- - -Activated if cache pool `cleverage_process` is defined. - -Task reference --------------- - -* **Service**: `CleverAge\ProcessBundle\Transformer\ArrayFilterTransformer` -* **Transformer code**: `array_filter` - -Accepted inputs ---------------- - -`array` or `\Iterable` - -Possible outputs ----------------- - -`array` containing only filtered data - -Options -------- - -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `condition` | `array` | | `[]` | See [ConditionTrait](TODO) | -____ diff --git a/Resources/config/services/task.yml b/Resources/config/services/task.yml index 04eed02e..61e64bf7 100644 --- a/Resources/config/services/task.yml +++ b/Resources/config/services/task.yml @@ -6,8 +6,3 @@ services: shared: false tags: - { name: monolog.logger, channel: cleverage_process_task } - - CleverAge\ProcessBundle\Task\Cache\: - resource: '../../../Task/Cache\*' - arguments: - $cache: '@cache.app' diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml index a88f4f5b..a058d18c 100644 --- a/Resources/config/services/transformer.yml +++ b/Resources/config/services/transformer.yml @@ -6,8 +6,3 @@ services: tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } - - CleverAge\ProcessBundle\Transformer\Cache\: - resource: '../../../Transformer/Cache\*' - arguments: - $cache: '@cache.app' diff --git a/Resources/tests/task/cache_deleter_task.yml b/Resources/tests/task/cache_deleter_task.yml deleted file mode 100644 index 7ce7165a..00000000 --- a/Resources/tests/task/cache_deleter_task.yml +++ /dev/null @@ -1,65 +0,0 @@ -clever_age_process: - configurations: - test.cache_deleter_task.delete_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' - options: - key: - constant: 'DeleterTaskTest_testDeleteExistingCache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_task.delete_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' - options: - key: - constant: 'DeleterTaskTest_testDeleteMissingCache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_task.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' - options: - key: - transformers: - implode: - separator: '_' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_task.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\DeleterTask' - options: - key: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/task/cache_getter_task.yml b/Resources/tests/task/cache_getter_task.yml deleted file mode 100644 index 3bd06b5e..00000000 --- a/Resources/tests/task/cache_getter_task.yml +++ /dev/null @@ -1,86 +0,0 @@ -clever_age_process: - configurations: - test.cache_getter_task.get_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' - options: - key: - constant: 'GetterTaskTest_testGetExistingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_task.get_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' - options: - key: - constant: 'GetterTaskTest_testGetMissingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_task.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' - options: - key: - transformers: - implode: - separator: '_' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_task.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\GetterTask' - options: - key: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/task/cache_setter_task.yml b/Resources/tests/task/cache_setter_task.yml deleted file mode 100644 index 340272d7..00000000 --- a/Resources/tests/task/cache_setter_task.yml +++ /dev/null @@ -1,75 +0,0 @@ -clever_age_process: - configurations: - test.cache_setter_task.set_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' - options: - key: - constant: 'SetterTaskTest_testSetExistingCache' - value: - transformers: - property_accessor: - property_path: '[0]' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_task.set_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' - options: - key: - constant: 'SetterTaskTest_testSetMissingCache' - value: - transformers: - property_accessor: - property_path: '[0]' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_task.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' - options: - key: - transformers: - implode: - separator: '_' - value: ~ - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_task.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\Cache\SetterTask' - options: - key: ~ - value: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_deleter_transformer.yml b/Resources/tests/transfomer/cache_deleter_transformer.yml deleted file mode 100644 index 33a7a7db..00000000 --- a/Resources/tests/transfomer/cache_deleter_transformer.yml +++ /dev/null @@ -1,94 +0,0 @@ -clever_age_process: - configurations: - test.cache_deleter_transformer.delete_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_deleter: - key: - constant: 'DeleterTransformerTest_testDeleteExistingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_transformer.delete_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_deleter: - key: - constant: 'DeleterTransformerTest_testDeleteMissingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_transformer.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_deleter: - key: - transformers: - implode: - separator: '_' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_deleter_transformer.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_deleter: - key: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_getter_transformer.yml b/Resources/tests/transfomer/cache_getter_transformer.yml deleted file mode 100644 index 01dc8347..00000000 --- a/Resources/tests/transfomer/cache_getter_transformer.yml +++ /dev/null @@ -1,118 +0,0 @@ -clever_age_process: - configurations: - test.cache_getter_transformer.get_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_getter: - key: - constant: 'GetterTransformerTest_testGetExistingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_transformer.get_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_getter: - key: - constant: 'GetterTransformerTest_testGetMissingCache' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_transformer.ignore_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_getter: - key: - constant: 'GetterTransformerTest_testIgnoreMissingCache' - ignore_not_hit: true - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_transformer.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_getter: - key: - transformers: - implode: - separator: '_' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_getter_transformer.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_getter: - key: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Resources/tests/transfomer/cache_setter_transformer.yml b/Resources/tests/transfomer/cache_setter_transformer.yml deleted file mode 100644 index 54b25988..00000000 --- a/Resources/tests/transfomer/cache_setter_transformer.yml +++ /dev/null @@ -1,104 +0,0 @@ -clever_age_process: - configurations: - test.cache_setter_transformer.set_existing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_setter: - key: - constant: 'SetterTransformerTest_testSetExistingCache' - value: - transformers: - property_accessor: - property_path: '[0]' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_transformer.set_missing_cache: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_setter: - key: - constant: 'SetterTransformerTest_testSetMissingCache' - value: - transformers: - property_accessor: - property_path: '[0]' - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_transformer.transform_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_setter: - key: - transformers: - implode: - separator: '_' - value: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - - test.cache_setter_transformer.bad_cache_key: - entry_point: get_cache - end_point: dummy - tasks: - get_cache: - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - cache_setter: - key: ~ - value: ~ - outputs: [dummy] - error_outputs: [missing_cache] - - missing_cache: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: 'missing cache' - outputs: [dummy] - - dummy: - service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Task/Cache/AbstractCacheTask.php b/Task/Cache/AbstractCacheTask.php deleted file mode 100644 index 87dd2635..00000000 --- a/Task/Cache/AbstractCacheTask.php +++ /dev/null @@ -1,123 +0,0 @@ - - */ -abstract class AbstractCacheTask extends AbstractConfigurableTask -{ - use TransformerTrait; - - /** @var CacheItemPoolInterface */ - private $cache; - - /** - * SetterTask constructor. - * - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - * @param CacheItemPoolInterface $cache - * @param TransformerRegistry $transformerRegistry - */ - public function __construct( - LoggerInterface $logger, - PropertyAccessorInterface $accessor, - CacheItemPoolInterface $cache, - TransformerRegistry $transformerRegistry - ) { - $this->logger = $logger; - $this->accessor = $accessor; - $this->cache = $cache; - $this->transformerRegistry = $transformerRegistry; - } - - /** - * @return CacheItemPoolInterface - */ - public function getCache(): CacheItemPoolInterface - { - return $this->cache; - } - - /** - * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'key', - ] - ); - $resolver->setAllowedTypes('key', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'key', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - } - - /** - * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - protected function configureMappingOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'code' => null, // Source property - 'constant' => null, - ] - ); - $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); - - $this->configureTransformersOptions($resolver); - } - - /** - * @param ProcessState $state - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * @return string - * - */ - protected function getKeyCache(ProcessState $state) - { - $options = $this->getOptions($state); - - return $this->transformValue($state->getInput(), $options['key']); - } -} diff --git a/Task/Cache/DeleterTask.php b/Task/Cache/DeleterTask.php deleted file mode 100644 index f6da0e53..00000000 --- a/Task/Cache/DeleterTask.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -class DeleterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws \Psr\Cache\InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $input = $state->getInput(); - - $this->getCache()->deleteItem($keyValue); - - $state->setOutput($input); - } -} diff --git a/Task/Cache/GetterTask.php b/Task/Cache/GetterTask.php deleted file mode 100644 index e59d6b89..00000000 --- a/Task/Cache/GetterTask.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ -class GetterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws \Psr\Cache\InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $cacheItem = $this->getCache()->getItem($keyValue); - - if (!$cacheItem->isHit()) { - $state->setErrorOutput($state->getInput()); - $state->setSkipped(true); - } - - $state->setOutput($cacheItem->get()); - } -} diff --git a/Task/Cache/SetterTask.php b/Task/Cache/SetterTask.php deleted file mode 100644 index 93164bdc..00000000 --- a/Task/Cache/SetterTask.php +++ /dev/null @@ -1,72 +0,0 @@ - - */ -class SetterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws \Psr\Cache\InvalidArgumentException - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $input = $state->getInput(); - - $cacheItem = $this->getCache()->getItem($keyValue); - $cachedValue = $this->transformValue($input, $this->getOption($state, 'value')); - $cacheItem->set($cachedValue); - $this->getCache()->save($cacheItem); - - $state->setOutput($input); - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setRequired( - [ - 'value', - ] - ); - $resolver->setAllowedTypes('value', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'value', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - - return $resolver; - } -} diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index 93a497f4..4b7807f3 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -1,4 +1,5 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('DeleterTaskTest_testDeleteExistingCache'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $this->processManager->execute('test.cache_deleter_task.delete_existing_cache', $input); - - self::assertFalse($this->cache->hasItem('DeleterTaskTest_testDeleteExistingCache')); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testDeleteMissingCache() - { - if ($this->cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $this->processManager->execute('test.cache_deleter_task.delete_missing_cache', $input); - - self::assertFalse($this->cache->hasItem('DeleterTaskTest_testDeleteMissingCache')); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['DeleterTaskTest', 'testTransformCacheKey']; - - $cacheItem = $this->cache->getItem('DeleterTaskTest_testTransformCacheKey'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $this->processManager->execute('test.cache_deleter_task.transform_cache_key', $input); - - self::assertFalse($this->cache->hasItem('DeleterTaskTest_testTransformCacheKey')); - - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['DeleterTaskTest', 'testBadCacheKey']; - - $result = $this->processManager->execute('test.cache_deleter_task.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Tests/Task/Cache/GetterTaskTest.php b/Tests/Task/Cache/GetterTaskTest.php deleted file mode 100644 index d0fd8770..00000000 --- a/Tests/Task/Cache/GetterTaskTest.php +++ /dev/null @@ -1,111 +0,0 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('GetterTaskTest_testGetExistingCache'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_task.get_existing_cache'); - self::assertEquals($input, $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testGetMissingCache() - { - if ($this->cache) { - $result = $this->processManager->execute('test.cache_getter_task.get_missing_cache'); - self::assertEquals('missing cache', $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['GetterTaskTest', 'testTransformCacheKey']; - - $cacheItem = $this->cache->getItem('GetterTaskTest_testTransformCacheKey'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_task.transform_cache_key', $input); - self::assertEquals($input, $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['GetterTaskTest', 'testBadCacheKey']; - - $cacheItem = $this->cache->getItem('GetterTaskTest_testBadCacheKey'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_task.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Tests/Task/Cache/SetterTaskTest.php b/Tests/Task/Cache/SetterTaskTest.php deleted file mode 100644 index 9bc5f49a..00000000 --- a/Tests/Task/Cache/SetterTaskTest.php +++ /dev/null @@ -1,128 +0,0 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('SetterTaskTest_testSetExistingCache'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $this->processManager->execute('test.cache_setter_task.set_existing_cache', $input); - - $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetExistingCache'); - self::assertEquals($input[0], $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testSetMissingCache() - { - if ($this->cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $result = $this->processManager->execute('test.cache_setter_task.set_missing_cache', $input); - self::assertEquals($input, $result); - - $resultCacheItem = $this->cache->getItem('SetterTaskTest_testSetMissingCache'); - self::assertEquals($input[0], $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['SetterTaskTest', 'testTransformCacheKey']; - - $this->processManager->execute('test.cache_setter_task.transform_cache_key', $input); - - $resultCacheItem = $this->cache->getItem('SetterTaskTest_testTransformCacheKey'); - self::assertEquals($input, $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['SetterTransformerTest', 'testBadCacheKey']; - - $result = $this->processManager->execute('test.cache_setter_task.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Tests/Transformer/Cache/DeleterTransformerTest.php b/Tests/Transformer/Cache/DeleterTransformerTest.php deleted file mode 100644 index 50da784c..00000000 --- a/Tests/Transformer/Cache/DeleterTransformerTest.php +++ /dev/null @@ -1,132 +0,0 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('DeleterTransformerTest_testDeleteExistingCache'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_deleter_transformer.delete_existing_cache', $input); - self::assertEquals($input, $result); - - self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testDeleteExistingCache')); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testDeleteMissingCache() - { - if ($this->cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $result = $this->processManager->execute('test.cache_deleter_transformer.delete_missing_cache', $input); - self::assertEquals($input, $result); - - self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testDeleteMissingCache')); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['DeleterTransformerTest', 'testTransformCacheKey']; - - $cacheItem = $this->cache->getItem('DeleterTransformerTest_testTransformCacheKey'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_deleter_transformer.transform_cache_key', $input); - self::assertEquals($input, $result); - - self::assertFalse($this->cache->hasItem('DeleterTransformerTest_testTransformCacheKey')); - - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['DeleterTransformerTest', 'testBadCacheKey']; - - $result = $this->processManager->execute('test.cache_deleter_transformer.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Tests/Transformer/Cache/GetterTransformerTest.php b/Tests/Transformer/Cache/GetterTransformerTest.php deleted file mode 100644 index 2423f713..00000000 --- a/Tests/Transformer/Cache/GetterTransformerTest.php +++ /dev/null @@ -1,122 +0,0 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('GetterTransformerTest_testGetExistingCache'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_transformer.get_existing_cache'); - self::assertEquals($input, $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testGetMissingCache() - { - if ($this->cache) { - $result = $this->processManager->execute('test.cache_getter_transformer.get_missing_cache'); - self::assertEquals('missing cache', $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testIgnoreMissingCache() - { - if ($this->cache) { - $result = $this->processManager->execute('test.cache_getter_transformer.ignore_missing_cache'); - self::assertNull($result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['GetterTransformerTest', 'testTransformCacheKey']; - - $cacheItem = $this->cache->getItem('GetterTransformerTest_testTransformCacheKey'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_transformer.transform_cache_key', $input); - self::assertEquals($input, $result); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['GetterTransformerTest', 'testBadCacheKey']; - - $cacheItem = $this->cache->getItem('GetterTransformerTest_testBadCacheKey'); - $cacheItem->set($input); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_getter_transformer.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Tests/Transformer/Cache/SetterTransformerTest.php b/Tests/Transformer/Cache/SetterTransformerTest.php deleted file mode 100644 index a6f54daf..00000000 --- a/Tests/Transformer/Cache/SetterTransformerTest.php +++ /dev/null @@ -1,130 +0,0 @@ -cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $cacheItem = $this->cache->getItem('SetterTransformerTest_testSetExistingCache'); - $cacheItem->set([]); - $this->cache->save($cacheItem); - - $result = $this->processManager->execute('test.cache_setter_transformer.set_existing_cache', $input); - self::assertEquals($input, $result); - - $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetExistingCache'); - self::assertEquals($input[0], $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testSetMissingCache() - { - if ($this->cache) { - $input = [ - [ - 'key1' => 'value1', - 'key2' => 'value2', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1b', - 'key2' => 'value2b', - 'key3' => ['something'], - ], - [ - 'key1' => 'value1c', - 'key2' => 'value2c', - 'key3' => [], - ], - ]; - - $result = $this->processManager->execute('test.cache_setter_transformer.set_missing_cache', $input); - self::assertEquals($input, $result); - - $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testSetMissingCache'); - self::assertEquals($input[0], $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testTransformCacheKey() - { - if ($this->cache) { - $input = ['SetterTransformerTest', 'testTransformCacheKey']; - - $result = $this->processManager->execute('test.cache_setter_transformer.transform_cache_key', $input); - self::assertEquals($input, $result); - - $resultCacheItem = $this->cache->getItem('SetterTransformerTest_testTransformCacheKey'); - self::assertEquals($input, $resultCacheItem->get()); - } - } - - /** - * @throws \Psr\Cache\InvalidArgumentException - */ - public function testBadCacheKey() - { - if ($this->cache) { - $input = ['SetterTransformerTest', 'testBadCacheKey']; - - $result = $this->processManager->execute('test.cache_setter_transformer.bad_cache_key', $input); - self::assertEquals('missing cache', $result); - } - } - - protected function setUp() - { - parent::setUp(); - - if (static::$kernel->getContainer()->has('cache.app')) { - $this->cache = static::$kernel->getContainer()->get('cache.app'); - } - } -} diff --git a/Transformer/Cache/AbstractCacheTransformer.php b/Transformer/Cache/AbstractCacheTransformer.php deleted file mode 100644 index 87161cd0..00000000 --- a/Transformer/Cache/AbstractCacheTransformer.php +++ /dev/null @@ -1,122 +0,0 @@ - - */ -abstract class AbstractCacheTransformer implements ConfigurableTransformerInterface -{ - use TransformerTrait; - - /** @var CacheItemPoolInterface */ - private $cache; - - /** - * SetterTask constructor. - * - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - * @param CacheItemPoolInterface $cache - * @param TransformerRegistry $transformerRegistry - */ - public function __construct( - LoggerInterface $logger, - PropertyAccessorInterface $accessor, - CacheItemPoolInterface $cache, - TransformerRegistry $transformerRegistry - ) { - $this->logger = $logger; - $this->accessor = $accessor; - $this->cache = $cache; - $this->transformerRegistry = $transformerRegistry; - } - - /** - * @return CacheItemPoolInterface - */ - public function getCache(): CacheItemPoolInterface - { - return $this->cache; - } - - /** - * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\AccessException - * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'key', - ] - ); - $resolver->setAllowedTypes('key', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'key', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - } - - /** - * @param OptionsResolver $resolver - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - */ - protected function configureMappingOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'code' => null, // Source property - 'constant' => null, - ] - ); - $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); - - $this->configureTransformersOptions($resolver); - } - - /** - * @param array $options - * - * @return string - */ - protected function getKeyCache($value, array $options = []) - { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - return $this->transformValue($value, $options['key']); - } -} diff --git a/Transformer/Cache/DeleterTransformer.php b/Transformer/Cache/DeleterTransformer.php deleted file mode 100644 index 4c3e6a4f..00000000 --- a/Transformer/Cache/DeleterTransformer.php +++ /dev/null @@ -1,42 +0,0 @@ - - */ -class DeleterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws \Psr\Cache\InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - - $this->getCache()->deleteItem($keyValue); - - return $value; - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_deleter'; - } -} diff --git a/Transformer/Cache/GetterTransformer.php b/Transformer/Cache/GetterTransformer.php deleted file mode 100644 index 1fff13f4..00000000 --- a/Transformer/Cache/GetterTransformer.php +++ /dev/null @@ -1,67 +0,0 @@ - - */ -class GetterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setDefaults( - [ - 'ignore_not_hit' => false, - ] - ); - $resolver->setAllowedTypes('ignore_not_hit', ['boolean']); - } - - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws \Psr\Cache\InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - $cacheItem = $this->getCache()->getItem($keyValue); - - if (!$cacheItem->isHit()) { - if ($options['ignore_not_hit']) { - return null; - } - - throw new TransformerException($keyValue, 0, 'Cache not hit'); - } - - return $cacheItem->get(); - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_getter'; - } -} diff --git a/Transformer/Cache/SetterTransformer.php b/Transformer/Cache/SetterTransformer.php deleted file mode 100644 index a21de578..00000000 --- a/Transformer/Cache/SetterTransformer.php +++ /dev/null @@ -1,83 +0,0 @@ - - */ -class SetterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws \Psr\Cache\InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - - $cacheItem = $this->getCache()->getItem($keyValue); - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - $cachedValue = $this->transformValue($value, $options['value']); - $cacheItem->set($cachedValue); - $this->getCache()->save($cacheItem); - - return $value; - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_setter'; - } - - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setRequired( - [ - 'value', - ] - ); - $resolver->setAllowedTypes('value', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'value', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - - return $resolver; - } - - -} From fd74736900352032565a0b82b7313035c5f1bbd8 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 7 May 2019 15:25:49 +0200 Subject: [PATCH 040/304] Deprecating getCurrentLine that was not consistent with actual line number in favor of getLineNumber that actually points to the current line of the cursor position --- Filesystem/CsvResource.php | 37 ++++++++++++++++-------------- Filesystem/FileStreamInterface.php | 4 +++- Filesystem/JsonStreamFile.php | 16 ++++++------- Manager/ProcessManager.php | 12 +++++----- Task/File/Csv/CsvReaderTask.php | 7 +++--- Task/File/Csv/CsvSplitterTask.php | 2 +- 6 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index c0bf293b..143a62e0 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -30,7 +30,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf /** @var resource */ protected $handler; - /** @var int */ + /** @var int|null */ protected $lineCount; /** @var array */ @@ -43,7 +43,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf protected $headerCount; /** @var int */ - protected $currentLine = 0; + protected $lineNumber = 1; /** @var bool */ protected $closed; @@ -163,17 +163,15 @@ public function writeHeaders(): void } /** - * @throws \LogicException - * - * @return int + * {@inheritDoc} */ - public function getCurrentLine(): int + public function getLineNumber(): int { if ($this->seekCalled) { throw new \LogicException('Cannot get current line number after calling "seek": the line number is lost'); } - return $this->currentLine; + return $this->lineNumber; } /** @@ -200,7 +198,7 @@ public function isEndOfFile(): bool public function readRaw($length = null) { $this->assertOpened(); - ++$this->currentLine; + ++$this->lineNumber; return fgetcsv($this->handler, $length, $this->delimiter, $this->enclosure, $this->escape); } @@ -215,19 +213,24 @@ public function readRaw($length = null) */ public function readLine($length = null): ?array { + if ($this->seekCalled) { + $filePosition = "at position {$this->tell()}"; + } else { + $filePosition = "on line {$this->getLineNumber()}"; + } $values = $this->readRaw($length); if (false === $values) { if ($this->isEndOfFile()) { return null; } - $message = "Unable to parse data on line {$this->currentLine} for {$this->getResourceName()}"; + $message = "Unable to parse data {$filePosition} for {$this->getResourceName()}"; throw new \UnexpectedValueException($message); } $count = \count($values); if ($count !== $this->headerCount) { - $message = "Number of columns not matching on line {$this->currentLine} for {$this->getResourceName()}: "; + $message = "Number of columns not matching {$filePosition} for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; throw new \UnexpectedValueException($message); } @@ -252,7 +255,7 @@ public function readLine($length = null): ?array public function writeRaw(array $fields): int { $this->assertOpened(); - ++$this->currentLine; + ++$this->lineNumber; return fputcsv($this->handler, $fields, $this->delimiter, $this->enclosure, $this->escape); } @@ -301,9 +304,9 @@ public function rewind(): void if (!rewind($this->handler)) { throw new \RuntimeException("Unable to rewind '{$this->getResourceName()}'"); } - $this->currentLine = 0; + $this->lineNumber = 1; if (!$this->manualHeaders) { - $this->readRaw(); // skip headers + $this->readRaw(); // skip headers if not manual headers } } @@ -393,15 +396,15 @@ protected function parseHeaders(array $headers = null): array { // If headers are not passed in the constructor but file is readable, try to read headers from file if (null === $headers) { - $headers = fgetcsv($this->handler, 0, $this->delimiter, $this->enclosure, $this->escape); - if (false === $headers || 0 === \count($headers)) { + $autoHeaders = $this->readRaw(); + if (false === $autoHeaders || 0 === \count($autoHeaders)) { throw new \UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any $bom = pack('H*', 'EFBBBF'); - $headers[0] = preg_replace("/^{$bom}/", '', $headers[0]); + $autoHeaders[0] = preg_replace("/^{$bom}/", '', $autoHeaders[0]); - return $headers; + return $autoHeaders; } $this->manualHeaders = true; diff --git a/Filesystem/FileStreamInterface.php b/Filesystem/FileStreamInterface.php index 5eca344d..3ab9d50c 100644 --- a/Filesystem/FileStreamInterface.php +++ b/Filesystem/FileStreamInterface.php @@ -21,9 +21,11 @@ interface FileStreamInterface public function getLineCount(): int; /** + * Warning! This returns the line number of the pointer inside the file so you need to call it BEFORE reading a line + * * @return int */ - public function getCurrentLine(): int; + public function getLineNumber(): int; /** * @return bool diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php index 6489c7a2..87d1d9b2 100644 --- a/Filesystem/JsonStreamFile.php +++ b/Filesystem/JsonStreamFile.php @@ -22,7 +22,7 @@ class JsonStreamFile implements FileStreamInterface, WritableFileInterface protected $lineCount; /** @var int */ - protected $currentLine = 0; + protected $lineNumber = 1; /** * JsonStreamFile constructor. @@ -63,11 +63,11 @@ public function getLineCount(): int } /** - * @return int + * {@inheritDoc} */ - public function getCurrentLine(): int + public function getLineNumber(): int { - return $this->currentLine; + return $this->lineNumber; } /** @@ -92,7 +92,7 @@ public function readLine($length = null): ?array } $rawLine = $this->file->fgets(); - $this->currentLine++; + $this->lineNumber++; return json_decode($rawLine, true); } @@ -105,9 +105,9 @@ public function readLine($length = null): ?array public function writeLine($item): int { $this->file->fwrite(json_encode($item).PHP_EOL); - $this->currentLine++; + $this->lineNumber++; - return $this->currentLine; + return $this->lineNumber; } /** @@ -116,6 +116,6 @@ public function writeLine($item): int public function rewind(): void { $this->file->rewind(); - $this->currentLine = 0; + $this->lineNumber = 1; } } diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 69c105c0..dbca158e 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -305,12 +305,12 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF } } if ($state->isStopped()) { - if ($state->getException()) { - throw new \RuntimeException( - "Process {$state->getProcessConfiguration()->getCode()} has failed", - -1, - $state->getException() - ); + $exception = $state->getException(); + if ($exception) { + $m = "Process {$state->getProcessConfiguration()->getCode()} has failed"; + $m .= " during process {$state->getTaskConfiguration()->getCode()}"; + $m .= " with message: '{$exception->getMessage()}'.\n"; + throw new \RuntimeException($m, -1, $exception); } return; diff --git a/Task/File/Csv/CsvReaderTask.php b/Task/File/Csv/CsvReaderTask.php index 2ebeb33b..40022b7b 100644 --- a/Task/File/Csv/CsvReaderTask.php +++ b/Task/File/Csv/CsvReaderTask.php @@ -59,22 +59,23 @@ public function execute(ProcessState $state) if (!$this->csv instanceof CsvFile) { $this->initFile($state); } + $lineNumber = $this->csv->getLineNumber(); $output = $this->csv->readLine(); if (null === $output) { if ($this->getOption($state, 'log_empty_lines')) { $logContext = [ 'csv_file' => $this->csv->getFilePath(), - 'csv_line' => $this->csv->getCurrentLine(), + 'csv_line' => $lineNumber, ]; - $this->logger->warning("Empty line detected at line: {$this->csv->getCurrentLine()}", $logContext); + $this->logger->warning("Empty line detected at line: {$lineNumber}", $logContext); } $state->setSkipped(true); } $state->addErrorContextValue('csv_file', $this->csv->getFilePath()); - $state->addErrorContextValue('csv_line', $this->csv->getCurrentLine()); + $state->addErrorContextValue('csv_line', $lineNumber); $state->setOutput($output); } diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index 705e4811..c3f948e7 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -124,7 +124,7 @@ protected function splitCsv(CsvFile $csv, $maxLines) ); $splitCsv->writeHeaders(); - while ($splitCsv->getCurrentLine() < $maxLines && !$csv->isEndOfFile()) { + while ($splitCsv->getLineNumber() < $maxLines && !$csv->isEndOfFile()) { $raw = $csv->readRaw(); if (false === $raw) { continue; // This is probably an empty line, no harm to skip it From fe760a705287d8cc1426b4dfb4cc8f5391862a9c Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Mon, 20 May 2019 12:20:31 +0200 Subject: [PATCH 041/304] Fixing required parameter in process help command --- Command/ProcessHelpCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index 24695081..8f01692d 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -28,6 +28,7 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Formatter\OutputFormatterStyle; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -80,7 +81,7 @@ protected function configure() { $this->setName('cleverage:process:help'); $this->setDescription('Describe the process'); - $this->addArgument('process_code'); + $this->addArgument('process_code', InputArgument::REQUIRED, 'The code of the process'); } /** From dbe8f13d2e897d83bf0db5af0074e9250f5fa3b2 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Thu, 23 May 2019 16:50:00 +0200 Subject: [PATCH 042/304] New DeserializerTask --- Task/Serialization/DeserializerTask.php | 77 +++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Task/Serialization/DeserializerTask.php diff --git a/Task/Serialization/DeserializerTask.php b/Task/Serialization/DeserializerTask.php new file mode 100644 index 00000000..4547d576 --- /dev/null +++ b/Task/Serialization/DeserializerTask.php @@ -0,0 +1,77 @@ + + */ +class DeserializerTask extends AbstractConfigurableTask +{ + /** @var SerializerInterface */ + protected $serializer; + + /** + * @param SerializerInterface $serializer + */ + public function __construct(SerializerInterface $serializer) + { + $this->serializer = $serializer; + } + + /** + * @param ProcessState $state + * + * @throws ExceptionInterface + */ + public function execute(ProcessState $state): void + { + $options = $this->getOptions($state); + $serializeData = $this->serializer->deserialize( + $state->getInput(), + $options['type'], + $options['format'], + $options['context'] + ); + $state->setOutput($serializeData); + } + + /** + * @param OptionsResolver $resolver + * + * @throws AccessException + * @throws UndefinedOptionsException + */ + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + 'type', + 'format', + ] + ); + $resolver->setAllowedTypes('type', ['string']); + $resolver->setAllowedTypes('format', ['string']); + $resolver->setDefaults( + [ + 'context' => [], + ] + ); + } +} From 11ff4df854a976c2376b1e07c9b6b9ac64873a98 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 4 Jun 2019 14:25:46 +0200 Subject: [PATCH 043/304] Fixed type issue --- Filesystem/JsonStreamFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php index 87d1d9b2..f971fc0c 100644 --- a/Filesystem/JsonStreamFile.php +++ b/Filesystem/JsonStreamFile.php @@ -102,7 +102,7 @@ public function readLine($length = null): ?array * * @return int */ - public function writeLine($item): int + public function writeLine(array $item): int { $this->file->fwrite(json_encode($item).PHP_EOL); $this->lineNumber++; From 7ad81fb1421fc06959348d92b2ace75e3867ee88 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 4 Jun 2019 14:29:42 +0200 Subject: [PATCH 044/304] Fixed "null" not being accepted for non-configurable transformers without options --- Transformer/TransformerTrait.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 99a9fc35..fd3abf35 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -108,6 +108,12 @@ function ( $transformerOptions = $transformerOptionsResolver->resolve( $transformerOptions ?? [] ); + } else { + if(!empty($transformerOptions)) { + throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); + } + // An array is required in transform method + $transformerOptions = []; } $closure = static function ($value) use ($transformer, $transformerOptions) { From 838f27e1614e75d73d43399d8b59b805b92f3756 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 4 Jun 2019 18:55:15 +0200 Subject: [PATCH 045/304] Added JSON buffering as an option --- Task/Process/ProcessLauncherTask.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index c46921b5..46f1235b 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -178,7 +178,7 @@ protected function launchProcess(ProcessState $state) $state->getInput(), $this->getOption($state, 'context'), [ - SubprocessInstance::OPTION_JSON_BUFFERING => true, + SubprocessInstance::OPTION_JSON_BUFFERING => $this->getOption($state, 'json_buffering'), ] ); @@ -255,12 +255,14 @@ function (Options $options, $value) { 'sleep_on_finalize_interval' => 1, 'process_options' => [], 'context' => [], + 'json_buffering' => false, ] ); $resolver->setAllowedTypes('max_processes', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); $resolver->setAllowedTypes('context', ['array']); + $resolver->setAllowedTypes('json_buffering', ['boolean']); $resolver->setAllowedTypes('process_options', ['array']); $resolver->setNormalizer( From dfb3b71b7837442e08370292241d76f05f880c53 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 25 Jun 2019 19:20:56 +0200 Subject: [PATCH 046/304] New folder browser task using input as folder path --- Task/File/InputFolderBrowserTask.php | 87 ++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Task/File/InputFolderBrowserTask.php diff --git a/Task/File/InputFolderBrowserTask.php b/Task/File/InputFolderBrowserTask.php new file mode 100644 index 00000000..ac4b03ee --- /dev/null +++ b/Task/File/InputFolderBrowserTask.php @@ -0,0 +1,87 @@ +folderPath = null; + $state->setSkipped(true); + } + + /** + * {@inheritDoc} + */ + public function initialize(ProcessState $state): void + { + parent::getOptions($state); + } + + /** + * {@inheritDoc} + */ + protected function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + $resolver->remove(['folder_path']); + + $resolver->setDefaults( + [ + 'base_folder_path' => '', + ] + ); + $resolver->setAllowedTypes('base_folder_path', ['string']); + } + + /** + * {@inheritDoc} + */ + protected function getOptions(ProcessState $state): array + { + $options = parent::getOptions($state); + if ($state->getInput()) { + $folderPath = $options['base_folder_path'].$state->getInput(); + if ($this->folderPath && $folderPath !== $this->folderPath) { + throw new \LogicException( + "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" + ); + } + $this->folderPath = $folderPath; + } + + if (!is_dir($this->folderPath)) { + throw new InvalidConfigurationException( + "Folder path does not exists or is not a folder: '{$this->folderPath}'" + ); + } + if (!is_readable($this->folderPath)) { + throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); + } + $options['folder_path'] = $this->folderPath; + + return $options; + } +} From 048329e3da345dfdcafe3bcd2d11087a56c37504 Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Thu, 27 Jun 2019 10:34:46 +0200 Subject: [PATCH 047/304] Cast the input in string (if not null) before launching the process --- Task/Process/ProcessLauncherTask.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index 46f1235b..fc9fec69 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -172,10 +172,12 @@ protected function handleInput(ProcessState $state) */ protected function launchProcess(ProcessState $state) { + $input = null !== $state->getInput() ? (string) $state->getInput() : null; + $subprocess = new SubprocessInstance( $this->kernel, $this->getOption($state, 'process'), - $state->getInput(), + $input, $this->getOption($state, 'context'), [ SubprocessInstance::OPTION_JSON_BUFFERING => $this->getOption($state, 'json_buffering'), From 43c16ddacda591c7daa7b3af8249737bb6f57efd Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Thu, 18 Jul 2019 16:40:22 +0200 Subject: [PATCH 048/304] Temporary fix for flush logic to get a more logical flush order --- Manager/ProcessManager.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index dbca158e..abcd33af 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -351,6 +351,10 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF } // This means we are over iterating this task so we can remove it from registry $this->removeProcessedIterable($taskConfiguration); + if (self::EXECUTE_FLUSH !== $executionFlag) { + // This task is now finished, we may flush it to test if there is anything lasting + $this->flush($taskConfiguration); + } if ($state->isStopped()) { return; } From 69d66b2b7755a7a8e634a65ded121cebd21cea5a Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 6 Aug 2019 15:29:55 +0200 Subject: [PATCH 049/304] Fixing log level for debug message --- Manager/ProcessManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index abcd33af..06d141d7 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -237,7 +237,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void && \count($taskConfiguration->getErrorOutputs()) > 0) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; - $this->taskLogger->error($m); + $this->taskLogger->debug($m); } // @todo Refactor this using a Registry with this feature: // https://symfony.com/doc/current/service_container/service_subscribers_locators.html From 18b44aaad1d8ca899140038fca7f3d67ffe85e80 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 20 Aug 2019 14:48:10 +0200 Subject: [PATCH 050/304] Added a warning log when trying to use a process input without an entrypoint --- Manager/ProcessManager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 06d141d7..1414a81f 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -135,6 +135,8 @@ public function execute(string $processCode, $input = null, array $context = []) // If defined, set the input of a task if ($processConfiguration->getEntryPoint()) { $processConfiguration->getEntryPoint()->getState()->setInput($input); + } elseif ($input !== null) { + $this->processLogger->warning('Process has no entry point for input'); } // Resolve task from main branch, starting by the end From a7fd0e3c085731cd33bcf98176bfcb5c58d2fd8c Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 25 Sep 2019 09:31:17 +0200 Subject: [PATCH 051/304] Ignoring null values in trim transformer --- Transformer/TrimTransformer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Transformer/TrimTransformer.php b/Transformer/TrimTransformer.php index 00575b7c..c69c76a5 100644 --- a/Transformer/TrimTransformer.php +++ b/Transformer/TrimTransformer.php @@ -31,6 +31,10 @@ class TrimTransformer implements ConfigurableTransformerInterface */ public function transform($value, array $options = []) { + if (null === $value) { + return null; + } + return trim($value, $options['charlist']); } From 9c5f6d255bb5eb3b85170a5b6ac3ca0233342ccc Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 10 May 2019 16:02:13 +0200 Subject: [PATCH 052/304] Allow float values for sleep intervals in process launcher --- Task/Process/ProcessLauncherTask.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index fc9fec69..5a16cbd3 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -134,7 +134,7 @@ public function next(ProcessState $state) return count($this->launchedProcesses) > 0; } - sleep($this->getOption($state, 'sleep_on_finalize_interval')); + usleep($this->getOption($state, 'sleep_on_finalize_interval')); return false; } @@ -149,7 +149,7 @@ protected function handleInput(ProcessState $state) $options = $this->getOptions($state); while (\count($this->launchedProcesses) >= $options['max_processes']) { $this->handleProcesses($state); - sleep($options['sleep_interval']); + usleep($options['sleep_interval']); } $process = $this->launchProcess($state); @@ -161,7 +161,7 @@ protected function handleInput(ProcessState $state) $this->logger->debug("Running command: {$process->getProcess()->getCommandLine()}", $logContext); - sleep($options['sleep_interval_after_launch']); + usleep($options['sleep_interval_after_launch']); } /** @@ -260,9 +260,18 @@ function (Options $options, $value) { 'json_buffering' => false, ] ); - $resolver->setAllowedTypes('max_processes', ['integer', 'double']); + $resolver->setAllowedTypes('max_processes', ['integer']); + $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); + $resolver->setAllowedTypes('sleep_on_finalize_interval', ['integer', 'double']); + $microsecondNormalizer = function (Options $options, $value) { + return (int)($value * 1000000); + }; + $resolver->setNormalizer('sleep_interval', $microsecondNormalizer); + $resolver->setNormalizer('sleep_interval_after_launch', $microsecondNormalizer); + $resolver->setNormalizer('sleep_on_finalize_interval', $microsecondNormalizer); + $resolver->setAllowedTypes('context', ['array']); $resolver->setAllowedTypes('json_buffering', ['boolean']); From 19d668bc8d9e7832e425a96e4c49f6ecbaaf2712 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 18 Jun 2019 17:07:04 +0200 Subject: [PATCH 053/304] Avoid failure if output data is not an array --- Command/ExecuteProcessCommand.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 3c841fd6..86d58a19 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -174,10 +174,14 @@ protected function handleOutputData($data, InputInterface $input, OutputInterfac } } } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { - $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); - $outputFile->writeLine($data); + // JsonStreamFile::writeLine only takes an array... + // TODO how to handle other cases ? + if(\is_array($data)) { + $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); + $outputFile->writeLine($data); + } - if ($output->isVerbose()) { + if ($output->isVerbose() && isset($outputFile)) { $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { From 995adf49a18e8eb22126898c3742f2a38af3dbcc Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 15 Oct 2019 17:03:42 +0200 Subject: [PATCH 054/304] Added a docker image to help with environment testing --- Dockerfile | 28 +++++++ Resources/tests/environment/README.md | 4 + Resources/tests/environment/sf4/composer.json | 73 +++++++++++++++++++ .../tests/environment/sf4/config/bundles.php | 8 ++ .../sf4/config/packages/framework.yaml | 10 +++ .../packages/test/cleverage_process.yml | 2 + .../tests/environment/sf4/phpunit.xml.dist | 25 +++++++ Tests/AbstractProcessTest.php | 17 +---- 8 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 Dockerfile create mode 100644 Resources/tests/environment/README.md create mode 100644 Resources/tests/environment/sf4/composer.json create mode 100644 Resources/tests/environment/sf4/config/bundles.php create mode 100644 Resources/tests/environment/sf4/config/packages/framework.yaml create mode 100644 Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml create mode 100644 Resources/tests/environment/sf4/phpunit.xml.dist diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b83cd62d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +ARG PHP_VERSION=7.1 +FROM php:${PHP_VERSION}-cli + +ARG SF_ENV=sf4 + +# Basic tools +RUN apt-get update +RUN apt-get install -y wget git zip unzip + +# Composer install +RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" +RUN php composer-setup.php +RUN php -r "unlink('composer-setup.php');" +RUN mv /composer.phar /usr/local/bin/composer +RUN chmod +x /usr/local/bin/composer + +# Basic sample symfony app install +RUN mkdir /app +WORKDIR /app +COPY Resources/tests/environment/${SF_ENV}/composer.json /app +RUN composer install + +# Additionnal config files for a test env +COPY Resources/tests/environment/${SF_ENV} /app/ + +# Drop the process-bundle sources into this folder +RUN mkdir /src-cleverage_process diff --git a/Resources/tests/environment/README.md b/Resources/tests/environment/README.md new file mode 100644 index 00000000..e5f0bbbc --- /dev/null +++ b/Resources/tests/environment/README.md @@ -0,0 +1,4 @@ +Test environment +================ + +Those files are used to build a test environment for this bundle. For now, only Symfony4.3 is available. diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json new file mode 100644 index 00000000..c76601a3 --- /dev/null +++ b/Resources/tests/environment/sf4/composer.json @@ -0,0 +1,73 @@ +{ + "type": "project", + "license": "proprietary", + "require": { + "php": "^7.1.3", + "ext-ctype": "*", + "ext-iconv": "*", + "symfony/dotenv": "4.3.*", + "symfony/flex": "^1.3.1", + "symfony/framework-bundle": "4.3.*", + + "symfony/expression-language": "~3.0|~4.0", + "symfony/monolog-bundle": "~3.3", + "symfony/console": "~3.0|~4.0", + "symfony/options-resolver": "~3.0|~4.0", + "symfony/process": "~3.0|~4.0", + "symfony/property-access": "~3.0|~4.0", + "symfony/serializer": "~3.0|~4.0", + "symfony/validator": "~3.0|~4.0", + "symfony/yaml": "~3.0|~4.0", + "sidus/base-bundle": "~1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.1", + "phpunit/phpunit": "^6.4" + }, + "config": { + "preferred-install": { + "*": "dist" + }, + "sort-packages": true + }, + "autoload": { + "psr-4": { + "App\\": "src/", + "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "replace": { + "paragonie/random_compat": "2.*", + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php71": "*", + "symfony/polyfill-php70": "*", + "symfony/polyfill-php56": "*" + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + }, + "conflict": { + "symfony/symfony": "*" + }, + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.3.*" + } + } +} diff --git a/Resources/tests/environment/sf4/config/bundles.php b/Resources/tests/environment/sf4/config/bundles.php new file mode 100644 index 00000000..74f2f799 --- /dev/null +++ b/Resources/tests/environment/sf4/config/bundles.php @@ -0,0 +1,8 @@ + ['all' => true], + CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], + Sidus\BaseBundle\SidusBaseBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], +]; diff --git a/Resources/tests/environment/sf4/config/packages/framework.yaml b/Resources/tests/environment/sf4/config/packages/framework.yaml new file mode 100644 index 00000000..5a1678d2 --- /dev/null +++ b/Resources/tests/environment/sf4/config/packages/framework.yaml @@ -0,0 +1,10 @@ +framework: + secret: '%env(APP_SECRET)%' + + serializer: + enabled: true + + #esi: true + #fragments: true + php_errors: + log: true diff --git a/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml new file mode 100644 index 00000000..a03e25d8 --- /dev/null +++ b/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml @@ -0,0 +1,2 @@ +imports: + - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf4/phpunit.xml.dist b/Resources/tests/environment/sf4/phpunit.xml.dist new file mode 100644 index 00000000..fbdc9945 --- /dev/null +++ b/Resources/tests/environment/sf4/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + /src-cleverage_process/Tests + + + diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 019fbb16..07dc32fa 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -22,9 +22,6 @@ */ abstract class AbstractProcessTest extends KernelTestCase { - /** @var ContainerInterface */ - protected $container; - /** @var ProcessManager */ protected $processManager; @@ -36,16 +33,10 @@ abstract class AbstractProcessTest extends KernelTestCase */ protected function setUp() { - $kernel = static::bootKernel( - [ - 'environment' => 'test', - 'debug' => true, - ] - ); + static::bootKernel(); - $this->container = $kernel->getContainer(); - $this->processManager = $this->container->get(ProcessManager::class); - $this->processConfigurationRegistry = $this->container->get(ProcessConfigurationRegistry::class); + $this->processManager = self::$container->get(ProcessManager::class); + $this->processConfigurationRegistry = self::$container->get(ProcessConfigurationRegistry::class); } /** @@ -58,7 +49,7 @@ protected function setUp() */ protected function assertDataQueue(array $expected, string $processName, bool $checkTask = true) { - $dataQueueListener = $this->container->get(DataQueueEventListener::class); + $dataQueueListener = self::$container->get(DataQueueEventListener::class); $actualQueue = $dataQueueListener->getQueue($processName); self::assertCount(\count($expected), $actualQueue, 'Event count does not match'); From 19464380f8bc14f8384266973f39fc4758787925 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 15 Oct 2019 17:56:15 +0200 Subject: [PATCH 055/304] Added a Travis configuration file --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..2c3e9f88 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: php + +services: + - docker + +before_script: + - docker build -t cleverage_process:test . + +script: + - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit From b1fc60fdd9b8992189b7e9652b0f9d1e4e8a32a6 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 16 Oct 2019 10:28:29 +0200 Subject: [PATCH 056/304] Fix for compat with symfony/phpunit-bridge v3 or v4 --- Tests/AbstractProcessTest.php | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 07dc32fa..100bcd9b 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -35,8 +35,8 @@ protected function setUp() { static::bootKernel(); - $this->processManager = self::$container->get(ProcessManager::class); - $this->processConfigurationRegistry = self::$container->get(ProcessConfigurationRegistry::class); + $this->processManager = $this->getContainer()->get(ProcessManager::class); + $this->processConfigurationRegistry = $this->getContainer()->get(ProcessConfigurationRegistry::class); } /** @@ -49,7 +49,7 @@ protected function setUp() */ protected function assertDataQueue(array $expected, string $processName, bool $checkTask = true) { - $dataQueueListener = self::$container->get(DataQueueEventListener::class); + $dataQueueListener = $this->getContainer()->get(DataQueueEventListener::class); $actualQueue = $dataQueueListener->getQueue($processName); self::assertCount(\count($expected), $actualQueue, 'Event count does not match'); @@ -76,4 +76,23 @@ protected function assertDataQueue(array $expected, string $processName, bool $c } } } + + /** + * Returns the booted symfony container + * + * Compatibility backport for symfony/phpunit-bridge that should work with v3 or v4 + * + * @return ContainerInterface + */ + protected function getContainer(): ContainerInterface + { + if(isset(self::$container)) { + return self::$container; + } + + $container = self::$kernel->getContainer(); + $container = $container->has('test.service_container') ? $container->get('test.service_container') : $container; + + return $container; + } } From d2eedc508b57d89fe733442e27a0a68ca2d3189e Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 18 Jun 2019 16:17:46 +0200 Subject: [PATCH 057/304] Generic transformer class allowing configuration driven transformer instances --- Resources/config/services/transformer.yml | 1 + Transformer/GenericTransformer.php | 114 ++++++++++++++++++++++ Transformer/TransformerTrait.php | 67 +++++++------ 3 files changed, 151 insertions(+), 31 deletions(-) create mode 100644 Transformer/GenericTransformer.php diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml index a058d18c..5a2e7dfa 100644 --- a/Resources/config/services/transformer.yml +++ b/Resources/config/services/transformer.yml @@ -1,6 +1,7 @@ services: CleverAge\ProcessBundle\Transformer\: resource: '../../../Transformer/*' + exclude: '../../../Transformer/GenericTransformer.php' autowire: true public: false tags: diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php new file mode 100644 index 00000000..73cef9c3 --- /dev/null +++ b/Transformer/GenericTransformer.php @@ -0,0 +1,114 @@ +contextualOptionResolver = $contextualOptionResolver; + $this->transformerRegistry = $transformerRegistry; + } + + public function initialize(string $code, array $options = []) + { + $this->transformerCode = $code; + $resolver = new OptionsResolver(); + $this->configureInitialOptions($resolver); + + $initialOptions = $resolver->resolve($options); + $this->contextualOptions = $initialOptions['contextual_options']; + $this->preconfiguredTransformerOptions = $initialOptions['transformers']; + } + + /** + * Called on instance creation + * + * @param OptionsResolver $resolver + */ + public function configureInitialOptions(OptionsResolver $resolver) + { + $resolver->setDefault('contextual_options', []); + // TODO define normalizer + + $resolver->setDefault('transformers', []); + } + + public function configureOptions(OptionsResolver $resolver) + { + foreach ($this->contextualOptions as $option => $optionConfig) { + // TODO allow more complex usage + $resolver->setDefault($option, null); + } + + // TODO we use the transformers option for internal processing here... but it's also accessible through config + $this->configureTransformersOptions($resolver); + $resolver->setNormalizer('transformers', function (Options $options, $transformerOptions) { + if ($transformerOptions !== []) { + throw new \InvalidArgumentException('Transformers option should not be used'); + } + + $transformerOptions = $this->normalizeTransformerOptions($options, $this->preconfiguredTransformerOptions); + $transformers = $this->normalizeTransformers($options, $transformerOptions); + + return $transformers; + }); + } + + public function transform($value, array $options = []) + { + return $this->applyTransformers($options['transformers'], $value); + } + + public function getCode() + { + return $this->transformerCode; + } + + public function normalizeTransformerOptions(Options $options, $transformerOptions) + { + $contextualizedOptionValues = []; + foreach ($this->contextualOptions as $contextualOption => $contextualOptionConfig) { + $contextualizedOptionValues[$contextualOption] = $options[$contextualOption]; + } + + return $this->contextualOptionResolver->contextualizeOptions($transformerOptions, $contextualizedOptionValues); + } + +} diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index fd3abf35..a81286d0 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -13,6 +13,7 @@ use CleverAge\ProcessBundle\Exception\MissingTransformerException; use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -90,40 +91,44 @@ protected function configureTransformersOptions(OptionsResolver $resolver, $opti { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); - $resolver->setNormalizer( - $optionName, - function ( - /** @noinspection PhpUnusedParameterInspection */ - Options $options, - $transformers - ) { - $transformerClosures = []; + $resolver->setNormalizer($optionName, \Closure::fromCallable([$this, 'normalizeTransformers'])); + } - foreach ($transformers as $origTransformerCode => $transformerOptions) { - $transformerOptionsResolver = new OptionsResolver(); - $transformerCode = $this->getCleanedTransfomerCode($origTransformerCode); - $transformer = $this->transformerRegistry->getTransformer($transformerCode); - if ($transformer instanceof ConfigurableTransformerInterface) { - $transformer->configureOptions($transformerOptionsResolver); - $transformerOptions = $transformerOptionsResolver->resolve( - $transformerOptions ?? [] - ); - } else { - if(!empty($transformerOptions)) { - throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); - } - // An array is required in transform method - $transformerOptions = []; - } + /** + * @param Options $options + * @param $transformers + * + * @return array + * + * @throws ExceptionInterface + */ + public function normalizeTransformers(Options $options, $transformers) + { + $transformerClosures = []; - $closure = static function ($value) use ($transformer, $transformerOptions) { - return $transformer->transform($value, $transformerOptions); - }; - $transformerClosures[$origTransformerCode] = $closure; + foreach ($transformers as $origTransformerCode => $transformerOptions) { + $transformerOptionsResolver = new OptionsResolver(); + $transformerCode = $this->getCleanedTransfomerCode($origTransformerCode); + $transformer = $this->transformerRegistry->getTransformer($transformerCode); + if ($transformer instanceof ConfigurableTransformerInterface) { + $transformer->configureOptions($transformerOptionsResolver); + $transformerOptions = $transformerOptionsResolver->resolve( + $transformerOptions ?? [] + ); + } else { + if (!empty($transformerOptions)) { + throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); } - - return $transformerClosures; + // An array is required in transform method + $transformerOptions = []; } - ); + + $closure = static function ($value) use ($transformer, $transformerOptions) { + return $transformer->transform($value, $transformerOptions); + }; + $transformerClosures[$origTransformerCode] = $closure; + } + + return $transformerClosures; } } From 4900dd89bca85534ebb2fe3a606ab0723630c035 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 18 Jun 2019 17:04:13 +0200 Subject: [PATCH 058/304] Added a configuration entry point for generic transformer & automatic service generation --- .../CleverAgeProcessExtension.php | 15 +++++ DependencyInjection/Configuration.php | 62 +++++++++++++++++-- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index aa65d2cd..73a6afe1 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -11,8 +11,10 @@ namespace CleverAge\ProcessBundle\DependencyInjection; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; +use CleverAge\ProcessBundle\Transformer\GenericTransformer; use Sidus\BaseBundle\DependencyInjection\SidusBaseExtension; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; /** * This is the class that loads and manages your bundle configuration. @@ -41,5 +43,18 @@ public function load(array $configs, ContainerBuilder $container) $processConfigurationRegistry = $container->getDefinition(ProcessConfigurationRegistry::class); $processConfigurationRegistry->replaceArgument(0, $config['configurations']); $processConfigurationRegistry->replaceArgument(1, $config['default_error_strategy']); + + // Automatic transformer creation from config + foreach ($config['generic_transformers'] as $transformerCode => $transformerConfig) { + $transformerDefinition = new Definition(GenericTransformer::class); + $transformerDefinition->setAutowired(true); + $transformerDefinition->addMethodCall('initialize',[ + $transformerCode, + $transformerConfig + ]); + $transformerDefinition->addTag('cleverage.transformer'); + + $container->setDefinition(GenericTransformer::class . "\\" . $transformerCode, $transformerDefinition); + } } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 18ca894b..8795ac57 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -49,10 +49,63 @@ public function getConfigTreeBuilder() $rootNode = $treeBuilder->root($this->root); $definition = $rootNode->children(); + // Default error strategy + $definition->scalarNode('default_error_strategy')->defaultValue(TaskConfiguration::STRATEGY_SKIP)->end(); + + $this->appendRootProcessConfigDefinition($definition); + $this->appendRootTransformersConfigDefinition($definition); + + $definition->end(); + + return $treeBuilder; + } + + /** + * "generic_transformers" root configuration + * @param NodeBuilder $definition + */ + protected function appendRootTransformersConfigDefinition(NodeBuilder $definition) + { + /** @var ArrayNodeDefinition $transformersArrayDefinition */ + $transformersArrayDefinition = $definition->arrayNode('generic_transformers') + ->useAttributeAsKey('code') + ->prototype('array'); + + // Process list + $transformerListDefinition = $transformersArrayDefinition + ->performNoDeepMerging() + ->cannotBeOverwritten() + ->children(); + + $this->appendTransformerConfigDefinition($transformerListDefinition); + + $transformerListDefinition->end(); + $transformersArrayDefinition->end(); + } + + /** + * Single transformer configuration + * @param NodeBuilder $definition + */ + protected function appendTransformerConfigDefinition(NodeBuilder $definition) + { + $definition + ->arrayNode('contextual_options')->prototype('variable')->end()->end() + ->arrayNode('transformers')->prototype('variable')->end()->end(); + + // TODO assertions configuration + } + + /** + * "configurations" root configuration + * @TODO rename root as "processes" ? + * + * @param NodeBuilder $definition + */ + protected function appendRootProcessConfigDefinition(NodeBuilder $definition) + { /** @var ArrayNodeDefinition $configurationsArrayDefinition */ - $configurationsArrayDefinition = $definition - ->scalarNode('default_error_strategy')->defaultValue(TaskConfiguration::STRATEGY_SKIP)->end() - ->arrayNode('configurations') + $configurationsArrayDefinition = $definition->arrayNode('configurations') ->useAttributeAsKey('code') ->prototype('array'); @@ -66,9 +119,6 @@ public function getConfigTreeBuilder() $processListDefinition->end(); $configurationsArrayDefinition->end(); - $definition->end(); - - return $treeBuilder; } /** From 74ed897fbe927b90e96c9d9ef981d721658a37e1 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 21 Jun 2019 15:48:02 +0200 Subject: [PATCH 059/304] Added helper method to test directly over a transformer --- Tests/AbstractProcessTest.php | 31 ++++++++++++++++++++++++++++++ Transformer/GenericTransformer.php | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 100bcd9b..154572b9 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -13,9 +13,13 @@ use CleverAge\ProcessBundle\Manager\ProcessManager; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; +use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\DependencyInjection\ContainerInterface; use CleverAge\ProcessBundle\EventListener\DataQueueEventListener; +use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Provide all necessary setup to test a process @@ -28,6 +32,9 @@ abstract class AbstractProcessTest extends KernelTestCase /** @var ProcessConfigurationRegistry */ protected $processConfigurationRegistry; + /** @var TransformerRegistry */ + protected $transformerRegistry; + /** * Initialize DI */ @@ -37,6 +44,7 @@ protected function setUp() $this->processManager = $this->getContainer()->get(ProcessManager::class); $this->processConfigurationRegistry = $this->getContainer()->get(ProcessConfigurationRegistry::class); + $this->transformerRegistry = $this->getContainer()->get(TransformerRegistry::class); } /** @@ -95,4 +103,27 @@ protected function getContainer(): ContainerInterface return $container; } + + /** + * Helper method to configure options and test a transformation + * + * @param string $transformerCode + * @param mixed $expected + * @param mixed $actual + * @param array $options + * + * @throws ExceptionInterface + */ + protected function assertTransformation(string $transformerCode, $expected, $actual, array $options = []) + { + $transformer = $this->transformerRegistry->getTransformer($transformerCode); + + if ($transformer instanceof ConfigurableTransformerInterface) { + $resolver = new OptionsResolver(); + $transformer->configureOptions($resolver); + $options = $resolver->resolve($options); + } + + self::assertEquals($expected, $transformer->transform($actual, $options)); + } } diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index 73cef9c3..5caa6d2c 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -74,7 +74,7 @@ public function configureOptions(OptionsResolver $resolver) { foreach ($this->contextualOptions as $option => $optionConfig) { // TODO allow more complex usage - $resolver->setDefault($option, null); + $resolver->setRequired($option); } // TODO we use the transformers option for internal processing here... but it's also accessible through config From 94ce7d797288c61cc1396a60b2019dff415ae13e Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 21 Jun 2019 17:45:22 +0200 Subject: [PATCH 060/304] Allow to configure generic options using YML --- Transformer/GenericTransformer.php | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index 5caa6d2c..ee27c56f 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -65,7 +65,17 @@ public function initialize(string $code, array $options = []) public function configureInitialOptions(OptionsResolver $resolver) { $resolver->setDefault('contextual_options', []); - // TODO define normalizer + $resolver->setAllowedTypes('contextual_options', 'array'); + $resolver->setNormalizer('contextual_options', function (Options $options, $value) { + $configuration = []; + foreach ($value as $optionCode => $optionConfig) { + $resolver = new OptionsResolver(); + $this->configureContextualOptions($resolver); + $configuration[$optionCode] = $resolver->resolve($optionConfig ?? []); + } + + return $configuration; + }); $resolver->setDefault('transformers', []); } @@ -73,8 +83,13 @@ public function configureInitialOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver) { foreach ($this->contextualOptions as $option => $optionConfig) { - // TODO allow more complex usage - $resolver->setRequired($option); + if ($optionConfig['default'] !== null || $optionConfig['default_is_null']) { + $resolver->setDefault($option, $optionConfig['default']); + } + + if ($optionConfig['required']) { + $resolver->setRequired($option); + } } // TODO we use the transformers option for internal processing here... but it's also accessible through config @@ -111,4 +126,11 @@ public function normalizeTransformerOptions(Options $options, $transformerOption return $this->contextualOptionResolver->contextualizeOptions($transformerOptions, $contextualizedOptionValues); } + public function configureContextualOptions(OptionsResolver $resolver) + { + $resolver->setDefault('required', true); + $resolver->setDefault('default', null); + $resolver->setDefault('default_is_null', false); + } + } From 36ead62f7b88d59a763f92eb6b983d3fb26f5f94 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 16 Oct 2019 17:13:07 +0200 Subject: [PATCH 061/304] Generic transformers should be private services --- DependencyInjection/CleverAgeProcessExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 73a6afe1..2d8fd9a9 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -48,6 +48,7 @@ public function load(array $configs, ContainerBuilder $container) foreach ($config['generic_transformers'] as $transformerCode => $transformerConfig) { $transformerDefinition = new Definition(GenericTransformer::class); $transformerDefinition->setAutowired(true); + $transformerDefinition->setPrivate(true); $transformerDefinition->addMethodCall('initialize',[ $transformerCode, $transformerConfig From 3fe5c5674fa1c19874a4686421894648a508d3a1 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 16 Oct 2019 17:38:07 +0200 Subject: [PATCH 062/304] Improved some code comments --- DependencyInjection/Configuration.php | 4 +--- Transformer/GenericTransformer.php | 34 +++++++++++++++++++++++++-- Transformer/TransformerTrait.php | 10 ++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 8795ac57..2540810f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -92,13 +92,11 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition) $definition ->arrayNode('contextual_options')->prototype('variable')->end()->end() ->arrayNode('transformers')->prototype('variable')->end()->end(); - - // TODO assertions configuration } /** * "configurations" root configuration - * @TODO rename root as "processes" ? + * @TODO rename this root as "processes" * * @param NodeBuilder $definition */ diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index ee27c56f..4661f265 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -46,6 +46,12 @@ public function __construct(ContextualOptionResolver $contextualOptionResolver, $this->transformerRegistry = $transformerRegistry; } + /** + * Register the generic options, and load the transformer list + * + * @param string $code + * @param array $options + */ public function initialize(string $code, array $options = []) { $this->transformerCode = $code; @@ -80,6 +86,11 @@ public function configureInitialOptions(OptionsResolver $resolver) $resolver->setDefault('transformers', []); } + /** + * Called on process startup, prepare the real transformers + * + * @param OptionsResolver $resolver + */ public function configureOptions(OptionsResolver $resolver) { foreach ($this->contextualOptions as $option => $optionConfig) { @@ -92,11 +103,11 @@ public function configureOptions(OptionsResolver $resolver) } } - // TODO we use the transformers option for internal processing here... but it's also accessible through config + // Get the transformer list + apply transformer option resolution by context $this->configureTransformersOptions($resolver); $resolver->setNormalizer('transformers', function (Options $options, $transformerOptions) { if ($transformerOptions !== []) { - throw new \InvalidArgumentException('Transformers option should not be used'); + throw new \InvalidArgumentException('Transformers option should not be used at this point'); } $transformerOptions = $this->normalizeTransformerOptions($options, $this->preconfiguredTransformerOptions); @@ -106,16 +117,30 @@ public function configureOptions(OptionsResolver $resolver) }); } + /** + * {@inheritDoc} + */ public function transform($value, array $options = []) { return $this->applyTransformers($options['transformers'], $value); } + /** + * {@inheritDoc} + */ public function getCode() { return $this->transformerCode; } + /** + * Get the real transformer from contextual options + generic definitions + * + * @param Options $options + * @param array $transformerOptions + * + * @return array + */ public function normalizeTransformerOptions(Options $options, $transformerOptions) { $contextualizedOptionValues = []; @@ -126,6 +151,11 @@ public function normalizeTransformerOptions(Options $options, $transformerOption return $this->contextualOptionResolver->contextualizeOptions($transformerOptions, $contextualizedOptionValues); } + /** + * Available options for contextual_options + * + * @param OptionsResolver $resolver + */ public function configureContextualOptions(OptionsResolver $resolver) { $resolver->setDefault('required', true); diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index a81286d0..b279ab77 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -64,10 +64,10 @@ protected function applyTransformers(array $transformers, $value) * @return string * * @example - * transformers: - * callback#1: + * transformers: + * callback#1: * callback: array_filter - * callback#2: + * callback#2: * callback: array_reverse * * @@ -95,10 +95,12 @@ protected function configureTransformersOptions(OptionsResolver $resolver, $opti } /** + * Transform the list of transformer codes + options into a list of Closure (better performances) + * * @param Options $options * @param $transformers * - * @return array + * @return \Closure[] * * @throws ExceptionInterface */ From d993e70358789799f2a5eae13864e27a228c9317 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 16 Oct 2019 17:53:23 +0200 Subject: [PATCH 063/304] Added a basic documentation for generic transformers --- .../03-generic_transformers_definition.md | 32 +++++++++++++++++++ README.md | 1 + Transformer/GenericTransformer.php | 4 +++ 3 files changed, 37 insertions(+) create mode 100644 Documentation/reference/03-generic_transformers_definition.md diff --git a/Documentation/reference/03-generic_transformers_definition.md b/Documentation/reference/03-generic_transformers_definition.md new file mode 100644 index 00000000..e4750591 --- /dev/null +++ b/Documentation/reference/03-generic_transformers_definition.md @@ -0,0 +1,32 @@ +Generic transformers definition +=============================== + +YAML Configuration +------------------ + +```yaml +clever_age_process: + generic_transformers: + : + contextual_options: + : + required: + default: + default_is_null: + transformers: + +``` +Options +------- + +For each contextual option, you can define + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `required` | `bool` | | `true` | Indicates if the option is required or not | +| `default` | `any` | | `null` | If not `null`, define the default value | +| `default_is_null` | `bool` | | `false` | If you need `null` to be the default value, use this option | + +The transformer options are the same than any other transformer using a sub-list of transformers. You can use the +syntax for contextual values (`{{ contextual_option_code }}`) to put placeholders that will be filled by those contextual +options. diff --git a/README.md b/README.md index 784cbe39..653dddaa 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Basically, it will greatly ease the configuration of import and exports but can - Reference - [Process definition](Documentation/reference/01-process_definition.md) - [Task definition](Documentation/reference/02-task_definition.md) + - [Generic transformers definition](Documentation/reference/03-generic_transformers_definition.md) - Basic and debug - [ConstantOutputTask](Documentation/reference/tasks/constant_output_task.md) - [ConstantIterableOutputTask](Documentation/reference/tasks/constant_iterable_output_task.md) diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index 4661f265..1c1bad99 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -159,8 +159,12 @@ public function normalizeTransformerOptions(Options $options, $transformerOption public function configureContextualOptions(OptionsResolver $resolver) { $resolver->setDefault('required', true); + $resolver->setAllowedTypes('required', 'bool'); + $resolver->setDefault('default', null); + $resolver->setDefault('default_is_null', false); + $resolver->setAllowedTypes('default_is_null', 'bool'); } } From e1fea75ae6cf4b81059032c59c606fd04cd476fd Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 16 Oct 2019 18:01:37 +0200 Subject: [PATCH 064/304] Added a basic unit test for generic transformers --- Makefile | 5 +++ .../tests/transfomer/generic_transformer.yml | 13 ++++++++ Tests/AbstractProcessTest.php | 6 ++-- Tests/Transformer/GenericTransformersTest.php | 33 +++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 Makefile create mode 100644 Resources/tests/transfomer/generic_transformer.yml create mode 100644 Tests/Transformer/GenericTransformersTest.php diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..cf29fdc0 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +build: + docker build -t cleverage_process:test . + +test: + docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit diff --git a/Resources/tests/transfomer/generic_transformer.yml b/Resources/tests/transfomer/generic_transformer.yml new file mode 100644 index 00000000..1fd0d37d --- /dev/null +++ b/Resources/tests/transfomer/generic_transformer.yml @@ -0,0 +1,13 @@ +clever_age_process: + generic_transformers: + test.generic_transformers.simple: + transformers: + default: + value: 'ok' + + test.generic_transformers.contextual_options: + contextual_options: + default_value: ~ + transformers: + default: + value: '{{ default_value }}' diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 154572b9..1f89f28b 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -109,12 +109,12 @@ protected function getContainer(): ContainerInterface * * @param string $transformerCode * @param mixed $expected - * @param mixed $actual + * @param mixed $value * @param array $options * * @throws ExceptionInterface */ - protected function assertTransformation(string $transformerCode, $expected, $actual, array $options = []) + protected function assertTransformation(string $transformerCode, $expected, $value, array $options = []) { $transformer = $this->transformerRegistry->getTransformer($transformerCode); @@ -124,6 +124,6 @@ protected function assertTransformation(string $transformerCode, $expected, $act $options = $resolver->resolve($options); } - self::assertEquals($expected, $transformer->transform($actual, $options)); + self::assertEquals($expected, $transformer->transform($value, $options)); } } diff --git a/Tests/Transformer/GenericTransformersTest.php b/Tests/Transformer/GenericTransformersTest.php new file mode 100644 index 00000000..e4af6d14 --- /dev/null +++ b/Tests/Transformer/GenericTransformersTest.php @@ -0,0 +1,33 @@ +assertTransformation('test.generic_transformers.simple','my_ok', 'my_ok'); + $this->assertTransformation('test.generic_transformers.simple','ok', null); + } + /** + * @throws ExceptionInterface + */ + public function testContextualOptions() + { + $this->assertTransformation('test.generic_transformers.contextual_options','my_ok', 'my_ok', [ + 'default_value' => 'ok' + ]); + $this->assertTransformation('test.generic_transformers.contextual_options','ok', null, [ + 'default_value' => 'ok' + ]); + } + +} From a0fa3faf17c05b389e92f755ee8c01abd6931eef Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 10 May 2019 11:29:33 +0200 Subject: [PATCH 065/304] Added a RulesTransformer into core process bundle --- Transformer/RulesTransformer.php | 171 +++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 Transformer/RulesTransformer.php diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php new file mode 100644 index 00000000..f19c73e9 --- /dev/null +++ b/Transformer/RulesTransformer.php @@ -0,0 +1,171 @@ + + * @author Vincent Chalnot + */ +class RulesTransformer implements ConfigurableTransformerInterface +{ + + use TransformerTrait; + + /** @var ExpressionLanguage */ + protected $language; + + /** + * RulesTransformer constructor. + * + * @param TransformerRegistry $transformerRegistry + */ + public function __construct(TransformerRegistry $transformerRegistry) + { + $this->language = new ExpressionLanguage(); + $this->transformerRegistry = $transformerRegistry; + } + + /** + * {@inheritdoc} + */ + public function transform($value, array $options = []) + { + foreach ($options['rules_set'] as $rule) { + if ($this->matchRule($value, $rule, $options['use_value_as_variables'])) { + if ($rule['set_null']) { + return null; + } elseif ($rule['constant'] !== null) { + return $rule['constant']; + } else { + return $this->applyTransformers($rule['transformers'], $value); + } + } + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function getCode() + { + return 'rules'; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('use_value_as_variables', true); + $resolver->setAllowedTypes('use_value_as_variables', 'bool'); + + $resolver->setDefault('expression_variables', ['value']); + $resolver->setAllowedTypes('expression_variables', ['null', 'array']); + + $resolver->setRequired('rules_set'); + $resolver->setAllowedTypes('rules_set', 'array'); + $resolver->setNormalizer('rules_set', function (Options $options, $conditionSet) { + + $rules = array_map(function ($item) use ($options) { + $resolver = new OptionsResolver(); + $this->configureRuleOptions($resolver, $options['expression_variables']); + + return $resolver->resolve($item); + }, $conditionSet); + + // Check default rule an order + $hasFoundDefault = false; + foreach ($rules as $rule) { + if ($rule['default']) { + if ($hasFoundDefault) { + throw new \InvalidArgumentException("Rules set cannot have more than 2 default rules"); + } + $hasFoundDefault = true; + } + + if ($hasFoundDefault && $rule['condition'] !== null) { + throw new \InvalidArgumentException("A conditional rule cannot be placed after a default rule"); + } + } + + return $rules; + }); + } + + /** + * Configure options for one "rule" block + * + * @param OptionsResolver $resolver + * @param array|null $expressionVariables + */ + public function configureRuleOptions(OptionsResolver $resolver, $expressionVariables = null) + { + $resolver->setDefaults([ + 'condition' => null, + 'default' => false, + 'constant' => null, + 'set_null' => false, + ]); + $resolver->setAllowedTypes('condition', ['null', 'string', ParsedExpression::class]); + $resolver->setAllowedTypes('default', 'bool'); + $resolver->setAllowedTypes('set_null', 'bool'); + + $expressionNormalizer = function (Options $options, $expression) use ($expressionVariables) { + if (is_array($expressionVariables) && $expression !== null) { + return $this->language->parse($expression, $expressionVariables); + } else { + return $expression; + } + }; + + $resolver->setNormalizer('condition', $expressionNormalizer); + $resolver->setNormalizer('default', function (Options $options, $value) { + if ($value && $options['condition']) { + throw new \InvalidArgumentException("A rule cannot have a condition and be the default in the same time"); + } + + return $value; + }); + + $this->configureTransformersOptions($resolver); + } + + /** + * Test if a value match a rule + * + * @param mixed $value + * @param string|ParsedExpression $rule + * @param bool $useValueAsVariable + * + * @return bool + */ + protected function matchRule($value, $rule, bool $useValueAsVariable): bool + { + if ($rule['condition'] !== null) { + $expressionValues = $useValueAsVariable ? $value : ['value' => $value]; + + return $this->language->evaluate($rule['condition'], $expressionValues); + } + + return $rule['default']; + } + +} From 1f3b3a1604138ffa684ced17b8486eabb5afdd71 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 10 May 2019 14:56:39 +0200 Subject: [PATCH 066/304] Added tests & documentation for the rules transformer --- .../reference/transformers/_template.md | 43 +++++++++ .../transformers/rules_transformer.md | 93 +++++++++++++++++++ .../tests/transfomer/rules_transformer.yml | 21 +++++ Tests/Transformer/RulesTransformerTest.php | 35 +++++++ Transformer/RulesTransformer.php | 2 +- 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 Documentation/reference/transformers/_template.md create mode 100644 Documentation/reference/transformers/rules_transformer.md create mode 100644 Resources/tests/transfomer/rules_transformer.yml create mode 100644 Tests/Transformer/RulesTransformerTest.php diff --git a/Documentation/reference/transformers/_template.md b/Documentation/reference/transformers/_template.md new file mode 100644 index 00000000..f11e3099 --- /dev/null +++ b/Documentation/reference/transformers/_template.md @@ -0,0 +1,43 @@ +TransformerName +=============== + +_Describe main goal an use cases of the transformer_ + +Task reference +-------------- + +* **Service**: `ClassName` +* **Transformer code**: `code` + +Accepted inputs +--------------- + +_Description of allowed types_ + +Possible outputs +---------------- + +_Description of possible types_ + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `code` | `type` | **X** _or nothing_ | `default value` _if available_ | _description_ | + +Examples +-------- + +_YAML samples and explanations_ + +* Example 1 + - details + - details + +```yaml +# Transformer options level +code: + option1: a + option2: b +``` diff --git a/Documentation/reference/transformers/rules_transformer.md b/Documentation/reference/transformers/rules_transformer.md new file mode 100644 index 00000000..e50f916a --- /dev/null +++ b/Documentation/reference/transformers/rules_transformer.md @@ -0,0 +1,93 @@ +RulesTransformer +================ + +Uses a set of rules to apply some set of transformers on a value. Basically behaves like a `if/elseif/else` block. + +By default a rule uses a variable named `value` containing anything you passed in input (`array`, `string`, ...). But this +can be overridden using options `use_value_as_variables` as `true` and setting `expression_variables` to a static list of +input variables. + +Note that `expression_variables` can also be set to `null` for more flexibility, but this disable initial parsing and decrease +performances. + +See [The ExpressionLanguage Component Reference](https://symfony.com/doc/current/components/expression_language.html) for +more information. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\RulesTransformer` +* **Transformer code**: `rules` + +Accepted inputs +--------------- + +`any` or an `array` of `variable code => value` injectable into an expression + +Possible outputs +---------------- + +`any` resulting from a transformation set. + +Without any matching rules, the value itself is returned. + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `rules_set` | `array` | **X** | | Ordered list of rules, see bellow for details | +| `use_value_as_variables` | `bool` | | `false` | Use given value as an array of variable to inject in expression | +| `expression_variables` | `array` or `null` | | `[value]` | Name of variables injected in the expression at initialization time | + +Foreach rule there is the following options. + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `condition` | `string` or `null` | | `null` | An expression used to match a value | +| `default` | `bool` | | `false` | Mark this rule as a default rule. The given rule must be the last, cannot have a condition, and there cannot have 2 default in the same time | +| `transformers` | `array` | | `[]` | List of transformer code => transformer options for subsequent transformations | +| `constant` | `any` | | `null` | If not `null`, given value will be directly output (takes precedence on `transformers`) | +| `set_null` | `bool` | | `false` | If `true`, `null` will be directly output (takes precedence on `constant`) | + +Examples +-------- + +* Simple rules with default value + - input value is an array containing an `order` object and a `customer` object + - output will be either a value from customer, or a numeric constant, or null + +```yaml +# Transformer options level +rules: + rules_set: + - condition: 'value["order"].origin === "marketplace"' + transformers: + property_accessor: + property_path: '[customer].id' + - condition: 'value["order"].origin === "e-commerce"' + constant: 1234 + - default: true + set_null: true +``` + +* Use value as variables + - same example as above + - can be useful for more verbose expression + - transformers still get the input as the initial array + +```yaml +# Transformer options level +rules: + use_value_as_variables: true + expression_variables: [order, customer] + rules_set: + - condition: 'order.origin === "marketplace"' + transformers: + property_accessor: + property_path: '[customer].id' + - condition: 'order.origin === "e-commerce"' + constant: 1234 + - default: true + set_null: true +``` diff --git a/Resources/tests/transfomer/rules_transformer.yml b/Resources/tests/transfomer/rules_transformer.yml new file mode 100644 index 00000000..47f9ba25 --- /dev/null +++ b/Resources/tests/transfomer/rules_transformer.yml @@ -0,0 +1,21 @@ +clever_age_process: + configurations: + test.rules_transformer.simple: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + rules: + rules_set: + - condition: 'value === "ok"' + transformers: + sprintf: + format: result1 + - condition: 'value === "ko"' + constant: result2 + - default: true + constant: result3 diff --git a/Tests/Transformer/RulesTransformerTest.php b/Tests/Transformer/RulesTransformerTest.php new file mode 100644 index 00000000..2156e5a4 --- /dev/null +++ b/Tests/Transformer/RulesTransformerTest.php @@ -0,0 +1,35 @@ +processManager->execute('test.rules_transformer.simple', 'ok'); + self::assertEquals('result1', $result1); + + $result2 = $this->processManager->execute('test.rules_transformer.simple', 'ko'); + self::assertEquals('result2', $result2); + + $result3 = $this->processManager->execute('test.rules_transformer.simple', 'any'); + self::assertEquals('result3', $result3); + } + +} diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php index f19c73e9..b534dfb8 100644 --- a/Transformer/RulesTransformer.php +++ b/Transformer/RulesTransformer.php @@ -74,7 +74,7 @@ public function getCode() */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefault('use_value_as_variables', true); + $resolver->setDefault('use_value_as_variables', false); $resolver->setAllowedTypes('use_value_as_variables', 'bool'); $resolver->setDefault('expression_variables', ['value']); From e43426a9ace621974493c15fdad4575d69f0896f Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 10 May 2019 15:32:10 +0200 Subject: [PATCH 067/304] Added index link for documentation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 653dddaa..bc8f6ba6 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Basically, it will greatly ease the configuration of import and exports but can - Transformers - [ArrayFilterTransformer](Documentation/reference/transformers/array_filter_transformer.md) - [MappingTransformer](Documentation/reference/transformers/mapping_transformer.md) + - [RulesTransformer](Documentation/reference/transformers/rules_transformer.md) - Examples - [Simple ETL] - [Roadmap and versions](Documentation/100-roadmap.md) From 0d7236fc90e429ee2f3f97cdaf4485ed685f0355 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 3 Jun 2019 18:16:16 +0200 Subject: [PATCH 068/304] Added a provider for ExpressionLanguage to override available functions --- ExpressionLanguage/PhpFunctionProvider.php | 45 +++++++++++++++++++ .../config/services/expression_language.yml | 9 ++++ Resources/config/services/transformer.yml | 8 ++++ Transformer/RulesTransformer.php | 5 ++- 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 ExpressionLanguage/PhpFunctionProvider.php create mode 100644 Resources/config/services/expression_language.yml diff --git a/ExpressionLanguage/PhpFunctionProvider.php b/ExpressionLanguage/PhpFunctionProvider.php new file mode 100644 index 00000000..d460de1f --- /dev/null +++ b/ExpressionLanguage/PhpFunctionProvider.php @@ -0,0 +1,45 @@ + + */ +class PhpFunctionProvider implements ExpressionFunctionProviderInterface +{ + /** @var array */ + protected $functions; + + /** + * PhpFunctionProvider constructor. + * + * @param array $functions + */ + public function __construct(array $functions) + { + $this->functions = $functions; + } + + /** + * @return ExpressionFunction[] + */ + public function getFunctions() + { + return array_map(function ($func) { + return ExpressionFunction::fromPhp($func); + }, $this->functions); + } +} diff --git a/Resources/config/services/expression_language.yml b/Resources/config/services/expression_language.yml new file mode 100644 index 00000000..63a47a74 --- /dev/null +++ b/Resources/config/services/expression_language.yml @@ -0,0 +1,9 @@ +services: + CleverAge\ProcessBundle\ExpressionLanguage\PhpFunctionProvider: + arguments: + - [ 'preg_match' ] + + cleverage_process.expression_language: + class: Symfony\Component\ExpressionLanguage\ExpressionLanguage + calls: + - ['registerProvider', ['@CleverAge\ProcessBundle\ExpressionLanguage\PhpFunctionProvider']] diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml index 5a2e7dfa..dc86da3f 100644 --- a/Resources/config/services/transformer.yml +++ b/Resources/config/services/transformer.yml @@ -7,3 +7,11 @@ services: tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } + + CleverAge\ProcessBundle\Transformer\RulesTransformer: + arguments: + $transformerRegistry: '@CleverAge\ProcessBundle\Registry\TransformerRegistry' + $language: '@cleverage_process.expression_language' + tags: + - { name: cleverage.transformer } + - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php index b534dfb8..95e3ae72 100644 --- a/Transformer/RulesTransformer.php +++ b/Transformer/RulesTransformer.php @@ -34,10 +34,11 @@ class RulesTransformer implements ConfigurableTransformerInterface * RulesTransformer constructor. * * @param TransformerRegistry $transformerRegistry + * @param ExpressionLanguage $language */ - public function __construct(TransformerRegistry $transformerRegistry) + public function __construct(TransformerRegistry $transformerRegistry, ExpressionLanguage $language) { - $this->language = new ExpressionLanguage(); + $this->language = $language; $this->transformerRegistry = $transformerRegistry; } From 0de594a733a51eff6868589cd7b9ca5baa56d92b Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 22 Oct 2019 21:19:43 +0200 Subject: [PATCH 069/304] Fix the quickstart example ERROR: Transformation 'mapping' have failed: Cannot read property "id" from an array. Maybe you intended to write the property path as "[id]" instead. --- Documentation/01-quick_start.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index a5dd83f6..5e36b390 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -81,9 +81,9 @@ clever_age_process: code: '[id]' slug: code: - - id - - firstname - - lastname + - '[id]' + - '[firstname]' + - '[lastname]' transformers: implode: separator: '-' From f4bb01c7f1a2d92a8a4bb9bc0a3ad69e12d91300 Mon Sep 17 00:00:00 2001 From: Alix Mauro Date: Mon, 23 Sep 2019 11:07:05 +0200 Subject: [PATCH 070/304] Adding option in mapping transformer to access the whole object. --- Documentation/reference/transformers/mapping_transformer.md | 2 +- Transformer/MappingTransformer.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/reference/transformers/mapping_transformer.md b/Documentation/reference/transformers/mapping_transformer.md index c822da30..0434c74c 100644 --- a/Documentation/reference/transformers/mapping_transformer.md +++ b/Documentation/reference/transformers/mapping_transformer.md @@ -41,7 +41,7 @@ Foreach property there is the following options. | Code | Type | Required | Default | Description | | ---- | ---- | :------: | ------- | ----------- | -| `code` | `string` or `array` or `null` | | `null` | A property path, or a list of property path. By default it would be the same as the destination property. Will be used as a source. | +| `code` | `string` or `array` or `null` | | `null` | A property path, or a list of property path. By default it would be the same as the destination property. Will be used as a source. The special value '.' access the whole object. | | `constant` | `any` | | `null` | If not `null`, will be directly used as a source (takes precedence on `code`) | | `set_null` | `bool` | | `false` | If `true`, `null` will be directly used as a source (takes precedence on `code`) | | `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for this source | diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index cdb7b99b..3bb16fe0 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -88,7 +88,9 @@ public function transform($input, array $options = []) $transformedValue = null; } else { $sourceProperty = $mapping['code'] ?? $targetProperty; - if (\is_array($sourceProperty)) { + if ($sourceProperty === '.') { + $transformedValue = $input; + } elseif (\is_array($sourceProperty)) { $transformedValue = []; /** @var array $sourceProperty */ foreach ($sourceProperty as $destKey => $srcKey) { From b2976d62422849f2ea7cb80aae12269ad1412f86 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 6 Nov 2019 11:10:27 +0100 Subject: [PATCH 071/304] Refactored the mapping transformer code for better readability + apply the '.' selector to array source property --- Transformer/MappingTransformer.php | 116 ++++++++++++++++++----------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 3bb16fe0..7c6910be 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -23,6 +23,7 @@ use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\PropertyAccess\Exception\RuntimeException; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** @@ -62,9 +63,9 @@ public function __construct( * @param mixed $input * @param array $options * + * @return mixed $value * @throws \Exception * - * @return mixed $value */ public function transform($input, array $options = []) { @@ -81,57 +82,47 @@ public function transform($input, array $options = []) /** @noinspection ForeachSourceInspection */ foreach ($options['mapping'] as $targetProperty => $mapping) { - $targetProperty = (string) $targetProperty; + $targetProperty = (string)$targetProperty; + $sourceProperty = $mapping['code'] ?? $targetProperty; + $ignoreMissingFlag = $mapping['ignore_missing'] || $options['ignore_missing']; + + // Prepare input value if (null !== $mapping['constant']) { - $transformedValue = $mapping['constant']; + $inputValue = $mapping['constant']; } elseif ($mapping['set_null']) { - $transformedValue = null; - } else { - $sourceProperty = $mapping['code'] ?? $targetProperty; - if ($sourceProperty === '.') { - $transformedValue = $input; - } elseif (\is_array($sourceProperty)) { - $transformedValue = []; - /** @var array $sourceProperty */ - foreach ($sourceProperty as $destKey => $srcKey) { - try { - $transformedValue[$destKey] = $this->accessor->getValue($input, $srcKey); - } catch (\RuntimeException $missingPropertyError) { - // @TODO no error if framework.property_access.throw_exception_on_invalid_index = false (default) - if ($mapping['ignore_missing'] || $options['ignore_missing']) { - continue; - } - $this->logger->debug( - 'Mapping exception', - [ - 'srcKey' => $srcKey, - 'message' => $missingPropertyError->getMessage(), - ] - ); - throw $missingPropertyError; - } - } - } else { + $inputValue = null; + } elseif (\is_array($sourceProperty)) { + $inputValue = []; + /** @var array $sourceProperty */ + foreach ($sourceProperty as $destKey => $srcKey) { try { - $transformedValue = $this->accessor->getValue($input, $sourceProperty); - } catch (\RuntimeException $missingPropertyError) { - // @TODO no error if framework.property_access.throw_exception_on_invalid_index = false (default) - if ($mapping['ignore_missing'] || $options['ignore_missing']) { + $inputValue[$destKey] = $this->extractInputValue($input, $srcKey); + } catch (RuntimeException $missingPropertyError) { + $this->handleInputMissingExceptions($missingPropertyError, $srcKey); + if ($ignoreMissingFlag) { continue; + } else { + throw $missingPropertyError; } - $this->logger->debug( - 'Mapping exception', - [ - 'message' => $missingPropertyError->getMessage(), - ] - ); + } + } + } else { + try { + $inputValue = $this->extractInputValue($input, $sourceProperty); + } catch (RuntimeException $missingPropertyError) { + $this->handleInputMissingExceptions($missingPropertyError, $sourceProperty); + if ($ignoreMissingFlag) { + continue; + } else { throw $missingPropertyError; } } + } + // Transform input value try { - $transformedValue = $this->applyTransformers($mapping['transformers'], $transformedValue); + $transformedValue = $this->applyTransformers($mapping['transformers'], $inputValue); } catch (TransformerException $exception) { $exception->setTargetProperty($targetProperty); $this->logger->debug( @@ -147,6 +138,7 @@ public function transform($input, array $options = []) throw $exception; } + // Set transformed value into result if (\is_callable($options['merge_callback'])) { $options['merge_callback']($result, $targetProperty, $transformedValue); } elseif ($this->accessor->isWritable($result, $targetProperty)) { @@ -193,10 +185,9 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('keep_input', ['boolean']); $resolver->setAllowedTypes('merge_callback', ['NULL', 'callable']); - /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'mapping', - function (Options $options, $value) { + function (/** @noinspection PhpUnusedParameterInspection */ Options $options, $value) { $resolvedMapping = []; $mappingResolver = new OptionsResolver(); $this->configureMappingOptions($mappingResolver); @@ -250,4 +241,43 @@ protected function configureMappingOptions(OptionsResolver $resolver) $this->configureTransformersOptions($resolver); } + + /** + * Custom rules to get a value from an input object or array + * + * @param mixed $input + * @param string $sourceProperty + * + * @throws RuntimeException + * + * @return mixed + */ + protected function extractInputValue($input, string $sourceProperty) + { + if ($sourceProperty === '.') { + return $input; + } + + return $this->accessor->getValue($input, $sourceProperty); + } + + /** + * Wrap error handling when there is an property access error + * + * @TODO WARNING there is no error if framework.property_access.throw_exception_on_invalid_index is false (which is + * the default) + * + * @param RuntimeException $missingPropertyError + * @param string $srcKey + */ + protected function handleInputMissingExceptions(RuntimeException $missingPropertyError, string $srcKey) + { + $this->logger->debug( + 'Mapping exception', + [ + 'srcKey' => $srcKey, + 'message' => $missingPropertyError->getMessage(), + ] + ); + } } From dcc32e90abb8e482e665081f78687ddfa473f511 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 6 Nov 2019 11:28:12 +0100 Subject: [PATCH 072/304] Added a few test cases for the '.' source property path --- .../tests/transfomer/mapping_transformer.yml | 47 +++++++++++++++++++ Tests/Transformer/MappingTransformerTest.php | 37 +++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Resources/tests/transfomer/mapping_transformer.yml b/Resources/tests/transfomer/mapping_transformer.yml index 5535a756..9c99663d 100644 --- a/Resources/tests/transfomer/mapping_transformer.yml +++ b/Resources/tests/transfomer/mapping_transformer.yml @@ -60,3 +60,50 @@ clever_age_process: mapping: "[field1][field2][field3]": code: '[value]' + + test.mapping_transformer.full_input: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + mapping: + mapping: + out: + code: '.' + + test.mapping_transformer.full_input_in_array: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + mapping: + mapping: + out: + code: + some_field: "[field]" + full: '.' + + test.mapping_transformer.multi_source_field_in_sequence: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + mapping: + mapping: + out: + code: + - "[field1]" + - "[field2]" + - "[field3]" diff --git a/Tests/Transformer/MappingTransformerTest.php b/Tests/Transformer/MappingTransformerTest.php index b78cfede..b8cf913c 100644 --- a/Tests/Transformer/MappingTransformerTest.php +++ b/Tests/Transformer/MappingTransformerTest.php @@ -60,4 +60,41 @@ public function testDeepMapping() self::assertEquals(['field1' => ['field2' => ['field3' => 'ok']]], $result); } + + /** + * Test the '.' source property path + */ + public function testFullInput() + { + $result = $this->processManager->execute('test.mapping_transformer.full_input', ['value' => 'ok']); + + self::assertEquals(['out' => ['value' => 'ok']], $result); + } + + /** + * Test the '.' source property path inside an array of source codes + */ + public function testFullInputInArray() + { + $result = $this->processManager->execute('test.mapping_transformer.full_input_in_array', ['field' => 'ok']); + + self::assertEquals(['out' => [ + 'some_field' => 'ok', + 'full' => ['field' => 'ok'], + ]], $result); + } + + /** + * Test that a source property can be an array with numeric keys (see commit e141cb61) + */ + public function testMultiSourceFieldInSequence() + { + $result = $this->processManager->execute('test.mapping_transformer.multi_source_field_in_sequence', [ + 'field1' => 'a', + 'field2' => 'b', + 'field3' => 'c', + ]); + + self::assertEquals(['out' => ['a', 'b', 'c']], $result); + } } From 09c3569da1ab53edf64747d636f655bc2f59e163 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 14 Nov 2019 15:32:34 +0100 Subject: [PATCH 073/304] #75 - avoid errors for empty processes --- Configuration/ProcessConfiguration.php | 12 ++++++++++- Resources/tests/process/empty_process.yml | 4 ++++ Tests/EmptyProcessTest.php | 26 +++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 Resources/tests/process/empty_process.yml create mode 100644 Tests/EmptyProcessTest.php diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index 7d904bdb..1b044455 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -228,6 +228,7 @@ public function getDependencyGroups(): array public function getMainTaskGroup(): array { if (null === $this->mainTaskGroup) { + $this->mainTaskGroup = []; $mainTask = $this->getMainTask(); foreach ($this->getDependencyGroups() as $branch) { @@ -249,16 +250,25 @@ public function getMainTaskGroup(): array * * @return TaskConfiguration */ - public function getMainTask(): TaskConfiguration + public function getMainTask(): ?TaskConfiguration { $entryTask = $this->getEntryPoint(); + + // If there's no entry point, we might use the end point if (!$entryTask) { $entryTask = $this->getEndPoint(); } + + // By default use the first defined task if (!$entryTask) { $entryTask = reset($this->taskConfigurations); } + // May happen with an empty array + if($entryTask === false) { + return null; + } + return $entryTask; } diff --git a/Resources/tests/process/empty_process.yml b/Resources/tests/process/empty_process.yml new file mode 100644 index 00000000..0f8c51bc --- /dev/null +++ b/Resources/tests/process/empty_process.yml @@ -0,0 +1,4 @@ +clever_age_process: + configurations: + test.empty_process: + tasks: [] diff --git a/Tests/EmptyProcessTest.php b/Tests/EmptyProcessTest.php new file mode 100644 index 00000000..8ddb7d09 --- /dev/null +++ b/Tests/EmptyProcessTest.php @@ -0,0 +1,26 @@ +processManager->execute('test.empty_process'); + self::assertTrue(true, 'There was an exception'); + } +} From 1b66371686f30f4e04e0e0d5fc549feb22b28c04 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 19 Nov 2019 18:26:40 +0100 Subject: [PATCH 074/304] Use docker hub image --- .travis.yml | 4 ++-- Makefile | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2c3e9f88..e535fab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ services: - docker before_script: - - docker build -t cleverage_process:test . + - docker pull cleverage/process-bundle:sf4 script: - - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit + - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit diff --git a/Makefile b/Makefile index cf29fdc0..dfb834b8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,2 @@ -build: - docker build -t cleverage_process:test . - test: - docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit + docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit From 038cdcfa88b039ad35f025455ea542516afd94f1 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 21 Nov 2019 10:22:27 +0100 Subject: [PATCH 075/304] Updated base symfony version for CI to 4.4 --- Makefile | 4 ++++ Resources/tests/environment/sf4/composer.json | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index dfb834b8..2afd75c1 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,6 @@ test: docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit + +test/build: + docker build -t cleverage_process:test . + docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index c76601a3..12de459e 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -5,9 +5,9 @@ "php": "^7.1.3", "ext-ctype": "*", "ext-iconv": "*", - "symfony/dotenv": "4.3.*", + "symfony/dotenv": "4.4.*", "symfony/flex": "^1.3.1", - "symfony/framework-bundle": "4.3.*", + "symfony/framework-bundle": "4.4.*", "symfony/expression-language": "~3.0|~4.0", "symfony/monolog-bundle": "~3.3", @@ -67,7 +67,7 @@ "extra": { "symfony": { "allow-contrib": false, - "require": "4.3.*" + "require": "4.4.*" } } } From d47c1537a5e586ee3910b3e8293e2dc47ca43d9b Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 21 Nov 2019 10:35:59 +0000 Subject: [PATCH 076/304] Update constant_output_task.md --- .../reference/tasks/constant_output_task.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/reference/tasks/constant_output_task.md b/Documentation/reference/tasks/constant_output_task.md index d5da07e9..3fbff205 100644 --- a/Documentation/reference/tasks/constant_output_task.md +++ b/Documentation/reference/tasks/constant_output_task.md @@ -25,3 +25,20 @@ Options | ---- | ---- | :------: | ------- | ----------- | | `output` | `any` | **X** | | Value to output | +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.process_name: + tasks: + constant_output_example: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 + outputs: [XXXX] +``` From 4c86d7ec449a3f156f79328f81ecad7226ead55c Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 21 Nov 2019 10:44:10 +0000 Subject: [PATCH 077/304] Fix documentation links --- Documentation/01-quick_start.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index 5e36b390..e110b1a1 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -50,11 +50,11 @@ Then you can add tasks in this array. They consist of a `service`, optionally co ``` Below you can see a minimal working ETL example. It consist of 3 tasks: -- the first *extract* some data (the [constant output task]() outputs... a constant value): it's an array with 3 +- the first *extract* some data (the [constant output task](./reference/tasks/constant_output_task.md) outputs... a constant value): it's an array with 3 keys/values -- the second *transform* the given value (the [transformer task]() is one of the most important!): the output is then an +- the second *transform* the given value (the [transformer task](./reference/tasks/transformer_task.md) is one of the most important!): the output is then an array with 2 keys/values, created using the value from previous task -- finally, the last will just display the result (it's a cheap *load*, using the [debug task](), only for development +- finally, the last will just display the result (it's a cheap *load*, using the [debug task](./reference/tasks/debug_task.md), only for development purpose!) ```yaml From 2505ab15995090f30f56e7aafc1c1c0ad1670dd7 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 26 Nov 2019 11:10:45 +0100 Subject: [PATCH 078/304] Fixing InputIteratorTask to also work with IteratorAggregate --- Task/InputIteratorTask.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index 3eaba6ee..c2386888 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -88,11 +88,14 @@ protected function handleIteratorFromInput(ProcessState $state) ); } + $input = $state->getInput(); // Create iterator - if ($state->getInput() instanceof \Iterator) { - $this->iterator = $state->getInput(); - } elseif (\is_array($state->getInput())) { - $this->iterator = new \ArrayIterator($state->getInput()); + if ($input instanceof \Iterator) { + $this->iterator = $input; + } elseif ($input instanceof \IteratorAggregate) { + $this->iterator = $input->getIterator(); + } elseif (\is_array($input)) { + $this->iterator = new \ArrayIterator($input); } // Assert iterator is OK From 449226b5579e8305b8bd1adc2cec6f26e01aed21 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 14 Nov 2019 15:18:16 +0100 Subject: [PATCH 079/304] #74 - add more information about enabling the serializer --- CleverAgeProcessBundle.php | 3 ++ .../Compiler/CheckSerializerCompilerPass.php | 36 +++++++++++++++++++ Documentation/01-quick_start.md | 2 ++ 3 files changed, 41 insertions(+) create mode 100644 DependencyInjection/Compiler/CheckSerializerCompilerPass.php diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index b325c6d4..d6b35630 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle; +use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -36,5 +37,7 @@ public function build(ContainerBuilder $container): void 'addTransformer' ) ); + + $container->addCompilerPass(new CheckSerializerCompilerPass()); } } diff --git a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php new file mode 100644 index 00000000..b7633f2d --- /dev/null +++ b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -0,0 +1,36 @@ + + */ +class CheckSerializerCompilerPass implements CompilerPassInterface +{ + const MSG = 'The Symfony serializer component do not seem enabled, consider toggling framework.serializer.enable (see https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled)'; + + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->has('serializer') && !$container->has(DenormalizerInterface::class)) { + throw new AutowiringFailedException('serializer', self::MSG); + } + } +} diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index e110b1a1..e16178a9 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -24,6 +24,8 @@ This bundle requires Symfony 3. You can install it using composer: composer require cleverage/process-bundle ``` +This bundle requires the Symfony Serializer Component, but it might be disabled by default. Consider enable it with https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled. + ## Process definition Most of the work is done through the bundle configuration. From 03e7a709683a525649319dd98a7368521b3e88fa Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 15 Oct 2019 11:53:31 +0200 Subject: [PATCH 080/304] Added contribution notes --- Documentation/01-quick_start.md | 10 +++++++++- Documentation/06-contribute.md | 22 ++++++++++++++++++++++ README.md | 3 ++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index e16178a9..031db4fc 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -24,7 +24,15 @@ This bundle requires Symfony 3. You can install it using composer: composer require cleverage/process-bundle ``` -This bundle requires the Symfony Serializer Component, but it might be disabled by default. Consider enable it with https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled. +Remember to update your AppKernel + +```php +$bundles[] = new CleverAge\ProcessBundle\CleverAgeProcessBundle(); +``` + +Some tasks and transformers use the main Symfony serializer service. You might need to explicitly enable it, or dependency +resolution might fail +* https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled ## Process definition diff --git a/Documentation/06-contribute.md b/Documentation/06-contribute.md index e69de29b..65e1d1f3 100644 --- a/Documentation/06-contribute.md +++ b/Documentation/06-contribute.md @@ -0,0 +1,22 @@ +Contribute +========== + +Every contributions are welcomed. This bundle aims to provide a standalone set of generic component. If a contribution +is too specific or requires dependencies, it might be put in a separated sub-bundle. + +## Pull request process + +Ideally, PR should provide an updated documentation and tests. + +Please use the following template for your tests. + +```markdown +## Feature description + +## PR requirements + +* [ ] Documentation +* [ ] Changelog update +* [ ] Unit tests +* Breaking changes : yes/no +``` diff --git a/README.md b/README.md index bc8f6ba6..c481d08b 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,10 @@ Basically, it will greatly ease the configuration of import and exports but can - [Quick start](Documentation/01-quick_start.md) - [Task types](Documentation/02-task_types.md) - [Custom tasks and development](Documentation/03-custom_tasks.md) -- [Advanced worklow] +- [Advanced workflow] - [Good practices] - [Testing] +- [Contribute](Documentation/06-contribute.md) - Cookbooks - [Common Setup](Documentation/cookbooks/01-common_setup.md) - [Transformations] From a358318b59d9c2b663f70df04c4c2744fd0d83c6 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 14:59:54 +0100 Subject: [PATCH 081/304] Updated contribution guidelines & templates to match github features --- CONTRIBUTING.md | 14 ++++++++++++++ Documentation/06-contribute.md | 22 ---------------------- ISSUE_TEMPLATE.md | 15 +++++++++++++++ PULL_REQUEST_TEMPLATE.md | 15 +++++++++++++++ README.md | 2 +- 5 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 Documentation/06-contribute.md create mode 100644 ISSUE_TEMPLATE.md create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f48e36a2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,14 @@ +Contributing +============ + +Every contributions are welcomed. This bundle aims to provide a standalone set of generic component. +If a contribution is too specific or requires dependencies, it might be put in a separated sub-bundle. + +Ideally every PR should contain documentation and unit test updates. + +## Deprecations notices + +When a feature should be deprecated, or when you have a breaking change for a future version, please : +* [Fill an issue](https://github.com/cleverage/process-bundle/issues/new) +* Add TODO comments with the following format: `@TODO deprecated v4.0` +* Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v4.0', E_USER_DEPRECATED);` diff --git a/Documentation/06-contribute.md b/Documentation/06-contribute.md deleted file mode 100644 index 65e1d1f3..00000000 --- a/Documentation/06-contribute.md +++ /dev/null @@ -1,22 +0,0 @@ -Contribute -========== - -Every contributions are welcomed. This bundle aims to provide a standalone set of generic component. If a contribution -is too specific or requires dependencies, it might be put in a separated sub-bundle. - -## Pull request process - -Ideally, PR should provide an updated documentation and tests. - -Please use the following template for your tests. - -```markdown -## Feature description - -## PR requirements - -* [ ] Documentation -* [ ] Changelog update -* [ ] Unit tests -* Breaking changes : yes/no -``` diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..81d6b2db --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,15 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Cookbooks + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..ad8dadf4 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Cookbooks + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/README.md b/README.md index c481d08b..f8eede52 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Basically, it will greatly ease the configuration of import and exports but can - [Advanced workflow] - [Good practices] - [Testing] -- [Contribute](Documentation/06-contribute.md) +- [Contribute](CONTRIBUTING.md) - Cookbooks - [Common Setup](Documentation/cookbooks/01-common_setup.md) - [Transformations] From 6c1d403874a9dc462db99a2f14e98f9dd4e78bda Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 15:22:18 +0100 Subject: [PATCH 082/304] Added Date parser/formatter documentation --- .../reference/transformers/date_format.md | 39 +++++++++++++++++++ .../reference/transformers/date_parser.md | 39 +++++++++++++++++++ README.md | 2 + Transformer/DateFormatTransformer.php | 16 +++++--- 4 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 Documentation/reference/transformers/date_format.md create mode 100644 Documentation/reference/transformers/date_parser.md diff --git a/Documentation/reference/transformers/date_format.md b/Documentation/reference/transformers/date_format.md new file mode 100644 index 00000000..e19e2590 --- /dev/null +++ b/Documentation/reference/transformers/date_format.md @@ -0,0 +1,39 @@ +DateFormatTransformer +===================== + +Transforms a `\DateTime` into a formatted `string`. It will throw an error if the date cannot be parsed. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\DateFormatTransformer` +* **Transformer code**: `date_format` + +Accepted inputs +--------------- + +`\DateTime` + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `format` | `string` | **X** | | See [PHP date formats](https://www.php.net/manual/fr/function.date.php) for supported values | + +Examples +-------- + +* Example : this will output a string like "2019-12-02" + +```yaml +# Transformer options level +transformers: + date_format: + format: Y-m-d +``` diff --git a/Documentation/reference/transformers/date_parser.md b/Documentation/reference/transformers/date_parser.md new file mode 100644 index 00000000..aa4e796b --- /dev/null +++ b/Documentation/reference/transformers/date_parser.md @@ -0,0 +1,39 @@ +DateParserTransformer +===================== + +Read a `string` to deduce the matching `\DateTime`. It will throw an error if the date cannot be read. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\DateParserTransformer` +* **Transformer code**: `date_parser` + +Accepted inputs +--------------- + +`string` + +Possible outputs +---------------- + +`\DateTime` + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `format` | `string` | **X** | | See [PHP date formats](https://www.php.net/manual/fr/function.date.php) for supported values | + +Examples +-------- + +* Example : this will correctly read the string "2019-12-02" + +```yaml +# Transformer options level +transformers: + date_parser: + format: Y-m-d +``` diff --git a/README.md b/README.md index f8eede52..e0bddf4b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Basically, it will greatly ease the configuration of import and exports but can - [ArrayFilterTransformer](Documentation/reference/transformers/array_filter_transformer.md) - [MappingTransformer](Documentation/reference/transformers/mapping_transformer.md) - [RulesTransformer](Documentation/reference/transformers/rules_transformer.md) + - [DateFormatTransformer](Documentation/reference/transformers/date_format.md) + - [DateParserTransformer](Documentation/reference/transformers/date_parser.md) - Examples - [Simple ETL] - [Roadmap and versions](Documentation/100-roadmap.md) diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 47cb731d..330016d8 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -18,13 +18,13 @@ * Transformer aiming to take a date as an input (object or string) and format it according to options. * In input it takes any value understood by \DateTime. * - * @example in YML config + * @example in YML config * transformers: * date_format: * format: Y-m-d * - * @deprecated the input string value will be removed in next version, use date_parser just before - * @TODO v1.2 : remove string input + * @TODO deprecated v4.0 : remove string input + * @TODO deprecated v4.0 : no false output */ class DateFormatTransformer implements ConfigurableTransformerInterface { @@ -32,8 +32,8 @@ class DateFormatTransformer implements ConfigurableTransformerInterface * @param mixed $value * @param array $options * - * @throws \Exception * @return mixed|string + * @throws \Exception */ public function transform($value, array $options = []) { @@ -44,12 +44,18 @@ public function transform($value, array $options = []) if ($value instanceof \DateTime) { $date = $value; } elseif (is_string($value)) { + @trigger_error('String input will be deprecated in v4.0', E_USER_DEPRECATED); $date = new \DateTime($value); } else { throw new \UnexpectedValueException('Given value cannot be parsed into a date'); } - return $date->format($options['format']); + $result = $date->format($options['format']); + if ($result === false) { + @trigger_error('The date cannot be formatted, this will throw an error starting from v4.0', E_USER_DEPRECATED); + } + + return $result; } /** From 4684428f077b161d520b5a6bec3c58a592c8c8cb Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 16:06:28 +0100 Subject: [PATCH 083/304] Fixes #61: added TransformerTrait documentation --- .../03-generic_transformers_definition.md | 6 ++-- .../reference/tasks/transformer_task.md | 4 +-- .../reference/traits/condition_trait.md | 17 +++++++++++ .../reference/traits/transformer_trait.md | 30 +++++++++++++++++++ .../transformers/array_filter_transformer.md | 2 +- .../transformers/mapping_transformer.md | 2 +- .../transformers/rules_transformer.md | 2 +- 7 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 Documentation/reference/traits/condition_trait.md create mode 100644 Documentation/reference/traits/transformer_trait.md diff --git a/Documentation/reference/03-generic_transformers_definition.md b/Documentation/reference/03-generic_transformers_definition.md index e4750591..68b40ca1 100644 --- a/Documentation/reference/03-generic_transformers_definition.md +++ b/Documentation/reference/03-generic_transformers_definition.md @@ -27,6 +27,6 @@ For each contextual option, you can define | `default` | `any` | | `null` | If not `null`, define the default value | | `default_is_null` | `bool` | | `false` | If you need `null` to be the default value, use this option | -The transformer options are the same than any other transformer using a sub-list of transformers. You can use the -syntax for contextual values (`{{ contextual_option_code }}`) to put placeholders that will be filled by those contextual -options. +The transformer options are the same than any other transformer using a sub-list of transformers (see [TransformerTrait](../traits/transformer_trait.md)). +You can use the syntax for contextual values (`{{ contextual_option_code }}`) to put placeholders that will be filled by +those contextual options. diff --git a/Documentation/reference/tasks/transformer_task.md b/Documentation/reference/tasks/transformer_task.md index 21657660..4a8b5b21 100644 --- a/Documentation/reference/tasks/transformer_task.md +++ b/Documentation/reference/tasks/transformer_task.md @@ -13,7 +13,7 @@ Task reference Accepted inputs --------------- -`any` +`any`: it should match the 1st expected input of the transform chain Possible outputs ---------------- @@ -25,5 +25,5 @@ Options | Code | Type | Required | Default | Description | | ---- | ---- | :------: | ------- | ----------- | -| `transformers` | `array` | **X** | | List of transformer code => transformer options | +| `transformers` | `array` | **X** | | List of transformers, see [TransformerTrait](../traits/transformer_trait.md) | diff --git a/Documentation/reference/traits/condition_trait.md b/Documentation/reference/traits/condition_trait.md new file mode 100644 index 00000000..3a88903d --- /dev/null +++ b/Documentation/reference/traits/condition_trait.md @@ -0,0 +1,17 @@ +ConditionTrait +============== + +Provide generic matching rules + +## Reference + +* Namespace: `CleverAge\ProcessBundle\Transformer\ConditionTrait` +* Options algorithm: _TODO_ + +## Usage + +_TODO_ + +## Implementors + +_TODO_ diff --git a/Documentation/reference/traits/transformer_trait.md b/Documentation/reference/traits/transformer_trait.md new file mode 100644 index 00000000..ad07adc0 --- /dev/null +++ b/Documentation/reference/traits/transformer_trait.md @@ -0,0 +1,30 @@ +TransformerTrait +================ + +Allow to hold a list of sub-transformers and recursively configure their options. + +## Reference + +* Namespace: `CleverAge\ProcessBundle\Transformer\TransformerTrait` +* Options algorithm: + - for each element: the key maps to a transformer code, and the value are resolved by the matching transformer + - note that the key may be followed by `#` and any digit, to allow multiple transformer of the same type. Example: +```yaml +transformers: + transformer_code#1: + some_options: ~ + transformer_code#2: + some_options: ~ +``` + +## Usage + +* Call `TransformerTrait::configureTransformersOptions` with your own `OptionResolver`. You can change `$optionName` if you want a custom option name +* Call `TransformerTrait::applyTransformers` with the resolved transformer options (i.e. `$options["transformers"]`) and the value you want to pass + +## Implementors + +* [TransformerTask](../tasks/transformer_task.md) +* [MappingTransformer](../transformers/mapping_transformer.md) +* [RulesTransformer](../transformers/rules_transformer.md) +* [Generic transformers](../03-generic_transformers_definition.md) diff --git a/Documentation/reference/transformers/array_filter_transformer.md b/Documentation/reference/transformers/array_filter_transformer.md index f072e08d..f91ad117 100644 --- a/Documentation/reference/transformers/array_filter_transformer.md +++ b/Documentation/reference/transformers/array_filter_transformer.md @@ -24,4 +24,4 @@ Options | Code | Type | Required | Default | Description | | ---- | ---- | :------: | ------- | ----------- | -| `condition` | `array` | | `[]` | See [ConditionTrait](TODO) | +| `condition` | `array` | | `[]` | See [ConditionTrait](../traits/condition_trait.md) | diff --git a/Documentation/reference/transformers/mapping_transformer.md b/Documentation/reference/transformers/mapping_transformer.md index 0434c74c..9830542d 100644 --- a/Documentation/reference/transformers/mapping_transformer.md +++ b/Documentation/reference/transformers/mapping_transformer.md @@ -45,7 +45,7 @@ Foreach property there is the following options. | `constant` | `any` | | `null` | If not `null`, will be directly used as a source (takes precedence on `code`) | | `set_null` | `bool` | | `false` | If `true`, `null` will be directly used as a source (takes precedence on `code`) | | `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for this source | -| `transformers` | `array` | | `[]` | List of transformer code => transformer options for subsequent transformations | +| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | Examples -------- diff --git a/Documentation/reference/transformers/rules_transformer.md b/Documentation/reference/transformers/rules_transformer.md index e50f916a..fd65827a 100644 --- a/Documentation/reference/transformers/rules_transformer.md +++ b/Documentation/reference/transformers/rules_transformer.md @@ -46,7 +46,7 @@ Foreach rule there is the following options. | ---- | ---- | :------: | ------- | ----------- | | `condition` | `string` or `null` | | `null` | An expression used to match a value | | `default` | `bool` | | `false` | Mark this rule as a default rule. The given rule must be the last, cannot have a condition, and there cannot have 2 default in the same time | -| `transformers` | `array` | | `[]` | List of transformer code => transformer options for subsequent transformations | +| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | | `constant` | `any` | | `null` | If not `null`, given value will be directly output (takes precedence on `transformers`) | | `set_null` | `bool` | | `false` | If `true`, `null` will be directly output (takes precedence on `constant`) | From 194d7734a4d037d50fd2b2c33e728405c746be7c Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 16:43:38 +0100 Subject: [PATCH 084/304] Added a make target to access a test shell with symfony --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 2afd75c1..1aff13fd 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +shell: + docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 bash + test: docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit From d3fcb40b4df0c94fe6f581fb14433c2a90eb6f5d Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 16:45:54 +0100 Subject: [PATCH 085/304] Fixes #76: added more information about unreachable tasks --- Manager/ProcessManager.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 1414a81f..6d518d04 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -595,7 +595,10 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // We won't throw an error to ease development... but there must be some kind of warning $state = $taskConfiguration->getState(); $logContext = ['main_task_list' => $mainTaskList]; - $this->processLogger->warning("Task '{$taskConfiguration->getCode()}' is unreachable", $logContext); + $this->processLogger->warning( + "Task '{$taskConfiguration->getCode()}' is unreachable, check that it's referenced in some other task output or in the main entry point", + $logContext + ); $this->handleState($state); } } From 73c6dadbd27328d229f2c9c6eaf1124b1357c725 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 26 Nov 2019 16:22:44 +0100 Subject: [PATCH 086/304] Prepared a changelog for v3.1 --- Documentation/changelog/CHANGELOG-3.1.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Documentation/changelog/CHANGELOG-3.1.md diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md new file mode 100644 index 00000000..96bdbfb8 --- /dev/null +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -0,0 +1,11 @@ +Changelog v3.0 => v3.1 +====================== + +Features +-------- + +Fixes +----- + +BC breaks +--------- From 6b94bb87a8455c4d40dd510384fa1183473e401f Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 15 Nov 2019 16:43:02 +0100 Subject: [PATCH 087/304] Added an XML reader/transformer feature --- Documentation/reference/tasks/_template.md | 44 ++++++ .../reference/tasks/xml_reader_task.md | 39 ++++++ .../reference/transformers/_template.md | 4 +- .../reference/transformers/xpath_evaluator.md | 92 +++++++++++++ Filesystem/XmlFile.php | 54 ++++++++ Task/File/Xml/XmlReaderTask.php | 63 +++++++++ Tests/AbstractProcessTest.php | 20 ++- .../XpathEvaluatorTransformerTest.php | 105 ++++++++++++++ Transformer/Xml/XpathEvaluatorTransformer.php | 130 ++++++++++++++++++ composer.json | 1 + 10 files changed, 548 insertions(+), 4 deletions(-) create mode 100644 Documentation/reference/tasks/_template.md create mode 100644 Documentation/reference/tasks/xml_reader_task.md create mode 100644 Documentation/reference/transformers/xpath_evaluator.md create mode 100644 Filesystem/XmlFile.php create mode 100644 Task/File/Xml/XmlReaderTask.php create mode 100644 Tests/Transformer/XpathEvaluatorTransformerTest.php create mode 100644 Transformer/Xml/XpathEvaluatorTransformer.php diff --git a/Documentation/reference/tasks/_template.md b/Documentation/reference/tasks/_template.md new file mode 100644 index 00000000..ed1d4a57 --- /dev/null +++ b/Documentation/reference/tasks/_template.md @@ -0,0 +1,44 @@ +TaskName +======== + +_Describe main goal an use cases of the task_ + +Task reference +-------------- + +* **Service**: `ClassName` + +Accepted inputs +--------------- + +_Description of allowed types_ + +Possible outputs +---------------- + +_Description of possible types_ + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `code` | `type` | **X** _or nothing_ | `default value` _if available_ | _description_ | + +Examples +-------- + +_YAML samples and explanations_ + +* Example 1 + - details + - details + +```yaml +# Task configuration level +code: + service: '@service_ref' + options: + a: 1 + b: 2 +``` diff --git a/Documentation/reference/tasks/xml_reader_task.md b/Documentation/reference/tasks/xml_reader_task.md new file mode 100644 index 00000000..b90cca68 --- /dev/null +++ b/Documentation/reference/tasks/xml_reader_task.md @@ -0,0 +1,39 @@ +XmlReaderTask +============= + +Open and read an XML file. +Requires `php-xml`. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Xml\XmlReaderTask` + +Accepted inputs +--------------- + +No input accepted. + +Possible outputs +---------------- + +A `\DOMDocument` built from the file. + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `file_path` | `string` | **X** | | Path of the file to read from (relative to symfony root or absolute) | +| `mode` | `string` | | `rb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | + +Examples +-------- + +```yaml +# Transformer options level +my_xml_reader: + service: '@CleverAge\ProcessBundle\Task\File\Xml\XmlReaderTask' + options: + file_path: '%kernel.project_dir%/var/data/file.xml' +``` diff --git a/Documentation/reference/transformers/_template.md b/Documentation/reference/transformers/_template.md index f11e3099..d5e98a70 100644 --- a/Documentation/reference/transformers/_template.md +++ b/Documentation/reference/transformers/_template.md @@ -3,8 +3,8 @@ TransformerName _Describe main goal an use cases of the transformer_ -Task reference --------------- +Transformer reference +--------------------- * **Service**: `ClassName` * **Transformer code**: `code` diff --git a/Documentation/reference/transformers/xpath_evaluator.md b/Documentation/reference/transformers/xpath_evaluator.md new file mode 100644 index 00000000..e6274cbf --- /dev/null +++ b/Documentation/reference/transformers/xpath_evaluator.md @@ -0,0 +1,92 @@ +XpathEvaluatorTransformer +========================= + +Manipulate a DOMNode to extract some information using xpath. +Requires `php-xml`. + +**Important** : due to the [behavior of `\DOMXpath::query`](https://www.php.net/manual/en/domxpath.query.php), if you want +to make a query on a sub element of the full `\DOMDocument` you need to start your query with a `.` to specify the current node. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Xml\XpathEvaluatorTransformer` +* **Transformer code**: `xpath_evaluator` + +Accepted inputs +--------------- + +`\DOMNode` only. + +Possible outputs +---------------- + +Depending on the options : +- `string` +- `\DOMNode` +- `null` +- an `array` of one of the type above + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `query` | `string` or `array` | **X** | | One or multiple Xpath queries, array keys are conserved | +| `single_result` | `boolean` | | `true` | Force the result to match a single value | +| `ignore_missing` | `boolean` | | `true` | Only used with `single_result`, avoid errors if the query doesn't match anything | +| `as_text` | `boolean` | | `true` | Return the textual content of the node, only if the query is a `\DOMText` (you might need to use the `text()` xpath selector) | + +Examples +-------- + +All examples assume this XML +```xml + + + ok1 + ok2 + ok3 + + + ok4 + ok5 + ok6 + + +``` + +* Example 1 : get a single value + +```yaml +# Transformer options level +xpath_evaluator: + query: '/a/b/c[0]/text()' +``` + +* Example 2 : get a multiple values + +```yaml +# Transformer options level +xpath_evaluator: + query: '/a/b/c/text()' + single_result: false +``` + +```yaml +# Transformer options level +xpath_evaluator: + query: + - '/a/d/e/text()' + - '/a/d/f/text()' + - '/a/d/g/text()' +``` + +* Example 3 : get a \DOMNode + +```yaml +# Transformer options level +xpath_evaluator: + query: '/a/b' + as_text: false +``` diff --git a/Filesystem/XmlFile.php b/Filesystem/XmlFile.php new file mode 100644 index 00000000..3a14d49d --- /dev/null +++ b/Filesystem/XmlFile.php @@ -0,0 +1,54 @@ + + */ +class XmlFile +{ + /** @var \SplFileObject */ + protected $file; + + /** + * XmlFile constructor. + * + * @param string $path + * @param string $mode + */ + public function __construct(string $path, string $mode = 'rb') + { + $this->file = new \SplFileObject($path, $mode); + } + + public function read(): \DOMDocument + { + $dom = new \DOMDocument(); + $this->file->rewind(); + $fileSize = $this->file->getSize(); + $fileContent = $this->file->fread($fileSize); + + $dom->loadXML($fileContent); + + return $dom; + } + + public function write(\DOMDocument $dom) + { + $content = $dom->saveXML(); + $result = $this->file->fwrite($content); + + if ($result === null) { + throw new \RuntimeException("Could not write content to file"); + } + } +} diff --git a/Task/File/Xml/XmlReaderTask.php b/Task/File/Xml/XmlReaderTask.php new file mode 100644 index 00000000..a827741b --- /dev/null +++ b/Task/File/Xml/XmlReaderTask.php @@ -0,0 +1,63 @@ + + */ +class XmlReaderTask extends AbstractConfigurableTask +{ + /** @var LoggerInterface */ + protected $logger; + + /** + * XmlReaderTask constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * {@inheritDoc} + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('file_path'); + $resolver->setAllowedTypes('file_path', 'string'); + + $resolver->setDefault('mode', 'rb'); + $resolver->setAllowedTypes('mode', 'string'); + } + + /** + * {@inheritDoc} + */ + public function execute(ProcessState $state) + { + if ($state->getInput() !== null) { + $this->logger->warning('Input has been ignored for XMLReaderTask'); + } + + $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); + $state->setOutput($file->read()); + } +} diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index 1f89f28b..9c5b8390 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -94,7 +94,7 @@ protected function assertDataQueue(array $expected, string $processName, bool $c */ protected function getContainer(): ContainerInterface { - if(isset(self::$container)) { + if (isset(self::$container)) { return self::$container; } @@ -115,6 +115,22 @@ protected function getContainer(): ContainerInterface * @throws ExceptionInterface */ protected function assertTransformation(string $transformerCode, $expected, $value, array $options = []) + { + $result = $this->transform($transformerCode, $value, $options); + self::assertEquals($expected, $result); + } + + /** + * Transform some value using referenced transformer with given options + * + * @param string $transformerCode + * @param mixed $value + * @param array $options + * + * @return mixed + * @throws ExceptionInterface + */ + protected function transform(string $transformerCode, $value, array $options = []) { $transformer = $this->transformerRegistry->getTransformer($transformerCode); @@ -124,6 +140,6 @@ protected function assertTransformation(string $transformerCode, $expected, $val $options = $resolver->resolve($options); } - self::assertEquals($expected, $transformer->transform($value, $options)); + return $transformer->transform($value, $options); } } diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/Tests/Transformer/XpathEvaluatorTransformerTest.php new file mode 100644 index 00000000..f8302a54 --- /dev/null +++ b/Tests/Transformer/XpathEvaluatorTransformerTest.php @@ -0,0 +1,105 @@ +loadXML('ok'); + $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ + 'query' => '/a/text()', + ]); + } + + public function testSubQuery() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok'); + + $node = $domDocument->getElementsByTagName('b')[0]; + $this->assertTransformation('xpath_evaluator', 'ok', $node, [ + 'query' => './c/text()', + ]); + } + + public function testMultiResults() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + $this->assertTransformation('xpath_evaluator', ['ok1', 'ok2', 'ok3'], $node, [ + 'query' => './c/text()', + 'single_result' => false, + ]); + } + + public function testMultiResultsAsNodeList() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + /** @var \DOMNodeList $result */ + $result = $this->transform('xpath_evaluator', $node, [ + 'query' => './c/text()', + 'single_result' => false, + 'as_text' => false, + ]); + + self::assertCount(3, $result); + self::assertEquals('ok1', $result[0]->textContent); + self::assertEquals('ok2', $result[1]->textContent); + self::assertEquals('ok3', $result[2]->textContent); + } + + public function testMultiQuery() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + $this->assertTransformation('xpath_evaluator', ['ok1', 'ok2', 'ok3'], $node, [ + 'query' => [ + './c/text()', + './d/text()', + './e/text()', + ], + ]); + } + + public function testMultiQueryWithKey() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + $this->assertTransformation('xpath_evaluator', [ + 'c' => 'ok1', + 'd' => 'ok2', + 'e' => 'ok3', + ], $node, [ + 'query' => [ + 'c' => './c/text()', + 'd' => './d/text()', + 'e' => './e/text()', + ], + ]); + } +} diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php new file mode 100644 index 00000000..9a30d33c --- /dev/null +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -0,0 +1,130 @@ +setRequired('query'); + $resolver->setAllowedTypes('query', ['string', 'array']); + + $resolver->setDefault('single_result', true); + $resolver->setAllowedTypes('single_result', 'bool'); + + $resolver->setDefault('ignore_missing', true); + $resolver->setAllowedTypes('ignore_missing', 'bool'); + + $resolver->setDefault('as_text', true); + $resolver->setAllowedTypes('as_text', 'bool'); + } + + /** + * {@inheritDoc} + */ + public function transform($value, array $options = []) + { + if (!$value instanceof \DOMNode) { + throw new \UnexpectedValueException("Input should be a " . \DOMNode::class); + } + + $xpath = $this->buildXpath($value); + + $query = $options['query']; + if (\is_array($query)) { + $result = \array_map(function ($subquery) use ($xpath, $value, $options) { + return $this->query($xpath, $subquery, $value, $options); + }, $query); + } else { + $result = $this->query($xpath, $query, $value, $options); + } + + return $result; + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + return 'xpath_evaluator'; + } + + /** + * @param \DOMNode $node + * + * @return \DOMXPath + */ + public function buildXpath(\DOMNode $node): \DOMXPath + { + $doc = $node instanceof \DOMDocument ? $node : $node->ownerDocument; + + return new \DOMXPath($doc); + } + + /** + * @param \DOMXPath $xpath + * @param string $query + * @param \DOMNode $node + * @param array $options + * + * @return mixed + */ + public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $options) + { + // TODO check if query is relative ? + $nodeList = $xpath->query($query, $node); + $results = iterator_to_array($nodeList); + + // Convert results to text + if ($options['as_text']) { + $results = \array_map(function (\DOMNode $item) use ($options) { + if (!$item instanceof \DOMText) { + // If you have this error maybe you need to use the "text()" xpath selector + throw new \UnexpectedValueException("Xpath result is not a text node"); + } + + return $item->textContent; + }, $results); + } + + // Unwrap the node list + if ($options['single_result']) { + if (count($results) > 1) { + throw new \UnexpectedValueException("There is too much results for query '{$query}'"); + } + + if (count($results) === 0 && !$options['ignore_missing']) { + throw new \UnexpectedValueException("There is not enough results for query '{$query}'"); + } + + if(count($results) === 1) { + $results = $results[0]; + } else { + $results = null; + } + + } + + return $results; + } + +} diff --git a/composer.json b/composer.json index 9cb59464..2d10787f 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "require": { "php": ">=7.1", "ext-json": "*", + "ext-dom": "*", "symfony/framework-bundle": "~3.0|~4.0", "symfony/expression-language": "~3.0|~4.0", "symfony/monolog-bundle": "~3.3", From de45fc18c56cebd021ceec93d6046581ee990e9b Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 18 Nov 2019 15:08:14 +0100 Subject: [PATCH 088/304] Allow to match directly XML attributes --- .../reference/tasks/xml_reader_task.md | 2 +- .../reference/transformers/xpath_evaluator.md | 6 +++--- Transformer/Xml/XpathEvaluatorTransformer.php | 20 +++++++++++-------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Documentation/reference/tasks/xml_reader_task.md b/Documentation/reference/tasks/xml_reader_task.md index b90cca68..4383f491 100644 --- a/Documentation/reference/tasks/xml_reader_task.md +++ b/Documentation/reference/tasks/xml_reader_task.md @@ -31,7 +31,7 @@ Examples -------- ```yaml -# Transformer options level +# Task configuration level my_xml_reader: service: '@CleverAge\ProcessBundle\Task\File\Xml\XmlReaderTask' options: diff --git a/Documentation/reference/transformers/xpath_evaluator.md b/Documentation/reference/transformers/xpath_evaluator.md index e6274cbf..2424925f 100644 --- a/Documentation/reference/transformers/xpath_evaluator.md +++ b/Documentation/reference/transformers/xpath_evaluator.md @@ -35,7 +35,7 @@ Options | `query` | `string` or `array` | **X** | | One or multiple Xpath queries, array keys are conserved | | `single_result` | `boolean` | | `true` | Force the result to match a single value | | `ignore_missing` | `boolean` | | `true` | Only used with `single_result`, avoid errors if the query doesn't match anything | -| `as_text` | `boolean` | | `true` | Return the textual content of the node, only if the query is a `\DOMText` (you might need to use the `text()` xpath selector) | +| `unwrap_value` | `boolean` | | `true` | Return the textual content of the node, only works if the result is a `\DOMText` (you might need to use the `text()` xpath selector) or a `\DOMAttr` | Examples -------- @@ -82,11 +82,11 @@ xpath_evaluator: - '/a/d/g/text()' ``` -* Example 3 : get a \DOMNode +* Example 3 : get a `\DOMNode` ```yaml # Transformer options level xpath_evaluator: query: '/a/b' - as_text: false + unwrap_value: false ``` diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php index 9a30d33c..96a61e17 100644 --- a/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -33,8 +33,8 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefault('ignore_missing', true); $resolver->setAllowedTypes('ignore_missing', 'bool'); - $resolver->setDefault('as_text', true); - $resolver->setAllowedTypes('as_text', 'bool'); + $resolver->setDefault('unwrap_value', true); + $resolver->setAllowedTypes('unwrap_value', 'bool'); } /** @@ -95,14 +95,18 @@ public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $op $results = iterator_to_array($nodeList); // Convert results to text - if ($options['as_text']) { - $results = \array_map(function (\DOMNode $item) use ($options) { - if (!$item instanceof \DOMText) { - // If you have this error maybe you need to use the "text()" xpath selector - throw new \UnexpectedValueException("Xpath result is not a text node"); + if ($options['unwrap_value']) { + $results = \array_map(function (\DOMNode $item) use ($query, $options) { + if ($item instanceof \DOMAttr) { + return $item->value; } - return $item->textContent; + if ($item instanceof \DOMText) { + // If you have an error, remember that you may need to use the "text()" xpath selector + return $item->textContent; + } + + throw new \UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); }, $results); } From 4986700528a860d5b1416b04022f1e93606d7c69 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 18 Nov 2019 15:12:03 +0100 Subject: [PATCH 089/304] Fixed test & added a test for attribute selector --- Tests/Transformer/XpathEvaluatorTransformerTest.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/Tests/Transformer/XpathEvaluatorTransformerTest.php index f8302a54..cadb21f6 100644 --- a/Tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/Tests/Transformer/XpathEvaluatorTransformerTest.php @@ -27,6 +27,15 @@ public function testSimpleQuery() ]); } + public function testAttributeValueQuery() + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ko'); + $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ + 'query' => '/node/@data', + ]); + } + public function testSubQuery() { $domDocument = new \DOMDocument(); @@ -60,7 +69,7 @@ public function testMultiResultsAsNodeList() $result = $this->transform('xpath_evaluator', $node, [ 'query' => './c/text()', 'single_result' => false, - 'as_text' => false, + 'unwrap_value' => false, ]); self::assertCount(3, $result); From acbf76f3865da9958b3d061788dbb3b7486db991 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 18 Nov 2019 17:11:03 +0100 Subject: [PATCH 090/304] Added the possibility to override subquery result options --- .../reference/transformers/xpath_evaluator.md | 26 +++++++++- .../XpathEvaluatorTransformerTest.php | 42 +++++++++++++++- Transformer/Xml/XpathEvaluatorTransformer.php | 50 +++++++++++++++++-- 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/Documentation/reference/transformers/xpath_evaluator.md b/Documentation/reference/transformers/xpath_evaluator.md index 2424925f..43fe7a4e 100644 --- a/Documentation/reference/transformers/xpath_evaluator.md +++ b/Documentation/reference/transformers/xpath_evaluator.md @@ -32,11 +32,21 @@ Options | Code | Type | Required | Default | Description | | ---- | ---- | :------: | ------- | ----------- | -| `query` | `string` or `array` | **X** | | One or multiple Xpath queries, array keys are conserved | +| `query` | `string` or `array` | **X** | | One or multiple Xpath queries. Using an array, you can either have a simple list of subqueries, or override some root-level query options | | `single_result` | `boolean` | | `true` | Force the result to match a single value | | `ignore_missing` | `boolean` | | `true` | Only used with `single_result`, avoid errors if the query doesn't match anything | | `unwrap_value` | `boolean` | | `true` | Return the textual content of the node, only works if the result is a `\DOMText` (you might need to use the `text()` xpath selector) or a `\DOMAttr` | +Subqueries, in their complex form, have the following options : + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `subquery` | `string` | **X** | | An Xpath query, no additional sublevel is allowed | +| `single_result` | `boolean` | | _Root-level value for `single_result`_ | Force the result to match a single value | +| `ignore_missing` | `boolean` | | _Root-level value for `ignore_missing`_ | Only used with `single_result`, avoid errors if the query doesn't match anything | +| `unwrap_value` | `boolean` | | _Root-level value for `unwrap_value`_ | Return the textual content of the node, only works if the result is a `\DOMText` (you might need to use the `text()` xpath selector) or a `\DOMAttr` | + + Examples -------- @@ -90,3 +100,17 @@ xpath_evaluator: query: '/a/b' unwrap_value: false ``` + +* Example 4 : subquery with partially overridden options + +```yaml +# Transformer options level +xpath_evaluator: + query: + all_c_values: + subquery: '/a/b/c/text()' + single_result: false + e_value: '/a/d/e/text()' + f_value: + subquery: '/a/d/f/text()' +``` diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/Tests/Transformer/XpathEvaluatorTransformerTest.php index cadb21f6..2b78d15b 100644 --- a/Tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/Tests/Transformer/XpathEvaluatorTransformerTest.php @@ -1,4 +1,5 @@ - + + ok1 + ok2 + ok3 + + + ok4 + ok5 + ok6 + + +XML; + $domDocument = new \DOMDocument(); + $domDocument->loadXML($xml); + + $node = $domDocument->getElementsByTagName('b')[0]; + $this->assertTransformation('xpath_evaluator', [ + 'all_c_values' => ['ok1', 'ok2', 'ok3'], + 'e_value' => 'ok4', + 'f_value' => 'ok5', + ], $node, [ + 'query' => [ + 'all_c_values' => [ + 'subquery' => '/a/b/c/text()', + 'single_result' => false, + ], + 'e_value' => '/a/d/e/text()', + 'f_value' => [ + 'subquery' => '/a/d/f/text()', + ], + ], + ]); + } } diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php index 96a61e17..ba0686ea 100644 --- a/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -11,6 +11,7 @@ namespace CleverAge\ProcessBundle\Transformer\Xml; use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -26,14 +27,55 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('query'); $resolver->setAllowedTypes('query', ['string', 'array']); + $resolver->setNormalizer('query', function(Options $options, $value) { + // Basic case : a single query + if(\is_string($value)) { + return $value; + } + + // Complex case : a list of subqueries, each can override root level options + if(\is_array($value)) { + $queryOptions = []; + $queryResolver = new OptionsResolver(); + $this->configureQueryOptions($queryResolver, $options); + $queryResolver->setRequired('subquery'); + $queryResolver->setAllowedTypes('subquery', 'string'); + + foreach ($value as $code => $subquery) { + if(\is_string($subquery)) { + $subquery = ['subquery' => $subquery]; + } + + $queryOptions[$code] = $queryResolver->resolve($subquery); + } + + return $queryOptions; + } - $resolver->setDefault('single_result', true); + // This should never be reached + throw new \InvalidArgumentException('Unhandled query'); + }); + + // Use same options & defaults for root option level and subquery options + $this->configureQueryOptions($resolver); + } + + /** + * Configure options about how to handle xpath query results. + * Available at root and subquery level. + * + * @param OptionsResolver $resolver + * @param Options|null $parentOptions + */ + public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null) + { + $resolver->setDefault('single_result', $parentOptions ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); - $resolver->setDefault('ignore_missing', true); + $resolver->setDefault('ignore_missing', $parentOptions ? $parentOptions['ignore_missing'] : true); $resolver->setAllowedTypes('ignore_missing', 'bool'); - $resolver->setDefault('unwrap_value', true); + $resolver->setDefault('unwrap_value', $parentOptions ? $parentOptions['unwrap_value'] : true); $resolver->setAllowedTypes('unwrap_value', 'bool'); } @@ -51,7 +93,7 @@ public function transform($value, array $options = []) $query = $options['query']; if (\is_array($query)) { $result = \array_map(function ($subquery) use ($xpath, $value, $options) { - return $this->query($xpath, $subquery, $value, $options); + return $this->query($xpath, $subquery['subquery'], $value, $subquery); }, $query); } else { $result = $this->query($xpath, $query, $value, $options); From 27ac068539eb702f5c9221892e33cdba9672a06c Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 18 Nov 2019 17:14:10 +0100 Subject: [PATCH 091/304] Fixed missing readme links --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e0bddf4b..bf4b55bd 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Basically, it will greatly ease the configuration of import and exports but can - Reference - [Process definition](Documentation/reference/01-process_definition.md) - [Task definition](Documentation/reference/02-task_definition.md) - - [Generic transformers definition](Documentation/reference/03-generic_transformers_definition.md) - Basic and debug - [ConstantOutputTask](Documentation/reference/tasks/constant_output_task.md) - [ConstantIterableOutputTask](Documentation/reference/tasks/constant_iterable_output_task.md) @@ -44,6 +43,8 @@ Basically, it will greatly ease the configuration of import and exports but can - File/CSV - [CsvReaderTask](Documentation/reference/tasks/csv_reader_task.md) - [CsvWriterTask](Documentation/reference/tasks/csv_writer_task.md) + - File/XML + - [XmlReaderTask](Documentation/reference/tasks/xml_reader_task.md) - Flow manipulation - [AggregateIterableTask](Documentation/reference/tasks/aggregate_iterable_task.md) - [InputAggregatorTask](Documentation/reference/tasks/input_aggregator_task.md) @@ -54,6 +55,8 @@ Basically, it will greatly ease the configuration of import and exports but can - [RulesTransformer](Documentation/reference/transformers/rules_transformer.md) - [DateFormatTransformer](Documentation/reference/transformers/date_format.md) - [DateParserTransformer](Documentation/reference/transformers/date_parser.md) + - [XpathEvaluatorTransformer](Documentation/reference/transformers/xpath_evaluator.md) + - [Generic transformers definition](Documentation/reference/03-generic_transformers_definition.md) - Examples - [Simple ETL] - [Roadmap and versions](Documentation/100-roadmap.md) From 29c64b2d530476809dfbc5a0eb2edb5985cf4863 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 26 Nov 2019 18:04:13 +0100 Subject: [PATCH 092/304] #83 - added events around process execution --- Event/ProcessEvent.php | 105 +++++++++++++++++++++++++++++++++++++ Manager/ProcessManager.php | 54 +++++++++++++++++-- 2 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 Event/ProcessEvent.php diff --git a/Event/ProcessEvent.php b/Event/ProcessEvent.php new file mode 100644 index 00000000..9ec1b809 --- /dev/null +++ b/Event/ProcessEvent.php @@ -0,0 +1,105 @@ + + */ +class ProcessEvent extends Event +{ + + const EVENT_PROCESS_STARTED = 'cleverage_process.start'; + const EVENT_PROCESS_ENDED = 'cleverage_process.end'; + const EVENT_PROCESS_FAILED = 'cleverage_process.fail'; + + /** @var string */ + protected $processCode; + + /** @var mixed */ + protected $processInput; + + /** @var mixed */ + protected $processOutput; + + /** @var array */ + protected $processContext; + + /** @var \Throwable|null */ + protected $processError; + + /** + * ProcessEvent constructor. + * + * @param string $processCode + * @param mixed $processInput + * @param array $processContext + * @param mixed $processOutput + * @param \Throwable|null $processError + */ + public function __construct( + string $processCode, + $processInput = null, + array $processContext = [], + $processOutput = null, + \Throwable $processError = null + ) { + $this->processCode = $processCode; + $this->processInput = $processInput; + $this->processOutput = $processOutput; + $this->processContext = $processContext; + $this->processError = $processError; + } + + /** + * @return string + */ + public function getProcessCode(): string + { + return $this->processCode; + } + + /** + * @return mixed + */ + public function getProcessInput() + { + return $this->processInput; + } + + /** + * @return mixed + */ + public function getProcessOutput() + { + return $this->processOutput; + } + + /** + * @return array + */ + public function getProcessContext(): array + { + return $this->processContext; + } + + /** + * @return \Throwable|null + */ + public function getProcessError(): ?\Throwable + { + return $this->processError; + } + +} diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 6d518d04..a8531854 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -13,6 +13,7 @@ use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use CleverAge\ProcessBundle\Context\ContextualOptionResolver; +use CleverAge\ProcessBundle\Event\ProcessEvent; use CleverAge\ProcessBundle\Exception\CircularProcessException; use CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException; use CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException; @@ -30,6 +31,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Execute processes @@ -73,25 +75,33 @@ class ProcessManager /** @var TaskConfiguration */ protected $taskConfiguration; + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + /** + * ProcessManager constructor. + * * @param ContainerInterface $container * @param ProcessLogger $processLogger * @param TaskLogger $taskLogger * @param ProcessConfigurationRegistry $processConfigurationRegistry * @param ContextualOptionResolver $contextualOptionResolver + * @param EventDispatcherInterface $eventDispatcher */ public function __construct( ContainerInterface $container, ProcessLogger $processLogger, TaskLogger $taskLogger, ProcessConfigurationRegistry $processConfigurationRegistry, - ContextualOptionResolver $contextualOptionResolver + ContextualOptionResolver $contextualOptionResolver, + EventDispatcherInterface $eventDispatcher ) { $this->container = $container; $this->processLogger = $processLogger; $this->taskLogger = $taskLogger; $this->processConfigurationRegistry = $processConfigurationRegistry; $this->contextualOptionResolver = $contextualOptionResolver; + $this->eventDispatcher = $eventDispatcher; } /** @@ -111,15 +121,51 @@ public function getTaskConfiguration(): ?TaskConfiguration } /** + * Execute a process with a given input and context + * + * This method decorates the real execution to add event & error handling + * @see ProcessManager::doExecute + * * @param string $processCode - * @param mixed $input + * @param null $input * @param array $context * - * @throws \Exception - * * @return mixed */ public function execute(string $processCode, $input = null, array $context = []) + { + try { + $this->eventDispatcher->dispatch( + ProcessEvent::EVENT_PROCESS_STARTED, + new ProcessEvent($processCode, $input, $context) + ); + $result = $this->doExecute($processCode, $input, $context); + $this->eventDispatcher->dispatch( + ProcessEvent::EVENT_PROCESS_ENDED, + new ProcessEvent($processCode, $input, $context, $result) + ); + } catch (\Throwable $error) { + $this->eventDispatcher->dispatch( + ProcessEvent::EVENT_PROCESS_ENDED, + new ProcessEvent($processCode, $input, $context, null, $error) + ); + + throw $error; + } + + return $result; + } + + /** + * Real process execution, with a given input and context + * + * @param string $processCode + * @param mixed $input + * @param array $context + * + * @return mixed + */ + protected function doExecute(string $processCode, $input = null, array $context = []) { $parentProcessHistory = $this->processHistory; $processConfiguration = $this->processConfigurationRegistry->getProcessConfiguration($processCode); From 6433dfa1ec5e08ce5a42013dca5817df7b91a31a Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 27 Nov 2019 15:44:08 +0100 Subject: [PATCH 093/304] #83 - added logs around process execution --- Manager/ProcessManager.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index a8531854..d0f0bf9a 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -139,12 +139,17 @@ public function execute(string $processCode, $input = null, array $context = []) ProcessEvent::EVENT_PROCESS_STARTED, new ProcessEvent($processCode, $input, $context) ); + $this->processLogger->debug('Process start'); + $result = $this->doExecute($processCode, $input, $context); + + $this->processLogger->debug('Process end'); $this->eventDispatcher->dispatch( ProcessEvent::EVENT_PROCESS_ENDED, new ProcessEvent($processCode, $input, $context, $result) ); } catch (\Throwable $error) { + $this->processLogger->critical('Critical process failure', ['error' => $error->getMessage()]); $this->eventDispatcher->dispatch( ProcessEvent::EVENT_PROCESS_ENDED, new ProcessEvent($processCode, $input, $context, null, $error) From 7707a0c04c6692eb5bee040569fd97c21392d3d2 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 2 Dec 2019 16:28:23 +0100 Subject: [PATCH 094/304] #82: disabled default error strategy --- DependencyInjection/Configuration.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 2540810f..ac73e949 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -50,7 +50,12 @@ public function getConfigTreeBuilder() $definition = $rootNode->children(); // Default error strategy - $definition->scalarNode('default_error_strategy')->defaultValue(TaskConfiguration::STRATEGY_SKIP)->end(); + $definition->enumNode('default_error_strategy') + ->values([ + TaskConfiguration::STRATEGY_SKIP, + TaskConfiguration::STRATEGY_STOP, + ]) + ->isRequired(); $this->appendRootProcessConfigDefinition($definition); $this->appendRootTransformersConfigDefinition($definition); @@ -62,6 +67,7 @@ public function getConfigTreeBuilder() /** * "generic_transformers" root configuration + * * @param NodeBuilder $definition */ protected function appendRootTransformersConfigDefinition(NodeBuilder $definition) @@ -85,6 +91,7 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio /** * Single transformer configuration + * * @param NodeBuilder $definition */ protected function appendTransformerConfigDefinition(NodeBuilder $definition) From b24bb771161c23db7b484defc02bf2df52cab5f1 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 3 Dec 2019 16:47:01 +0100 Subject: [PATCH 095/304] #82 - added the configuration for default error strategy --- Resources/tests/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/tests/config.yml b/Resources/tests/config.yml index 407d3a3f..521b8f01 100644 --- a/Resources/tests/config.yml +++ b/Resources/tests/config.yml @@ -2,3 +2,6 @@ imports: - { resource: process/* } - { resource: task/* } - { resource: transfomer/* } + +clever_age_process: + default_error_strategy: stop From 277b6a76107e4a969acfe676fe4014a47bcb81a8 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 3 Dec 2019 17:01:16 +0100 Subject: [PATCH 096/304] #82 - added doc & changelog --- DependencyInjection/Configuration.php | 3 +++ Documentation/01-quick_start.md | 16 ++++++++++++++++ Documentation/changelog/CHANGELOG-3.1.md | 3 +++ 3 files changed, 22 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ac73e949..eab4840f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -81,6 +81,7 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio $transformerListDefinition = $transformersArrayDefinition ->performNoDeepMerging() ->cannotBeOverwritten() + ->info('Unique custom transformer code') ->children(); $this->appendTransformerConfigDefinition($transformerListDefinition); @@ -117,6 +118,7 @@ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) // Process list $processListDefinition = $configurationsArrayDefinition ->performNoDeepMerging() + ->info('Unique custom process code') ->cannotBeOverwritten() ->children(); @@ -149,6 +151,7 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition) $taskListDefinition = $tasksArrayDefinition ->performNoDeepMerging() ->cannotBeOverwritten() + ->info('Unique custom task code') ->children(); $this->appendTaskConfigDefinition($taskListDefinition); diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index 031db4fc..0de77dde 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -34,6 +34,22 @@ Some tasks and transformers use the main Symfony serializer service. You might n resolution might fail * https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled +## Global configuration + +You can use `./bin/console config:dump-reference clever_age_process` to have a summary of current configuration. + +Aside from process and transformer configurations, there is the `default_error_strategy` setting that allow you to define +behavior if a task encounter an error. Up to v3.0, the default value was to `skip` iterations with errors. Starting from v3.1, +the configuration should be defined by the user. + +We recommend to use the `stop` configuration (see bellow), and then specify task by task which one can be `skipped`. + +Recommended example : +```yaml +clever_age_process: + default_error_strategy: stop +``` + ## Process definition Most of the work is done through the bundle configuration. diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 96bdbfb8..ca18737c 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -9,3 +9,6 @@ Fixes BC breaks --------- + +* [GIHTUB-82](https://github.com/cleverage/process-bundle/issues/82): the `default_error_strategy` is now mandatory. +If you have any doubt, you can use `default_error_strategy: skip` to keep previous behavior. From a9bf7408fec20e7b7752c5ce50f45ba27476a94e Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 3 Dec 2019 17:43:33 +0100 Subject: [PATCH 097/304] #83 - added doc about events --- Documentation/03b-advanced_workflows.md | 9 ------- Documentation/04-advanced_workflow.md | 26 +++++++++++++++++++ ...good_practices.md => 05-good_practices.md} | 0 .../{05-testing.md => 06-testing.md} | 0 Documentation/changelog/CHANGELOG-3.1.md | 3 +++ README.md | 2 +- 6 files changed, 30 insertions(+), 10 deletions(-) delete mode 100644 Documentation/03b-advanced_workflows.md create mode 100644 Documentation/04-advanced_workflow.md rename Documentation/{04-good_practices.md => 05-good_practices.md} (100%) rename Documentation/{05-testing.md => 06-testing.md} (100%) diff --git a/Documentation/03b-advanced_workflows.md b/Documentation/03b-advanced_workflows.md deleted file mode 100644 index 6699470c..00000000 --- a/Documentation/03b-advanced_workflows.md +++ /dev/null @@ -1,9 +0,0 @@ -task resolution & blocking - -wrapping execution in subprocess - -errors & skips - -multithreading - -orphan tasks diff --git a/Documentation/04-advanced_workflow.md b/Documentation/04-advanced_workflow.md new file mode 100644 index 00000000..d00a2cff --- /dev/null +++ b/Documentation/04-advanced_workflow.md @@ -0,0 +1,26 @@ +Advanced Workflow +================= + +## Process execution flow + +_TODO_ +* task resolution & blocking +* wrapping execution in subprocess +* errors & skips +* orphan tasks + +## Events + +Events are being send around process execution (see `CleverAge\ProcessBundle\Event\ProcessEvent`) : +* `cleverage_process.start` : on process start +* `cleverage_process.end` : on successful process end +* `cleverage_process.fail` : on failed process end (with the associated error) + +You can also use [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) to manually trigger an event in the middle of a process. + +## Parallelization + +_TODO_ +* ProcessLauncherTask +* EnqueueBundle +* pthread diff --git a/Documentation/04-good_practices.md b/Documentation/05-good_practices.md similarity index 100% rename from Documentation/04-good_practices.md rename to Documentation/05-good_practices.md diff --git a/Documentation/05-testing.md b/Documentation/06-testing.md similarity index 100% rename from Documentation/05-testing.md rename to Documentation/06-testing.md diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index ca18737c..10c776c1 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -4,6 +4,9 @@ Changelog v3.0 => v3.1 Features -------- +* [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) +around process execution + Fixes ----- diff --git a/README.md b/README.md index bf4b55bd..f3d5c600 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Basically, it will greatly ease the configuration of import and exports but can - [Quick start](Documentation/01-quick_start.md) - [Task types](Documentation/02-task_types.md) - [Custom tasks and development](Documentation/03-custom_tasks.md) -- [Advanced workflow] +- [Advanced workflow](Documentation/04-advanced_workflow.md) - [Good practices] - [Testing] - [Contribute](CONTRIBUTING.md) From a003ae80670365e5f2779b110bf4e20d6537a7cd Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 3 Dec 2019 17:53:05 +0100 Subject: [PATCH 098/304] #86 - added a simple XML file writer --- Documentation/changelog/CHANGELOG-3.1.md | 1 + .../reference/tasks/xml_writer_task.md | 39 +++++++++++ README.md | 1 + Task/File/Xml/XmlWriterTask.php | 65 +++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 Documentation/reference/tasks/xml_writer_task.md create mode 100644 Task/File/Xml/XmlWriterTask.php diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 10c776c1..333c508c 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -6,6 +6,7 @@ Features * [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) around process execution +* [GITHUB-86](https://github.com/cleverage/process-bundle/issues/86): added XML manipulation tools Fixes ----- diff --git a/Documentation/reference/tasks/xml_writer_task.md b/Documentation/reference/tasks/xml_writer_task.md new file mode 100644 index 00000000..e8678317 --- /dev/null +++ b/Documentation/reference/tasks/xml_writer_task.md @@ -0,0 +1,39 @@ +XmlWriterTask +============= + +Open and write an XML file. +Requires `php-xml`. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Xml\XmlWriterTask` + +Accepted inputs +--------------- + +A `\DOMDocument` to dump into the file. + +Possible outputs +---------------- + +Resulting file path. + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `file_path` | `string` | **X** | | Path of the file to write into (relative to symfony root or absolute) | +| `mode` | `string` | | `rb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | + +Examples +-------- + +```yaml +# Task configuration level +my_xml_reader: + service: '@CleverAge\ProcessBundle\Task\File\Xml\XmlWriterTask' + options: + file_path: '%kernel.project_dir%/var/data/file.xml' +``` diff --git a/README.md b/README.md index f3d5c600..5079bd7f 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Basically, it will greatly ease the configuration of import and exports but can - [CsvWriterTask](Documentation/reference/tasks/csv_writer_task.md) - File/XML - [XmlReaderTask](Documentation/reference/tasks/xml_reader_task.md) + - [XmlWriterTask](Documentation/reference/tasks/xml_writer_task.md) - Flow manipulation - [AggregateIterableTask](Documentation/reference/tasks/aggregate_iterable_task.md) - [InputAggregatorTask](Documentation/reference/tasks/input_aggregator_task.md) diff --git a/Task/File/Xml/XmlWriterTask.php b/Task/File/Xml/XmlWriterTask.php new file mode 100644 index 00000000..83eecf2f --- /dev/null +++ b/Task/File/Xml/XmlWriterTask.php @@ -0,0 +1,65 @@ + + */ +class XmlWriterTask extends AbstractConfigurableTask +{ + /** @var LoggerInterface */ + protected $logger; + + /** + * XmlReaderTask constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * {@inheritDoc} + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('file_path'); + $resolver->setAllowedTypes('file_path', 'string'); + + $resolver->setDefault('mode', 'wb'); + $resolver->setAllowedTypes('mode', 'string'); + } + + /** + * {@inheritDoc} + */ + public function execute(ProcessState $state) + { + $input = $state->getInput(); + if (!$input instanceof \DOMDocument) { + throw new \UnexpectedValueException('Input must be a \DOMDocument'); + } + + $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); + $file->write($input); + $state->setOutput($this->getOption($state, 'file_path')); + } +} From 3ac007d8024d79c67d1aed8c96e6a674d02d1052 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 4 Dec 2019 17:19:10 +0100 Subject: [PATCH 099/304] Fixes #99 - improved some error messages with sub-transformer exceptions --- Exception/TransformerException.php | 8 +-- .../transfomer/transformer_exception.yml | 22 +++++++ .../Transformer/TransformerExceptionTest.php | 57 +++++++++++++++++++ Transformer/ArrayMapTransformer.php | 14 +++-- 4 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 Resources/tests/transfomer/transformer_exception.yml create mode 100644 Tests/Transformer/TransformerExceptionTest.php diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index d2eb86a5..43e4873c 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -46,11 +46,11 @@ public function setTargetProperty(string $targetProperty): void protected function updateMessage() { - if ($this->targetProperty) { + if (isset($this->targetProperty)) { $m = sprintf( - "Transformation '%s' have failed for target property '%s'", - $this->transformerCode, - $this->targetProperty + "For target property '%s', transformation '%s' have failed", + $this->targetProperty, + $this->transformerCode ); } else { $m = sprintf( diff --git a/Resources/tests/transfomer/transformer_exception.yml b/Resources/tests/transfomer/transformer_exception.yml new file mode 100644 index 00000000..84b6ca8d --- /dev/null +++ b/Resources/tests/transfomer/transformer_exception.yml @@ -0,0 +1,22 @@ +clever_age_process: + configurations: + test.transformer_exception.deep: + entry_point: transform + end_point: transform + tasks: + transform: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + error_strategy: stop + options: + transformers: + mapping: + mapping: + '[field]': + transformers: + array_map: + transformers: + array_map: + transformers: + implode: ~ + default: + value: anything diff --git a/Tests/Transformer/TransformerExceptionTest.php b/Tests/Transformer/TransformerExceptionTest.php new file mode 100644 index 00000000..b1ab1df8 --- /dev/null +++ b/Tests/Transformer/TransformerExceptionTest.php @@ -0,0 +1,57 @@ +getMessage()); + } + + /** + * Simple test case using a simulated error inside a mapping transformer and array_map transformers + */ + public function testDeepError() + { + $input = [ + 'field' => [ + [ + ['a', 'b'], + 1, // Error here + ], + ], + ]; + + $message = null; + try { + $this->processManager->execute('test.transformer_exception.deep', $input); + } catch (\RuntimeException $exception) { + $message = $exception->getMessage(); + } + + self::assertNotNull($message); + self::assertContains("For target property '1', transformation 'implode' have failed", $message); + } +} diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index d7ed5506..3db87dcb 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Transformer; +use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -50,11 +51,16 @@ public function transform($values, array $options = []) $results = []; /** @noinspection ForeachSourceInspection */ foreach ($values as $key => $item) { - $item = $this->applyTransformers($options['transformers'], $item); - if (null === $item && $options['skip_null']) { - continue; + try { + $item = $this->applyTransformers($options['transformers'], $item); + if (null === $item && $options['skip_null']) { + continue; + } + $results[$key] = $item; + } catch (TransformerException $exception) { + $exception->setTargetProperty((string)$key); + throw $exception; } - $results[$key] = $item; } return $results; From 107b85c286032494af3a7dc32759208aaea8009a Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 4 Dec 2019 18:11:44 +0100 Subject: [PATCH 100/304] Added documentation about Blackfire usage --- Dockerfile | 12 ++++ Documentation/cookbooks/memory_usage_graph.md | 3 +- .../cookbooks/performances_monitoring.md | 65 +++++++++++++++++++ README.md | 2 + 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 Documentation/cookbooks/performances_monitoring.md diff --git a/Dockerfile b/Dockerfile index b83cd62d..e55e6c7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,11 +2,22 @@ ARG PHP_VERSION=7.1 FROM php:${PHP_VERSION}-cli ARG SF_ENV=sf4 +ARG BLACKFIRE_PHP_VERSION=71 +ARG BLACKFIRE_PROBE_VERSION=1.29.1 +ARG BLACKFIRE_AGENT_VERSION=1.30.0 # Basic tools RUN apt-get update RUN apt-get install -y wget git zip unzip +# Blackfire install +RUN curl -o $(php -i | grep -P "^extension_dir " | sed "s/^.* => //g")/blackfire.so -D - -L -s https://packages.blackfire.io/binaries/blackfire-php/${BLACKFIRE_PROBE_VERSION}/blackfire-php-linux_amd64-php-${BLACKFIRE_PHP_VERSION}.so +RUN curl -o /usr/bin/blackfire-agent -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-agent-linux_amd64 +RUN chmod +x /usr/bin/blackfire-agent +RUN curl -o /usr/bin/blackfire -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-cli-linux_amd64 +RUN chmod +x /usr/bin/blackfire +RUN docker-php-ext-enable blackfire + # Composer install RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" @@ -18,6 +29,7 @@ RUN chmod +x /usr/local/bin/composer # Basic sample symfony app install RUN mkdir /app WORKDIR /app +ENV HOME /app COPY Resources/tests/environment/${SF_ENV}/composer.json /app RUN composer install diff --git a/Documentation/cookbooks/memory_usage_graph.md b/Documentation/cookbooks/memory_usage_graph.md index a2ab2628..c72161f9 100644 --- a/Documentation/cookbooks/memory_usage_graph.md +++ b/Documentation/cookbooks/memory_usage_graph.md @@ -1,4 +1,5 @@ -## How to easily graph the memory usage of your app for debug purposes +Memory usage analysis +===================== This method is clearly not the most elegant one but it doesn't require any special tool apart from Gnuplot on your desktop environment. diff --git a/Documentation/cookbooks/performances_monitoring.md b/Documentation/cookbooks/performances_monitoring.md new file mode 100644 index 00000000..633284ec --- /dev/null +++ b/Documentation/cookbooks/performances_monitoring.md @@ -0,0 +1,65 @@ +Performances Monitoring +======================= + +For heavy work there is multiple solutions to improve speed (_TODO add link to multithreading cookbook_) and memory consumption. + +While developing custom tasks you might want to see how well your PHP code behaves, and one solution is to use [Blackfire](https://blackfire.io) +to analyse call graphs with timings & memory analysis. + +## Setup + +If you're using the official PHP docker image, you can add the Blackfire probe to your container ([Official documentation](https://blackfire.io/docs/up-and-running/installation)) : + +```dockerfile +ARG BLACKFIRE_PHP_VERSION=71 +ARG BLACKFIRE_PROBE_VERSION=1.29.1 +ARG BLACKFIRE_AGENT_VERSION=1.30.0 + +# Blackfire PHP Probe +RUN curl -o $(php -i | grep -P "^extension_dir " | sed "s/^.* => //g")/blackfire.so -D - -L -s https://packages.blackfire.io/binaries/blackfire-php/${BLACKFIRE_PROBE_VERSION}/blackfire-php-linux_amd64-php-${BLACKFIRE_PHP_VERSION}.so +RUN docker-php-ext-enable blackfire +# Blackfire Agent (for HTTP calls) +RUN curl -o /usr/bin/blackfire-agent -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-agent-linux_amd64 +RUN chmod +x /usr/bin/blackfire-agent +# Blackfire CLI (for console) +RUN curl -o /usr/bin/blackfire -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-cli-linux_amd64 +RUN chmod +x /usr/bin/blackfire +``` + +Then, with your [own credentials](https://blackfire.io/my/settings/credentials), execute inside your container +```shell script +blackfire config --client-id=$CLIENT_ID --client-token=$CLIENT_TOKEN +``` + +You can also pass those ids during the run call. + +## Usage + +Just prefix `blackfire run` while executing your PHP commands inside your container, and Blackfire will provide you an URL +with the resulting call graph. Be careful to cleanup the cache before calling Blackfire, to avoid any noise. + +```shell script +$ ./bin/console c:c --env=test + + // Clearing the cache for the test environment with debug true + + + [OK] Cache for the "test" environment (debug=true) was successfully cleared. + + +$ blackfire --client-id=xxx-xxx-xxx-xxx-xxx --client-token=xxxxxxxxxxx run php bin/console --env=test cleverage:process:execute test.simple_process +Starting process 'test.simple_process'... +Process 'test.simple_process' executed successfully + +Blackfire Run completed +Graph URL https://blackfire.io/profiles/xxx-xxx-xxx-xxx-xxx/graph +No tests! Create some now https://blackfire.io/docs/cookbooks/tests +No recommendations + +Wall Time 102ms +I/O Wait n/a +CPU Time n/a +Memory 5.35MB +Network n/a n/a n/a +SQL n/a n/a +``` diff --git a/README.md b/README.md index 5079bd7f..de1794af 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Basically, it will greatly ease the configuration of import and exports but can - [Subprocess] - [File manipulation] - [Direct call (in controller)] + - [Performances monitoring](Documentation/cookbooks/performances_monitoring.md) + - [Memory usage analysis](Documentation/cookbooks/memory_usage_graph.md) - Reference - [Process definition](Documentation/reference/01-process_definition.md) - [Task definition](Documentation/reference/02-task_definition.md) From 52c0a908e522d5091d43ff59e64fb6448aed4e91 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 17 Dec 2019 15:44:25 +0100 Subject: [PATCH 101/304] Allowing integer keys in WrapperTransformer --- Transformer/WrapperTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transformer/WrapperTransformer.php b/Transformer/WrapperTransformer.php index 9ec70468..6d9e44a7 100644 --- a/Transformer/WrapperTransformer.php +++ b/Transformer/WrapperTransformer.php @@ -46,7 +46,7 @@ public function configureOptions(OptionsResolver $resolver) 'wrapper_key', ] ); - $resolver->setAllowedTypes('wrapper_key', ['string']); + $resolver->setAllowedTypes('wrapper_key', ['string', 'int']); } /** From 9f37cef883b70cfad8ee97cfa75322fa427eae35 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 8 Jan 2020 21:53:43 +0100 Subject: [PATCH 102/304] New transformers: constant and expression_language_map --- Resources/config/services/transformer.yml | 16 +-- Transformer/ConstantTransformer.php | 60 ++++++++ .../ExpressionLanguageMapTransformer.php | 128 ++++++++++++++++++ 3 files changed, 194 insertions(+), 10 deletions(-) create mode 100644 Transformer/ConstantTransformer.php create mode 100644 Transformer/ExpressionLanguageMapTransformer.php diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml index dc86da3f..cdb44895 100644 --- a/Resources/config/services/transformer.yml +++ b/Resources/config/services/transformer.yml @@ -1,17 +1,13 @@ services: - CleverAge\ProcessBundle\Transformer\: - resource: '../../../Transformer/*' - exclude: '../../../Transformer/GenericTransformer.php' + _defaults: autowire: true public: false - tags: - - { name: cleverage.transformer } - - { name: monolog.logger, channel: cleverage_process_transformer } - - CleverAge\ProcessBundle\Transformer\RulesTransformer: - arguments: - $transformerRegistry: '@CleverAge\ProcessBundle\Registry\TransformerRegistry' + bind: $language: '@cleverage_process.expression_language' + + CleverAge\ProcessBundle\Transformer\: + resource: '../../../Transformer/*' + exclude: '../../../Transformer/GenericTransformer.php' tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Transformer/ConstantTransformer.php b/Transformer/ConstantTransformer.php new file mode 100644 index 00000000..28858c2a --- /dev/null +++ b/Transformer/ConstantTransformer.php @@ -0,0 +1,60 @@ + + */ +class ConstantTransformer implements ConfigurableTransformerInterface +{ + /** + * @param OptionsResolver $resolver + * + * @throws ExceptionInterface + */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + 'constant', + ] + ); + } + + /** + * Must return the transformed $value + * + * @param mixed $value + * @param array $options + * + * @return mixed $value + */ + public function transform($value, array $options = []) + { + return $options['constant'] ?? null; + } + + /** + * Returns the unique code to identify the transformer + * + * @return string + */ + public function getCode(): string + { + return 'constant'; + } +} diff --git a/Transformer/ExpressionLanguageMapTransformer.php b/Transformer/ExpressionLanguageMapTransformer.php new file mode 100644 index 00000000..9f3427bf --- /dev/null +++ b/Transformer/ExpressionLanguageMapTransformer.php @@ -0,0 +1,128 @@ + + */ +class ExpressionLanguageMapTransformer implements ConfigurableTransformerInterface +{ + /** @var ExpressionLanguage */ + protected $language; + + /** + * @param ExpressionLanguage $language + */ + public function __construct(ExpressionLanguage $language) + { + $this->language = $language; + } + + /** + * @param OptionsResolver $resolver + * + * @throws ExceptionInterface + */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + 'map', + ] + ); + $resolver->setAllowedTypes('map', ['array']); + $resolver->setDefaults( + [ + 'ignore_missing' => false, + 'keep_missing' => false, + ] + ); + $resolver->setAllowedTypes('ignore_missing', ['boolean']); + $resolver->setAllowedTypes('keep_missing', ['boolean']); + $resolver->setNormalizer( + 'map', + function (Options $options, $values) { + if (!is_array($values)) { + throw new \UnexpectedValueException('The map must be an array'); + } + $resolver = new OptionsResolver(); + $resolver->setRequired( + [ + 'condition', + 'output', + ] + ); + $resolver->setNormalizer( + 'condition', + function (Options $options, $value) { + return $this->language->parse($value, ['data']); + } + ); + $resolver->setNormalizer( + 'output', + function (Options $options, $value) { + return $this->language->parse($value, ['data']); + } + ); + $parsedValues = []; + foreach ($values as $value) { + $parsedValues[] = $resolver->resolve($value); + } + + return $parsedValues; + } + ); + } + + /** + * Must return the transformed $value + * + * @param mixed $value + * @param array $options + * + * @return mixed $value + */ + public function transform($value, array $options = []) + { + $input = ['data' => $value]; + foreach ($options['map'] as $mapItem) { + if ($this->language->evaluate($mapItem['condition'], $input)) { + return $this->language->evaluate($mapItem['output'], $input); + } + } + + if ($options['keep_missing']) { + return $value; + } + if (!$options['ignore_missing']) { + throw new \UnexpectedValueException("No expression accepting value '{$value}' in map"); + } + + return null; + } + + /** + * Returns the unique code to identify the transformer + * + * @return string + */ + public function getCode(): string + { + return 'expression_language_map'; + } +} From d774afce77fe7617bfb643fa6cb621ccb3c8a54f Mon Sep 17 00:00:00 2001 From: Alix Mauro Date: Fri, 13 Dec 2019 09:45:47 +0100 Subject: [PATCH 103/304] Add GroupByAggregateIterableTask. --- Task/GroupByAggregateIterableTask.php | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Task/GroupByAggregateIterableTask.php diff --git a/Task/GroupByAggregateIterableTask.php b/Task/GroupByAggregateIterableTask.php new file mode 100644 index 00000000..c334cd11 --- /dev/null +++ b/Task/GroupByAggregateIterableTask.php @@ -0,0 +1,86 @@ + + */ +class GroupByAggregateIterableTask extends AbstractConfigurableTask implements BlockingTaskInterface +{ + /** @var string */ + const GROUP_BY_OPTION = 'group_by_accessors'; + + /** @var array */ + protected $result; + + /** @var PropertyAccessorInterface */ + protected $accessor; + + /** + * @param PropertyAccessorInterface $accessor + */ + public function __construct(PropertyAccessorInterface $accessor) + { + $this->result = []; + $this->accessor = $accessor; + } + + /** + * {@inheritDoc} + */ + public function execute(ProcessState $state): void + { + $options = $this->getOptions($state); + $input = $state->getInput(); + $groupByAccessors = $options[self::GROUP_BY_OPTION]; + + $keyParts = []; + foreach ($groupByAccessors as $groupByAccessor) { + try { + $keyParts[] = $this->accessor->getValue($input, $groupByAccessor); + } catch (\Exception $e) { + $state->addErrorContextValue('property', $groupByAccessor); + $state->setException($e); + + return; + } + } + + $key = implode('-', $keyParts); + $this->result[$key] = $input; + } + + /** + * {@inheritDoc} + */ + public function proceed(ProcessState $state): void + { + if (0 === \count($this->result)) { + $state->setSkipped(true); + } else { + $state->setOutput($this->result); + } + } + + /** + * {@inheritDoc} + */ + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + self::GROUP_BY_OPTION, + ] + ); + $resolver->setAllowedTypes(self::GROUP_BY_OPTION, ['array']); + } +} From 746f8bf4acbc6bbf8c3bef19a603db78bb10ca9c Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 11 Feb 2020 18:15:44 +0100 Subject: [PATCH 104/304] Fixing value type check in ConvertValueTransformer, array values where producing weird bugs in production --- Transformer/ConvertValueTransformer.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Transformer/ConvertValueTransformer.php b/Transformer/ConvertValueTransformer.php index 62f7ce96..5f516487 100644 --- a/Transformer/ConvertValueTransformer.php +++ b/Transformer/ConvertValueTransformer.php @@ -44,6 +44,11 @@ public function transform($value, array $options = []) "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" ); } + if (is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here + throw new \UnexpectedValueException( + "Unexpected input of type 'array' in convert_value transformer" + ); + } $value = (string) $value; // Let's cast it to string } From 3235c94321df9757a1eb7fc5e8bcfd86638e3b5e Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 12 Feb 2020 11:17:24 +0100 Subject: [PATCH 105/304] #83 - fixed dispatching correct event in case of failure --- Manager/ProcessManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index d0f0bf9a..8de01fdb 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -151,7 +151,7 @@ public function execute(string $processCode, $input = null, array $context = []) } catch (\Throwable $error) { $this->processLogger->critical('Critical process failure', ['error' => $error->getMessage()]); $this->eventDispatcher->dispatch( - ProcessEvent::EVENT_PROCESS_ENDED, + ProcessEvent::EVENT_PROCESS_FAILED, new ProcessEvent($processCode, $input, $context, null, $error) ); From 07d20b4e34477a6183cf751d666fe3aa3289c1e6 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 12 Feb 2020 11:31:57 +0100 Subject: [PATCH 106/304] #109 - added an event at the start of the CLI process execution --- Command/ExecuteProcessCommand.php | 18 +++++- Documentation/04-advanced_workflow.md | 3 + Documentation/changelog/CHANGELOG-3.1.md | 1 + Event/ConsoleProcessEvent.php | 77 ++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 Event/ConsoleProcessEvent.php diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 86d58a19..e8e6b270 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Command; +use CleverAge\ProcessBundle\Event\ConsoleProcessEvent; use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use Symfony\Component\Console\Command\Command; @@ -19,6 +20,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; @@ -38,14 +40,19 @@ class ExecuteProcessCommand extends Command /** @var ProcessManager */ protected $processManager; + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + /** - * @param ProcessManager $processManager + * ExecuteProcessCommand constructor. * - * @throws LogicException + * @param ProcessManager $processManager + * @param EventDispatcherInterface $eventDispatcher */ - public function __construct(ProcessManager $processManager) + public function __construct(ProcessManager $processManager, EventDispatcherInterface $eventDispatcher) { $this->processManager = $processManager; + $this->eventDispatcher = $eventDispatcher; parent::__construct(); } @@ -101,6 +108,11 @@ protected function execute(InputInterface $input, OutputInterface $output) $context = $this->parseContextValues($input); + $this->eventDispatcher->dispatch( + ConsoleProcessEvent::EVENT_CLI_INIT, + new ConsoleProcessEvent($input, $output, $inputData, $context) + ); + /** @noinspection ForeachSourceInspection */ foreach ($input->getArgument('processCodes') as $code) { if (!$output->isQuiet()) { diff --git a/Documentation/04-advanced_workflow.md b/Documentation/04-advanced_workflow.md index d00a2cff..bef6e3f1 100644 --- a/Documentation/04-advanced_workflow.md +++ b/Documentation/04-advanced_workflow.md @@ -16,6 +16,9 @@ Events are being send around process execution (see `CleverAge\ProcessBundle\Eve * `cleverage_process.end` : on successful process end * `cleverage_process.fail` : on failed process end (with the associated error) +Another event is send when a process is executed with the CLI (see `CleverAge\ProcessBundle\Event\ConsoleProcessEvent`) : +* `cleverage_process.cli.init` : before executing any process, giving access to console Input/Output objects + You can also use [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) to manually trigger an event in the middle of a process. ## Parallelization diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 333c508c..1d5a9e26 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -7,6 +7,7 @@ Features * [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) around process execution * [GITHUB-86](https://github.com/cleverage/process-bundle/issues/86): added XML manipulation tools +* [GITHUB-109](https://github.com/cleverage/process-bundle/issues/109): added an event during CLI process execution Fixes ----- diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php new file mode 100644 index 00000000..17d3441e --- /dev/null +++ b/Event/ConsoleProcessEvent.php @@ -0,0 +1,77 @@ +consoleInput = $input; + $this->consoleOutput = $output; + $this->processInput = $processInput; + $this->processContext = $processContext; + } + + + /** + * @return InputInterface + */ + public function getConsoleInput(): InputInterface + { + return $this->consoleInput; + } + + /** + * @return OutputInterface + */ + public function getConsoleOutput(): OutputInterface + { + return $this->consoleOutput; + } + + /** + * @return mixed + */ + public function getProcessInput() + { + return $this->processInput; + } + + /** + * @return array + */ + public function getProcessContext(): array + { + return $this->processContext; + } +} From efd68b7b09b1838ee8ebb1579d42a601a0ff8e7d Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 12 Feb 2020 11:56:24 +0100 Subject: [PATCH 107/304] #106 - tasks referenced as an entry point should not have ancestors --- Documentation/changelog/CHANGELOG-3.1.md | 2 ++ .../reference/01-process_definition.md | 3 ++- .../InvalidProcessConfigurationException.php | 18 +++++++++++++----- Registry/ProcessConfigurationRegistry.php | 8 +++++++- Resources/tests/process/simple_process.yml | 11 +++++++++++ Tests/BasicTest.php | 8 ++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 1d5a9e26..cde97f88 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -17,3 +17,5 @@ BC breaks * [GIHTUB-82](https://github.com/cleverage/process-bundle/issues/82): the `default_error_strategy` is now mandatory. If you have any doubt, you can use `default_error_strategy: skip` to keep previous behavior. +* [GITHUB-106](https://github.com/cleverage/process-bundle/issues/106): an entry-point cannot have an ancestor anymore. +The behaviour was undefined, and now it will throw an exception. diff --git a/Documentation/reference/01-process_definition.md b/Documentation/reference/01-process_definition.md index 0298b31f..adc6913b 100644 --- a/Documentation/reference/01-process_definition.md +++ b/Documentation/reference/01-process_definition.md @@ -26,7 +26,8 @@ Process attributes **help**: optional string to describe in depth a process. Displayed in process help. Can be multiline. -**entry_point**: optional task code (default is none) that will receive the process input +**entry_point**: optional task code (default is none) that will receive the process input. The referenced task cannot have +ancestors. **end_point**: optional task code (default is none) that will provide the process output diff --git a/Exception/InvalidProcessConfigurationException.php b/Exception/InvalidProcessConfigurationException.php index d79a3f7f..1b4c9a12 100644 --- a/Exception/InvalidProcessConfigurationException.php +++ b/Exception/InvalidProcessConfigurationException.php @@ -23,12 +23,20 @@ class InvalidProcessConfigurationException extends \UnexpectedValueException imp * * @return InvalidProcessConfigurationException */ - public static function createNotInMain( - TaskConfiguration $taskConfig, - array $mainTaskList - ): InvalidProcessConfigurationException { - $taskListStr = '['.implode(', ', $mainTaskList).']'; + public static function createNotInMain(TaskConfiguration $taskConfig, array $mainTaskList): self + { + $taskListStr = '[' . implode(', ', $mainTaskList) . ']'; return new self("Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr}"); } + + /** + * @param TaskConfiguration $taskConfig + * + * @return InvalidProcessConfigurationException + */ + public static function createEntryPointHasAncestors(TaskConfiguration $taskConfig): self + { + return new self("The entry-point '{$taskConfig->getCode()}' cannot have an ancestor"); + } } diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 79dfaf34..ff467ae0 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Registry; +use CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException; use function array_key_exists; use function array_keys; use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; @@ -47,9 +48,9 @@ public function __construct(array $rawConfiguration, string $defaultErrorStrateg /** * @param string $processCode * + * @return ProcessConfiguration * @throws MissingProcessException * - * @return ProcessConfiguration */ public function getProcessConfiguration(string $processCode): ProcessConfiguration { @@ -158,6 +159,11 @@ protected function resolveConfiguration(string $processCode): void } } + // #106 - entry point should not have an ancestor + if ($processConfig->getEntryPoint() && $processConfig->getEntryPoint()->getPreviousTasksConfigurations()) { + throw InvalidProcessConfigurationException::createEntryPointHasAncestors($processConfig->getEntryPoint()); + } + $this->processConfigurations[$processCode] = $processConfig; } diff --git a/Resources/tests/process/simple_process.yml b/Resources/tests/process/simple_process.yml index c2c2ea58..45934790 100644 --- a/Resources/tests/process/simple_process.yml +++ b/Resources/tests/process/simple_process.yml @@ -6,3 +6,14 @@ clever_age_process: tasks: data: service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.entry_point_with_ancestor: + entry_point: data2 + end_point: data2 + tasks: + data1: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + outputs: [data2] + + data2: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index 4b7807f3..cbecc16b 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -90,4 +90,12 @@ public function testErrorProcessBlocking() 'test.error_process_with_blocking' ); } + + /** + * @expectedException \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException + */ + public function testFailingEntryPointWithAncestors() + { + $this->processManager->execute('test.entry_point_with_ancestor'); + } } From 0b9065ad574f3c939234d623e599be3c1e085590 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 12 Feb 2020 15:11:21 +0100 Subject: [PATCH 108/304] #107 - allow to use directly a string in task outputs and errors configurations --- DependencyInjection/Configuration.php | 13 ++++++++--- Documentation/changelog/CHANGELOG-3.1.md | 2 ++ Documentation/reference/02-task_definition.md | 4 ++-- Resources/tests/process/simple_process.yml | 23 +++++++++++++++++++ Tests/BasicTest.php | 12 ++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index eab4840f..43dcac73 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -175,16 +175,23 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) LogLevel::INFO, LogLevel::DEBUG, ]; + $definition ->scalarNode('service')->isRequired()->end() ->scalarNode('description')->defaultValue('')->end() ->scalarNode('help')->defaultValue('')->end() ->arrayNode('options')->prototype('variable')->end()->end() - ->arrayNode('outputs')->prototype('scalar')->end()->end() - ->arrayNode('errors')->prototype('scalar')->end()->setDeprecated()->end() - ->arrayNode('error_outputs')->prototype('scalar')->end()->end() ->scalarNode('error_strategy')->defaultNull()->end() ->enumNode('log_level')->values($logLevels)->defaultValue(LogLevel::CRITICAL)->end() ->booleanNode('log_errors')->defaultTrue()->setDeprecated()->end(); + + foreach (['outputs', 'errors', 'error_outputs'] as $nodeName) { + $definition->arrayNode($nodeName) + ->beforeNormalization() + ->ifString()->then(function ($item) { + return [$item]; + })->end() + ->prototype('scalar')->end()->end(); + } } } diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index cde97f88..1a5e0f25 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -8,6 +8,8 @@ Features around process execution * [GITHUB-86](https://github.com/cleverage/process-bundle/issues/86): added XML manipulation tools * [GITHUB-109](https://github.com/cleverage/process-bundle/issues/109): added an event during CLI process execution +* [GITHUB-107](https://github.com/cleverage/process-bundle/issues/107): allow to use directly a string in task `outputs` +and `errors` configurations Fixes ----- diff --git a/Documentation/reference/02-task_definition.md b/Documentation/reference/02-task_definition.md index e5c3bec9..f222848c 100644 --- a/Documentation/reference/02-task_definition.md +++ b/Documentation/reference/02-task_definition.md @@ -28,9 +28,9 @@ Process attributes **options**: optional list of parameters to pass to a task -**outputs**: optional list of following tasks +**outputs**: optional list of following tasks, it can be a simple string -**errors**: optional list of following tasks, in case of error +**errors**: optional list of following tasks, in case of error, it can be a simple string **error_strategy**: either *skip* (default) or *stop*, defines if a task can be continued or not diff --git a/Resources/tests/process/simple_process.yml b/Resources/tests/process/simple_process.yml index 45934790..7a2b22e8 100644 --- a/Resources/tests/process/simple_process.yml +++ b/Resources/tests/process/simple_process.yml @@ -7,6 +7,7 @@ clever_age_process: data: service: '@CleverAge\ProcessBundle\Task\DummyTask' + # Should fail test.entry_point_with_ancestor: entry_point: data2 end_point: data2 @@ -17,3 +18,25 @@ clever_age_process: data2: service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.string_outputs: + entry_point: data1 + end_point: data2 + tasks: + data1: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + outputs: data2 + + data2: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + + test.string_errors: + entry_point: data1 + end_point: data2 + tasks: + data1: + service: '@CleverAge\ProcessBundle\Task\Debug\ErrorForwarderTask' + errors: data2 + + data2: + service: '@CleverAge\ProcessBundle\Task\DummyTask' diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index cbecc16b..4fa2d62c 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -98,4 +98,16 @@ public function testFailingEntryPointWithAncestors() { $this->processManager->execute('test.entry_point_with_ancestor'); } + + /** + * Check that the use of a string in task "outputs" or "errors" is possible + */ + public function testStringOutput() + { + $result = $this->processManager->execute('test.string_outputs', 'success'); + self::assertEquals('success', $result); + + $result = $this->processManager->execute('test.string_errors', 'success'); + self::assertEquals('success', $result); + } } From bc96831d627c3229cf9ba0646f46c2226355cc6c Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 12 Feb 2020 16:55:37 +0100 Subject: [PATCH 109/304] Removed a useless escape --- Task/File/FileMoverTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Task/File/FileMoverTask.php b/Task/File/FileMoverTask.php index 2d7d9179..fbfb13ea 100644 --- a/Task/File/FileMoverTask.php +++ b/Task/File/FileMoverTask.php @@ -87,7 +87,7 @@ protected function makeFilenameUnique($dest) $fs = new Filesystem(); $i = 1; while ($fs->exists($dest)) { - if (preg_match('/^(.*?)(-\d+)?(\.[^\.]*)$/', $dest, $matches)) { + if (preg_match('/^(.*?)(-\d+)?(\.[^.]*)$/', $dest, $matches)) { $dest = $matches[1].'-'.$i.$matches[3]; ++$i; } else { From 5b784c3450918756538fc60c74736997b4ad6057 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 19 Feb 2020 10:31:48 +0100 Subject: [PATCH 110/304] #83 - added tests for triggered events --- Dockerfile | 12 +++--- Event/ConsoleProcessEvent.php | 11 ++++- Resources/tests/environment/php/conf.ini | 1 + Tests/ProcessManagerTest.php | 55 ++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 Resources/tests/environment/php/conf.ini create mode 100644 Tests/ProcessManagerTest.php diff --git a/Dockerfile b/Dockerfile index e55e6c7f..5361bf84 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,12 +19,12 @@ RUN chmod +x /usr/bin/blackfire RUN docker-php-ext-enable blackfire # Composer install -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" -RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" -RUN php composer-setup.php -RUN php -r "unlink('composer-setup.php');" -RUN mv /composer.phar /usr/local/bin/composer -RUN chmod +x /usr/local/bin/composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# PHP setup +RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" +COPY Resources/tests/environment/php/conf.ini "$PHP_INI_DIR/conf.d/" + # Basic sample symfony app install RUN mkdir /app diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 17d3441e..4d9658f9 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -1,5 +1,12 @@ -prophesize(EventDispatcherInterface::class); + + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_STARTED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy->shouldBeCalled(); + $edProphecy->addMethodProphecy($dispatchStartProphecy); + + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_ENDED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy->shouldBeCalled(); + $edProphecy->addMethodProphecy($dispatchStartProphecy); + + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_FAILED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy->shouldNotBeCalled(); + $edProphecy->addMethodProphecy($dispatchStartProphecy); + + /** @var EventDispatcherInterface $eventDispatcher */ + $eventDispatcher = $edProphecy->reveal(); + $processManager = new ProcessManager( + self::$container, + self::$container->get(ProcessLogger::class), + self::$container->get(TaskLogger::class), + self::$container->get(ProcessConfigurationRegistry::class), + self::$container->get(ContextualOptionResolver::class), + $eventDispatcher + ); + + $processManager->execute('test.simple_process'); + } +} From 37bb00deafe499d84f62c74def1cd6b7cbcb1885 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 19 Feb 2020 10:59:23 +0100 Subject: [PATCH 111/304] [doc] Updated changelog --- .../CHANGELOG-2.0-1.1.md} | 10 ++ Documentation/changelog/CHANGELOG-3.1.md | 27 +++- README.md | 149 +----------------- 3 files changed, 32 insertions(+), 154 deletions(-) rename Documentation/{100-roadmap.md => changelog/CHANGELOG-2.0-1.1.md} (83%) diff --git a/Documentation/100-roadmap.md b/Documentation/changelog/CHANGELOG-2.0-1.1.md similarity index 83% rename from Documentation/100-roadmap.md rename to Documentation/changelog/CHANGELOG-2.0-1.1.md index edc816ef..655c3480 100644 --- a/Documentation/100-roadmap.md +++ b/Documentation/changelog/CHANGELOG-2.0-1.1.md @@ -30,6 +30,16 @@ MappingTransformer * The option "ignore_extra" is renamed to "keep_input". +Other +----- + +* Fixed issues with blocking tasks +* Removed deprecated methods +* added input/output in process manager (may allow a start_process_task) + +New issues : +* Error workflow + Planned (v2+) ============ diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 1a5e0f25..98ea3126 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -1,8 +1,19 @@ -Changelog v3.0 => v3.1 -====================== +Release v3.1 +============ -Features --------- +v3.1-dev +------ + +### Features + +### Fixes + +### BC breaks + +v3.1.0 +------ + +### Features * [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) around process execution @@ -11,11 +22,11 @@ around process execution * [GITHUB-107](https://github.com/cleverage/process-bundle/issues/107): allow to use directly a string in task `outputs` and `errors` configurations -Fixes ------ +### Fixes + +* [GITHUB-99](https://github.com/cleverage/process-bundle/issues/99): transformer exception message improvements -BC breaks ---------- +### BC breaks * [GIHTUB-82](https://github.com/cleverage/process-bundle/issues/82): the `default_error_strategy` is now mandatory. If you have any doubt, you can use `default_error_strategy: skip` to keep previous behavior. diff --git a/README.md b/README.md index de1794af..a4034255 100644 --- a/README.md +++ b/README.md @@ -62,149 +62,6 @@ Basically, it will greatly ease the configuration of import and exports but can - [Generic transformers definition](Documentation/reference/03-generic_transformers_definition.md) - Examples - [Simple ETL] -- [Roadmap and versions](Documentation/100-roadmap.md) - - -------- - -_obsolete documentation_ - -## Configuration reference - -### Defining processes -```yml -clever_age_process: - configurations: - : - options: ~ # Global options for the whole process, not currently used - entry_point: # Code of the first task to execute - tasks: # See the next chapter - : - # You can use two syntax for service declaration - service: '@' - - # Or, alternatively, if you don't want to declare unecessary services if no argument is needed to construct this task - service: MyNamespace\FooBarBundle\Task\MyTask - - # In both cases the service/class must implements the TaskInterface - - # Options to pass to the task, see each task for more information - options: {} - - # List of the tasks to pass the output to - outputs: [, ...] - - # Other possible values are: 'stop' and 'continue' - error_strategy: skip - - # Logs any errors encountered - log_level: critical - - # More tasks -``` -Note that orphan tasks will be reported as errors before the process starts - -### Existing tasks - -#### StatCounterTask -Accepts an array or an object as an input and sets values before returning it as the output. -At the end of the process, during the finalize(), it will log the number of item processed. -```yml -: - service: '@CleverAge\ProcessBundle\Task\Reporting\StatCounterTask' -``` -No supported options, no output. - -#### ValidatorTask -Validate data from the input and pass it to the output -```yml -: - service: '@CleverAge\ProcessBundle\Task\Validation\ValidatorTask' - outputs: [] # Array of tasks accepting the same data than the input -``` - -## Creating a custom task - -### Creating the class - -```php - Iterable -> Task -> Task -> Blocking -> Task - -## Release notes - -### v1.1 - -* Fixed issues with blocking tasks -* Removed deprecated methods [...] -* added input/output in process manager (may allow a start_process_task) - -New issues : -* Error workflow +- Changelog + - [v3.1](Documentation/changelog/CHANGELOG-3.1.md) + - [Older versions](Documentation/changelog/CHANGELOG-2.0-1.1.md) From 766a480c2baa5af6880cd88abda18dd14413c47d Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 13 Mar 2020 16:59:17 +0100 Subject: [PATCH 112/304] [doc] Added a simple demo image --- Documentation/01-quick_start.md | 2 ++ Documentation/basic-etl.png | Bin 0 -> 307893 bytes 2 files changed, 2 insertions(+) create mode 100644 Documentation/basic-etl.png diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index 0de77dde..928a07cd 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -16,6 +16,8 @@ The most common example is the ETL. It's a kind of application whose main purpos - *Transform* this data into something else (modify the values, change the format, compute some statistics, ...) - *Load* the transformed data into a destination (another database, file, API, ...) +![Basic ETL](basic-etl.png) + ## Installation This bundle requires Symfony 3. You can install it using composer: diff --git a/Documentation/basic-etl.png b/Documentation/basic-etl.png new file mode 100644 index 0000000000000000000000000000000000000000..e2f0f0f50cc93bb4c1330953f60d1d16a2ada380 GIT binary patch literal 307893 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

  • CX%|3S&Sr7>?dTCugeHL4SXGkoP2$-;V`KK%>3g;iCw)3`Q#6k3FUs=dfEa zd8u1R0kw6cG@3?=!ds!Kh>lqE3YH@Xpm1$*bGNEGYvGti%-KR79?lKO6Bt|5q43Qw zcXsAj-j1Kx0$kqDRxa`DKO&jd7yr>z+@9xfi}p1)FMjoIt)GUx|6QJe=u6t5ujdO;?zF4jm+ViL<17l%CR7pK5`B^ z;_hjeG26i61_dC5Jj|i}z&``TU{uNKYa+v@B^(qece;>81JH7<$H7BOh)Sl!$1-@?K>o*u{0YJ{Ov<9yG_mN#?o+lWvu!8ti)VI@#_ zySrpz!A~&5#FW5saDRPz9xhxzU3b_GBShqO0(dr5G;bUuWlH3shG(mxRqGZ4%og(go`Ao6r`Q`1i7sF+rslj}2Ec(d>= zFf;;06H5Fk2+2F$)J;1Z=O1QU{QNZlH3GSAGO*qrx}alsxZ9B*DAkFmB%SI-riq|5 zrP##LSiL@+h@LhyafkDp1|AE81$IP5^>Q6}bwxIX&cS-;KO_R~{}}zHCG4uMHxJzw zdw=q>B0L{gPT*a~3}yWD!=J%bGE!}=02Q;qI=#LwcBRMSLC2C%u&hE!y_;FKyRhMM zu1}9=)ttt1IO1|Iq?`+W&mJ^7uGm?PXnICN%`G;pH|i^!5%z=HI^;$SIA`Ynm34Nd*Ay zJr5HEV|qHdIS1kxFi4-p5?XMe-3_52kE;$^M)0->3();0$H$ww*Ky%cgN%V@+^n** zKcW0??<62vLJIJr|>)1vlDKRcE`A z5~hQ>wB1`pX%_Rm2-H+D+6*)6@;KkZ>XIMaSXxxIu~u5V(gRXtg#4xZ1C}fE3m_N# zAp|fI)r`Kd?}5U0@!(PEw}`!2!6CBm@kzHRwCk4#->?(80sZn>9db^V++>`a;)g=) zo-l8}&xkTTrwZn~7-(#qEe2?q+o`Pk11&wc`Q&yDqI&L3zFXgP5Q$GgesUac&f08k-md+u~FvR+zl`B70kt_a@U&vKa2 zes#|lb5B(Z@ZRU${CJU%VAcIU3@P+~Mr;_&wrgBb>>LTw*))MfxTKtpy+I=@jR;Dn z4^iB({$mko3KxEwetY{?62^QSDVT0%)fc^?&cm)>F-&!$eR9&-rYU&F}Yiw-UJlNd~|YlFhCB7_iB6-phfsXH`jc8dK+(n z0Voya5$B;MMSKhSpXsTzkSKcv;IgiLcO{+KIZB4MtYine+!}nzaT}N69qj}MqtRLF=Vho z8O4x*7>pH>(dLH>kI5{cwHm`rb{`NCB_O~9jTBkQU@v3oK?{N8wYt&Jz6-FkFQ1d6 z0e*z*|L^ed#=E!6Z*eZpq3G9{(a)b^7fEz&0P}ptOWZ|-A$~8OR9w6yQ^wHR_Ord3pdFfa(|E!jX?~Q>oYX(vBcq=9`y6lBI;=i-2&joUHa5D1;x|^U7}p}bJ{oVlr(oPRVpw% zBNy9ove|NNxwZ}i69#VVk0F+HM@uJO@V&;t5RecSA=nh~eIeD{_YKF*T z3=Nz8*-J*IcbWyzVrF5I5~X*fbmPb0P?fseJlo}QY}M3{@qagS#s?FM#Q|?LN~*>Jp!Lc3=(bwP zdh8s8DMi%#aCVJ;(JN#zgIM^38G-bRbMTnDUayFV3y;UwPaa=Ga|6_bKq9^jY{yVg z3!byKPq0c34=vkEp$s+Ukh1cN$UCWLWJWRvMHmtyv2^olis@MOXSPlfDVuPS4-w$h z-SA^FCK^)wZmU=K2YQ&$L=}8s&^@eZ2J!oDl;MG6XDm$rcvh7ZW3aHVq0|Epf-yH4 zKPfrBb2~AvrFqWT9-NYrz*1c47!#JqV?w~{=F0Pf5eN?%7StAl&MLr9Cs8)?QpY8)4r)CZq+*H>OtFb^n)R=M6zQ9& z_Rk*yVXd-Fa`udiw}eGxou#3Lf5MFeH8tnGWT6qXwD7ume(z=#NzBLr!(HQ}fv`gxs|Ak}*pZhjc7v;$X!-WlnVZ={cO1QZH9VvYQ*Pu5$XD zSy?5TY4|{xdI`^4I;?YcHR);NGyI-(v+3(|k(a;y;^!wByjB&$|9I<+p;(8OltyFs zDJiLNLkW_BpHw&ni_S?6c;c&OMz3Z|y*IDk?bGEOUnqw3-SoaH76HXkteuUG=n)Tu zKH11_F?rYKTu2!g3+wyqSNmC8bu==zx+u@FdTh>zrsTEf)2~^K$N2b(=xQ;Wv%;o* z^qM1pjJ9UVYL&RMYx5y?$JI44PF{At;V;@4+*4+0aU3FxuqJL+!dYc(s#G{K+o`UO zjEN?KI4~hl1^j`$at(=XbqXpxvet}z_I%N^Q=v){U}V?^;npwBiI`{vNDmE(mC7I9 zHFIiZaM|?X;tC5oE8$PG|m)=$Z$Qni?u5%mxm92PXXw^W2SfaSO_GAK3x> z6Rrdrc0qxueR+OOj2eA;o3#w$BuqnKUPD5)KUvM8y1ENJ8)0_5h<-S`(a*8Q}V0Nd`J`WBK>7i9(X%c70RwIH&84>l5qRACMM?y3`Ke z0cQ~e2~_rtcA_9;XCZWT_h%!c1$~%`NkJcF zrAS1I#=5;c4ZCimAM_2hj!Mr>d3c0m!ao-bOlRh`dk0|wCJVBtU{&^->f*}W!6Mm2 z54MJ%fL_6i(;4EDOfp$Tc|EtH=7a67ghkKsZ)10wN_O+|(yKIyq(mjy8Dtl!v`R>u zO9Opa2I=fLv&M$4;!#7b)cKV&01K9)CJ)Zx{-sw*Nd@)xrsEFv;%+gebYAV$qh&xm z8c2bq2nCEH#k$5U)y)HtgRTlPb7N@V9a-p843TwoM;EHAqUrH683fT!(G0}5cL+;wb5CG6#ams!BxD17$ zS&eqgd4MN`2qnvr4n>{7)ZrBBK{u@~plGu#=uQDE0}lNZ6I$B>1=`wD_)A^P{&r(_^M!f3tRMhO z(W!fHe>RilbQwaWl6o0)U;v9-X;A_OhTUQE1wbAzMTexYtEv*4xO9UK_LZxA9cm7& z@?oUJUPQUxp()pFtq;=@cBy+H#K2X#LLb`On`UKYAZ4Ym%Y@Q1%Gmqwcw!IAPdpHB z)%j*Vd&B-Yp08#g*Ve!}m*gnp_rkH=7UX}QU~9dd;v?F={=c`;ytX!cz+o%kx%Y#E zDW+b}yz2Gk@|1P{!L4>O1IP_9B3&Fvx2xdgljbd3$_1+Sk7X^qn`l&>g$na;!orO^ zYSKVAX$#4S*nIXZ|FEPO&zfIvmqyNOzSP{FE)|_7k9FYOnb+512msub(P>eNQY0QN zGBP3}ckT8p#Hu3ibri_b(!kSTTgbNoO^?*JSkTZ!8-m6spx4$)8+&cL7FQ8~dtkP( zi#Fc)nqzj3qA;GYhWZmHD5ue2a%O2sg$h=5YK)KfXvNjFxo~qb6dg@vW6yN*2pzO| zR_+U_tSq*rz9^>nAx`eT0}85;j76u?O55e>?Zi4>o^TU|{>v9hD>w)HVh{U2RJ93I z(#7<$sN~wErQgs5fws=3LHMzePie&f-l;>t>ueXWwmMC6dG!NgTD0Lm8_G+hzkXX* zj}>_6W-!#HSi^gDgu-v;=@SjdedhJY2~?ChgJAiDO56yA+s))`p*tLjj5tDL@S)ke zrz`6q-uA7e^uw9m_;}c!EY0&3GmPd&yU*EH6&!$B(R`0j*d4!0PUK$i^8bT5Xk1?&cB;Db^(c1?6(SxpoAI=o&KmXV72<3jL&vNaK`oZ>+lBy9IOb3tpwp%#K;D6rPv$^5qIk342fVlzx!9 zzPt=VlUjMpGJ2-Dw)Wi=Rv+ez00B`|g-@YzUia1`e@yhVO!8Fbwd>T;(YIs|i00K| z-s#y*`M${mbABKnpcT+g5^dl9&si%jhUEgHGkAGGL$0M^eCZ0)sJX=O$+ zN;zpTGccg0Sg2iyDkbJo-#F5`@^ysPl{R)sO9uf;n0^C&$90o^rYac25=z2Gi9 z6UG~3Mjd$GdeeSy1#>V&ET5-LxN1EB4P5M7YtZxH>s6iN%-MC+G;J`_A@MU#NiWqm z9CM!tpmSW;yJ4Y4ST{svkL;}LL#iR8#MPyyGw}Nvr1U|#y)iH`HtRM+%tWJv201#_ zAJFwqX9w*c9+D^d`0V+AJ4u{woc%W39Fr3-qAj@Vt9{w?q4bxUpxh{>UjuUS7;?qCS4du%x}PgOHzEic1ap%rIJi-ESWe20t-3t}CXKKW8?R z1pCIBOQy>*sHgGsQ!vK(5W9RIsVo8sbUsEFbmAx9P(H*#eGKLdwflq}3b%cANqQGj`N zUg-doyOWwn264DoLWTlAK7O2?dIAkviYAJ-2LYF;O}3(@q^Zp_0+7aHm zO46oWoDs?rHVu;myukAXDWjznG_?4^u}c|dXn^WCmm~5Nz}(E9q5ur_CF254Sr0im z?f8X|V)74GfEY;d&~K3%4XbpAf&wcu)}OK9B`E5rL~XxF*TO+Rj8=!+>Sclj5TgMY z|Cy55TPOaN%Gav#A3{M!M&{dY6jy#zXC{2D^7iWYZk^@eK>!$T zL&r1t0p$sKiku}Xbmk>LhZn~8rclEjQ1&&kf@AFZH1&{)KV2&Qqs$#6DQoKNU(|N~ z<6u(|nMoFvV!y)bRoPcxYL=I-oe1kv9xw78U5bq2Wt?vTBA<&JFc0V_{PjgdOG_L6 zWpqOjJNF(6PX;0J^COz}+Mw8QS2G|a$N34|4k4)|IJeg7hot93MXlnhp#=dPZT?Sf zL&8XOT2_kd6)oe}Vg>jU{t(6M-v0ix!*D>x)X6%kV^?L)PNhFVGm1*QhY4ps~)1ER;dVLMm9$O$Z>= zdfNQQ-g`qtweS%YbCgb#8p)yA(}i>j)H^V+DFEspIOiEv%qc#-$XEEs<_)DR8FO-L zVF*ed?}QV2!4fz;pYHEJ>Rhkk`|U$HDo|5?Bha$B>9!hiV)_9*Ml{hoyFV_r zfx?7;OqAbD4=rQ{F9VJNhJRP(A0G7ViCd!9X=(Hg%Iy`PT#{ny#dv=MkH66u7-X#z z0DneXSjSRJ#Mk(^q^c+o^m5siveof#zTiJ;2zz^b|0HHv{&~C1I`C*}T98pB^#cs8 zlreimMBPIj5I9(SE?qI9xj{`<>@9$}8BSM82;V+{TE`y0N;YL=a*HHF#c4`JB(yRx z#Kx``1cWdG?tI5svAai1Wwtenx*4UhF?^rd)i6v?*vc+_hiS^uZ~9pZ2G-UiSQ8|? ztX>x*-9aHx_xFOUPJUmcJ+Ob9!cixJLYhDL`3W?P;GqjNnda5U|D;7Z74vD$(8fVR zCWoXodj-ZMX||d&Gpp)7dco|E4?z1^T*83hsz&1T)~bLyP*-0V0z`w`_Ll~dKQo7Z zLZYB}a&mv!{>A2>N2&=qiG-;4MhF01s5!8@TN$y2n3gz%vJ`a1AwOoF6rPDot6D+a zW3*a^xwmbEL=>Yf!gql0wKd}%BGcSL50*%*EK*;QL5Fq?un9?ZN7!(4LE?gXot#IN z4M+{?xmUVmg$#3v6VaS?__ni&U%CP04-v1axgD+r7S70Sy%-Lop@HVgxbsoVyjYNm zyw1kv)`Ru#VXlqvgo@_AS(gG4CahxDPYT|r+B8dB1QLI_>@Rh$6U=h^T_V=ad@cP= z+sJ4gUqI?G>$*sNDYd`|5Gd%j10HaP1lLgNpOfZf%8g;D!*Fm*O$We}tyv>2IvT_s z1NLuyd=0g|HQ}MP)>+4#vq*25aE+y1OC%aduk=r1#$+^Rkvp^ie-qh_5o-SQgykY9 zTTmyfI=7%E$rI<(gK~)iU?L%YL;u9QNTx72-;V)U8bAvm{F@da6%Zg&rBo2>N{jm9 zmtF4|Zkieta%z_>_SJ1!yfT80RZ+f4ezb8K3UF7btBdaeW0+$KuM)F_*bqqsYXenL z0zcL8;(ZoitdXr{B=6 z+KkR_I!sUMzkta~=emy=hhip7W1|2O8@Sraq+vmm8Gfmb!kZYiQx_S zMBwG+Xk_~#{BQ`U^AfSOwZ&wRSy92PHM6tP&w7AF{g8ZiPDE_j_VLI`QCo-LzEeZm z%|`$xv=Ie=G&jlzxEV92Xt=nYvbe6_IHeEBTm=Bea37Aar=bWnNqV-wKN>BY`am!) ze;>HE9TO75cJSjJfo27Nan;GM84s_tgDk@w1Ypp8(8>}<8A>9guORfp7{MDD_l4ao zK1oDObxwU{2x6S#3e5NfBKso{j96o`yT1P3M)lY!_9#1GjRPyYHkto1H?fVpXn4*9 z(kViMtS-5PN-f>aZv?o06O~N90e!R@-(MWxP_>Io%aVGMVmE6T@a|idz#=y^7y%;T z=jq!yl}%M4UtlIJA_hkKZ}PIv)KMVt@DPt06hGa#RiWous+Ub~Cx3c}j0XyEPj$~L z{{f&^IWXwnbx_fpn`fuIG0GH~ z*5c-ZF>h`;V&H`M3w(UKNl1qsqr z%&tWZ{X9vNkoKMA^eihwrSbwLMsYzxR_20{j|z`feY$LVuHHks9+9hW+oysk#^dZ( z6^vupl#QjOZHJ<(M#LMbTUN5kv!#EgZEP_8^%ijCm+r1R8+7crX{CybFs;z8%wHiC z!pJ)6LKAa<76OZr!hbo+;4VoaJM-U+Lk5ZEKhkEuq|jqI?dt^jwDh(Ag^z{tPTSC46O$6y3eLV3muo!>MS7ERwE+DOJd^S z%n9US;iq%3qy2fXaZM_A>4x3nA}|FgQ{D1h5=+ygW=>YzgsJ6(1Q*3WDoNyF2%gro zplZC?Oe6sd#6&0uB zIfk-(TBhkJ8$CU8ZPX0D@UlXe)Q~0eh%31ZP^|R9!}(O9ZcHQ^ro@PVi#wM%lxI;! z`o!mKHl>T7Xi|k$7UuQX<6A?SR9-qJb?rObv3al z&12IKD=zR~97%b7KVD_S^uBs6tewd1smn)sAxA{GR7XT$qJ(c5v=4U%7gg7UWT$@H z&e+`@ykNeRQ{Xa6R{d5zm0eT}juk8W@uRl@l4Nv{ir5G1)BB&{fOi~CJ;x!}5_ROe z-SAURbpr*|t>>kdd`;_Y9?31aCamFDgt5l4so?T5go#riRt#;r=;g)gs<|gz>BwcfMR*>h@zR-Hv`g$HJF>)F_C8l;$vrcRQ z@aO6DxXl?E>=3s&k=?6Fv`kc2v>ZEhbS}{XGn3m$8x{D}h?<^B*~CAe@kQzMHQ~+! zBFO9fPZnsn?!oey%&%DtgJ>9 zgbjJqY-pCVqMg%Nh#NF;*v-6v01)lRQ|l$4ZTaF>@p&mAV1YTV5<}^;)c$^(+V3Y1 zYu+dHc;-p&)fug?RMs77t+K0Nduu0evV}Sm_Og2$pDeQXLdBttkJ5aFoZc>p*%mdU z`7h78roRK?CP)5Ak<1Rx0UStlhmmjT++6LG<7?~f`tuscP3zU8pHqBq4Yyx=EB7x& z!zrUZ{AGw*Py6AI4b`aS<+Q0{r^z@nOK9_kKF1iNF5cU5VF>B5FRNz-1$#NnY@!nO z`}>^ugHKi2#MJNlnT3wI>FGzCI~g1JUm%C6jBSz2OR4V)s2LSD6e&?L!M9V!!4cCM zvnc@FHx|*WTCh&IE2eQf<5PFKxWWt{s-Q?I3rm5uFM zx948>h;^P5XugS7ux&&{GoL@B{!s}EYP`BG(GeB>m1uAL1LryWrG=P)jFz2=(P1Mu zD2WORs6D3jhyK{=Is^(b!68;RQ;lO8TnL3vTTnhe>|ysMrg9YLmx@YECB>GsyM!4< zB_WhLREijH2`v^b=jDau5Z2t7TU?GR;icz)$r7WkWMnFX4IDSJU(dr4A?M6zPi%px z9jBHd5A_nokaT_LD0R>F1gpuZ7dJ29ce)i<7~$iy%JCNRexQF_nuwHVlsfo^nhNvH zt=VRRgI%op;P-RInXQhkteu0q`^?DBsIHn?;-8l$j(E@S399N}6(18iH5(~)x;~+B zbHg`T#H{nP9*&QualzXAS8&N4@DK0S^<|_@@V>a-S&FRlvx%}BPUq=zaLg{KKo&J| zI8iIcn}U&We;le2@mrQ8db%w9Fo{NM*d8Ab=oU|)TrVbs=Wud`jIr20py>4{TOLL!y!)fdH+5Kxi2B z(UztGWEe5wXM_;j!Mg_)lcjUIah+0iP%0^{%K@0`k?|prZ9_gqKP>N9HeE)%GCv7ag3!J>xi^On$ zUp>doVqVAJ&|5%CUO`t^7LJ6S-I8q-TeKNgW_cxadd9%<{2e=)LtRi2#hk3yJevTA zc)B)h5P#b(r4uLPG*nD^b#!BreAXQmCAG#>$;eGzeKi)z+Bb7^ z`0lZ>5o{fa)1>6~c4H`h7qcRh#1bc`%7f+AgX4Mjw|LdtUq<=h93B&zs^^WiUJ~Wy zg_&!rFwB7!ytMo<=Tcg_yiRFMFZ|L@en{@hBCe^IW^T^0)_$nq8}C={o#Q4~StR*= z2?=^#aMZ!83eb>?Ne$n9Z6g~;S?y<)60>Lyk1S)~?K2R!$OYEg*qFH&4yVw;_qPW_ z?#A`>oC5%T*&=T_JBG%daVx&AihbyK)I z6CH)puJG5FfdQR5Db779>25>%(1lGKxSP&n$rYz)?C(REP?lx9J@YPXb=kA+PT(7B z;6d^BvJ=Ip;+NmKw6M%AOJeydCg+C)hh8v7(Q9gi9`C(qS61ZjYmP+Ki=gDP_^LiaO71^4=<=0`$aiO&lCb-G@XigGq)X53Uh7f zMx}Sn=H}G2bMKFNB_Ugmz9=6=J&HYBeY5tMZitkXgmyAB#wFbLMijw;V&;Y*wD;_? zS8v|vI+jEHZ}~T^I5^Z{q8m2tEhz*Q23A1oW67o87r`esGaFWBLF@xRZU7~B zp0%}}P+PqSuc2Z?86U4D85xxltmSGc1KwEmC2?10PJVW8HpR@vRTvj{UC%2i`-1*& z*2y_VEK}KVLxWh+gZ^Aaxn6E}t5mN#t6*|U7?B~RliqCHXJKRT#brrQR}Pooj?fCb zwm~s$Qsy%um8U&BM6Q*&qvQ9#LMVBmgd)MjXHN=?sVJ|na=OE7K27PBQNV$EipOgrVZZ(@N@T;MvSt63?Nzl?3 zNV6vgtOWTJ&I6&^lqrlb%hFt2eDNe8)7O-Af>^J`FhB9&$}=C*@iTb{(?I~U0wXsF=yG%4!Ztr;-ZKmpXCKz zorfop?$W!|a*VNbKiZ`Eb*rML{pmUvK<&@8N~@+ua(&FJ?2U{JM_{WEI-gYQZI(+( zchV-y=2Y^d#}K?E;qVm@XzPfH-6H>Ltxp(0JOH{KUX2`$={OSuv83uUX}n*3%;>0} z+^kv-JddBAzV$hP5;3XVuE`cIHW>+fm8{kEi5P6@Xf3_A*i$x#T_q)r$J#sPRLwtG z-apRYsmS#==0Us^g#?cT%0c!5-&$q-*aTohzu>R7bSsd2wch693^lN&-qNGxs_)rd`b~D43ao0s^KI(MUix37?>^5RL}Dv;O!s40KZqa7v6~ z`Ffk_q{}AZVs~BraLze)KK!WP0HZ7`%Q%ynjz~G^MtFZuT54}8DmQuo4qghQeUExLM~c=3 zI6+nfHk=6_BmziT*@e`rt)TMSSS^lh$6Q7xMSEV)yV5N03O0*Sf!|cz8?C}DMe%9* zSirDokN9(qz-Kz9X(3&x;`=33u)eaAA%uY8mZW41uOKDR@3I|}(WRbZ5>2bBDE4Fl zjg;8k1e?DDqWy-{2zQ}oz;dK23JS1FB=!aoFhr&MKGCP2j|O7&&Yaj-9}x}vQh=Sm zjHrl*jIOJblmoFmpmL3yVb*>7gEp767>s;rHd4j$$ai1H#;Cc>ya`SKR9{IQ{Re^0QZr zOjUS<)!alxeQ_}}E)nd}lParlig}68mW0bqVMFP{+Z!~9V&BhWm4$Eq?5FL~`GbS5 zE=}>oa$a-G=do$`rbY8OyB3%k4?(9v{Yru_kQRt^v}@f&v8oThj38Zq5ZmD%0$EZX z_EvcZV~Z6Rg_CmCnR@O;XhghNVAIG*rG&uG%>)ETe*{A8d*zNJlb4okYLro%`Tayi zp~2n>?T0yvYletqEwr?dl8!#-1TMnD)Z^6jatgCsElgTx73l>(AJWqG}i#+tYSvKah&9TE#JicFPbWBmu|D}L~HJ;2<0Wlw)G}>_~X1w z*dIyU%N#s5w&A|;n{46NK$!W+AT)=~@Gxf7!m>ewJayS3T%-$yG`Y>)S%b9I8SUqQ z;*0qExVT@OR#RC86yLkhJT76z#unN_z**M_9yGvsm z?dx%zPgZl;T$cqKv@ZeiHDW5fmJasutN4-y^73&N?8Ecd4v%+eL<`Ha>8)HjW0m#w zN2%WlGcuq{DX`UFCFWpm{h=<{eT{$Q|0xXi_0AMZFhV)nGFVF?2gxKQqJc18a_8nm z4qq!Yt)6X#!t8AdhTQ7$x-z(qGd-7ea=0N5vs1Gbj+*vaF1Ap@IM{aaChHXaBLOT2C5woU-bCyJ z3i?RO_OIjOTqLLkIT^PYD0cZ2RbK%Cl>0F{jX6@QQNa!p&-=x1H%PIM19Ua5Q3U`A z;YVS!gY#0PknJ)_LPa%7B|K&q_>@*%NzN41++3&vr`Mw(q%4SJVsc0Cg+ieJHAbo) z4Vev`V+30Gw%W`fb*hAd(zto!^s=qyD=3ZfTCA#pBOqIEw6diT#ou#1vmiEn;!x1} zaqXzbZXwGe8UZXvDE^VwP)oY3tQx_>(^F;nJ1|0o4zjH;;WDX+ig8kNal*Gc6&QM? zWxFTmg_=lWX=}&60e&*b5n?{_wYtyj?l4_mEDP*5xAprGbX%_ zY!ZLHim51b$Hy?D5I7C@Om1ZWo8xlkyTHnd(A}JDUlSBEpA_#k()+U)j-!gMJ>ZS8pd9>EC2d-qWRCd6D589EUmq|gu5BES$tVpeW<2Ibx6;@3-vuY zjn@Xr4drEdFjRgHhG3y?I4pH#Wg*9*6Iuuc2gsp|8=O=*#d+h=>1ZHNcs5TIB5SVQ zT9)W-1y9YoyaJ`$Eh@8Jz|*tQPS<#BC_+#85qg5Wy*|FaabGYhdQL>y(i{Q`L`9V~ zR3szoOf>-+T5)pHyTX`jKRrpx>y4*#vh5)}Juk}{CtHjSxJwc8^#)T?;GS*h>Cs$Q z<)mHx{N`+ITO3c+n0Y=F$5d26Tfc?v%@+J>tEi!hWuhAVxO{M0&r>fC(s6Nz+kyc> zeEsr!+>;r;;LGNkj6B)#4A!ekiZ5_iB9-c*sY#Xuqv61FiV8CHz zz630RAGS2G7R1Em^{-b!ad0O>csR!8Pz~rOjf&75CO-JJS-r5{Rg}l z3435>mMekp+E^wIigV^u`$lc+SM6@bn&3WN!&i)WyZM8ARc?ES9?ZbMXFDjP#*l zh)G|><<63uVmGvU%K(hKDJ$Ff9?#j?EYWi*?_4ktf+>_xc1tX^q^dfDjZJ!$kyT_> z&o!#CxX7-JrE0EjaADoxVT6L_)vNpQBpyS|sjsJAWJgwEkCO|*R!$y06caX3@Lr3H zQ$jsP6OERMF|RJ(Eu)+L5$ZS zAE?r`Pl1v8eh-zF=|g$<7KCDI4%M>bYU7TNofX0yjp+$^f~}?9{cqLl>mDok-u0i> zn0xmV#W+sNZEOsYsN++F#{>OBU%=FZnuG+&7bE5>K0buKjK?Us+}dH_eUJV$z_1Ot zC-!`L9~q(4%A~hfa#Mvq$g!P@bHcjnW^nj9ck8N(PU3k)Q&Nt2PdR9zqA0V`giQzC z6Bs^BR?WePVJ=>18e}^wxL8=sN#JlXWok_giCecnN2P4&;m#25YP@Vfk=LZ9%P

    <}BgBhmKt`D|9#EsLd1=)gXGMwM9_^L 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 G@BaYTo^D$J literal 0 HcmV?d00001 From 579461735fcd75ed6645502ec7f84c4e6cadffc8 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Mon, 30 Mar 2020 16:54:14 +0200 Subject: [PATCH 113/304] FilterTask now outputs skipped content to error output --- Task/FilterTask.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Task/FilterTask.php b/Task/FilterTask.php index 5613e482..7ac49f8f 100644 --- a/Task/FilterTask.php +++ b/Task/FilterTask.php @@ -52,6 +52,7 @@ public function execute(ProcessState $state) { $input = $state->getInput(); if (!$this->checkCondition($input, $this->getOptions($state))) { + $state->setErrorOutput($input); $state->setSkipped(true); return; From 52ffad0f251f09828d384d7aae2415226da54675 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 22 Apr 2020 15:26:58 +0200 Subject: [PATCH 114/304] Adding simple file reader task and cast transformer --- Task/File/FileReaderTask.php | 58 +++++++++++++++++++++++++++++++++ Transformer/CastTransformer.php | 56 +++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 Task/File/FileReaderTask.php create mode 100644 Transformer/CastTransformer.php diff --git a/Task/File/FileReaderTask.php b/Task/File/FileReaderTask.php new file mode 100644 index 00000000..78942f46 --- /dev/null +++ b/Task/File/FileReaderTask.php @@ -0,0 +1,58 @@ + + */ +class FileReaderTask extends AbstractConfigurableTask +{ + /** + * @param ProcessState $state + * + * @throws ExceptionInterface + * @throws IOException + */ + public function execute(ProcessState $state) + { + $options = $this->getOptions($state); + + $state->setOutput(file_get_contents($options['filename'])); + } + + /** + * @param OptionsResolver $resolver + * + * @throws AccessException + * @throws UndefinedOptionsException + */ + protected function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'filename', + ] + ); + $resolver->setAllowedTypes('filename', ['string']); + } +} diff --git a/Transformer/CastTransformer.php b/Transformer/CastTransformer.php new file mode 100644 index 00000000..40068e72 --- /dev/null +++ b/Transformer/CastTransformer.php @@ -0,0 +1,56 @@ + + * @author Vincent Chalnot + */ +class CastTransformer implements ConfigurableTransformerInterface +{ + /** + * {@inheritdoc} + */ + public function transform($value, array $options = []) + { + settype($value, $options['type']); + + return $value; + } + + /** + * {@inheritdoc} + */ + public function getCode() + { + return 'cast'; + } + + /** + * @param OptionsResolver $resolver + * + * @throws ExceptionInterface + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'type', + ] + ); + $resolver->setAllowedTypes('type', ['string']); + } +} From cf41019e1a68120b10eaf45a8de0ac0926daabb5 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 29 May 2020 17:20:01 +0200 Subject: [PATCH 115/304] Removed useless, CPU intensive, log --- Task/File/Csv/CsvSplitterTask.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index c3f948e7..0838dcd0 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -47,9 +47,6 @@ public function execute(ProcessState $state) $options['mode'] ); - if ($csv->getLineCount() > $options['max_lines']) { - $this->logger->debug("Found big CSV file ({$csv->getLineCount()} lines), splitting..."); - } $this->csv = $csv; } From ae2ad46bf96288ca4739c08ff277276ec2738d04 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Mon, 15 Jun 2020 15:08:27 +0200 Subject: [PATCH 116/304] Adding basic debug transformer --- Transformer/DebugTransformer.php | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Transformer/DebugTransformer.php diff --git a/Transformer/DebugTransformer.php b/Transformer/DebugTransformer.php new file mode 100644 index 00000000..56a179f2 --- /dev/null +++ b/Transformer/DebugTransformer.php @@ -0,0 +1,41 @@ + + */ +class DebugTransformer implements TransformerInterface +{ + /** + * @inheritDoc + */ + public function transform($value, array $options = []) + { + if (class_exists(VarDumper::class)) { + VarDumper::dump($value); + } + + return $value; + } + + /** + * @inheritDoc + */ + public function getCode() + { + return 'dump'; + } +} From 5341099d4ef3166f29bd38811ed7adc2d15bfd47 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Tue, 23 Jun 2020 11:46:48 +0200 Subject: [PATCH 117/304] Adding ArrayUnsetTransformer --- Transformer/ArrayUnsetTransformer.php | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Transformer/ArrayUnsetTransformer.php diff --git a/Transformer/ArrayUnsetTransformer.php b/Transformer/ArrayUnsetTransformer.php new file mode 100644 index 00000000..dbc61ad5 --- /dev/null +++ b/Transformer/ArrayUnsetTransformer.php @@ -0,0 +1,49 @@ +setRequired('key'); + $resolver->setAllowedTypes('key', ['string', 'int']); + } +} From fba57c5540471cb67036d01b27eeeae3c17dd063 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Mon, 29 Jun 2020 12:55:37 +0200 Subject: [PATCH 118/304] Allowing ValidatorTask to output constraint violations with an option --- Task/Validation/ValidatorTask.php | 49 ++++++++++++++++++++++---- Transformer/ArrayFilterTransformer.php | 1 - Transformer/MappingTransformer.php | 9 ++--- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index 47bcec6b..9e009c93 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -13,6 +13,7 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; use Sidus\BaseBundle\Validator\Mapping\Loader\BaseLoader; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\Options; @@ -55,7 +56,7 @@ public function execute(ProcessState $state) $options = $this->getOptions($state); $violations = $this->validator->validate( $state->getInput(), - $this->getOption($state, 'constraints'), + $options['constraints'], $options['groups'] ); @@ -69,11 +70,18 @@ public function execute(ProcessState $state) 'violation_code' => $violation->getCode(), 'invalid_value' => $invalidValue, ]; - if ($this->getOption($state, 'log_errors')) { - $this->logger->warning($violation->getMessage(), $logContext); + if ($options['log_errors']) { + $this->logger->log($options['log_errors'], $violation->getMessage(), $logContext); } } + if ($options['error_output_violations']) { + $state->setErrorOutput($violations); + $state->setSkipped(true); + + return; + } + throw new \UnexpectedValueException("{$violations->count()} constraint violations detected on validation"); } @@ -85,14 +93,38 @@ public function execute(ProcessState $state) */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setDefault('log_errors', true); - $resolver->addAllowedTypes('log_errors', ['bool']); + $resolver->setDefault('log_errors', LogLevel::CRITICAL); + $resolver->setAllowedValues( + 'log_errors', + [ + LogLevel::ALERT, + LogLevel::CRITICAL, + LogLevel::DEBUG, + LogLevel::EMERGENCY, + LogLevel::ERROR, + LogLevel::INFO, + LogLevel::NOTICE, + LogLevel::WARNING, + true, + false, + ] + ); + $resolver->setNormalizer( + 'log_errors', + static function (Options $options, $value) { + if (true === $value) { + return LogLevel::CRITICAL; + } + + return $value; + } + ); $resolver->setDefault('groups', null); - $resolver->addAllowedTypes('groups', ['NULL', 'array']); + $resolver->setAllowedTypes('groups', ['NULL', 'array']); $resolver->setDefault('constraints', null); - $resolver->addAllowedTypes('constraints', ['NULL', 'array']); + $resolver->setAllowedTypes('constraints', ['NULL', 'array']); $resolver->setNormalizer( 'constraints', static function (Options $options, $constraints) { @@ -103,5 +135,8 @@ static function (Options $options, $constraints) { return (new BaseLoader())->loadCustomConstraints($constraints); } ); + + $resolver->setDefault('error_output_violations', false); + $resolver->setAllowedTypes('error_output_violations', ['bool']); } } diff --git a/Transformer/ArrayFilterTransformer.php b/Transformer/ArrayFilterTransformer.php index 2fce191e..7e7ca35c 100644 --- a/Transformer/ArrayFilterTransformer.php +++ b/Transformer/ArrayFilterTransformer.php @@ -20,7 +20,6 @@ */ class ArrayFilterTransformer implements ConfigurableTransformerInterface { - use ConditionTrait; /** diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 7c6910be..14f6917b 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -82,7 +82,7 @@ public function transform($input, array $options = []) /** @noinspection ForeachSourceInspection */ foreach ($options['mapping'] as $targetProperty => $mapping) { - $targetProperty = (string)$targetProperty; + $targetProperty = (string) $targetProperty; $sourceProperty = $mapping['code'] ?? $targetProperty; $ignoreMissingFlag = $mapping['ignore_missing'] || $options['ignore_missing']; @@ -101,9 +101,8 @@ public function transform($input, array $options = []) $this->handleInputMissingExceptions($missingPropertyError, $srcKey); if ($ignoreMissingFlag) { continue; - } else { - throw $missingPropertyError; } + throw $missingPropertyError; } } } else { @@ -113,11 +112,9 @@ public function transform($input, array $options = []) $this->handleInputMissingExceptions($missingPropertyError, $sourceProperty); if ($ignoreMissingFlag) { continue; - } else { - throw $missingPropertyError; } + throw $missingPropertyError; } - } // Transform input value From 9bbc10749dbc1c1059655dc81c7db025045b1d00 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 10 Sep 2020 11:34:58 +0200 Subject: [PATCH 119/304] Fixed a bad static access --- Tests/ProcessManagerTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/ProcessManagerTest.php b/Tests/ProcessManagerTest.php index 041eeeab..a684b2e0 100644 --- a/Tests/ProcessManagerTest.php +++ b/Tests/ProcessManagerTest.php @@ -42,11 +42,11 @@ public function testProcessEvents() /** @var EventDispatcherInterface $eventDispatcher */ $eventDispatcher = $edProphecy->reveal(); $processManager = new ProcessManager( - self::$container, - self::$container->get(ProcessLogger::class), - self::$container->get(TaskLogger::class), - self::$container->get(ProcessConfigurationRegistry::class), - self::$container->get(ContextualOptionResolver::class), + $this->getContainer(), + $this->getContainer()->get(ProcessLogger::class), + $this->getContainer()->get(TaskLogger::class), + $this->getContainer()->get(ProcessConfigurationRegistry::class), + $this->getContainer()->get(ContextualOptionResolver::class), $eventDispatcher ); From 2b1b86c6c43720ffe608ef8d614ab8b0f3701b72 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Thu, 3 Dec 2020 18:10:47 +0100 Subject: [PATCH 120/304] Fixing AbstractIterableOutputTask that was inconsistent when chained, refactoring InputIteratorTask that had the proper implementation with the AbstractIterableOutputTask as parent --- Task/AbstractIterableOutputTask.php | 39 ++++++++++++- Task/InputIteratorTask.php | 88 ++++------------------------- 2 files changed, 48 insertions(+), 79 deletions(-) diff --git a/Task/AbstractIterableOutputTask.php b/Task/AbstractIterableOutputTask.php index f46425e7..5ea5ffb1 100644 --- a/Task/AbstractIterableOutputTask.php +++ b/Task/AbstractIterableOutputTask.php @@ -14,6 +14,7 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Base class to handle output iterations @@ -34,9 +35,8 @@ abstract class AbstractIterableOutputTask extends AbstractConfigurableTask imple */ public function execute(ProcessState $state) { - if (null === $this->iterator) { - $this->iterator = $this->initializeIterator($state); - } + $this->handleIteratorFromInput($state); + $state->addErrorContextValue('iterator_key', $this->iterator->key()); if ($this->iterator->valid()) { @@ -67,6 +67,39 @@ public function next(ProcessState $state) return $this->iterator->valid(); } + /** + * Create or recreate an iterator from input + * + * @param ProcessState $state + */ + protected function handleIteratorFromInput(ProcessState $state) + { + if ($this->iterator instanceof \Iterator) { + if ($this->iterator->valid()) { + return; // No action needed, execution is in progress + } + // Cleanup invalid iterator => prepare for new iteration cycle + $this->iterator = null; + } + + // This should never be reached + if (null !== $this->iterator) { + throw new \UnexpectedValueException( + "At this point iterator should have been null, maybe it's a wrong type..." + ); + } + + $this->iterator = $this->initializeIterator($state); + } + + /** + * Allow to not implement this method, not required by most tasks, removing inheritance would break back-compat + * + * @inheritDoc + */ + protected function configureOptions(OptionsResolver $resolver) + { + } /** * @param ProcessState $state diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index c2386888..1e97daa4 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -15,92 +15,28 @@ use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; /** - * Class InputIteratorTask + * Iterates from the input of the previous task * * @author Madeline Veyrenc */ -class InputIteratorTask implements IterableTaskInterface +class InputIteratorTask extends AbstractIterableOutputTask { - /** @var \Iterator */ - protected $iterator; - - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) - { - $this->handleIteratorFromInput($state); - - $state->addErrorContextValue('iterate_on_array_key', $this->iterator->key()); - - // If the initial value is already null, skip right now the next steps - if ($this->iterator->valid()) { - $state->setOutput($this->iterator->current()); - } else { - $state->setSkipped(true); - $this->iterator = null; - } - } - /** - * Moves the internal pointer to the next element, - * return true if the task has a next element - * return false if the task has terminated it's iteration - * - * @param ProcessState $state - * - * @return bool + * @inheritDoc */ - public function next(ProcessState $state) + protected function initializeIterator(ProcessState $state): \Iterator { - if (!$this->iterator) { - return false; - } - $this->iterator->next(); - $state->removeErrorContext('iterate_on_array_key'); - - return $this->iterator->valid(); - } - - /** - * Create or recreate an iterator from input - * - * @param ProcessState $state - */ - protected function handleIteratorFromInput(ProcessState $state) - { - if ($this->iterator instanceof \Iterator) { - if ($this->iterator->valid()) { - // No action needed, execution is in progress - return; - } - // Cleanup invalid iterator => prepare for new iteration cycle - $this->iterator = null; - } - - // This should never be reached - if (null !== $this->iterator) { - throw new \UnexpectedValueException( - "At this point iterator should have been null, maybe it's a wrong type..." - ); - } - $input = $state->getInput(); - // Create iterator if ($input instanceof \Iterator) { - $this->iterator = $input; - } elseif ($input instanceof \IteratorAggregate) { - $this->iterator = $input->getIterator(); - } elseif (\is_array($input)) { - $this->iterator = new \ArrayIterator($input); + return $input; } - - // Assert iterator is OK - if (!$this->iterator instanceof \Iterator) { - throw new \UnexpectedValueException('Cannot create iterator from input'); + if ($input instanceof \IteratorAggregate) { + return $input->getIterator(); } + if (\is_array($input)) { + return new \ArrayIterator($input); + } + + throw new \UnexpectedValueException('Cannot create iterator from input'); } } From 3ecc75c093780f7bdf5dbf1597bfc4145969a827 Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Wed, 9 Dec 2020 15:08:54 +0100 Subject: [PATCH 121/304] Adding simple task to launch system commands --- Task/Process/CommandRunnerTask.php | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Task/Process/CommandRunnerTask.php diff --git a/Task/Process/CommandRunnerTask.php b/Task/Process/CommandRunnerTask.php new file mode 100644 index 00000000..d7d61c83 --- /dev/null +++ b/Task/Process/CommandRunnerTask.php @@ -0,0 +1,77 @@ + + * @author Vincent Chalnot + */ +class CommandRunnerTask extends AbstractConfigurableTask +{ + /** @var KernelInterface */ + protected $kernel; + + /** + * @param KernelInterface $kernel + */ + public function __construct(KernelInterface $kernel) + { + $this->kernel = $kernel; + } + + /** + * @inheritDoc + */ + public function execute(ProcessState $state): void + { + $options = $this->getOptions($state); + $process = new Process( + $options['commandline'], + $options['cwd'], + $options['env'], + $state->getInput(), + $options['timeout'], + $options['options'] + ); + $process->inheritEnvironmentVariables(true); + $process->mustRun(); + $state->setOutput($process->getOutput()); + } + + /** + * @inheritDoc + */ + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired( + [ + 'commandline', + ] + ); + $resolver->setAllowedTypes('commandline', ['string', 'array']); + $resolver->setDefaults( + [ + 'cwd' => $this->kernel->getProjectDir(), // This method is not actually in the interface, this is bad + 'env' => null, + 'timeout' => 60, + 'options' => null, + ] + ); + } +} From 2a08da286a1c5d29e071e94dbebe62dc46966100 Mon Sep 17 00:00:00 2001 From: Corentin Bouix Date: Mon, 25 Jan 2021 17:25:06 +0100 Subject: [PATCH 122/304] Fix - FolderBrowserTask: Accept array type for `name_pattern` option --- Documentation/changelog/CHANGELOG-3.1.md | 2 ++ Task/File/FolderBrowserTask.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 98ea3126..1f2dd70c 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -8,6 +8,8 @@ v3.1-dev ### Fixes +* FolderBrowserTask: Accept array type for `name_pattern` option + ### BC breaks v3.1.0 diff --git a/Task/File/FolderBrowserTask.php b/Task/File/FolderBrowserTask.php index c51d6c9c..165fc3f3 100644 --- a/Task/File/FolderBrowserTask.php +++ b/Task/File/FolderBrowserTask.php @@ -135,7 +135,7 @@ static function (Options $options, $value) { 'empty_log_level' => LogLevel::WARNING, ] ); - $resolver->setAllowedTypes('name_pattern', ['NULL', 'string']); + $resolver->setAllowedTypes('name_pattern', ['NULL', 'string', 'array']); $resolver->setAllowedValues( 'empty_log_level', [ From 3efd921294ff82df806ca9c30f17f6488fa77914 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 2 Feb 2021 16:05:28 +0100 Subject: [PATCH 123/304] #121 : removed dependency to sidus/base-bundle, allow Sf5, fixed OptionsResolver needing "null" instead of "NULL" --- .../CleverAgeProcessExtension.php | 47 +++++++++++++--- DependencyInjection/Configuration.php | 5 +- Dockerfile | 5 +- .../cookbooks/performances_monitoring.md | 18 +----- Resources/tests/environment/sf4/composer.json | 55 +++++-------------- .../tests/environment/sf4/config/bundles.php | 1 - Resources/tests/environment/sf5/composer.json | 46 ++++++++++++++++ .../tests/environment/sf5/config/bundles.php | 7 +++ .../sf5/config/packages/framework.yaml | 10 ++++ .../packages/test/cleverage_process.yml | 2 + .../tests/environment/sf5/phpunit.xml.dist | 25 +++++++++ Task/File/Csv/AbstractCsvResourceTask.php | 2 +- Task/File/FolderBrowserTask.php | 2 +- Task/InputAggregatorTask.php | 2 +- Task/Reporting/LoggerTask.php | 2 +- Task/Serialization/DenormalizerTask.php | 2 +- Task/Validation/ValidatorTask.php | 8 +-- Transformer/DenormalizeTransformer.php | 2 +- Transformer/MappingTransformer.php | 4 +- Transformer/NormalizeTransformer.php | 2 +- Validator/ConstraintLoader.php | 47 ++++++++++++++++ composer.json | 21 ++++--- 22 files changed, 217 insertions(+), 98 deletions(-) create mode 100644 Resources/tests/environment/sf5/composer.json create mode 100644 Resources/tests/environment/sf5/config/bundles.php create mode 100644 Resources/tests/environment/sf5/config/packages/framework.yaml create mode 100644 Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml create mode 100644 Resources/tests/environment/sf5/phpunit.xml.dist create mode 100644 Validator/ConstraintLoader.php diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 2d8fd9a9..78f3d030 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -1,4 +1,5 @@ - * @author Madeline Veyrenc */ -class CleverAgeProcessExtension extends SidusBaseExtension +class CleverAgeProcessExtension extends Extension { /** * @param array $configs @@ -35,7 +39,10 @@ class CleverAgeProcessExtension extends SidusBaseExtension */ public function load(array $configs, ContainerBuilder $container) { - parent::load($configs, $container); + // Get the path of the service folder wherever the bundle is installed + $reflection = new \ReflectionClass($this); + $serviceFolderPath = \dirname($reflection->getFileName(), 2).'/Resources/config/services'; + $this->findServices($container, $serviceFolderPath); $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); @@ -49,13 +56,35 @@ public function load(array $configs, ContainerBuilder $container) $transformerDefinition = new Definition(GenericTransformer::class); $transformerDefinition->setAutowired(true); $transformerDefinition->setPrivate(true); - $transformerDefinition->addMethodCall('initialize',[ - $transformerCode, - $transformerConfig - ]); + $transformerDefinition->addMethodCall( + 'initialize', + [ + $transformerCode, + $transformerConfig, + ] + ); $transformerDefinition->addTag('cleverage.transformer'); - $container->setDefinition(GenericTransformer::class . "\\" . $transformerCode, $transformerDefinition); + $container->setDefinition(GenericTransformer::class."\\".$transformerCode, $transformerDefinition); + } + } + + /** + * Recursively import config files into container + * + * @param ContainerBuilder $container + * @param string $path + * @param string $extension + * + * @throws \Exception + */ + protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yml') + { + $finder = new Finder(); + $finder->in($path)->name('*.'.$extension)->files(); + $loader = new YamlFileLoader($container, new FileLocator($path)); + foreach ($finder as $file) { + $loader->load($file->getFilename()); } } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 43dcac73..c67f0552 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -45,9 +45,8 @@ public function __construct($root = 'clever_age_process') */ public function getConfigTreeBuilder() { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root($this->root); - $definition = $rootNode->children(); + $treeBuilder = new TreeBuilder($this->root); + $definition = $treeBuilder->getRootNode()->children(); // Default error strategy $definition->enumNode('default_error_strategy') diff --git a/Dockerfile b/Dockerfile index 5361bf84..57309227 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -ARG PHP_VERSION=7.1 +ARG PHP_VERSION=7.2 FROM php:${PHP_VERSION}-cli ARG SF_ENV=sf4 -ARG BLACKFIRE_PHP_VERSION=71 +ARG BLACKFIRE_PHP_VERSION=72 ARG BLACKFIRE_PROBE_VERSION=1.29.1 ARG BLACKFIRE_AGENT_VERSION=1.30.0 @@ -25,7 +25,6 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" COPY Resources/tests/environment/php/conf.ini "$PHP_INI_DIR/conf.d/" - # Basic sample symfony app install RUN mkdir /app WORKDIR /app diff --git a/Documentation/cookbooks/performances_monitoring.md b/Documentation/cookbooks/performances_monitoring.md index 633284ec..8a7e798d 100644 --- a/Documentation/cookbooks/performances_monitoring.md +++ b/Documentation/cookbooks/performances_monitoring.md @@ -8,23 +8,7 @@ to analyse call graphs with timings & memory analysis. ## Setup -If you're using the official PHP docker image, you can add the Blackfire probe to your container ([Official documentation](https://blackfire.io/docs/up-and-running/installation)) : - -```dockerfile -ARG BLACKFIRE_PHP_VERSION=71 -ARG BLACKFIRE_PROBE_VERSION=1.29.1 -ARG BLACKFIRE_AGENT_VERSION=1.30.0 - -# Blackfire PHP Probe -RUN curl -o $(php -i | grep -P "^extension_dir " | sed "s/^.* => //g")/blackfire.so -D - -L -s https://packages.blackfire.io/binaries/blackfire-php/${BLACKFIRE_PROBE_VERSION}/blackfire-php-linux_amd64-php-${BLACKFIRE_PHP_VERSION}.so -RUN docker-php-ext-enable blackfire -# Blackfire Agent (for HTTP calls) -RUN curl -o /usr/bin/blackfire-agent -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-agent-linux_amd64 -RUN chmod +x /usr/bin/blackfire-agent -# Blackfire CLI (for console) -RUN curl -o /usr/bin/blackfire -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-cli-linux_amd64 -RUN chmod +x /usr/bin/blackfire -``` +If you're using the official PHP docker image, you can add the Blackfire probe to your container ([Official documentation](https://blackfire.io/docs/integrations/docker/php-docker)). Then, with your [own credentials](https://blackfire.io/my/settings/credentials), execute inside your container ```shell script diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index 12de459e..544aedcc 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -2,33 +2,23 @@ "type": "project", "license": "proprietary", "require": { - "php": "^7.1.3", - "ext-ctype": "*", - "ext-iconv": "*", - "symfony/dotenv": "4.4.*", - "symfony/flex": "^1.3.1", - "symfony/framework-bundle": "4.4.*", + "symfony/framework-bundle": "^4.4", + "symfony/dotenv": "^4.4", + "symfony/flex": "^1.11", - "symfony/expression-language": "~3.0|~4.0", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0", - "symfony/options-resolver": "~3.0|~4.0", - "symfony/process": "~3.0|~4.0", - "symfony/property-access": "~3.0|~4.0", - "symfony/serializer": "~3.0|~4.0", - "symfony/validator": "~3.0|~4.0", - "symfony/yaml": "~3.0|~4.0", - "sidus/base-bundle": "~1.0" + "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/console": "~3.0|~4.0|~5.0", + "symfony/options-resolver": "~3.0|~4.0|~5.0", + "symfony/process": "~3.0|~4.0|~5.0", + "symfony/property-access": "~3.0|~4.0|~5.0", + "symfony/serializer": "~3.0|~4.0|~5.0", + "symfony/validator": "~3.0|~4.0|~5.0", + "symfony/yaml": "~3.0|~4.0|~5.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.1", - "phpunit/phpunit": "^6.4" - }, - "config": { - "preferred-install": { - "*": "dist" - }, - "sort-packages": true + "symfony/phpunit-bridge": "^4.4|^5.0", + "phpunit/phpunit": "~6.4" }, "autoload": { "psr-4": { @@ -41,14 +31,6 @@ "App\\Tests\\": "tests/" } }, - "replace": { - "paragonie/random_compat": "2.*", - "symfony/polyfill-ctype": "*", - "symfony/polyfill-iconv": "*", - "symfony/polyfill-php71": "*", - "symfony/polyfill-php70": "*", - "symfony/polyfill-php56": "*" - }, "scripts": { "auto-scripts": { "cache:clear": "symfony-cmd", @@ -60,14 +42,5 @@ "post-update-cmd": [ "@auto-scripts" ] - }, - "conflict": { - "symfony/symfony": "*" - }, - "extra": { - "symfony": { - "allow-contrib": false, - "require": "4.4.*" - } } } diff --git a/Resources/tests/environment/sf4/config/bundles.php b/Resources/tests/environment/sf4/config/bundles.php index 74f2f799..d1a265ef 100644 --- a/Resources/tests/environment/sf4/config/bundles.php +++ b/Resources/tests/environment/sf4/config/bundles.php @@ -3,6 +3,5 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], - Sidus\BaseBundle\SidusBaseBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], ]; diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json new file mode 100644 index 00000000..a634b81c --- /dev/null +++ b/Resources/tests/environment/sf5/composer.json @@ -0,0 +1,46 @@ +{ + "type": "project", + "license": "proprietary", + "require": { + "symfony/framework-bundle": "^5.0", + "symfony/dotenv": "^5.0", + "symfony/flex": "^1.11", + + "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/console": "~3.0|~4.0|~5.0", + "symfony/options-resolver": "~3.0|~4.0|~5.0", + "symfony/process": "~3.0|~4.0|~5.0", + "symfony/property-access": "~3.0|~4.0|~5.0", + "symfony/serializer": "~3.0|~4.0|~5.0", + "symfony/validator": "~3.0|~4.0|~5.0", + "symfony/yaml": "~3.0|~4.0|~5.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4|^5.0", + "phpunit/phpunit": "~6.4" + }, + "autoload": { + "psr-4": { + "App\\": "src/", + "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + } +} diff --git a/Resources/tests/environment/sf5/config/bundles.php b/Resources/tests/environment/sf5/config/bundles.php new file mode 100644 index 00000000..d1a265ef --- /dev/null +++ b/Resources/tests/environment/sf5/config/bundles.php @@ -0,0 +1,7 @@ + ['all' => true], + CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], +]; diff --git a/Resources/tests/environment/sf5/config/packages/framework.yaml b/Resources/tests/environment/sf5/config/packages/framework.yaml new file mode 100644 index 00000000..5a1678d2 --- /dev/null +++ b/Resources/tests/environment/sf5/config/packages/framework.yaml @@ -0,0 +1,10 @@ +framework: + secret: '%env(APP_SECRET)%' + + serializer: + enabled: true + + #esi: true + #fragments: true + php_errors: + log: true diff --git a/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml new file mode 100644 index 00000000..a03e25d8 --- /dev/null +++ b/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml @@ -0,0 +1,2 @@ +imports: + - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf5/phpunit.xml.dist b/Resources/tests/environment/sf5/phpunit.xml.dist new file mode 100644 index 00000000..fbdc9945 --- /dev/null +++ b/Resources/tests/environment/sf5/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + /src-cleverage_process/Tests + + + diff --git a/Task/File/Csv/AbstractCsvResourceTask.php b/Task/File/Csv/AbstractCsvResourceTask.php index 06ac9f8f..ade22f63 100644 --- a/Task/File/Csv/AbstractCsvResourceTask.php +++ b/Task/File/Csv/AbstractCsvResourceTask.php @@ -82,7 +82,7 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('delimiter', ['string']); $resolver->setAllowedTypes('enclosure', ['string']); $resolver->setAllowedTypes('escape', ['string']); - $resolver->setAllowedTypes('headers', ['NULL', 'array']); + $resolver->setAllowedTypes('headers', ['null', 'array']); } /** diff --git a/Task/File/FolderBrowserTask.php b/Task/File/FolderBrowserTask.php index 165fc3f3..4353f1a9 100644 --- a/Task/File/FolderBrowserTask.php +++ b/Task/File/FolderBrowserTask.php @@ -135,7 +135,7 @@ static function (Options $options, $value) { 'empty_log_level' => LogLevel::WARNING, ] ); - $resolver->setAllowedTypes('name_pattern', ['NULL', 'string', 'array']); + $resolver->setAllowedTypes('name_pattern', ['null', 'string', 'array']); $resolver->setAllowedValues( 'empty_log_level', [ diff --git a/Task/InputAggregatorTask.php b/Task/InputAggregatorTask.php index 3de4568d..bbc09214 100644 --- a/Task/InputAggregatorTask.php +++ b/Task/InputAggregatorTask.php @@ -91,7 +91,7 @@ protected function configureOptions(OptionsResolver $resolver) ); $resolver->setAllowedTypes('input_codes', 'array'); $resolver->setAllowedTypes('clean_input_on_override', 'boolean'); - $resolver->setAllowedTypes('keep_inputs', ['NULL', 'array']); + $resolver->setAllowedTypes('keep_inputs', ['null', 'array']); } /** diff --git a/Task/Reporting/LoggerTask.php b/Task/Reporting/LoggerTask.php index 9fbe855e..05d1ba03 100644 --- a/Task/Reporting/LoggerTask.php +++ b/Task/Reporting/LoggerTask.php @@ -97,6 +97,6 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('level', ['string']); $resolver->setAllowedTypes('message', ['string']); $resolver->setAllowedTypes('context', ['array']); - $resolver->setAllowedTypes('reference', ['string', 'NULL']); + $resolver->setAllowedTypes('reference', ['string', 'null']); } } diff --git a/Task/Serialization/DenormalizerTask.php b/Task/Serialization/DenormalizerTask.php index fbb5d37f..86fa370c 100644 --- a/Task/Serialization/DenormalizerTask.php +++ b/Task/Serialization/DenormalizerTask.php @@ -86,7 +86,7 @@ protected function configureOptions(OptionsResolver $resolver) 'context' => [], ] ); - $resolver->setAllowedTypes('format', ['NULL', 'string']); + $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } } diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index 9e009c93..eed1d004 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -12,9 +12,9 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; +use CleverAge\ProcessBundle\Validator\ConstraintLoader; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Sidus\BaseBundle\Validator\Mapping\Loader\BaseLoader; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -121,10 +121,10 @@ static function (Options $options, $value) { ); $resolver->setDefault('groups', null); - $resolver->setAllowedTypes('groups', ['NULL', 'array']); + $resolver->setAllowedTypes('groups', ['null', 'array']); $resolver->setDefault('constraints', null); - $resolver->setAllowedTypes('constraints', ['NULL', 'array']); + $resolver->setAllowedTypes('constraints', ['null', 'array']); $resolver->setNormalizer( 'constraints', static function (Options $options, $constraints) { @@ -132,7 +132,7 @@ static function (Options $options, $constraints) { return null; } - return (new BaseLoader())->loadCustomConstraints($constraints); + return (new ConstraintLoader())->buildConstraints($constraints); } ); diff --git a/Transformer/DenormalizeTransformer.php b/Transformer/DenormalizeTransformer.php index d16609ba..285ba84e 100644 --- a/Transformer/DenormalizeTransformer.php +++ b/Transformer/DenormalizeTransformer.php @@ -55,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver) 'context' => [], ] ); - $resolver->setAllowedTypes('format', ['NULL', 'string']); + $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 14f6917b..5eb54d4a 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -180,7 +180,7 @@ public function configureOptions(OptionsResolver $resolver) ); $resolver->setAllowedTypes('ignore_missing', ['boolean']); $resolver->setAllowedTypes('keep_input', ['boolean']); - $resolver->setAllowedTypes('merge_callback', ['NULL', 'callable']); + $resolver->setAllowedTypes('merge_callback', ['null', 'callable']); $resolver->setNormalizer( 'mapping', @@ -232,7 +232,7 @@ protected function configureMappingOptions(OptionsResolver $resolver) 'ignore_missing' => false, ] ); - $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); + $resolver->setAllowedTypes('code', ['null', 'string', 'array']); $resolver->setAllowedTypes('set_null', ['boolean']); $resolver->setAllowedTypes('ignore_missing', ['boolean']); diff --git a/Transformer/NormalizeTransformer.php b/Transformer/NormalizeTransformer.php index 772eb294..f9cfe5bf 100644 --- a/Transformer/NormalizeTransformer.php +++ b/Transformer/NormalizeTransformer.php @@ -49,7 +49,7 @@ public function configureOptions(OptionsResolver $resolver) 'context' => [], ] ); - $resolver->setAllowedTypes('format', ['NULL', 'string']); + $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } diff --git a/Validator/ConstraintLoader.php b/Validator/ConstraintLoader.php new file mode 100644 index 00000000..35faa377 --- /dev/null +++ b/Validator/ConstraintLoader.php @@ -0,0 +1,47 @@ + $childNodes) { + if (is_numeric($name) && \is_array($childNodes) && 1 === \count($childNodes)) { + $options = current($childNodes); + + if (\is_array($options)) { + $options = $this->buildConstraints($options); + } + + $values[] = $this->newConstraint(key($childNodes), $options); + } else { + if (\is_array($childNodes)) { + $childNodes = $this->buildConstraints($childNodes); + } + + $values[$name] = $childNodes; + } + } + + return $values; + } +} diff --git a/composer.json b/composer.json index 2d10787f..eb0ba7b3 100644 --- a/composer.json +++ b/composer.json @@ -40,17 +40,16 @@ "php": ">=7.1", "ext-json": "*", "ext-dom": "*", - "symfony/framework-bundle": "~3.0|~4.0", - "symfony/expression-language": "~3.0|~4.0", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0", - "symfony/options-resolver": "~3.0|~4.0", - "symfony/process": "~3.0|~4.0", - "symfony/property-access": "~3.0|~4.0", - "symfony/serializer": "~3.0|~4.0", - "symfony/validator": "~3.0|~4.0", - "symfony/yaml": "~3.0|~4.0", - "sidus/base-bundle": "~1.0" + "symfony/framework-bundle": "~3.0|~4.0|~5.0", + "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/console": "~3.0|~4.0|~5.0", + "symfony/options-resolver": "~3.0|~4.0|~5.0", + "symfony/process": "~3.0|~4.0|~5.0", + "symfony/property-access": "~3.0|~4.0|~5.0", + "symfony/serializer": "~3.0|~4.0|~5.0", + "symfony/validator": "~3.0|~4.0|~5.0", + "symfony/yaml": "~3.0|~4.0|~5.0" }, "require-dev": { "phpunit/phpunit": "~6.4" From ff06f5ca1cc81055df4590d8e60c4bc620015f44 Mon Sep 17 00:00:00 2001 From: Fabien Salles Date: Mon, 22 Feb 2021 15:58:17 +0100 Subject: [PATCH 124/304] Add Backcompat event dispatcher in order to delete deprecations notices (#118) Co-authored-by: Valentin Clavreul --- EventDispatcher/BackcompatEventDispatcher.php | 29 +++++++++++++++++++ Manager/ProcessManager.php | 14 ++++----- Resources/config/services/event.yml | 4 +++ Resources/config/services/manager.yml | 2 ++ Tests/ProcessManagerTest.php | 6 ++-- composer.json | 1 + 6 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 EventDispatcher/BackcompatEventDispatcher.php diff --git a/EventDispatcher/BackcompatEventDispatcher.php b/EventDispatcher/BackcompatEventDispatcher.php new file mode 100644 index 00000000..ae9ead8d --- /dev/null +++ b/EventDispatcher/BackcompatEventDispatcher.php @@ -0,0 +1,29 @@ + + */ +class BackcompatEventDispatcher implements ContractsEventDispatcherInterface +{ + /** @var EventDispatcherInterface */ + private $dispatcher; + + public function __construct(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + public function dispatch($event, string $eventName = null) + { + if($this->dispatcher instanceof ContractsEventDispatcherInterface) { + $this->dispatcher->dispatch($event, $eventName); + } else { + $this->dispatcher->dispatch($eventName, $event); + } + } +} diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 8de01fdb..74aa326c 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -31,7 +31,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Execute processes @@ -136,8 +136,8 @@ public function execute(string $processCode, $input = null, array $context = []) { try { $this->eventDispatcher->dispatch( - ProcessEvent::EVENT_PROCESS_STARTED, - new ProcessEvent($processCode, $input, $context) + new ProcessEvent($processCode, $input, $context), + ProcessEvent::EVENT_PROCESS_STARTED ); $this->processLogger->debug('Process start'); @@ -145,14 +145,14 @@ public function execute(string $processCode, $input = null, array $context = []) $this->processLogger->debug('Process end'); $this->eventDispatcher->dispatch( - ProcessEvent::EVENT_PROCESS_ENDED, - new ProcessEvent($processCode, $input, $context, $result) + new ProcessEvent($processCode, $input, $context, $result), + ProcessEvent::EVENT_PROCESS_ENDED ); } catch (\Throwable $error) { $this->processLogger->critical('Critical process failure', ['error' => $error->getMessage()]); $this->eventDispatcher->dispatch( - ProcessEvent::EVENT_PROCESS_FAILED, - new ProcessEvent($processCode, $input, $context, null, $error) + new ProcessEvent($processCode, $input, $context, null, $error), + ProcessEvent::EVENT_PROCESS_FAILED ); throw $error; diff --git a/Resources/config/services/event.yml b/Resources/config/services/event.yml index f4a5bb70..6c1a9dac 100644 --- a/Resources/config/services/event.yml +++ b/Resources/config/services/event.yml @@ -1,4 +1,8 @@ services: + CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher: + public: false + autowire: true + CleverAge\ProcessBundle\EventListener\DataQueueEventListener: public: false tags: diff --git a/Resources/config/services/manager.yml b/Resources/config/services/manager.yml index 05caef11..364b45c0 100644 --- a/Resources/config/services/manager.yml +++ b/Resources/config/services/manager.yml @@ -2,6 +2,8 @@ services: CleverAge\ProcessBundle\Manager\ProcessManager: autowire: true public: false + arguments: + $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' CleverAge\ProcessBundle\Context\ContextualOptionResolver: public: false diff --git a/Tests/ProcessManagerTest.php b/Tests/ProcessManagerTest.php index a684b2e0..b94b8e98 100644 --- a/Tests/ProcessManagerTest.php +++ b/Tests/ProcessManagerTest.php @@ -27,15 +27,15 @@ public function testProcessEvents() { $edProphecy = $this->prophesize(EventDispatcherInterface::class); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_STARTED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_STARTED]); $dispatchStartProphecy->shouldBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_ENDED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_ENDED]); $dispatchStartProphecy->shouldBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ProcessEvent::EVENT_PROCESS_FAILED, new TypeToken(ProcessEvent::class)]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_FAILED]); $dispatchStartProphecy->shouldNotBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); diff --git a/composer.json b/composer.json index eb0ba7b3..0d8fa08c 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,7 @@ "php": ">=7.1", "ext-json": "*", "ext-dom": "*", + "symfony/event-dispatcher-contracts": "~1.1", "symfony/framework-bundle": "~3.0|~4.0|~5.0", "symfony/expression-language": "~3.0|~4.0|~5.0", "symfony/monolog-bundle": "~3.3|~5.0", From 027bb29b8c4344c72e1cb97abcc6cf9b71a823e4 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 22 Feb 2021 16:31:56 +0100 Subject: [PATCH 125/304] Use event interfaces that should works in both sf4 and sf5 --- Dockerfile | 10 +++++----- Event/ConsoleProcessEvent.php | 2 +- Event/EventDispatcherTaskEvent.php | 2 +- Event/ProcessEvent.php | 2 +- EventDispatcher/BackcompatEventDispatcher.php | 9 ++++++++- Manager/ProcessManager.php | 2 +- Resources/config/services/task.yml | 2 ++ Resources/tests/environment/sf4/composer.json | 2 ++ Resources/tests/environment/sf5/composer.json | 2 ++ .../{cleverage_process.yml => cleverage_process.yaml} | 0 Resources/tests/environment/sf5/phpunit.xml.dist | 1 - Task/Event/EventDispatcherTask.php | 4 ++-- composer.json | 5 +++-- hooks/build | 6 ++++++ 14 files changed, 34 insertions(+), 15 deletions(-) rename Resources/tests/environment/sf5/config/packages/test/{cleverage_process.yml => cleverage_process.yaml} (100%) create mode 100755 hooks/build diff --git a/Dockerfile b/Dockerfile index 57309227..e971b585 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,14 @@ ARG PHP_VERSION=7.2 FROM php:${PHP_VERSION}-cli -ARG SF_ENV=sf4 -ARG BLACKFIRE_PHP_VERSION=72 -ARG BLACKFIRE_PROBE_VERSION=1.29.1 -ARG BLACKFIRE_AGENT_VERSION=1.30.0 - # Basic tools RUN apt-get update RUN apt-get install -y wget git zip unzip # Blackfire install +ARG BLACKFIRE_PHP_VERSION=72 +ARG BLACKFIRE_PROBE_VERSION=1.29.1 +ARG BLACKFIRE_AGENT_VERSION=1.30.0 RUN curl -o $(php -i | grep -P "^extension_dir " | sed "s/^.* => //g")/blackfire.so -D - -L -s https://packages.blackfire.io/binaries/blackfire-php/${BLACKFIRE_PROBE_VERSION}/blackfire-php-linux_amd64-php-${BLACKFIRE_PHP_VERSION}.so RUN curl -o /usr/bin/blackfire-agent -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-agent-linux_amd64 RUN chmod +x /usr/bin/blackfire-agent @@ -26,6 +24,8 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" COPY Resources/tests/environment/php/conf.ini "$PHP_INI_DIR/conf.d/" # Basic sample symfony app install +ARG SF_ENV=sf4 +ENV APP_ENV test RUN mkdir /app WORKDIR /app ENV HOME /app diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 4d9658f9..52181387 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; /** * Event object used during CLI process manipulation diff --git a/Event/EventDispatcherTaskEvent.php b/Event/EventDispatcherTaskEvent.php index 3663feaa..ae9c4efd 100644 --- a/Event/EventDispatcherTaskEvent.php +++ b/Event/EventDispatcherTaskEvent.php @@ -11,7 +11,7 @@ namespace CleverAge\ProcessBundle\Event; use CleverAge\ProcessBundle\Model\ProcessState; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; /** * Class EventDispatcherTaskEvent diff --git a/Event/ProcessEvent.php b/Event/ProcessEvent.php index 9ec1b809..cfa05563 100644 --- a/Event/ProcessEvent.php +++ b/Event/ProcessEvent.php @@ -10,7 +10,7 @@ namespace CleverAge\ProcessBundle\Event; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; /** * Event object for process start/stop/fail diff --git a/EventDispatcher/BackcompatEventDispatcher.php b/EventDispatcher/BackcompatEventDispatcher.php index ae9ead8d..e477d0e1 100644 --- a/EventDispatcher/BackcompatEventDispatcher.php +++ b/EventDispatcher/BackcompatEventDispatcher.php @@ -2,13 +2,18 @@ namespace CleverAge\ProcessBundle\EventDispatcher; +use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; /** + * A dispatcher that is flexible enough to handle every sf version + * We use the PSR interface that is more simple, since PHP allow this kind of override + * + * @deprecated once sf3.4 is fully dropped, only "ContractsEventDispatcherInterface" should be used * @author Fabien Salles */ -class BackcompatEventDispatcher implements ContractsEventDispatcherInterface +class BackcompatEventDispatcher implements PsrEventDispatcherInterface { /** @var EventDispatcherInterface */ private $dispatcher; @@ -21,8 +26,10 @@ public function __construct(EventDispatcherInterface $dispatcher) public function dispatch($event, string $eventName = null) { if($this->dispatcher instanceof ContractsEventDispatcherInterface) { + // This should match most recent Sf version $this->dispatcher->dispatch($event, $eventName); } else { + // Back-compatibility with Sf3 style dispatcher $this->dispatcher->dispatch($eventName, $event); } } diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 74aa326c..dcdfe51a 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -31,7 +31,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Psr\EventDispatcher\EventDispatcherInterface; /** * Execute processes diff --git a/Resources/config/services/task.yml b/Resources/config/services/task.yml index 61e64bf7..98c9804a 100644 --- a/Resources/config/services/task.yml +++ b/Resources/config/services/task.yml @@ -6,3 +6,5 @@ services: shared: false tags: - { name: monolog.logger, channel: cleverage_process_task } + bind: + $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index 544aedcc..ee581312 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -6,6 +6,8 @@ "symfony/dotenv": "^4.4", "symfony/flex": "^1.11", + "symfony/event-dispatcher-contracts": "~1.0|~2.0", + "psr/event-dispatcher": "1.0.0", "symfony/expression-language": "~3.0|~4.0|~5.0", "symfony/monolog-bundle": "~3.3|~5.0", "symfony/console": "~3.0|~4.0|~5.0", diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json index a634b81c..bce244a1 100644 --- a/Resources/tests/environment/sf5/composer.json +++ b/Resources/tests/environment/sf5/composer.json @@ -6,6 +6,8 @@ "symfony/dotenv": "^5.0", "symfony/flex": "^1.11", + "symfony/event-dispatcher-contracts": "~1.0|~2.0", + "psr/event-dispatcher": "1.0.0", "symfony/expression-language": "~3.0|~4.0|~5.0", "symfony/monolog-bundle": "~3.3|~5.0", "symfony/console": "~3.0|~4.0|~5.0", diff --git a/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml similarity index 100% rename from Resources/tests/environment/sf5/config/packages/test/cleverage_process.yml rename to Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml diff --git a/Resources/tests/environment/sf5/phpunit.xml.dist b/Resources/tests/environment/sf5/phpunit.xml.dist index fbdc9945..b2a3a915 100644 --- a/Resources/tests/environment/sf5/phpunit.xml.dist +++ b/Resources/tests/environment/sf5/phpunit.xml.dist @@ -5,7 +5,6 @@ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" backupGlobals="false" colors="true" - bootstrap="config/bootstrap.php" > diff --git a/Task/Event/EventDispatcherTask.php b/Task/Event/EventDispatcherTask.php index a169e3a6..d103889c 100644 --- a/Task/Event/EventDispatcherTask.php +++ b/Task/Event/EventDispatcherTask.php @@ -13,7 +13,7 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Event\EventDispatcherTaskEvent; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\OptionsResolver\Exception\AccessException; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException; @@ -54,7 +54,7 @@ public function execute(ProcessState $state) $event = new EventDispatcherTaskEvent($state); - $this->eventDispatcher->dispatch($options['event_name'], $event); + $this->eventDispatcher->dispatch($event, $options['event_name']); } /** diff --git a/composer.json b/composer.json index 0d8fa08c..f9069777 100644 --- a/composer.json +++ b/composer.json @@ -37,10 +37,11 @@ } }, "require": { - "php": ">=7.1", + "php": ">=7.2", "ext-json": "*", "ext-dom": "*", - "symfony/event-dispatcher-contracts": "~1.1", + "symfony/event-dispatcher-contracts": "~1.0|~2.0", + "psr/event-dispatcher": "1.0.0", "symfony/framework-bundle": "~3.0|~4.0|~5.0", "symfony/expression-language": "~3.0|~4.0|~5.0", "symfony/monolog-bundle": "~3.3|~5.0", diff --git a/hooks/build b/hooks/build new file mode 100755 index 00000000..d12dd88b --- /dev/null +++ b/hooks/build @@ -0,0 +1,6 @@ +#!/bin/bash + +# This script file is used by https://hub.docker.com/ for automated build +# See https://docs.docker.com/docker-hub/builds/advanced/ for available variables + +docker build --build-arg SF_ENV=${DOCKER_TAG} -f ${DOCKERFILE_PATH} -t ${IMAGE_NAME} . From c508cb2197e719e8ab4c5090e3f1c39b0ecfb076 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 22 Feb 2021 17:46:30 +0100 Subject: [PATCH 126/304] Added tests for sf3 and a patch Event class that provide compatibility for any Symfony version --- Event/ConsoleProcessEvent.php | 3 +- Event/EventDispatcherTaskEvent.php | 3 +- Event/GenericEvent.php | 20 ++++++ Event/ProcessEvent.php | 4 +- Resources/tests/environment/sf3/composer.json | 49 +++++++++++++ .../tests/environment/sf3/config/bundles.php | 7 ++ .../config/packages/dev/cleverage_process.yml | 2 + .../sf3/config/packages/framework.yaml | 10 +++ .../packages/test/cleverage_process.yml | 2 + .../tests/environment/sf3/phpunit.xml.dist | 25 +++++++ .../tests/environment/sf3/src/Kernel.php | 72 +++++++++++++++++++ .../sf3/src/SetPublicServicesCompilerPass.php | 27 +++++++ Resources/tests/environment/sf4/composer.json | 2 +- Resources/tests/environment/sf5/composer.json | 2 +- Tests/ProcessManagerTest.php | 2 +- composer.json | 2 +- 16 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 Event/GenericEvent.php create mode 100644 Resources/tests/environment/sf3/composer.json create mode 100644 Resources/tests/environment/sf3/config/bundles.php create mode 100644 Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml create mode 100644 Resources/tests/environment/sf3/config/packages/framework.yaml create mode 100644 Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml create mode 100644 Resources/tests/environment/sf3/phpunit.xml.dist create mode 100644 Resources/tests/environment/sf3/src/Kernel.php create mode 100644 Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 52181387..e9d10a73 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -12,12 +12,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Contracts\EventDispatcher\Event; /** * Event object used during CLI process manipulation */ -class ConsoleProcessEvent extends Event +class ConsoleProcessEvent extends GenericEvent { const EVENT_CLI_INIT = 'cleverage_process.cli.init'; diff --git a/Event/EventDispatcherTaskEvent.php b/Event/EventDispatcherTaskEvent.php index ae9c4efd..2f10650a 100644 --- a/Event/EventDispatcherTaskEvent.php +++ b/Event/EventDispatcherTaskEvent.php @@ -11,14 +11,13 @@ namespace CleverAge\ProcessBundle\Event; use CleverAge\ProcessBundle\Model\ProcessState; -use Symfony\Contracts\EventDispatcher\Event; /** * Class EventDispatcherTaskEvent * * @author Madeline Veyrenc */ -class EventDispatcherTaskEvent extends Event +class EventDispatcherTaskEvent extends GenericEvent { /** * @var ProcessState diff --git a/Event/GenericEvent.php b/Event/GenericEvent.php new file mode 100644 index 00000000..795a767c --- /dev/null +++ b/Event/GenericEvent.php @@ -0,0 +1,20 @@ + */ -class ProcessEvent extends Event +class ProcessEvent extends GenericEvent { const EVENT_PROCESS_STARTED = 'cleverage_process.start'; diff --git a/Resources/tests/environment/sf3/composer.json b/Resources/tests/environment/sf3/composer.json new file mode 100644 index 00000000..d9d851fe --- /dev/null +++ b/Resources/tests/environment/sf3/composer.json @@ -0,0 +1,49 @@ +{ + "type": "project", + "license": "proprietary", + "require": { + "symfony/framework-bundle": "^3.4", + "symfony/routing": "^3.4", + "symfony/dotenv": "^3.4", + "symfony/flex": "^1.11", + + "symfony/event-dispatcher-contracts": "~1.0|~2.0", + "psr/event-dispatcher": "1.0.0", + "symfony/expression-language": "~3.0", + "symfony/monolog-bundle": "~3.3", + "symfony/console": "~3.0", + "symfony/options-resolver": "~3.0", + "symfony/process": "~3.0", + "symfony/property-access": "~3.0", + "symfony/serializer": "~3.0", + "symfony/validator": "~3.0", + "symfony/yaml": "~3.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4|^5.0", + "phpunit/phpunit": "~6.4" + }, + "autoload": { + "psr-4": { + "App\\": "src/", + "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + } +} diff --git a/Resources/tests/environment/sf3/config/bundles.php b/Resources/tests/environment/sf3/config/bundles.php new file mode 100644 index 00000000..d1a265ef --- /dev/null +++ b/Resources/tests/environment/sf3/config/bundles.php @@ -0,0 +1,7 @@ + ['all' => true], + CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], +]; diff --git a/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml b/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml new file mode 100644 index 00000000..a03e25d8 --- /dev/null +++ b/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml @@ -0,0 +1,2 @@ +imports: + - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf3/config/packages/framework.yaml b/Resources/tests/environment/sf3/config/packages/framework.yaml new file mode 100644 index 00000000..5a1678d2 --- /dev/null +++ b/Resources/tests/environment/sf3/config/packages/framework.yaml @@ -0,0 +1,10 @@ +framework: + secret: '%env(APP_SECRET)%' + + serializer: + enabled: true + + #esi: true + #fragments: true + php_errors: + log: true diff --git a/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml new file mode 100644 index 00000000..a03e25d8 --- /dev/null +++ b/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml @@ -0,0 +1,2 @@ +imports: + - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf3/phpunit.xml.dist b/Resources/tests/environment/sf3/phpunit.xml.dist new file mode 100644 index 00000000..fbdc9945 --- /dev/null +++ b/Resources/tests/environment/sf3/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + /src-cleverage_process/Tests + + + diff --git a/Resources/tests/environment/sf3/src/Kernel.php b/Resources/tests/environment/sf3/src/Kernel.php new file mode 100644 index 00000000..f9f1c817 --- /dev/null +++ b/Resources/tests/environment/sf3/src/Kernel.php @@ -0,0 +1,72 @@ +getProjectDir().'/var/cache/'.$this->environment; + } + + public function getLogDir() + { + return $this->getProjectDir().'/var/log'; + } + + /** + * Override the default native Kernel build to set public services that will be used for tests + * + * @param ContainerBuilder $container + */ + protected function build(ContainerBuilder $container) + { + $container->addCompilerPass(new SetPublicServicesCompilerPass()); + } + + public function registerBundles() + { + $contents = require $this->getProjectDir().'/config/bundles.php'; + foreach ($contents as $class => $envs) { + if ($envs[$this->environment] ?? $envs['all'] ?? false) { + yield new $class(); + } + } + } + + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) + { + $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); + // Feel free to remove the "container.autowiring.strict_mode" parameter + // if you are using symfony/dependency-injection 4.0+ as it's the default behavior + $container->setParameter('container.autowiring.strict_mode', true); + $container->setParameter('container.dumper.inline_class_loader', true); + $confDir = $this->getProjectDir().'/config'; + + $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $confDir = $this->getProjectDir().'/config'; + + $routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); + } +} diff --git a/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php b/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php new file mode 100644 index 00000000..43389bc2 --- /dev/null +++ b/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php @@ -0,0 +1,27 @@ +getDefinition(ProcessManager::class)->setPublic(true); + $container->getDefinition(ProcessConfigurationRegistry::class)->setPublic(true); + $container->getDefinition(TransformerRegistry::class)->setPublic(true); + $container->getDefinition(DataQueueEventListener::class)->setPublic(true); + $container->getDefinition(ProcessLogger::class)->setPublic(true); + $container->getDefinition(TaskLogger::class)->setPublic(true); + $container->getDefinition(ContextualOptionResolver::class)->setPublic(true); + } +} diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index ee581312..0c08c553 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -9,7 +9,7 @@ "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", "symfony/expression-language": "~3.0|~4.0|~5.0", - "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/monolog-bundle": "~3.3", "symfony/console": "~3.0|~4.0|~5.0", "symfony/options-resolver": "~3.0|~4.0|~5.0", "symfony/process": "~3.0|~4.0|~5.0", diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json index bce244a1..fd332f0d 100644 --- a/Resources/tests/environment/sf5/composer.json +++ b/Resources/tests/environment/sf5/composer.json @@ -9,7 +9,7 @@ "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", "symfony/expression-language": "~3.0|~4.0|~5.0", - "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/monolog-bundle": "~3.3", "symfony/console": "~3.0|~4.0|~5.0", "symfony/options-resolver": "~3.0|~4.0|~5.0", "symfony/process": "~3.0|~4.0|~5.0", diff --git a/Tests/ProcessManagerTest.php b/Tests/ProcessManagerTest.php index b94b8e98..799b0837 100644 --- a/Tests/ProcessManagerTest.php +++ b/Tests/ProcessManagerTest.php @@ -18,7 +18,7 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Prophecy\Argument\Token\TypeToken; use Prophecy\Prophecy\MethodProphecy; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Psr\EventDispatcher\EventDispatcherInterface; class ProcessManagerTest extends AbstractProcessTest { diff --git a/composer.json b/composer.json index f9069777..8d3d8ea5 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "psr/event-dispatcher": "1.0.0", "symfony/framework-bundle": "~3.0|~4.0|~5.0", "symfony/expression-language": "~3.0|~4.0|~5.0", - "symfony/monolog-bundle": "~3.3|~5.0", + "symfony/monolog-bundle": "~3.3", "symfony/console": "~3.0|~4.0|~5.0", "symfony/options-resolver": "~3.0|~4.0|~5.0", "symfony/process": "~3.0|~4.0|~5.0", From 40e8fd1831fccbbb401e66abd6fb58652dec9bbb Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 22 Feb 2021 17:55:17 +0100 Subject: [PATCH 127/304] Enable tests for current symfony versions --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index e535fab2..1aa13225 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,12 @@ services: - docker before_script: + - docker pull cleverage/process-bundle:sf3 - docker pull cleverage/process-bundle:sf4 + - docker pull cleverage/process-bundle:sf5 +# Tests should be done in reversed order to check most important versions first script: + - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf5 php vendor/bin/phpunit - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit + - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf3 php vendor/bin/phpunit From be493eff6e3cfb87f1cc37769b40bc13f5790eed Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 23 Feb 2021 11:55:07 +0100 Subject: [PATCH 128/304] Fixed event dispatcher call --- Command/ExecuteProcessCommand.php | 6 +++--- Resources/config/services/command.yml | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index e8e6b270..a019aeed 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -20,7 +20,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; @@ -109,8 +109,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $context = $this->parseContextValues($input); $this->eventDispatcher->dispatch( - ConsoleProcessEvent::EVENT_CLI_INIT, - new ConsoleProcessEvent($input, $output, $inputData, $context) + new ConsoleProcessEvent($input, $output, $inputData, $context), + ConsoleProcessEvent::EVENT_CLI_INIT ); /** @noinspection ForeachSourceInspection */ diff --git a/Resources/config/services/command.yml b/Resources/config/services/command.yml index 8e355004..8813faf6 100644 --- a/Resources/config/services/command.yml +++ b/Resources/config/services/command.yml @@ -3,3 +3,5 @@ services: resource: '../../../Command/*' autowire: true autoconfigure: true + bind: + $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' From 1cc25a5865ecd9e62c9a969e4fa8117e1477d7b9 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 10:05:05 +0100 Subject: [PATCH 129/304] Updated copyright notices, and updated documentation --- CleverAgeProcessBundle.php | 2 +- Command/ExecuteProcessCommand.php | 2 +- Command/ListProcessCommand.php | 2 +- Command/ProcessHelpCommand.php | 2 +- Configuration/ProcessConfiguration.php | 2 +- Configuration/TaskConfiguration.php | 2 +- Context/ContextualOptionResolver.php | 2 +- .../CleverAgeProcessExtension.php | 2 +- .../Compiler/CheckSerializerCompilerPass.php | 2 +- .../Compiler/RegistryCompilerPass.php | 2 +- DependencyInjection/Configuration.php | 2 +- Documentation/01-quick_start.md | 19 +++++++ Documentation/changelog/CHANGELOG-3.1.md | 54 ++++++++++++++++++- Documentation/changelog/CHANGELOG-3.2.md | 18 +++++++ Event/ConsoleProcessEvent.php | 2 +- Event/EventDispatcherTaskEvent.php | 2 +- Event/GenericEvent.php | 11 +++- Event/ProcessEvent.php | 2 +- EventDispatcher/BackcompatEventDispatcher.php | 10 +++- EventListener/DataQueueEventListener.php | 2 +- Exception/CircularProcessException.php | 2 +- .../InvalidProcessConfigurationException.php | 2 +- Exception/MissingProcessException.php | 2 +- .../MissingTaskConfigurationException.php | 2 +- Exception/MissingTransformerException.php | 2 +- Exception/MultiBranchProcessException.php | 2 +- Exception/ProcessExceptionInterface.php | 2 +- Exception/TransformerException.php | 2 +- ExpressionLanguage/PhpFunctionProvider.php | 2 +- Filesystem/CsvFile.php | 2 +- Filesystem/CsvResource.php | 2 +- Filesystem/FileStreamInterface.php | 2 +- Filesystem/JsonStreamFile.php | 2 +- Filesystem/SeekableFileInterface.php | 2 +- Filesystem/StructuredFileInterface.php | 2 +- Filesystem/WritableFileInterface.php | 2 +- .../WritableStructuredFileInterface.php | 2 +- Filesystem/XmlFile.php | 2 +- Logger/AbstractLogger.php | 2 +- Logger/AbstractProcessor.php | 2 +- Logger/ProcessLogger.php | 2 +- Logger/ProcessProcessor.php | 2 +- Logger/TaskLogger.php | 2 +- Logger/TaskProcessor.php | 2 +- Logger/TransformerProcessor.php | 2 +- Manager/ProcessManager.php | 2 +- Model/AbstractConfigurableTask.php | 2 +- Model/BlockingTaskInterface.php | 2 +- Model/FinalizableTaskInterface.php | 2 +- Model/FlushableTaskInterface.php | 2 +- Model/InitializableTaskInterface.php | 2 +- Model/IterableTaskInterface.php | 2 +- Model/ProcessHistory.php | 2 +- Model/ProcessState.php | 2 +- Model/SubprocessInstance.php | 2 +- Model/TaskInterface.php | 2 +- README.md | 3 ++ Registry/ProcessConfigurationRegistry.php | 2 +- Registry/TransformerRegistry.php | 2 +- Task/AbstractIterableOutputTask.php | 2 +- Task/AggregateIterableTask.php | 2 +- Task/ArrayMergeTask.php | 2 +- Task/ColumnAggregatorTask.php | 2 +- Task/ConstantIterableOutputTask.php | 2 +- Task/ConstantOutputTask.php | 2 +- Task/CounterTask.php | 2 +- Task/Debug/DebugTask.php | 2 +- Task/Debug/DieTask.php | 2 +- Task/Debug/ErrorForwarderTask.php | 2 +- Task/Debug/MemInfoDumpTask.php | 2 +- Task/DummyTask.php | 2 +- Task/Event/EventDispatcherTask.php | 2 +- Task/File/Csv/AbstractCsvResourceTask.php | 2 +- Task/File/Csv/AbstractCsvTask.php | 2 +- Task/File/Csv/CsvReaderTask.php | 2 +- Task/File/Csv/CsvSplitterTask.php | 2 +- Task/File/Csv/CsvWriterTask.php | 2 +- Task/File/Csv/InputCsvReaderTask.php | 2 +- Task/File/FileFetchTask.php | 2 +- Task/File/FileMoverTask.php | 2 +- Task/File/FileReaderTask.php | 2 +- Task/File/FileRemoverTask.php | 2 +- Task/File/FileWriterTask.php | 2 +- Task/File/FolderBrowserTask.php | 2 +- Task/File/InputFolderBrowserTask.php | 2 +- Task/File/JsonStream/JsonStreamReaderTask.php | 2 +- Task/File/Xml/XmlReaderTask.php | 2 +- Task/File/Xml/XmlWriterTask.php | 2 +- Task/File/YamlReaderTask.php | 2 +- Task/File/YamlWriterTask.php | 2 +- Task/FilterTask.php | 2 +- Task/InputAggregatorTask.php | 2 +- Task/InputIteratorTask.php | 2 +- Task/IterableBatchTask.php | 2 +- Task/ObjectUpdaterTask.php | 2 +- Task/Process/CommandRunnerTask.php | 2 +- Task/Process/ProcessExecutorTask.php | 2 +- Task/Process/ProcessLauncherTask.php | 2 +- Task/PropertyGetterTask.php | 2 +- Task/PropertySetterTask.php | 2 +- Task/Reporting/AdvancedStatCounterTask.php | 2 +- Task/Reporting/LoggerTask.php | 2 +- Task/Reporting/StatCounterTask.php | 2 +- Task/RowAggregatorTask.php | 2 +- Task/Serialization/DenormalizerTask.php | 2 +- Task/Serialization/DeserializerTask.php | 2 +- Task/Serialization/NormalizerTask.php | 2 +- Task/Serialization/SerializerTask.php | 2 +- Task/SimpleBatchTask.php | 2 +- Task/SkipEmptyTask.php | 2 +- Task/SplitJoinLineTask.php | 2 +- Task/StopTask.php | 2 +- Task/TransformerTask.php | 2 +- Task/Validation/ValidatorTask.php | 2 +- Tests/AbstractProcessTest.php | 2 +- Tests/BasicTest.php | 2 +- Tests/BlockingTaskTest.php | 2 +- Tests/CircularProcessTest.php | 2 +- Tests/ContextTest.php | 2 +- Tests/EmptyProcessTest.php | 2 +- Tests/ExceptionManagementTest.php | 2 +- Tests/FlushableTaskTest.php | 2 +- Tests/IterableTaskTest.php | 2 +- Tests/MultiBranchProcessTest.php | 2 +- Tests/MultiWorkflowTest.php | 2 +- Tests/ProcessManagerTest.php | 2 +- Tests/Task/ColumnAggregatorTaskTest.php | 2 +- Tests/Task/FilterTaskTest.php | 2 +- Tests/Task/ProcessExecutorTaskTest.php | 2 +- Tests/Task/StopTaskTest.php | 2 +- Tests/Task/TransformerTaskTest.php | 2 +- Tests/Task/ValidatorTaskTest.php | 2 +- .../ArrayFilterTransformerTest.php | 2 +- Tests/Transformer/CallbackTransformerTest.php | 2 +- Tests/Transformer/DateTransformersTest.php | 2 +- Tests/Transformer/HashTransformerTest.php | 2 +- Tests/Transformer/MappingTransformerTest.php | 2 +- Tests/Transformer/RulesTransformerTest.php | 2 +- .../Transformer/TransformerExceptionTest.php | 2 +- .../Transformer/TypeSetterTransformerTest.php | 2 +- Tests/Transformer/UnsetTransformerTest.php | 2 +- .../XpathEvaluatorTransformerTest.php | 2 +- Transformer/ArrayElementTransformer.php | 2 +- Transformer/ArrayFilterTransformer.php | 2 +- Transformer/ArrayFirstTransformer.php | 2 +- Transformer/ArrayLastTransformer.php | 2 +- Transformer/ArrayMapTransformer.php | 2 +- Transformer/ArrayUnsetTransformer.php | 2 +- Transformer/CallbackTransformer.php | 2 +- Transformer/CastTransformer.php | 2 +- Transformer/ConditionTrait.php | 2 +- .../ConfigurableTransformerInterface.php | 2 +- Transformer/ConstantTransformer.php | 2 +- Transformer/ConvertValueTransformer.php | 2 +- Transformer/DateFormatTransformer.php | 2 +- Transformer/DateParserTransformer.php | 2 +- Transformer/DebugTransformer.php | 2 +- Transformer/DefaultTransformer.php | 2 +- Transformer/DenormalizeTransformer.php | 2 +- Transformer/EvaluatorTransformer.php | 2 +- Transformer/ExplodeTransformer.php | 2 +- .../ExpressionLanguageMapTransformer.php | 2 +- Transformer/GenericTransformer.php | 2 +- Transformer/HashTransformer.php | 2 +- Transformer/ImplodeTransformer.php | 2 +- Transformer/MappingTransformer.php | 2 +- Transformer/NormalizeTransformer.php | 2 +- Transformer/PregFilterTransformer.php | 2 +- Transformer/PropertyAccessorTransformer.php | 2 +- .../RecursivePropertySetterTransformer.php | 2 +- Transformer/RulesTransformer.php | 2 +- Transformer/SlugifyTransformer.php | 2 +- Transformer/SprintfTransformer.php | 2 +- Transformer/TransformerInterface.php | 2 +- Transformer/TransformerTrait.php | 2 +- Transformer/TrimTransformer.php | 2 +- Transformer/TypeSetterTransformer.php | 2 +- Transformer/UnsetTransformer.php | 2 +- Transformer/WrapperTransformer.php | 2 +- Transformer/Xml/XpathEvaluatorTransformer.php | 2 +- Validator/ConstraintLoader.php | 10 +++- 181 files changed, 294 insertions(+), 179 deletions(-) create mode 100644 Documentation/changelog/CHANGELOG-3.2.md diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index d6b35630..c933aff1 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index a019aeed..316c1053 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index 40169158..12dc9d83 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index 8f01692d..74504387 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index 1b044455..f196c353 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index b2b39ef3..8644174b 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Context/ContextualOptionResolver.php b/Context/ContextualOptionResolver.php index 8604795b..c0871ebb 100644 --- a/Context/ContextualOptionResolver.php +++ b/Context/ContextualOptionResolver.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 78f3d030..42cb0bb1 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index b7633f2d..6945f68e 100644 --- a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/DependencyInjection/Compiler/RegistryCompilerPass.php index 2894d471..99ec2a2d 100644 --- a/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c67f0552..ad7add20 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Documentation/01-quick_start.md b/Documentation/01-quick_start.md index 928a07cd..a4c9b14f 100644 --- a/Documentation/01-quick_start.md +++ b/Documentation/01-quick_start.md @@ -52,6 +52,25 @@ clever_age_process: default_error_strategy: stop ``` +When creating custom tasks and transformers, you can use Symfony automatic registration, but remember there is a few required configurations : +```yaml +services: + App\Transformer\: + resource: 'relative/path/to/Transformer/*' + autowire: true + autoconfigure: true + public: false + tags: + - { name: cleverage.transformer } # Needed by the process registry to find transformers + + App\Task\: + resource: 'relative/path/to/Task/*' + autowire: true + autoconfigure: true + shared: false # Important to avoid shared data between task usage + public: true # Needed by the Process Manager to find tasks +``` + ## Process definition Most of the work is done through the bundle configuration. diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/Documentation/changelog/CHANGELOG-3.1.md index 1f2dd70c..0128828d 100644 --- a/Documentation/changelog/CHANGELOG-3.1.md +++ b/Documentation/changelog/CHANGELOG-3.1.md @@ -6,12 +6,64 @@ v3.1-dev ### Features +_Nothing yet_ + ### Fixes -* FolderBrowserTask: Accept array type for `name_pattern` option +_Nothing yet_ ### BC breaks +_Nothing yet_ + +v3.1.5 +------ + +### Fixes + +* [GITHUB-120](https://github.com/cleverage/process-bundle/pull/120): FolderBrowserTask: Accept array type for `name_pattern` option + + +v3.1.4 +------ + +### Features + +* (_backport from v3.0.9_) Adding simple task to launch system commands + + +v3.1.3 +------ + +### Features + +* (_backport from v3.0.7_) Allowing ValidatorTask to output constraint violations with an option +* (_backport from v3.0.6_) Adding ArrayUnsetTransformer +* (_backport from v3.0.5_) Adding basic debug transformer + +### Fixes + +* (_backport from v3.0.8_) Fixing AbstractIterableOutputTask that was inconsistent when chained, refactoring InputIteratorTask that had the proper implementation with the AbstractIterableOutputTask as parent + +v3.1.2 +------ + +### Fixes + +* Fixed bad static access in tests + +v3.1.1 +------ + +### Features + +* (_backport from v3.0.4_) Adding simple file reader task and cast transformer +* (_backport from v3.0.3_) FilterTask now outputs skipped content to error output + +### Fixes + +* Removed useless, CPU intensive, log on CsvSplitterTask + v3.1.0 ------ diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md new file mode 100644 index 00000000..3b931674 --- /dev/null +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -0,0 +1,18 @@ +Release v3.2 +============ + +v3.2-dev +------ + +### Features + +* [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 +* [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners + +### Fixes + +_Nothing yet_ + +### BC breaks + +_Nothing yet_ diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index e9d10a73..6a14aaf5 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/EventDispatcherTaskEvent.php b/Event/EventDispatcherTaskEvent.php index 2f10650a..f504d149 100644 --- a/Event/EventDispatcherTaskEvent.php +++ b/Event/EventDispatcherTaskEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2019 Clever-Age + * Copyright (C) 2017-2021 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/GenericEvent.php b/Event/GenericEvent.php index 795a767c..d41b590f 100644 --- a/Event/GenericEvent.php +++ b/Event/GenericEvent.php @@ -1,5 +1,12 @@ - Date: Wed, 24 Feb 2021 11:00:08 +0100 Subject: [PATCH 130/304] Improved dev tools --- .env.dist | 8 +++++++ .gitignore | 1 + CONTRIBUTING.md | 4 ++++ Makefile | 63 ++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 .env.dist diff --git a/.env.dist b/.env.dist new file mode 100644 index 00000000..7998cb6f --- /dev/null +++ b/.env.dist @@ -0,0 +1,8 @@ +# This file contains default values for development environment variables + +# To customize this file, first copy it to `.env` +# Then you can configure variables + +# Set those variables using the values from https://blackfire.io/my/settings/credentials +BLACKFIRE_CLIENT_ID= +BLACKFIRE_CLIENT_TOKEN= diff --git a/.gitignore b/.gitignore index ff72e2d0..b3647c23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /composer.lock /vendor +.env diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f48e36a2..06b24c8f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,3 +12,7 @@ When a feature should be deprecated, or when you have a breaking change for a fu * [Fill an issue](https://github.com/cleverage/process-bundle/issues/new) * Add TODO comments with the following format: `@TODO deprecated v4.0` * Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v4.0', E_USER_DEPRECATED);` + +You can check which deprecation notice is triggered in tests +* `make shell` +* `SYMFONY_DEPRECATIONS_HELPER=0 ./vendor/bin/phpunit` diff --git a/Makefile b/Makefile index 1aff13fd..3e661d6e 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,60 @@ -shell: - docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 bash +# Include .env.dist for the default values +include .env.dist -test: - docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit +# Include .env only if it exists +ifneq ("",$(wildcard $(.env))) +include .env +endif -test/build: +# Default image to use for tests +SF_ENV=sf4 +LOCAL_DOCKER_TAG=cleverage_process:test +DOCKER_RUN=docker run -it --rm \ + -e BLACKFIRE_CLIENT_ID=$(BLACKFIRE_CLIENT_ID) \ + -e BLACKFIRE_CLIENT_TOKEN=$(BLACKFIRE_CLIENT_TOKEN) \ + --mount type=bind,src=$$(pwd),dst=/src-cleverage_process + +pull: pull/$(SF_ENV) + +pull/sf3: + docker pull cleverage/process-bundle:sf3 + +pull/sf4: + docker pull cleverage/process-bundle:sf4 + +pull/sf5: + docker pull cleverage/process-bundle:sf5 + +build/local: docker build -t cleverage_process:test . - docker run -it --mount type=bind,src=$$(pwd),dst=/src-cleverage_process cleverage_process:test php vendor/bin/phpunit + +build/%: + DOCKER_TAG=$(@F) DOCKERFILE_PATH=Dockerfile IMAGE_NAME=cleverage_process:$(@F) + +shell: shell/$(SF_ENV) + +shell/local: build/local + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) bash + +shell/%: pull/% + $(DOCKER_RUN) cleverage/process-bundle:$(@F) bash + +test: test/$(SF_ENV) + +test/local: build/local + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) php vendor/bin/phpunit + +test/%: pull/% + $(DOCKER_RUN) cleverage/process-bundle:$(@F) php vendor/bin/phpunit + +bench: bench/$(SF_ENV) + +bench/local: build/local + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) /bin/bash -c \ + "./bin/console --env=test c:c; \ + blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" + +bench/%: pull/% + $(DOCKER_RUN) cleverage/process-bundle:$(@F) /bin/bash -c \ + "./bin/console --env=test c:c; \ + blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" From 5a932d9144276404746a2cb52683ea056de1d3a5 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 11:36:18 +0100 Subject: [PATCH 131/304] Fixed a few deprecations for Sf5 --- .../CleverAgeProcessExtension.php | 2 +- DependencyInjection/Configuration.php | 61 ++++++++++++++----- Resources/config/services/command.yml | 1 + Resources/config/services/manager.yml | 1 + 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 42cb0bb1..c84ef9c5 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -55,7 +55,7 @@ public function load(array $configs, ContainerBuilder $container) foreach ($config['generic_transformers'] as $transformerCode => $transformerConfig) { $transformerDefinition = new Definition(GenericTransformer::class); $transformerDefinition->setAutowired(true); - $transformerDefinition->setPrivate(true); + $transformerDefinition->setPublic(false); $transformerDefinition->addMethodCall( 'initialize', [ diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ad7add20..bd2beb31 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -14,6 +14,7 @@ use Psr\Log\LogLevel; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\NodeBuilder; +use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -50,10 +51,12 @@ public function getConfigTreeBuilder() // Default error strategy $definition->enumNode('default_error_strategy') - ->values([ - TaskConfiguration::STRATEGY_SKIP, - TaskConfiguration::STRATEGY_STOP, - ]) + ->values( + [ + TaskConfiguration::STRATEGY_SKIP, + TaskConfiguration::STRATEGY_STOP, + ] + ) ->isRequired(); $this->appendRootProcessConfigDefinition($definition); @@ -175,22 +178,50 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) LogLevel::DEBUG, ]; - $definition - ->scalarNode('service')->isRequired()->end() - ->scalarNode('description')->defaultValue('')->end() - ->scalarNode('help')->defaultValue('')->end() - ->arrayNode('options')->prototype('variable')->end()->end() - ->scalarNode('error_strategy')->defaultNull()->end() - ->enumNode('log_level')->values($logLevels)->defaultValue(LogLevel::CRITICAL)->end() - ->booleanNode('log_errors')->defaultTrue()->setDeprecated()->end(); + $definition->scalarNode('service')->isRequired(); + $definition->scalarNode('description')->defaultValue(''); + $definition->scalarNode('help')->defaultValue(''); + $definition->arrayNode('options')->prototype('variable')->end(); + $definition->scalarNode('error_strategy')->defaultNull(); + $definition->enumNode('log_level')->values($logLevels)->defaultValue(LogLevel::CRITICAL); + + $logErrorNode = $definition->booleanNode('log_errors')->defaultTrue(); + $this->deprecateNode($logErrorNode, + 'cleverage/process-bundle', + '2.0', + 'The child node "%node%" at path "%path%" is deprecated in favor of "log_level".' + ); foreach (['outputs', 'errors', 'error_outputs'] as $nodeName) { $definition->arrayNode($nodeName) ->beforeNormalization() - ->ifString()->then(function ($item) { - return [$item]; - })->end() + ->ifString()->then( + function ($item) { + return [$item]; + } + )->end() ->prototype('scalar')->end()->end(); } } + + /** + * An helper method to deprecate a node. + * Provides compatibility with Sf3, 4 and 5 + * + * @TODO remove this once support for Symfony 3 and 4 is dropped + * + * @param NodeDefinition $node + * @param string $package + * @param string $version + * @param string $message + */ + protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message) + { + $deprecationMethodReflection = new \ReflectionMethod(NodeDefinition::class, 'setDeprecated'); + if($deprecationMethodReflection->getNumberOfParameters() === 1) { + $node->setDeprecated("Since {$package} {$version}: {$message}"); + } else { + $node->setDeprecated($package, $version, $message); + } + } } diff --git a/Resources/config/services/command.yml b/Resources/config/services/command.yml index 8813faf6..eecb9004 100644 --- a/Resources/config/services/command.yml +++ b/Resources/config/services/command.yml @@ -5,3 +5,4 @@ services: autoconfigure: true bind: $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' + $container: '@service_container' diff --git a/Resources/config/services/manager.yml b/Resources/config/services/manager.yml index 364b45c0..2aa51fdb 100644 --- a/Resources/config/services/manager.yml +++ b/Resources/config/services/manager.yml @@ -4,6 +4,7 @@ services: public: false arguments: $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' + $container: '@service_container' CleverAge\ProcessBundle\Context\ContextualOptionResolver: public: false From 272ede4c70f6d92f29c3ee3d5cc66ea6892b3bf6 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 11:39:02 +0100 Subject: [PATCH 132/304] Added a dummy "long" process to quickly test blackfire setup --- Resources/tests/process/long_process.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Resources/tests/process/long_process.yml diff --git a/Resources/tests/process/long_process.yml b/Resources/tests/process/long_process.yml new file mode 100644 index 00000000..37a06bbe --- /dev/null +++ b/Resources/tests/process/long_process.yml @@ -0,0 +1,13 @@ +clever_age_process: + configurations: + test.long_process: + entry_point: data + tasks: + data: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + options: + output: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + outputs: [doNothing] + + doNothing: + service: '@CleverAge\ProcessBundle\Task\DummyTask' From a47509ef3fafa210a44a8c0e0315c4377fb69857 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 15:20:52 +0100 Subject: [PATCH 133/304] Prepared release v3.2.0 --- Documentation/changelog/CHANGELOG-3.2.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 3b931674..73ec8bb1 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -6,8 +6,7 @@ v3.2-dev ### Features -* [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 -* [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners +_Nothing yet_ ### Fixes @@ -16,3 +15,12 @@ _Nothing yet_ ### BC breaks _Nothing yet_ + + +v3.2.0 +------ + +### Features + +* [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 +* [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners From f6074f9b5c1ae20c18e70e3deb2b0ee3139037e4 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 15:45:37 +0100 Subject: [PATCH 134/304] Setup Github actions for internal notifications --- .github/workflows/notifications.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/notifications.yml diff --git a/.github/workflows/notifications.yml b/.github/workflows/notifications.yml new file mode 100644 index 00000000..00aa3926 --- /dev/null +++ b/.github/workflows/notifications.yml @@ -0,0 +1,23 @@ +name: Rocket chat notifications + +# Controls when the action will run. +on: + push: + tags: + - '*' + +jobs: + notification: + runs-on: ubuntu-latest + + steps: + - name: Get the tag short reference + id: get_tag + run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//} + + - name: Rocket.Chat Notification + uses: RocketChat/Rocket.Chat.GitHub.Action.Notification@1.1.1 + with: + type: success + job_name: "[cleverage/process-bundle](https://github.com/cleverage/process-bundle) : ${{ steps.get_tag.outputs.TAG }} has been released" + url: ${{ secrets.CLEVER_AGE_ROCKET_CHAT_WEBOOK_URL }} From 163c472a69d0823fad73c564779125a06d239195 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 24 Feb 2021 16:43:39 +0100 Subject: [PATCH 135/304] Fixed config error in Symfony 3.4 --- .gitignore | 3 ++ DependencyInjection/Configuration.php | 49 ++++++++++++------- Documentation/changelog/CHANGELOG-3.2.md | 6 +++ Makefile | 24 ++++++--- Resources/tests/environment/sf3/composer.json | 2 + Resources/tests/environment/sf4/composer.json | 18 ++++--- Resources/tests/environment/sf5/composer.json | 18 ++++--- composer.json | 2 + 8 files changed, 82 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index b3647c23..5a331df4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /composer.lock /vendor +/vendor-sf3 +/vendor-sf4 +/vendor-sf5 .env diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index bd2beb31..e5be1694 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -46,9 +46,8 @@ public function __construct($root = 'clever_age_process') */ public function getConfigTreeBuilder() { - $treeBuilder = new TreeBuilder($this->root); - $definition = $treeBuilder->getRootNode()->children(); - + [$treeBuilder, $rootNode] = $this->createTreeBuilder($this->root); + $definition = $rootNode->children(); // Default error strategy $definition->enumNode('default_error_strategy') ->values( @@ -62,8 +61,6 @@ public function getConfigTreeBuilder() $this->appendRootProcessConfigDefinition($definition); $this->appendRootTransformersConfigDefinition($definition); - $definition->end(); - return $treeBuilder; } @@ -87,9 +84,6 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio ->children(); $this->appendTransformerConfigDefinition($transformerListDefinition); - - $transformerListDefinition->end(); - $transformersArrayDefinition->end(); } /** @@ -125,9 +119,6 @@ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) ->children(); $this->appendProcessConfigDefinition($processListDefinition); - - $processListDefinition->end(); - $configurationsArrayDefinition->end(); } /** @@ -157,9 +148,6 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition) ->children(); $this->appendTaskConfigDefinition($taskListDefinition); - - $taskListDefinition->end(); - $tasksArrayDefinition->end(); } /** @@ -186,7 +174,8 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) $definition->enumNode('log_level')->values($logLevels)->defaultValue(LogLevel::CRITICAL); $logErrorNode = $definition->booleanNode('log_errors')->defaultTrue(); - $this->deprecateNode($logErrorNode, + $this->deprecateNode( + $logErrorNode, 'cleverage/process-bundle', '2.0', 'The child node "%node%" at path "%path%" is deprecated in favor of "log_level".' @@ -200,7 +189,7 @@ function ($item) { return [$item]; } )->end() - ->prototype('scalar')->end()->end(); + ->prototype('scalar'); } } @@ -218,10 +207,36 @@ function ($item) { protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message) { $deprecationMethodReflection = new \ReflectionMethod(NodeDefinition::class, 'setDeprecated'); - if($deprecationMethodReflection->getNumberOfParameters() === 1) { + if ($deprecationMethodReflection->getNumberOfParameters() === 1) { $node->setDeprecated("Since {$package} {$version}: {$message}"); } else { $node->setDeprecated($package, $version, $message); } } + + /** + * An helper method to create a TreeBuilder and get the root node. + * Provides compatibility with Sf3, 4 and 5 + * + * @TODO remove this once support for Symfony 3 and 4 is dropped + * + * @param string $root + * + * @return array A tuple containing [TreeBuilder, NodeDefinition] + */ + protected function createTreeBuilder(string $root): array + { + $treeBuilderReflection = new \ReflectionClass(TreeBuilder::class); + $treeBuilderConstructReflection = $treeBuilderReflection->getConstructor(); + + if ($treeBuilderConstructReflection && $treeBuilderConstructReflection->getNumberOfParameters() > 0) { + $treeBuilder = new TreeBuilder($this->root); + $rootNode = $treeBuilder->getRootNode(); + } else { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root($this->root); + } + + return [$treeBuilder, $rootNode]; + } } diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 73ec8bb1..14458d0d 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -16,6 +16,12 @@ _Nothing yet_ _Nothing yet_ +v3.2.1 +------ + +### Fixes + +* Fatal error while loading configuration in Symfony 3.4 v3.2.0 ------ diff --git a/Makefile b/Makefile index 3e661d6e..4204d451 100644 --- a/Makefile +++ b/Makefile @@ -29,32 +29,42 @@ build/local: docker build -t cleverage_process:test . build/%: - DOCKER_TAG=$(@F) DOCKERFILE_PATH=Dockerfile IMAGE_NAME=cleverage_process:$(@F) + DOCKER_TAG=$(@F) DOCKERFILE_PATH=Dockerfile IMAGE_NAME=cleverage/process-bundle:$(@F) ./hooks/build shell: shell/$(SF_ENV) -shell/local: build/local +shell/local: $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) bash -shell/%: pull/% +shell/%: $(DOCKER_RUN) cleverage/process-bundle:$(@F) bash test: test/$(SF_ENV) -test/local: build/local +test/local: + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) ./bin/console c:c $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) php vendor/bin/phpunit -test/%: pull/% +test/%: + $(DOCKER_RUN) cleverage/process-bundle:$(@F) ./bin/console c:c $(DOCKER_RUN) cleverage/process-bundle:$(@F) php vendor/bin/phpunit bench: bench/$(SF_ENV) -bench/local: build/local +bench/local: $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) /bin/bash -c \ "./bin/console --env=test c:c; \ blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" -bench/%: pull/% +bench/%: $(DOCKER_RUN) cleverage/process-bundle:$(@F) /bin/bash -c \ "./bin/console --env=test c:c; \ blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" + +vendor: vendor/$(SF_ENV) + +vendor/%: + rm -rf vendor-$(@F) || true + docker container create --name cleverage_process_bundle_tmp cleverage/process-bundle:$(@F) + docker cp cleverage_process_bundle_tmp:/app/vendor vendor-$(@F) + docker container rm cleverage_process_bundle_tmp diff --git a/Resources/tests/environment/sf3/composer.json b/Resources/tests/environment/sf3/composer.json index d9d851fe..33d973b7 100644 --- a/Resources/tests/environment/sf3/composer.json +++ b/Resources/tests/environment/sf3/composer.json @@ -9,6 +9,8 @@ "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", + "symfony/config": "~3.0", + "symfony/dependency-injection": "~3.0", "symfony/expression-language": "~3.0", "symfony/monolog-bundle": "~3.3", "symfony/console": "~3.0", diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index 0c08c553..c706badb 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -8,15 +8,17 @@ "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", - "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/config": "~4.0", + "symfony/dependency-injection": "~4.0", + "symfony/expression-language": "~4.0", "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0|~5.0", - "symfony/options-resolver": "~3.0|~4.0|~5.0", - "symfony/process": "~3.0|~4.0|~5.0", - "symfony/property-access": "~3.0|~4.0|~5.0", - "symfony/serializer": "~3.0|~4.0|~5.0", - "symfony/validator": "~3.0|~4.0|~5.0", - "symfony/yaml": "~3.0|~4.0|~5.0" + "symfony/console": "~4.0", + "symfony/options-resolver": "~4.0", + "symfony/process": "~4.0", + "symfony/property-access": "~4.0", + "symfony/serializer": "~4.0", + "symfony/validator": "~4.0", + "symfony/yaml": "~4.0" }, "require-dev": { "symfony/phpunit-bridge": "^4.4|^5.0", diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json index fd332f0d..24f1f6b4 100644 --- a/Resources/tests/environment/sf5/composer.json +++ b/Resources/tests/environment/sf5/composer.json @@ -8,15 +8,17 @@ "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", - "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/config": "~5.0", + "symfony/dependency-injection": "~5.0", + "symfony/expression-language": "~5.0", "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0|~5.0", - "symfony/options-resolver": "~3.0|~4.0|~5.0", - "symfony/process": "~3.0|~4.0|~5.0", - "symfony/property-access": "~3.0|~4.0|~5.0", - "symfony/serializer": "~3.0|~4.0|~5.0", - "symfony/validator": "~3.0|~4.0|~5.0", - "symfony/yaml": "~3.0|~4.0|~5.0" + "symfony/console": "~5.0", + "symfony/options-resolver": "~5.0", + "symfony/process": "~5.0", + "symfony/property-access": "~5.0", + "symfony/serializer": "~5.0", + "symfony/validator": "~5.0", + "symfony/yaml": "~5.0" }, "require-dev": { "symfony/phpunit-bridge": "^4.4|^5.0", diff --git a/composer.json b/composer.json index 8d3d8ea5..cb3f7048 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,8 @@ "ext-dom": "*", "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", + "symfony/config": "~3.0|~4.0|~5.0", + "symfony/dependency-injection": "~3.0|~4.0|~5.0", "symfony/framework-bundle": "~3.0|~4.0|~5.0", "symfony/expression-language": "~3.0|~4.0|~5.0", "symfony/monolog-bundle": "~3.3", From a4eb6c077d42bd3c9db1b0975e410cb61d79e604 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 3 Mar 2021 11:04:22 +0100 Subject: [PATCH 136/304] Ignore empty lines while counting CSV file lines --- Documentation/changelog/CHANGELOG-3.2.md | 2 +- Filesystem/CsvResource.php | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 14458d0d..c1ef371f 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -10,7 +10,7 @@ _Nothing yet_ ### Fixes -_Nothing yet_ +* Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. ### BC breaks diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index aea01487..09f937d4 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -113,11 +113,15 @@ public function getHandler() } /** - * Warning! This method will rewind the file to the beginning before and after counting the lines! + * Count the number of CSV lines (with correct enclosure detection), ignoring blank lines. * - * @throws \RuntimeException + * Warning! This method will rewind the file to the beginning before and after counting the lines! + * Do not use in the middle of a process. + * This can be very slow. * * @return int + *@throws \RuntimeException + * */ public function getLineCount(): int { @@ -125,8 +129,9 @@ public function getLineCount(): int $this->rewind(); $line = 0; while (!$this->isEndOfFile()) { - ++$line; - $this->readRaw(); + if ($this->readRaw()) { + ++$line; + } } $this->rewind(); From 9a9896e04a943605bc7de536e4566844b9aa2223 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Fri, 5 Mar 2021 10:14:36 +0100 Subject: [PATCH 137/304] Fixed AbstractIterableOutputTask : some iterations are skipped when iterating inside a bigger loop --- Documentation/changelog/CHANGELOG-3.2.md | 1 + Task/AbstractIterableOutputTask.php | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index c1ef371f..b35cf713 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -11,6 +11,7 @@ _Nothing yet_ ### Fixes * Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. +* Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop ### BC breaks diff --git a/Task/AbstractIterableOutputTask.php b/Task/AbstractIterableOutputTask.php index ba9f5245..bf177af3 100644 --- a/Task/AbstractIterableOutputTask.php +++ b/Task/AbstractIterableOutputTask.php @@ -1,4 +1,5 @@ -removeErrorContext('iterator_key'); - return $this->iterator->valid(); + if (!$this->iterator->valid()) { + // Reset the iterator to allow the following iteration + $this->iterator = null; + + return false; + } + + return true; } + /** * Create or recreate an iterator from input * From 802345bba30836f09334af98652da87413261f3c Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 8 Mar 2021 11:43:22 +0100 Subject: [PATCH 138/304] Added a note about the removal of sidus/base-bundle --- Documentation/changelog/CHANGELOG-3.2.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index b35cf713..b0f9dc9a 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -31,3 +31,8 @@ v3.2.0 * [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 * [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners + +### BC breaks + +There is no BC break for this version, but note that `sidus/base-bundle` has been removed from dependencies. +If you use it, it should already be inside your own composer.json. From c89939673e36f716c51024cac99d9231d1b0e82c Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 22 Mar 2021 11:44:58 +0100 Subject: [PATCH 139/304] Updated some error message to be more explicit --- Documentation/changelog/CHANGELOG-3.2.md | 1 + .../InvalidProcessConfigurationException.php | 32 +++++++++++++------ Manager/ProcessManager.php | 4 +-- Registry/ProcessConfigurationRegistry.php | 2 +- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index b0f9dc9a..d31b7390 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -12,6 +12,7 @@ _Nothing yet_ * Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. * Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop +* `\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException` now displays the failing process code ### BC breaks diff --git a/Exception/InvalidProcessConfigurationException.php b/Exception/InvalidProcessConfigurationException.php index 2b61918b..0989557c 100644 --- a/Exception/InvalidProcessConfigurationException.php +++ b/Exception/InvalidProcessConfigurationException.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Exception; +use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; /** @@ -18,25 +19,36 @@ class InvalidProcessConfigurationException extends \UnexpectedValueException implements ProcessExceptionInterface { /** - * @param TaskConfiguration $taskConfig - * @param array $mainTaskList + * @param ProcessConfiguration $processConfiguration + * @param TaskConfiguration $taskConfig + * @param array $mainTaskList * * @return InvalidProcessConfigurationException */ - public static function createNotInMain(TaskConfiguration $taskConfig, array $mainTaskList): self - { - $taskListStr = '[' . implode(', ', $mainTaskList) . ']'; + public static function createNotInMain( + ProcessConfiguration $processConfiguration, + TaskConfiguration $taskConfig, + array $mainTaskList + ): self { + $taskListStr = '['.implode(', ', $mainTaskList).']'; - return new self("Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr}"); + return new self( + "Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr} (from process: {$processConfiguration->getCode()})" + ); } /** - * @param TaskConfiguration $taskConfig + * @param ProcessConfiguration $processConfiguration + * @param TaskConfiguration $taskConfig * * @return InvalidProcessConfigurationException */ - public static function createEntryPointHasAncestors(TaskConfiguration $taskConfig): self - { - return new self("The entry-point '{$taskConfig->getCode()}' cannot have an ancestor"); + public static function createEntryPointHasAncestors( + ProcessConfiguration $processConfiguration, + TaskConfiguration $taskConfig + ): self { + return new self( + "The entry-point '{$taskConfig->getCode()}' cannot have an ancestor (from process: {$processConfiguration->getCode()})" + ); } } diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index c9014998..34db26bf 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -657,10 +657,10 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check coherence for entry/end points $processConfiguration->getEndPoint(); if ($entryPoint && !\in_array($entryPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain($entryPoint, $mainTaskList); + throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $entryPoint, $mainTaskList); } if ($endPoint && !\in_array($endPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain($endPoint, $mainTaskList); + throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $endPoint, $mainTaskList); } } diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 0d964c6d..0c815e04 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -161,7 +161,7 @@ protected function resolveConfiguration(string $processCode): void // #106 - entry point should not have an ancestor if ($processConfig->getEntryPoint() && $processConfig->getEntryPoint()->getPreviousTasksConfigurations()) { - throw InvalidProcessConfigurationException::createEntryPointHasAncestors($processConfig->getEntryPoint()); + throw InvalidProcessConfigurationException::createEntryPointHasAncestors($processConfig, $processConfig->getEntryPoint()); } $this->processConfigurations[$processCode] = $processConfig; From 2ea72738da2434e3ea1d1a9d9cc673dcd8e51328 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 31 Mar 2021 11:45:17 +0200 Subject: [PATCH 140/304] Better message when option type is wrong for sub-transformers --- Documentation/changelog/CHANGELOG-3.2.md | 1 + Transformer/TransformerTrait.php | 47 +++++++++++++++++------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index d31b7390..d8e9387c 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -13,6 +13,7 @@ _Nothing yet_ * Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. * Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop * `\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException` now displays the failing process code +* `\CleverAge\ProcessBundle\Transformer\TransformerTrait` now displays a more explicit message on wrong options type ### BC breaks diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index dae2e159..30133616 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -1,4 +1,6 @@ -getCleanedTransfomerCode($origTransformerCode); $transformer = $this->transformerRegistry->getTransformer($transformerCode); + $transformerOptions = $this->checkTransformerOptions($transformerOptions, $origTransformerCode); if ($transformer instanceof ConfigurableTransformerInterface) { $transformer->configureOptions($transformerOptionsResolver); - $transformerOptions = $transformerOptionsResolver->resolve( - $transformerOptions ?? [] - ); - } else { - if (!empty($transformerOptions)) { - throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); - } - // An array is required in transform method - $transformerOptions = []; + $transformerOptions = $transformerOptionsResolver->resolve($transformerOptions); + } elseif (!empty($transformerOptions)) { + throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); } $closure = static function ($value) use ($transformer, $transformerOptions) { @@ -133,4 +130,28 @@ public function normalizeTransformers(Options $options, $transformers) return $transformerClosures; } + + /** + * Check the options to always return an array, or fail on unexpected values + * + * @param mixed $transformerOptions + * @param string $transformerCode + * + * @return array + */ + private function checkTransformerOptions($transformerOptions, string $transformerCode): array + { + if (is_array($transformerOptions)) { + return $transformerOptions; + } + if ($transformerOptions === null) { + return []; + } + + $type = is_object($transformerOptions) ? get_class($transformerOptions) : gettype($transformerOptions); + + throw new \InvalidArgumentException( + "Options for transformer {$transformerCode} are invalid : found {$type}, expected array or null" + ); + } } From ab2a398eea9952a4ed281bd1071931e24cf01422 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 13 Apr 2021 11:03:50 +0200 Subject: [PATCH 141/304] Adjusted release notes for v3.2.2 --- Documentation/changelog/CHANGELOG-3.2.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index d8e9387c..7e45b2c1 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -10,14 +10,22 @@ _Nothing yet_ ### Fixes +_Nothing yet_ + +### BC breaks + +_Nothing yet_ + +v3.2.2 +------ + +### Fixes + * Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. * Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop * `\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException` now displays the failing process code * `\CleverAge\ProcessBundle\Transformer\TransformerTrait` now displays a more explicit message on wrong options type -### BC breaks - -_Nothing yet_ v3.2.1 ------ From ff0e32c9cee7e9fe3c8325cce4639f35f663f610 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Tue, 20 Apr 2021 10:57:17 +0200 Subject: [PATCH 142/304] Fixed return value of list and help commands --- Command/ListProcessCommand.php | 2 ++ Command/ProcessHelpCommand.php | 2 ++ Documentation/changelog/CHANGELOG-3.2.md | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index 12dc9d83..60d9fc82 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -103,6 +103,8 @@ protected function execute(InputInterface $input, OutputInterface $output) foreach ($outputMessages as $message) { $output->writeln($message); } + + return 0; } /** diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index 74504387..d9d942bd 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -148,6 +148,8 @@ static function ($task) use ($nextTaskCode) { $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } + + return 0; } /** diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 7e45b2c1..faa9ff77 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -10,7 +10,7 @@ _Nothing yet_ ### Fixes -_Nothing yet_ +* Fixed return value of list and help commands (mandatory for Symfony 5) ### BC breaks From 09e2c9afdfd298cff67057cd4d1aa299269460b1 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Wed, 21 Apr 2021 16:54:37 +0200 Subject: [PATCH 143/304] Added the possibility to cache transformer data & a "multi-replace" transformer --- Documentation/changelog/CHANGELOG-3.2.md | 6 +- Transformer/CachedTransformer.php | 98 ++++++++++++++++++++++++ Transformer/MultiReplaceTransformer.php | 44 +++++++++++ composer.json | 2 + 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 Transformer/CachedTransformer.php create mode 100644 Transformer/MultiReplaceTransformer.php diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index faa9ff77..7b795a97 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -6,7 +6,8 @@ v3.2-dev ### Features -_Nothing yet_ +* Added `multi_replace` transformer +* Added `cached` transformer ### Fixes @@ -14,7 +15,8 @@ _Nothing yet_ ### BC breaks -_Nothing yet_ +* Added `psr/cache` as a dependency, but it shouldn't break anything +* Added `ext-intl` as a dependency, since required by the `slugify` transformer v3.2.2 ------ diff --git a/Transformer/CachedTransformer.php b/Transformer/CachedTransformer.php new file mode 100644 index 00000000..8ce2cb05 --- /dev/null +++ b/Transformer/CachedTransformer.php @@ -0,0 +1,98 @@ +transformerRegistry = $transformerRegistry; + $this->cache = $cache; + $this->logger = $logger; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('cache_key'); + $resolver->setAllowedTypes('cache_key', 'string'); + $this->configureTransformersOptions($resolver); + $this->configureTransformersOptions($resolver, 'key_transformers'); + } + + public function transform($value, array $options = []) + { + $cacheKey = $this->generateCacheKey($options['cache_key'], $value, $options); + if ($cacheKey && $this->cache instanceof CacheItemPoolInterface) { + try { + $cacheItem = $this->cache->getItem($cacheKey); + if ($cacheItem->isHit()) { + + return $cacheItem->get(); + } else { + $newValue = $this->applyTransformers($options['transformers'], $value); + $cacheItem->set($newValue); + $success = $this->cache->saveDeferred($cacheItem); + + if (!$success) { + $this->logger->warning('Cannot save cache item', ['cache_key' => $cacheKey]); + } + + return $newValue; + } + } catch (InvalidArgumentException $exception) { + $this->logger->warning('Cannot get cache item', ['cache_key' => $cacheKey, 'message' => $exception->getMessage()]); + } + } + + return $this->applyTransformers($options['transformers'], $value); + } + + public function getCode() + { + return 'cached'; + } + + protected function generateCacheKey($cacheKeyRoot, $value, $options) + { + $value = $this->applyTransformers($options['key_transformers'], $value); + + if (!\is_string($value)) { + return false; + } + + return \implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, \rawurlencode($value)]); + } + +} diff --git a/Transformer/MultiReplaceTransformer.php b/Transformer/MultiReplaceTransformer.php new file mode 100644 index 00000000..b8e73157 --- /dev/null +++ b/Transformer/MultiReplaceTransformer.php @@ -0,0 +1,44 @@ + _replacement_ to apply on input strings + */ +class MultiReplaceTransformer implements ConfigurableTransformerInterface +{ + public function transform($value, array $options = []) + { + foreach($options['replace_mapping'] as $pattern => $replacement) { + $value = str_replace($pattern, $replacement, $value); + } + + return $value; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('replace_mapping'); + $resolver->setAllowedTypes('replace_mapping', 'array'); + } + + public function getCode() + { + return 'multi_replace'; + } + +} diff --git a/composer.json b/composer.json index cb3f7048..ff66c075 100644 --- a/composer.json +++ b/composer.json @@ -40,8 +40,10 @@ "php": ">=7.2", "ext-json": "*", "ext-dom": "*", + "ext-intl": "*", "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", + "psr/cache": "^1.0.0", "symfony/config": "~3.0|~4.0|~5.0", "symfony/dependency-injection": "~3.0|~4.0|~5.0", "symfony/framework-bundle": "~3.0|~4.0|~5.0", From 478f9d8a17910b530cc3fc60891263638b4bf567 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Mon, 26 Apr 2021 11:20:11 +0200 Subject: [PATCH 144/304] Prepared release notes for v3.2.3 --- Documentation/changelog/CHANGELOG-3.2.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 7b795a97..63875a9b 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -6,6 +6,21 @@ v3.2-dev ### Features +_Nothing yet_ + +### Fixes + +_Nothing yet_ + +### BC breaks + +_Nothing yet_ + +v3.2.3 +------ + +### Features + * Added `multi_replace` transformer * Added `cached` transformer From 896bab11c407a826e88e79a93e6910a4d41ae142 Mon Sep 17 00:00:00 2001 From: Valentin Clavreul Date: Thu, 23 Sep 2021 11:43:57 +0200 Subject: [PATCH 145/304] Added a TTL option for the cached transformer --- Documentation/changelog/CHANGELOG-3.2.md | 7 +++++ Transformer/CachedTransformer.php | 35 +++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/Documentation/changelog/CHANGELOG-3.2.md index 63875a9b..70e07389 100644 --- a/Documentation/changelog/CHANGELOG-3.2.md +++ b/Documentation/changelog/CHANGELOG-3.2.md @@ -16,6 +16,13 @@ _Nothing yet_ _Nothing yet_ +v3.2.4 +------ + +### Features + +* Added a `ttl` option in the `cached` transformer + v3.2.3 ------ diff --git a/Transformer/CachedTransformer.php b/Transformer/CachedTransformer.php index 8ce2cb05..eeecbd34 100644 --- a/Transformer/CachedTransformer.php +++ b/Transformer/CachedTransformer.php @@ -14,6 +14,7 @@ use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; use Psr\Log\LoggerInterface; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class CachedTransformer implements ConfigurableTransformerInterface @@ -36,8 +37,11 @@ class CachedTransformer implements ConfigurableTransformerInterface * @param CacheItemPoolInterface $cache * @param LoggerInterface $logger */ - public function __construct(TransformerRegistry $transformerRegistry, CacheItemPoolInterface $cache, LoggerInterface $logger) - { + public function __construct( + TransformerRegistry $transformerRegistry, + CacheItemPoolInterface $cache, + LoggerInterface $logger + ) { $this->transformerRegistry = $transformerRegistry; $this->cache = $cache; $this->logger = $logger; @@ -47,6 +51,24 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('cache_key'); $resolver->setAllowedTypes('cache_key', 'string'); + + $resolver->setDefault('ttl', null); + $resolver->setAllowedTypes('ttl', ['null', 'string', \DateTimeInterface::class]); + $resolver->setNormalizer( + 'ttl', + function (Options $options, $value) { + /** + * Best use is a relative date string like "+1 hour" + * @see https://www.php.net/manual/en/datetime.formats.relative.php + */ + if (is_string($value)) { + $value = new \DateTime($value); + } + + return $value; + } + ); + $this->configureTransformersOptions($resolver); $this->configureTransformersOptions($resolver, 'key_transformers'); } @@ -58,11 +80,13 @@ public function transform($value, array $options = []) try { $cacheItem = $this->cache->getItem($cacheKey); if ($cacheItem->isHit()) { - return $cacheItem->get(); } else { $newValue = $this->applyTransformers($options['transformers'], $value); $cacheItem->set($newValue); + if ($options['ttl']) { + $cacheItem->expiresAt($options['ttl']); + } $success = $this->cache->saveDeferred($cacheItem); if (!$success) { @@ -72,7 +96,10 @@ public function transform($value, array $options = []) return $newValue; } } catch (InvalidArgumentException $exception) { - $this->logger->warning('Cannot get cache item', ['cache_key' => $cacheKey, 'message' => $exception->getMessage()]); + $this->logger->warning( + 'Cannot get cache item', + ['cache_key' => $cacheKey, 'message' => $exception->getMessage()] + ); } } From 0a420887eeeb18f660d034fa67189e3ef7fef779 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 23 Mar 2022 09:44:33 +0100 Subject: [PATCH 146/304] Upgrade psr/cache --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ff66c075..eb84c24c 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-intl": "*", "symfony/event-dispatcher-contracts": "~1.0|~2.0", "psr/event-dispatcher": "1.0.0", - "psr/cache": "^1.0.0", + "psr/cache": "^1|^2|^3", "symfony/config": "~3.0|~4.0|~5.0", "symfony/dependency-injection": "~3.0|~4.0|~5.0", "symfony/framework-bundle": "~3.0|~4.0|~5.0", From d9b325d9782e1f09657d29541b083c6606706f1c Mon Sep 17 00:00:00 2001 From: Vincent Chalnot Date: Thu, 12 Jan 2023 16:45:02 +0100 Subject: [PATCH 147/304] Allowing date formatting for all DateTimeInterface Previously, DateTimeImmutable were not allowed for example --- Transformer/DateFormatTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 5b0739b2..7f6a097a 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -41,7 +41,7 @@ public function transform($value, array $options = []) return $value; } - if ($value instanceof \DateTime) { + if ($value instanceof \DateTimeInterface) { $date = $value; } elseif (is_string($value)) { @trigger_error('String input will be deprecated in v4.0', E_USER_DEPRECATED); From 7ead8d03b05cfa7e1c41b3442ac94fb96bb82046 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 26 Jan 2023 11:27:29 +0100 Subject: [PATCH 148/304] Fix Symfony 5/6 --- Model/SubprocessInstance.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Model/SubprocessInstance.php b/Model/SubprocessInstance.php index 839147de..e5b41553 100644 --- a/Model/SubprocessInstance.php +++ b/Model/SubprocessInstance.php @@ -121,8 +121,14 @@ public function buildProcess() $arguments[] = $this->processCode; $this->process = new Process($arguments, null, null, $this->input); - $this->process->setCommandLine($this->process->getCommandLine()); - $this->process->inheritEnvironmentVariables(); + + if (method_exists(Process::class, 'fromShellCommandline')) { + $this->process = Process::fromShellCommandline($this->process->getCommandLine(), null, null, $this->input); + } else { + $this->process->setCommandLine($this->process->getCommandLine()); + $this->process->inheritEnvironmentVariables(); + } + $this->process->enableOutput(); return $this; From c1b3276d03e93cf991ae77382e3e6e0cc8fd9d3f Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 16 Feb 2023 13:05:45 +0100 Subject: [PATCH 149/304] Add annotation to avoid message --- Validator/ConstraintLoader.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Validator/ConstraintLoader.php b/Validator/ConstraintLoader.php index a7c623cd..2f1a050f 100644 --- a/Validator/ConstraintLoader.php +++ b/Validator/ConstraintLoader.php @@ -15,6 +15,9 @@ class ConstraintLoader extends AbstractLoader { + /** + * @return bool + */ public function loadClassMetadata(ClassMetadata $metadata) { return false; From 340ac99fd426a37038986522092c1c880ed7d1cb Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 09:30:30 +0100 Subject: [PATCH 150/304] Update copyright --- CleverAgeProcessBundle.php | 2 +- Command/ExecuteProcessCommand.php | 2 +- Command/ListProcessCommand.php | 2 +- Command/ProcessHelpCommand.php | 2 +- Configuration/ProcessConfiguration.php | 2 +- Configuration/TaskConfiguration.php | 2 +- Context/ContextualOptionResolver.php | 2 +- DependencyInjection/CleverAgeProcessExtension.php | 2 +- DependencyInjection/Compiler/CheckSerializerCompilerPass.php | 2 +- DependencyInjection/Compiler/RegistryCompilerPass.php | 2 +- DependencyInjection/Configuration.php | 2 +- Event/ConsoleProcessEvent.php | 2 +- Event/EventDispatcherTaskEvent.php | 2 +- Event/GenericEvent.php | 2 +- Event/ProcessEvent.php | 2 +- EventDispatcher/BackcompatEventDispatcher.php | 2 +- EventListener/DataQueueEventListener.php | 2 +- Exception/CircularProcessException.php | 2 +- Exception/InvalidProcessConfigurationException.php | 2 +- Exception/MissingProcessException.php | 2 +- Exception/MissingTaskConfigurationException.php | 2 +- Exception/MissingTransformerException.php | 2 +- Exception/MultiBranchProcessException.php | 2 +- Exception/ProcessExceptionInterface.php | 2 +- Exception/TransformerException.php | 2 +- ExpressionLanguage/PhpFunctionProvider.php | 2 +- Filesystem/CsvFile.php | 2 +- Filesystem/CsvResource.php | 2 +- Filesystem/FileStreamInterface.php | 2 +- Filesystem/JsonStreamFile.php | 2 +- Filesystem/SeekableFileInterface.php | 2 +- Filesystem/StructuredFileInterface.php | 2 +- Filesystem/WritableFileInterface.php | 2 +- Filesystem/WritableStructuredFileInterface.php | 2 +- Filesystem/XmlFile.php | 2 +- LICENSE | 2 +- Logger/AbstractLogger.php | 2 +- Logger/AbstractProcessor.php | 2 +- Logger/ProcessLogger.php | 2 +- Logger/ProcessProcessor.php | 2 +- Logger/TaskLogger.php | 2 +- Logger/TaskProcessor.php | 2 +- Logger/TransformerProcessor.php | 2 +- Manager/ProcessManager.php | 2 +- Model/AbstractConfigurableTask.php | 2 +- Model/BlockingTaskInterface.php | 2 +- Model/FinalizableTaskInterface.php | 2 +- Model/FlushableTaskInterface.php | 2 +- Model/InitializableTaskInterface.php | 2 +- Model/IterableTaskInterface.php | 2 +- Model/ProcessHistory.php | 2 +- Model/ProcessState.php | 2 +- Model/SubprocessInstance.php | 2 +- Model/TaskInterface.php | 2 +- Registry/ProcessConfigurationRegistry.php | 2 +- Registry/TransformerRegistry.php | 2 +- Task/AbstractIterableOutputTask.php | 2 +- Task/AggregateIterableTask.php | 2 +- Task/ArrayMergeTask.php | 2 +- Task/ColumnAggregatorTask.php | 2 +- Task/ConstantIterableOutputTask.php | 2 +- Task/ConstantOutputTask.php | 2 +- Task/CounterTask.php | 2 +- Task/Debug/DebugTask.php | 2 +- Task/Debug/DieTask.php | 2 +- Task/Debug/ErrorForwarderTask.php | 2 +- Task/Debug/MemInfoDumpTask.php | 2 +- Task/DummyTask.php | 2 +- Task/Event/EventDispatcherTask.php | 2 +- Task/File/Csv/AbstractCsvResourceTask.php | 2 +- Task/File/Csv/AbstractCsvTask.php | 2 +- Task/File/Csv/CsvReaderTask.php | 2 +- Task/File/Csv/CsvSplitterTask.php | 2 +- Task/File/Csv/CsvWriterTask.php | 2 +- Task/File/Csv/InputCsvReaderTask.php | 2 +- Task/File/FileFetchTask.php | 2 +- Task/File/FileMoverTask.php | 2 +- Task/File/FileReaderTask.php | 2 +- Task/File/FileRemoverTask.php | 2 +- Task/File/FileWriterTask.php | 2 +- Task/File/FolderBrowserTask.php | 2 +- Task/File/InputFolderBrowserTask.php | 2 +- Task/File/JsonStream/JsonStreamReaderTask.php | 2 +- Task/File/Xml/XmlReaderTask.php | 2 +- Task/File/Xml/XmlWriterTask.php | 2 +- Task/File/YamlReaderTask.php | 2 +- Task/File/YamlWriterTask.php | 2 +- Task/FilterTask.php | 2 +- Task/InputAggregatorTask.php | 2 +- Task/InputIteratorTask.php | 2 +- Task/IterableBatchTask.php | 2 +- Task/ObjectUpdaterTask.php | 2 +- Task/Process/CommandRunnerTask.php | 2 +- Task/Process/ProcessExecutorTask.php | 2 +- Task/Process/ProcessLauncherTask.php | 2 +- Task/PropertyGetterTask.php | 2 +- Task/PropertySetterTask.php | 2 +- Task/Reporting/AdvancedStatCounterTask.php | 2 +- Task/Reporting/LoggerTask.php | 2 +- Task/Reporting/StatCounterTask.php | 2 +- Task/RowAggregatorTask.php | 2 +- Task/Serialization/DenormalizerTask.php | 2 +- Task/Serialization/DeserializerTask.php | 2 +- Task/Serialization/NormalizerTask.php | 2 +- Task/Serialization/SerializerTask.php | 2 +- Task/SimpleBatchTask.php | 2 +- Task/SkipEmptyTask.php | 2 +- Task/SplitJoinLineTask.php | 2 +- Task/StopTask.php | 2 +- Task/TransformerTask.php | 2 +- Task/Validation/ValidatorTask.php | 2 +- Tests/AbstractProcessTest.php | 2 +- Tests/BasicTest.php | 2 +- Tests/BlockingTaskTest.php | 2 +- Tests/CircularProcessTest.php | 2 +- Tests/ContextTest.php | 2 +- Tests/EmptyProcessTest.php | 2 +- Tests/ExceptionManagementTest.php | 2 +- Tests/FlushableTaskTest.php | 2 +- Tests/IterableTaskTest.php | 2 +- Tests/MultiBranchProcessTest.php | 2 +- Tests/MultiWorkflowTest.php | 2 +- Tests/ProcessManagerTest.php | 2 +- Tests/Task/ColumnAggregatorTaskTest.php | 2 +- Tests/Task/FilterTaskTest.php | 2 +- Tests/Task/ProcessExecutorTaskTest.php | 2 +- Tests/Task/StopTaskTest.php | 2 +- Tests/Task/TransformerTaskTest.php | 2 +- Tests/Task/ValidatorTaskTest.php | 2 +- Tests/Transformer/ArrayFilterTransformerTest.php | 2 +- Tests/Transformer/CallbackTransformerTest.php | 2 +- Tests/Transformer/DateTransformersTest.php | 2 +- Tests/Transformer/HashTransformerTest.php | 2 +- Tests/Transformer/MappingTransformerTest.php | 2 +- Tests/Transformer/RulesTransformerTest.php | 2 +- Tests/Transformer/TransformerExceptionTest.php | 2 +- Tests/Transformer/TypeSetterTransformerTest.php | 2 +- Tests/Transformer/UnsetTransformerTest.php | 2 +- Tests/Transformer/XpathEvaluatorTransformerTest.php | 2 +- Transformer/ArrayElementTransformer.php | 2 +- Transformer/ArrayFilterTransformer.php | 2 +- Transformer/ArrayFirstTransformer.php | 2 +- Transformer/ArrayLastTransformer.php | 2 +- Transformer/ArrayMapTransformer.php | 2 +- Transformer/ArrayUnsetTransformer.php | 2 +- Transformer/CachedTransformer.php | 2 +- Transformer/CallbackTransformer.php | 2 +- Transformer/CastTransformer.php | 2 +- Transformer/ConditionTrait.php | 2 +- Transformer/ConfigurableTransformerInterface.php | 2 +- Transformer/ConstantTransformer.php | 2 +- Transformer/ConvertValueTransformer.php | 2 +- Transformer/DateFormatTransformer.php | 2 +- Transformer/DateParserTransformer.php | 2 +- Transformer/DebugTransformer.php | 2 +- Transformer/DefaultTransformer.php | 2 +- Transformer/DenormalizeTransformer.php | 2 +- Transformer/EvaluatorTransformer.php | 2 +- Transformer/ExplodeTransformer.php | 2 +- Transformer/ExpressionLanguageMapTransformer.php | 2 +- Transformer/GenericTransformer.php | 2 +- Transformer/HashTransformer.php | 2 +- Transformer/ImplodeTransformer.php | 2 +- Transformer/MappingTransformer.php | 2 +- Transformer/MultiReplaceTransformer.php | 2 +- Transformer/NormalizeTransformer.php | 2 +- Transformer/PregFilterTransformer.php | 2 +- Transformer/PropertyAccessorTransformer.php | 2 +- Transformer/RecursivePropertySetterTransformer.php | 2 +- Transformer/RulesTransformer.php | 2 +- Transformer/SlugifyTransformer.php | 2 +- Transformer/SprintfTransformer.php | 2 +- Transformer/TransformerInterface.php | 2 +- Transformer/TransformerTrait.php | 2 +- Transformer/TrimTransformer.php | 2 +- Transformer/TypeSetterTransformer.php | 2 +- Transformer/UnsetTransformer.php | 2 +- Transformer/WrapperTransformer.php | 2 +- Transformer/Xml/XpathEvaluatorTransformer.php | 2 +- Validator/ConstraintLoader.php | 2 +- 180 files changed, 180 insertions(+), 180 deletions(-) diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index c933aff1..3b5b930f 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 316c1053..103354fa 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index 60d9fc82..69b1fee5 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index d9d942bd..e76b76ed 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index f196c353..f452148e 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index 8644174b..cbb47591 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Context/ContextualOptionResolver.php b/Context/ContextualOptionResolver.php index c0871ebb..095e08e6 100644 --- a/Context/ContextualOptionResolver.php +++ b/Context/ContextualOptionResolver.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index c84ef9c5..880191fe 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 6945f68e..168ef4b8 100644 --- a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/DependencyInjection/Compiler/RegistryCompilerPass.php index 99ec2a2d..be19999f 100644 --- a/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e5be1694..57aad899 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 6a14aaf5..5a707692 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/EventDispatcherTaskEvent.php b/Event/EventDispatcherTaskEvent.php index f504d149..c4dff488 100644 --- a/Event/EventDispatcherTaskEvent.php +++ b/Event/EventDispatcherTaskEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/GenericEvent.php b/Event/GenericEvent.php index d41b590f..65a5f296 100644 --- a/Event/GenericEvent.php +++ b/Event/GenericEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Event/ProcessEvent.php b/Event/ProcessEvent.php index 8a82b124..6c5fb303 100644 --- a/Event/ProcessEvent.php +++ b/Event/ProcessEvent.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/EventDispatcher/BackcompatEventDispatcher.php b/EventDispatcher/BackcompatEventDispatcher.php index 0ad4b25f..9ff83377 100644 --- a/EventDispatcher/BackcompatEventDispatcher.php +++ b/EventDispatcher/BackcompatEventDispatcher.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/EventListener/DataQueueEventListener.php b/EventListener/DataQueueEventListener.php index fb59f0e7..49f8ac14 100644 --- a/EventListener/DataQueueEventListener.php +++ b/EventListener/DataQueueEventListener.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/CircularProcessException.php b/Exception/CircularProcessException.php index e1433ee9..5ca9a0bf 100644 --- a/Exception/CircularProcessException.php +++ b/Exception/CircularProcessException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/InvalidProcessConfigurationException.php b/Exception/InvalidProcessConfigurationException.php index 0989557c..da4e718d 100644 --- a/Exception/InvalidProcessConfigurationException.php +++ b/Exception/InvalidProcessConfigurationException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/MissingProcessException.php b/Exception/MissingProcessException.php index 3a1c4262..2ef4a1b7 100644 --- a/Exception/MissingProcessException.php +++ b/Exception/MissingProcessException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/MissingTaskConfigurationException.php b/Exception/MissingTaskConfigurationException.php index 6361f7d4..912cbae6 100644 --- a/Exception/MissingTaskConfigurationException.php +++ b/Exception/MissingTaskConfigurationException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/MissingTransformerException.php b/Exception/MissingTransformerException.php index d4b1981e..b47d1f12 100644 --- a/Exception/MissingTransformerException.php +++ b/Exception/MissingTransformerException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/MultiBranchProcessException.php b/Exception/MultiBranchProcessException.php index d7bd67c1..736a25dd 100644 --- a/Exception/MultiBranchProcessException.php +++ b/Exception/MultiBranchProcessException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/ProcessExceptionInterface.php b/Exception/ProcessExceptionInterface.php index ad371cf5..8782d0ce 100644 --- a/Exception/ProcessExceptionInterface.php +++ b/Exception/ProcessExceptionInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index 658264f9..e9a2c9c5 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/ExpressionLanguage/PhpFunctionProvider.php b/ExpressionLanguage/PhpFunctionProvider.php index e994b1df..6e60b7af 100644 --- a/ExpressionLanguage/PhpFunctionProvider.php +++ b/ExpressionLanguage/PhpFunctionProvider.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/CsvFile.php b/Filesystem/CsvFile.php index 8a58a89d..e14eecd4 100644 --- a/Filesystem/CsvFile.php +++ b/Filesystem/CsvFile.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index 09f937d4..b660d0de 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/FileStreamInterface.php b/Filesystem/FileStreamInterface.php index 7b8d5299..61e029cc 100644 --- a/Filesystem/FileStreamInterface.php +++ b/Filesystem/FileStreamInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/JsonStreamFile.php b/Filesystem/JsonStreamFile.php index 4fb5df8f..1c0342fc 100644 --- a/Filesystem/JsonStreamFile.php +++ b/Filesystem/JsonStreamFile.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/SeekableFileInterface.php b/Filesystem/SeekableFileInterface.php index 5b456b35..c385a7ed 100644 --- a/Filesystem/SeekableFileInterface.php +++ b/Filesystem/SeekableFileInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/StructuredFileInterface.php b/Filesystem/StructuredFileInterface.php index 113decec..dd00aaf9 100644 --- a/Filesystem/StructuredFileInterface.php +++ b/Filesystem/StructuredFileInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/WritableFileInterface.php b/Filesystem/WritableFileInterface.php index 2b23bd64..35285319 100644 --- a/Filesystem/WritableFileInterface.php +++ b/Filesystem/WritableFileInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/WritableStructuredFileInterface.php b/Filesystem/WritableStructuredFileInterface.php index 5778634f..c1b3a58a 100644 --- a/Filesystem/WritableStructuredFileInterface.php +++ b/Filesystem/WritableStructuredFileInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Filesystem/XmlFile.php b/Filesystem/XmlFile.php index 3a1f0c0e..4733caa5 100644 --- a/Filesystem/XmlFile.php +++ b/Filesystem/XmlFile.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/LICENSE b/LICENSE index fdc61317..d32c6b75 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2015-2019 Clever-Age +Copyright (c) 2015-2023 Clever-Age Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Logger/AbstractLogger.php b/Logger/AbstractLogger.php index fca21ddc..eae8cc7d 100644 --- a/Logger/AbstractLogger.php +++ b/Logger/AbstractLogger.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/AbstractProcessor.php b/Logger/AbstractProcessor.php index 6145f0b5..740ec4ad 100644 --- a/Logger/AbstractProcessor.php +++ b/Logger/AbstractProcessor.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/ProcessLogger.php b/Logger/ProcessLogger.php index 0ce95d3c..099a8024 100644 --- a/Logger/ProcessLogger.php +++ b/Logger/ProcessLogger.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/ProcessProcessor.php b/Logger/ProcessProcessor.php index 5337fabc..2fa87f34 100644 --- a/Logger/ProcessProcessor.php +++ b/Logger/ProcessProcessor.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/TaskLogger.php b/Logger/TaskLogger.php index e0248c40..1e7dad26 100644 --- a/Logger/TaskLogger.php +++ b/Logger/TaskLogger.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/TaskProcessor.php b/Logger/TaskProcessor.php index 09b2090c..d6cbaf06 100644 --- a/Logger/TaskProcessor.php +++ b/Logger/TaskProcessor.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Logger/TransformerProcessor.php b/Logger/TransformerProcessor.php index e26af43f..8517671c 100644 --- a/Logger/TransformerProcessor.php +++ b/Logger/TransformerProcessor.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 34db26bf..66294acd 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/AbstractConfigurableTask.php b/Model/AbstractConfigurableTask.php index 3a7e7d62..cdac8a8c 100644 --- a/Model/AbstractConfigurableTask.php +++ b/Model/AbstractConfigurableTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/BlockingTaskInterface.php b/Model/BlockingTaskInterface.php index 7671db01..a13fef89 100644 --- a/Model/BlockingTaskInterface.php +++ b/Model/BlockingTaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/FinalizableTaskInterface.php b/Model/FinalizableTaskInterface.php index 9f1a4949..a553bbbb 100644 --- a/Model/FinalizableTaskInterface.php +++ b/Model/FinalizableTaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/FlushableTaskInterface.php b/Model/FlushableTaskInterface.php index 3207da8f..f9f37d92 100644 --- a/Model/FlushableTaskInterface.php +++ b/Model/FlushableTaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/InitializableTaskInterface.php b/Model/InitializableTaskInterface.php index 178650ca..320883df 100644 --- a/Model/InitializableTaskInterface.php +++ b/Model/InitializableTaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/IterableTaskInterface.php b/Model/IterableTaskInterface.php index 1329bcb8..1aa38878 100644 --- a/Model/IterableTaskInterface.php +++ b/Model/IterableTaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/ProcessHistory.php b/Model/ProcessHistory.php index 66aadf82..e8d92786 100644 --- a/Model/ProcessHistory.php +++ b/Model/ProcessHistory.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/ProcessState.php b/Model/ProcessState.php index ee4214e2..2ccc01a9 100644 --- a/Model/ProcessState.php +++ b/Model/ProcessState.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/SubprocessInstance.php b/Model/SubprocessInstance.php index e5b41553..09364244 100644 --- a/Model/SubprocessInstance.php +++ b/Model/SubprocessInstance.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Model/TaskInterface.php b/Model/TaskInterface.php index 8248892a..096107c6 100644 --- a/Model/TaskInterface.php +++ b/Model/TaskInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 0c815e04..49212f5f 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Registry/TransformerRegistry.php b/Registry/TransformerRegistry.php index 911c5dc3..fa1bf245 100644 --- a/Registry/TransformerRegistry.php +++ b/Registry/TransformerRegistry.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/AbstractIterableOutputTask.php b/Task/AbstractIterableOutputTask.php index bf177af3..9bf4a9f8 100644 --- a/Task/AbstractIterableOutputTask.php +++ b/Task/AbstractIterableOutputTask.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/AggregateIterableTask.php b/Task/AggregateIterableTask.php index df6a2e39..4319b20f 100644 --- a/Task/AggregateIterableTask.php +++ b/Task/AggregateIterableTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/ArrayMergeTask.php b/Task/ArrayMergeTask.php index a4a11b85..458031d9 100644 --- a/Task/ArrayMergeTask.php +++ b/Task/ArrayMergeTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/ColumnAggregatorTask.php b/Task/ColumnAggregatorTask.php index e6351ae4..0d0fba86 100644 --- a/Task/ColumnAggregatorTask.php +++ b/Task/ColumnAggregatorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/ConstantIterableOutputTask.php b/Task/ConstantIterableOutputTask.php index 9c744c17..79b47ffd 100644 --- a/Task/ConstantIterableOutputTask.php +++ b/Task/ConstantIterableOutputTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/ConstantOutputTask.php b/Task/ConstantOutputTask.php index 9017e708..3d762f3c 100644 --- a/Task/ConstantOutputTask.php +++ b/Task/ConstantOutputTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/CounterTask.php b/Task/CounterTask.php index 1726432f..c526a915 100644 --- a/Task/CounterTask.php +++ b/Task/CounterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Debug/DebugTask.php b/Task/Debug/DebugTask.php index 58791d56..b0789674 100644 --- a/Task/Debug/DebugTask.php +++ b/Task/Debug/DebugTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Debug/DieTask.php b/Task/Debug/DieTask.php index 045bfbc9..3ded8829 100644 --- a/Task/Debug/DieTask.php +++ b/Task/Debug/DieTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Debug/ErrorForwarderTask.php b/Task/Debug/ErrorForwarderTask.php index 7dd47565..79d5782a 100644 --- a/Task/Debug/ErrorForwarderTask.php +++ b/Task/Debug/ErrorForwarderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Debug/MemInfoDumpTask.php b/Task/Debug/MemInfoDumpTask.php index ccfc7830..839a033a 100644 --- a/Task/Debug/MemInfoDumpTask.php +++ b/Task/Debug/MemInfoDumpTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/DummyTask.php b/Task/DummyTask.php index c5e2e655..dde67358 100644 --- a/Task/DummyTask.php +++ b/Task/DummyTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Event/EventDispatcherTask.php b/Task/Event/EventDispatcherTask.php index 0a43cafd..16312ef0 100644 --- a/Task/Event/EventDispatcherTask.php +++ b/Task/Event/EventDispatcherTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/AbstractCsvResourceTask.php b/Task/File/Csv/AbstractCsvResourceTask.php index 292b1672..af78f8bc 100644 --- a/Task/File/Csv/AbstractCsvResourceTask.php +++ b/Task/File/Csv/AbstractCsvResourceTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/AbstractCsvTask.php b/Task/File/Csv/AbstractCsvTask.php index e908d928..9ff30134 100644 --- a/Task/File/Csv/AbstractCsvTask.php +++ b/Task/File/Csv/AbstractCsvTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/CsvReaderTask.php b/Task/File/Csv/CsvReaderTask.php index 68f363c5..19fc8b03 100644 --- a/Task/File/Csv/CsvReaderTask.php +++ b/Task/File/Csv/CsvReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index 19040d4a..e76c7485 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/CsvWriterTask.php b/Task/File/Csv/CsvWriterTask.php index 9f29c17b..ca89eb8e 100644 --- a/Task/File/Csv/CsvWriterTask.php +++ b/Task/File/Csv/CsvWriterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Csv/InputCsvReaderTask.php b/Task/File/Csv/InputCsvReaderTask.php index 5cc9a1e3..1e449649 100644 --- a/Task/File/Csv/InputCsvReaderTask.php +++ b/Task/File/Csv/InputCsvReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FileFetchTask.php b/Task/File/FileFetchTask.php index f31f2482..fd27ecc2 100644 --- a/Task/File/FileFetchTask.php +++ b/Task/File/FileFetchTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FileMoverTask.php b/Task/File/FileMoverTask.php index a1273b44..f4633f47 100644 --- a/Task/File/FileMoverTask.php +++ b/Task/File/FileMoverTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FileReaderTask.php b/Task/File/FileReaderTask.php index e67e6721..480b8887 100644 --- a/Task/File/FileReaderTask.php +++ b/Task/File/FileReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FileRemoverTask.php b/Task/File/FileRemoverTask.php index 324e0f86..09c53a58 100644 --- a/Task/File/FileRemoverTask.php +++ b/Task/File/FileRemoverTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FileWriterTask.php b/Task/File/FileWriterTask.php index 308715c8..b93941c6 100644 --- a/Task/File/FileWriterTask.php +++ b/Task/File/FileWriterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/FolderBrowserTask.php b/Task/File/FolderBrowserTask.php index ea27667e..af20fde7 100644 --- a/Task/File/FolderBrowserTask.php +++ b/Task/File/FolderBrowserTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/InputFolderBrowserTask.php b/Task/File/InputFolderBrowserTask.php index 17514d18..7f445df8 100644 --- a/Task/File/InputFolderBrowserTask.php +++ b/Task/File/InputFolderBrowserTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/Task/File/JsonStream/JsonStreamReaderTask.php index 87b26a8e..5a52168f 100644 --- a/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/Task/File/JsonStream/JsonStreamReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Xml/XmlReaderTask.php b/Task/File/Xml/XmlReaderTask.php index 752a2e51..ad87875b 100644 --- a/Task/File/Xml/XmlReaderTask.php +++ b/Task/File/Xml/XmlReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/Xml/XmlWriterTask.php b/Task/File/Xml/XmlWriterTask.php index f62b1f3c..7607fda6 100644 --- a/Task/File/Xml/XmlWriterTask.php +++ b/Task/File/Xml/XmlWriterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/YamlReaderTask.php b/Task/File/YamlReaderTask.php index 3acb6b33..61de6e8a 100644 --- a/Task/File/YamlReaderTask.php +++ b/Task/File/YamlReaderTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/File/YamlWriterTask.php b/Task/File/YamlWriterTask.php index fa52acb2..d69f1ac3 100644 --- a/Task/File/YamlWriterTask.php +++ b/Task/File/YamlWriterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/FilterTask.php b/Task/FilterTask.php index 23fcbcd1..80eb7725 100644 --- a/Task/FilterTask.php +++ b/Task/FilterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/InputAggregatorTask.php b/Task/InputAggregatorTask.php index 001cb497..0ea77c4f 100644 --- a/Task/InputAggregatorTask.php +++ b/Task/InputAggregatorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index 97ee1ad9..a9e661fa 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/IterableBatchTask.php b/Task/IterableBatchTask.php index 5335a0cb..78e35d31 100644 --- a/Task/IterableBatchTask.php +++ b/Task/IterableBatchTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/ObjectUpdaterTask.php b/Task/ObjectUpdaterTask.php index 8cc0ec94..53ec1902 100644 --- a/Task/ObjectUpdaterTask.php +++ b/Task/ObjectUpdaterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Process/CommandRunnerTask.php b/Task/Process/CommandRunnerTask.php index fe13ad47..499ec68c 100644 --- a/Task/Process/CommandRunnerTask.php +++ b/Task/Process/CommandRunnerTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Process/ProcessExecutorTask.php b/Task/Process/ProcessExecutorTask.php index d36a639a..e80bcee6 100644 --- a/Task/Process/ProcessExecutorTask.php +++ b/Task/Process/ProcessExecutorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index 3d7202ca..fbf17bfa 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/PropertyGetterTask.php b/Task/PropertyGetterTask.php index be2dbdb8..aa346296 100644 --- a/Task/PropertyGetterTask.php +++ b/Task/PropertyGetterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/PropertySetterTask.php b/Task/PropertySetterTask.php index 5fee35e5..07c85f76 100644 --- a/Task/PropertySetterTask.php +++ b/Task/PropertySetterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Reporting/AdvancedStatCounterTask.php b/Task/Reporting/AdvancedStatCounterTask.php index 84ecafe7..4e6bfbb2 100644 --- a/Task/Reporting/AdvancedStatCounterTask.php +++ b/Task/Reporting/AdvancedStatCounterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Reporting/LoggerTask.php b/Task/Reporting/LoggerTask.php index 5a9e6933..2f790312 100644 --- a/Task/Reporting/LoggerTask.php +++ b/Task/Reporting/LoggerTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Reporting/StatCounterTask.php b/Task/Reporting/StatCounterTask.php index fb16ac03..53a777ab 100644 --- a/Task/Reporting/StatCounterTask.php +++ b/Task/Reporting/StatCounterTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/RowAggregatorTask.php b/Task/RowAggregatorTask.php index 61fafa72..132483a0 100644 --- a/Task/RowAggregatorTask.php +++ b/Task/RowAggregatorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Serialization/DenormalizerTask.php b/Task/Serialization/DenormalizerTask.php index f4b7f6f3..3fe38766 100644 --- a/Task/Serialization/DenormalizerTask.php +++ b/Task/Serialization/DenormalizerTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Serialization/DeserializerTask.php b/Task/Serialization/DeserializerTask.php index 0eb2a18f..f8be4034 100644 --- a/Task/Serialization/DeserializerTask.php +++ b/Task/Serialization/DeserializerTask.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Serialization/NormalizerTask.php b/Task/Serialization/NormalizerTask.php index 9323ce91..bdf711fd 100644 --- a/Task/Serialization/NormalizerTask.php +++ b/Task/Serialization/NormalizerTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Serialization/SerializerTask.php b/Task/Serialization/SerializerTask.php index 7e0ddf23..ddfc0c3d 100644 --- a/Task/Serialization/SerializerTask.php +++ b/Task/Serialization/SerializerTask.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/SimpleBatchTask.php b/Task/SimpleBatchTask.php index 4ba46193..25f2b201 100644 --- a/Task/SimpleBatchTask.php +++ b/Task/SimpleBatchTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/SkipEmptyTask.php b/Task/SkipEmptyTask.php index af357094..727c4438 100644 --- a/Task/SkipEmptyTask.php +++ b/Task/SkipEmptyTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/SplitJoinLineTask.php b/Task/SplitJoinLineTask.php index e9a19671..620be258 100644 --- a/Task/SplitJoinLineTask.php +++ b/Task/SplitJoinLineTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/StopTask.php b/Task/StopTask.php index 9b75034c..c23995ec 100644 --- a/Task/StopTask.php +++ b/Task/StopTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/TransformerTask.php b/Task/TransformerTask.php index 8f44fef2..5a911898 100644 --- a/Task/TransformerTask.php +++ b/Task/TransformerTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index c7d7c5dc..16c6bb10 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index f01d3d82..dc972a1d 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index 0ffe3c82..184b4009 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/BlockingTaskTest.php b/Tests/BlockingTaskTest.php index f86177b6..15697c95 100644 --- a/Tests/BlockingTaskTest.php +++ b/Tests/BlockingTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/CircularProcessTest.php b/Tests/CircularProcessTest.php index 5f73c082..be5f1eaa 100644 --- a/Tests/CircularProcessTest.php +++ b/Tests/CircularProcessTest.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/ContextTest.php b/Tests/ContextTest.php index 2c146a7d..cefde99b 100644 --- a/Tests/ContextTest.php +++ b/Tests/ContextTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/EmptyProcessTest.php b/Tests/EmptyProcessTest.php index b0a927e2..6880fb13 100644 --- a/Tests/EmptyProcessTest.php +++ b/Tests/EmptyProcessTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/ExceptionManagementTest.php b/Tests/ExceptionManagementTest.php index 57bdd51b..1bafa2e9 100644 --- a/Tests/ExceptionManagementTest.php +++ b/Tests/ExceptionManagementTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/FlushableTaskTest.php b/Tests/FlushableTaskTest.php index a923bf43..b8b63ff3 100644 --- a/Tests/FlushableTaskTest.php +++ b/Tests/FlushableTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/IterableTaskTest.php b/Tests/IterableTaskTest.php index 2a2f88b1..521b60fa 100644 --- a/Tests/IterableTaskTest.php +++ b/Tests/IterableTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/MultiBranchProcessTest.php b/Tests/MultiBranchProcessTest.php index f4cdeb65..062ea9d0 100644 --- a/Tests/MultiBranchProcessTest.php +++ b/Tests/MultiBranchProcessTest.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/MultiWorkflowTest.php b/Tests/MultiWorkflowTest.php index e062338d..912c7916 100644 --- a/Tests/MultiWorkflowTest.php +++ b/Tests/MultiWorkflowTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/ProcessManagerTest.php b/Tests/ProcessManagerTest.php index 218a5461..ca6e70ef 100644 --- a/Tests/ProcessManagerTest.php +++ b/Tests/ProcessManagerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/ColumnAggregatorTaskTest.php b/Tests/Task/ColumnAggregatorTaskTest.php index 43e1471c..8639330d 100644 --- a/Tests/Task/ColumnAggregatorTaskTest.php +++ b/Tests/Task/ColumnAggregatorTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/FilterTaskTest.php b/Tests/Task/FilterTaskTest.php index 412e8991..6715f7b1 100644 --- a/Tests/Task/FilterTaskTest.php +++ b/Tests/Task/FilterTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/ProcessExecutorTaskTest.php b/Tests/Task/ProcessExecutorTaskTest.php index efb6483d..87fabf4e 100644 --- a/Tests/Task/ProcessExecutorTaskTest.php +++ b/Tests/Task/ProcessExecutorTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/StopTaskTest.php b/Tests/Task/StopTaskTest.php index 5c706818..d1478d02 100644 --- a/Tests/Task/StopTaskTest.php +++ b/Tests/Task/StopTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/TransformerTaskTest.php b/Tests/Task/TransformerTaskTest.php index f4f31978..4213c45a 100644 --- a/Tests/Task/TransformerTaskTest.php +++ b/Tests/Task/TransformerTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Task/ValidatorTaskTest.php b/Tests/Task/ValidatorTaskTest.php index 9fbd0958..b21f3771 100644 --- a/Tests/Task/ValidatorTaskTest.php +++ b/Tests/Task/ValidatorTaskTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/ArrayFilterTransformerTest.php b/Tests/Transformer/ArrayFilterTransformerTest.php index 2a6a5acf..091871bc 100644 --- a/Tests/Transformer/ArrayFilterTransformerTest.php +++ b/Tests/Transformer/ArrayFilterTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/CallbackTransformerTest.php b/Tests/Transformer/CallbackTransformerTest.php index 810b170c..120b7ae3 100644 --- a/Tests/Transformer/CallbackTransformerTest.php +++ b/Tests/Transformer/CallbackTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/DateTransformersTest.php b/Tests/Transformer/DateTransformersTest.php index 8c649a15..2e120f8e 100644 --- a/Tests/Transformer/DateTransformersTest.php +++ b/Tests/Transformer/DateTransformersTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/HashTransformerTest.php b/Tests/Transformer/HashTransformerTest.php index 057dfc6f..bc1e8aaf 100644 --- a/Tests/Transformer/HashTransformerTest.php +++ b/Tests/Transformer/HashTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/MappingTransformerTest.php b/Tests/Transformer/MappingTransformerTest.php index b4de3762..40dfdbdc 100644 --- a/Tests/Transformer/MappingTransformerTest.php +++ b/Tests/Transformer/MappingTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/RulesTransformerTest.php b/Tests/Transformer/RulesTransformerTest.php index e8ac768d..8f61d766 100644 --- a/Tests/Transformer/RulesTransformerTest.php +++ b/Tests/Transformer/RulesTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/TransformerExceptionTest.php b/Tests/Transformer/TransformerExceptionTest.php index 179e7b9d..96504d55 100644 --- a/Tests/Transformer/TransformerExceptionTest.php +++ b/Tests/Transformer/TransformerExceptionTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/TypeSetterTransformerTest.php b/Tests/Transformer/TypeSetterTransformerTest.php index e38979c6..2f778008 100644 --- a/Tests/Transformer/TypeSetterTransformerTest.php +++ b/Tests/Transformer/TypeSetterTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/UnsetTransformerTest.php b/Tests/Transformer/UnsetTransformerTest.php index 501d51f4..90ac90a6 100644 --- a/Tests/Transformer/UnsetTransformerTest.php +++ b/Tests/Transformer/UnsetTransformerTest.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/Tests/Transformer/XpathEvaluatorTransformerTest.php index 0d404fdd..5580485f 100644 --- a/Tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/Tests/Transformer/XpathEvaluatorTransformerTest.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayElementTransformer.php b/Transformer/ArrayElementTransformer.php index c483df94..c0225b72 100644 --- a/Transformer/ArrayElementTransformer.php +++ b/Transformer/ArrayElementTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayFilterTransformer.php b/Transformer/ArrayFilterTransformer.php index adfa5853..26021410 100644 --- a/Transformer/ArrayFilterTransformer.php +++ b/Transformer/ArrayFilterTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayFirstTransformer.php b/Transformer/ArrayFirstTransformer.php index 83c37453..81ce3a87 100644 --- a/Transformer/ArrayFirstTransformer.php +++ b/Transformer/ArrayFirstTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayLastTransformer.php b/Transformer/ArrayLastTransformer.php index bbaefa9b..e2a5e0e5 100644 --- a/Transformer/ArrayLastTransformer.php +++ b/Transformer/ArrayLastTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index 945e4b5f..0f6615de 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ArrayUnsetTransformer.php b/Transformer/ArrayUnsetTransformer.php index ccf3272c..59eb9db0 100644 --- a/Transformer/ArrayUnsetTransformer.php +++ b/Transformer/ArrayUnsetTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/CachedTransformer.php b/Transformer/CachedTransformer.php index eeecbd34..4e763883 100644 --- a/Transformer/CachedTransformer.php +++ b/Transformer/CachedTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/CallbackTransformer.php b/Transformer/CallbackTransformer.php index 9822faa8..47a92512 100644 --- a/Transformer/CallbackTransformer.php +++ b/Transformer/CallbackTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/CastTransformer.php b/Transformer/CastTransformer.php index 8278df31..04487b41 100644 --- a/Transformer/CastTransformer.php +++ b/Transformer/CastTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ConditionTrait.php b/Transformer/ConditionTrait.php index 9c528715..ff499c46 100644 --- a/Transformer/ConditionTrait.php +++ b/Transformer/ConditionTrait.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ConfigurableTransformerInterface.php b/Transformer/ConfigurableTransformerInterface.php index 164d775b..9ee4568e 100644 --- a/Transformer/ConfigurableTransformerInterface.php +++ b/Transformer/ConfigurableTransformerInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ConstantTransformer.php b/Transformer/ConstantTransformer.php index c8cb17a1..3c0730ce 100644 --- a/Transformer/ConstantTransformer.php +++ b/Transformer/ConstantTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ConvertValueTransformer.php b/Transformer/ConvertValueTransformer.php index 3d683713..9c5620cf 100644 --- a/Transformer/ConvertValueTransformer.php +++ b/Transformer/ConvertValueTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 7f6a097a..485b956a 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/DateParserTransformer.php b/Transformer/DateParserTransformer.php index 9aa300c4..586e3205 100644 --- a/Transformer/DateParserTransformer.php +++ b/Transformer/DateParserTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/DebugTransformer.php b/Transformer/DebugTransformer.php index 43fe59cd..bdb774d7 100644 --- a/Transformer/DebugTransformer.php +++ b/Transformer/DebugTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/DefaultTransformer.php b/Transformer/DefaultTransformer.php index 11ef3671..e1b6ae81 100644 --- a/Transformer/DefaultTransformer.php +++ b/Transformer/DefaultTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/DenormalizeTransformer.php b/Transformer/DenormalizeTransformer.php index ce2f0816..d826ddd6 100644 --- a/Transformer/DenormalizeTransformer.php +++ b/Transformer/DenormalizeTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/EvaluatorTransformer.php b/Transformer/EvaluatorTransformer.php index ae732bb3..bee97819 100644 --- a/Transformer/EvaluatorTransformer.php +++ b/Transformer/EvaluatorTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ExplodeTransformer.php b/Transformer/ExplodeTransformer.php index ba7f6c17..1c32b532 100644 --- a/Transformer/ExplodeTransformer.php +++ b/Transformer/ExplodeTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ExpressionLanguageMapTransformer.php b/Transformer/ExpressionLanguageMapTransformer.php index 0cff2c4d..8a3214d0 100644 --- a/Transformer/ExpressionLanguageMapTransformer.php +++ b/Transformer/ExpressionLanguageMapTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index 61b68ea8..5c7dcd71 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/HashTransformer.php b/Transformer/HashTransformer.php index 99878e5b..d4ed5d32 100644 --- a/Transformer/HashTransformer.php +++ b/Transformer/HashTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/ImplodeTransformer.php b/Transformer/ImplodeTransformer.php index bf06b1af..9bdeaa2b 100644 --- a/Transformer/ImplodeTransformer.php +++ b/Transformer/ImplodeTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index db9f3d06..147755e9 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/MultiReplaceTransformer.php b/Transformer/MultiReplaceTransformer.php index b8e73157..63e28da9 100644 --- a/Transformer/MultiReplaceTransformer.php +++ b/Transformer/MultiReplaceTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/NormalizeTransformer.php b/Transformer/NormalizeTransformer.php index 3eb9ad71..8a9c7c04 100644 --- a/Transformer/NormalizeTransformer.php +++ b/Transformer/NormalizeTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/PregFilterTransformer.php b/Transformer/PregFilterTransformer.php index 54cf3e21..d2a52348 100644 --- a/Transformer/PregFilterTransformer.php +++ b/Transformer/PregFilterTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/PropertyAccessorTransformer.php b/Transformer/PropertyAccessorTransformer.php index 60d7bbb0..d267b0a6 100644 --- a/Transformer/PropertyAccessorTransformer.php +++ b/Transformer/PropertyAccessorTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/RecursivePropertySetterTransformer.php b/Transformer/RecursivePropertySetterTransformer.php index 4f84e22b..f6578722 100644 --- a/Transformer/RecursivePropertySetterTransformer.php +++ b/Transformer/RecursivePropertySetterTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php index 171156ac..30ab9260 100644 --- a/Transformer/RulesTransformer.php +++ b/Transformer/RulesTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/SlugifyTransformer.php b/Transformer/SlugifyTransformer.php index 49126650..c097b915 100644 --- a/Transformer/SlugifyTransformer.php +++ b/Transformer/SlugifyTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/SprintfTransformer.php b/Transformer/SprintfTransformer.php index f20035cd..e1ed00ba 100644 --- a/Transformer/SprintfTransformer.php +++ b/Transformer/SprintfTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/TransformerInterface.php b/Transformer/TransformerInterface.php index 50358e6e..7a0cb343 100644 --- a/Transformer/TransformerInterface.php +++ b/Transformer/TransformerInterface.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 30133616..3f68f7c9 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -4,7 +4,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/TrimTransformer.php b/Transformer/TrimTransformer.php index 9c459597..b30d57b9 100644 --- a/Transformer/TrimTransformer.php +++ b/Transformer/TrimTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/TypeSetterTransformer.php b/Transformer/TypeSetterTransformer.php index 20bc1f13..e558f29a 100644 --- a/Transformer/TypeSetterTransformer.php +++ b/Transformer/TypeSetterTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/UnsetTransformer.php b/Transformer/UnsetTransformer.php index 7c201116..966f6dd7 100644 --- a/Transformer/UnsetTransformer.php +++ b/Transformer/UnsetTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/WrapperTransformer.php b/Transformer/WrapperTransformer.php index 307b2c57..4b10389a 100644 --- a/Transformer/WrapperTransformer.php +++ b/Transformer/WrapperTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php index d775c532..53404f6b 100644 --- a/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Validator/ConstraintLoader.php b/Validator/ConstraintLoader.php index 2f1a050f..765caf13 100644 --- a/Validator/ConstraintLoader.php +++ b/Validator/ConstraintLoader.php @@ -2,7 +2,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (C) 2017-2021 Clever-Age + * Copyright (c) 2017-2023 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. From e94bc10f689741cc4a9ce1ea3427cbbd7d6b2d11 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 09:58:35 +0100 Subject: [PATCH 151/304] ajout phpstan --- Makefile | 2 - Resources/tests/environment/sf4/composer.json | 11 +- Resources/tests/environment/sf5/composer.json | 11 +- composer.json | 140 ++++++++++-------- phpstan.neon | 7 + 5 files changed, 102 insertions(+), 69 deletions(-) create mode 100644 phpstan.neon diff --git a/Makefile b/Makefile index 4204d451..f8f4b1ac 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,6 @@ endif SF_ENV=sf4 LOCAL_DOCKER_TAG=cleverage_process:test DOCKER_RUN=docker run -it --rm \ - -e BLACKFIRE_CLIENT_ID=$(BLACKFIRE_CLIENT_ID) \ - -e BLACKFIRE_CLIENT_TOKEN=$(BLACKFIRE_CLIENT_TOKEN) \ --mount type=bind,src=$$(pwd),dst=/src-cleverage_process pull: pull/$(SF_ENV) diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json index c706badb..6736c0c2 100644 --- a/Resources/tests/environment/sf4/composer.json +++ b/Resources/tests/environment/sf4/composer.json @@ -22,7 +22,10 @@ }, "require-dev": { "symfony/phpunit-bridge": "^4.4|^5.0", - "phpunit/phpunit": "~6.4" + "phpunit/phpunit": "~6.4", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpstan/extension-installer": "*" }, "autoload": { "psr-4": { @@ -46,5 +49,11 @@ "post-update-cmd": [ "@auto-scripts" ] + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "symfony/flex": true + } } } diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json index 24f1f6b4..78c50e4b 100644 --- a/Resources/tests/environment/sf5/composer.json +++ b/Resources/tests/environment/sf5/composer.json @@ -22,7 +22,10 @@ }, "require-dev": { "symfony/phpunit-bridge": "^4.4|^5.0", - "phpunit/phpunit": "~6.4" + "phpunit/phpunit": "~6.4", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpstan/extension-installer": "*" }, "autoload": { "psr-4": { @@ -46,5 +49,11 @@ "post-update-cmd": [ "@auto-scripts" ] + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "symfony/flex": true + } } } diff --git a/composer.json b/composer.json index eb84c24c..1fa67ca9 100644 --- a/composer.json +++ b/composer.json @@ -1,70 +1,80 @@ { - "name": "cleverage/process-bundle", - "description": "Process, import/export, transform and validate data with a simple API with Symfony3", - "keywords": [ - "process", - "task", - "etl", - "transformation", - "import", - "export" - ], - "homepage": "https://github.com/cleverage/process-bundle", - "type": "symfony-bundle", - "license": "MIT", - "authors": [ - { - "name": "Vincent Chalnot", - "email": "vchalnot@clever-age.com", - "homepage": "http://chalnot.fr", - "role": "Lead Developer" - }, - { - "name": "Valentin Clavreul", - "email": "vclavreul@clever-age.com", - "role": "Developer" - }, - { - "name": "Madeline Veyrenc", - "email": "mveyrenc@clever-age.com", - "homepage": "https://github.com/mveyrenc", - "role": "Developer" - } - ], - "autoload": { - "psr-4": { - "CleverAge\\ProcessBundle\\": "" - } + "name": "cleverage/process-bundle", + "description": "Process, import/export, transform and validate data with a simple API with Symfony3", + "keywords": [ + "process", + "task", + "etl", + "transformation", + "import", + "export" + ], + "homepage": "https://github.com/cleverage/process-bundle", + "type": "symfony-bundle", + "license": "MIT", + "authors": [ + { + "name": "Vincent Chalnot", + "email": "vchalnot@clever-age.com", + "homepage": "http://chalnot.fr", + "role": "Lead Developer" }, - "require": { - "php": ">=7.2", - "ext-json": "*", - "ext-dom": "*", - "ext-intl": "*", - "symfony/event-dispatcher-contracts": "~1.0|~2.0", - "psr/event-dispatcher": "1.0.0", - "psr/cache": "^1|^2|^3", - "symfony/config": "~3.0|~4.0|~5.0", - "symfony/dependency-injection": "~3.0|~4.0|~5.0", - "symfony/framework-bundle": "~3.0|~4.0|~5.0", - "symfony/expression-language": "~3.0|~4.0|~5.0", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0|~5.0", - "symfony/options-resolver": "~3.0|~4.0|~5.0", - "symfony/process": "~3.0|~4.0|~5.0", - "symfony/property-access": "~3.0|~4.0|~5.0", - "symfony/serializer": "~3.0|~4.0|~5.0", - "symfony/validator": "~3.0|~4.0|~5.0", - "symfony/yaml": "~3.0|~4.0|~5.0" + { + "name": "Valentin Clavreul", + "email": "vclavreul@clever-age.com", + "role": "Developer" }, - "require-dev": { - "phpunit/phpunit": "~6.4" - }, - "suggest": { - "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", - "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", - "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", - "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", - "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle" + { + "name": "Madeline Veyrenc", + "email": "mveyrenc@clever-age.com", + "homepage": "https://github.com/mveyrenc", + "role": "Developer" + } + ], + "autoload": { + "psr-4": { + "CleverAge\\ProcessBundle\\": "" + } + }, + "require": { + "php": ">=7.2", + "ext-json": "*", + "ext-dom": "*", + "ext-intl": "*", + "symfony/event-dispatcher-contracts": "~1.0|~2.0", + "psr/event-dispatcher": "1.0.0", + "psr/cache": "^1|^2|^3", + "symfony/config": "~3.0|~4.0|~5.0", + "symfony/dependency-injection": "~3.0|~4.0|~5.0", + "symfony/framework-bundle": "~3.0|~4.0|~5.0", + "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/monolog-bundle": "~3.3", + "symfony/console": "~3.0|~4.0|~5.0", + "symfony/options-resolver": "~3.0|~4.0|~5.0", + "symfony/process": "~3.0|~4.0|~5.0", + "symfony/property-access": "~3.0|~4.0|~5.0", + "symfony/serializer": "~3.0|~4.0|~5.0", + "symfony/validator": "~3.0|~4.0|~5.0", + "symfony/yaml": "~3.0|~4.0|~5.0" + }, + "require-dev": { + "roave/security-advisories": "dev-latest", + "phpunit/phpunit": "~6.4", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpstan/extension-installer": "*" + }, + "suggest": { + "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", + "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", + "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", + "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", + "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "symfony/flex": true } + } } diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..0489d450 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,7 @@ +parameters: + level: 1 + paths: + - . + excludePaths: + - vendor/* + - rector.php From 1626c38f0fad56a596299d527f384181247dc72a Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:15:28 +0100 Subject: [PATCH 152/304] upgrade to php8.1 and symfony 6 --- Resources/tests/environment/sf3/composer.json | 51 ------------- .../tests/environment/sf3/config/bundles.php | 7 -- .../config/packages/dev/cleverage_process.yml | 2 - .../sf3/config/packages/framework.yaml | 10 --- .../packages/test/cleverage_process.yml | 2 - .../tests/environment/sf3/phpunit.xml.dist | 25 ------- .../tests/environment/sf3/src/Kernel.php | 72 ------------------- .../sf3/src/SetPublicServicesCompilerPass.php | 27 ------- Resources/tests/environment/sf4/composer.json | 59 --------------- .../tests/environment/sf4/config/bundles.php | 7 -- .../sf4/config/packages/framework.yaml | 10 --- .../packages/test/cleverage_process.yml | 2 - .../tests/environment/sf4/phpunit.xml.dist | 25 ------- composer.json | 30 ++++---- 14 files changed, 15 insertions(+), 314 deletions(-) delete mode 100644 Resources/tests/environment/sf3/composer.json delete mode 100644 Resources/tests/environment/sf3/config/bundles.php delete mode 100644 Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml delete mode 100644 Resources/tests/environment/sf3/config/packages/framework.yaml delete mode 100644 Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml delete mode 100644 Resources/tests/environment/sf3/phpunit.xml.dist delete mode 100644 Resources/tests/environment/sf3/src/Kernel.php delete mode 100644 Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php delete mode 100644 Resources/tests/environment/sf4/composer.json delete mode 100644 Resources/tests/environment/sf4/config/bundles.php delete mode 100644 Resources/tests/environment/sf4/config/packages/framework.yaml delete mode 100644 Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml delete mode 100644 Resources/tests/environment/sf4/phpunit.xml.dist diff --git a/Resources/tests/environment/sf3/composer.json b/Resources/tests/environment/sf3/composer.json deleted file mode 100644 index 33d973b7..00000000 --- a/Resources/tests/environment/sf3/composer.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "type": "project", - "license": "proprietary", - "require": { - "symfony/framework-bundle": "^3.4", - "symfony/routing": "^3.4", - "symfony/dotenv": "^3.4", - "symfony/flex": "^1.11", - - "symfony/event-dispatcher-contracts": "~1.0|~2.0", - "psr/event-dispatcher": "1.0.0", - "symfony/config": "~3.0", - "symfony/dependency-injection": "~3.0", - "symfony/expression-language": "~3.0", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0", - "symfony/options-resolver": "~3.0", - "symfony/process": "~3.0", - "symfony/property-access": "~3.0", - "symfony/serializer": "~3.0", - "symfony/validator": "~3.0", - "symfony/yaml": "~3.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4|^5.0", - "phpunit/phpunit": "~6.4" - }, - "autoload": { - "psr-4": { - "App\\": "src/", - "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" - } - }, - "autoload-dev": { - "psr-4": { - "App\\Tests\\": "tests/" - } - }, - "scripts": { - "auto-scripts": { - "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" - }, - "post-install-cmd": [ - "@auto-scripts" - ], - "post-update-cmd": [ - "@auto-scripts" - ] - } -} diff --git a/Resources/tests/environment/sf3/config/bundles.php b/Resources/tests/environment/sf3/config/bundles.php deleted file mode 100644 index d1a265ef..00000000 --- a/Resources/tests/environment/sf3/config/bundles.php +++ /dev/null @@ -1,7 +0,0 @@ - ['all' => true], - CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], - Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], -]; diff --git a/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml b/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml deleted file mode 100644 index a03e25d8..00000000 --- a/Resources/tests/environment/sf3/config/packages/dev/cleverage_process.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf3/config/packages/framework.yaml b/Resources/tests/environment/sf3/config/packages/framework.yaml deleted file mode 100644 index 5a1678d2..00000000 --- a/Resources/tests/environment/sf3/config/packages/framework.yaml +++ /dev/null @@ -1,10 +0,0 @@ -framework: - secret: '%env(APP_SECRET)%' - - serializer: - enabled: true - - #esi: true - #fragments: true - php_errors: - log: true diff --git a/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml deleted file mode 100644 index a03e25d8..00000000 --- a/Resources/tests/environment/sf3/config/packages/test/cleverage_process.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf3/phpunit.xml.dist b/Resources/tests/environment/sf3/phpunit.xml.dist deleted file mode 100644 index fbdc9945..00000000 --- a/Resources/tests/environment/sf3/phpunit.xml.dist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - /src-cleverage_process/Tests - - - diff --git a/Resources/tests/environment/sf3/src/Kernel.php b/Resources/tests/environment/sf3/src/Kernel.php deleted file mode 100644 index f9f1c817..00000000 --- a/Resources/tests/environment/sf3/src/Kernel.php +++ /dev/null @@ -1,72 +0,0 @@ -getProjectDir().'/var/cache/'.$this->environment; - } - - public function getLogDir() - { - return $this->getProjectDir().'/var/log'; - } - - /** - * Override the default native Kernel build to set public services that will be used for tests - * - * @param ContainerBuilder $container - */ - protected function build(ContainerBuilder $container) - { - $container->addCompilerPass(new SetPublicServicesCompilerPass()); - } - - public function registerBundles() - { - $contents = require $this->getProjectDir().'/config/bundles.php'; - foreach ($contents as $class => $envs) { - if ($envs[$this->environment] ?? $envs['all'] ?? false) { - yield new $class(); - } - } - } - - protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) - { - $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); - // Feel free to remove the "container.autowiring.strict_mode" parameter - // if you are using symfony/dependency-injection 4.0+ as it's the default behavior - $container->setParameter('container.autowiring.strict_mode', true); - $container->setParameter('container.dumper.inline_class_loader', true); - $confDir = $this->getProjectDir().'/config'; - - $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); - } - - protected function configureRoutes(RouteCollectionBuilder $routes) - { - $confDir = $this->getProjectDir().'/config'; - - $routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob'); - $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); - $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); - } -} diff --git a/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php b/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php deleted file mode 100644 index 43389bc2..00000000 --- a/Resources/tests/environment/sf3/src/SetPublicServicesCompilerPass.php +++ /dev/null @@ -1,27 +0,0 @@ -getDefinition(ProcessManager::class)->setPublic(true); - $container->getDefinition(ProcessConfigurationRegistry::class)->setPublic(true); - $container->getDefinition(TransformerRegistry::class)->setPublic(true); - $container->getDefinition(DataQueueEventListener::class)->setPublic(true); - $container->getDefinition(ProcessLogger::class)->setPublic(true); - $container->getDefinition(TaskLogger::class)->setPublic(true); - $container->getDefinition(ContextualOptionResolver::class)->setPublic(true); - } -} diff --git a/Resources/tests/environment/sf4/composer.json b/Resources/tests/environment/sf4/composer.json deleted file mode 100644 index 6736c0c2..00000000 --- a/Resources/tests/environment/sf4/composer.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "type": "project", - "license": "proprietary", - "require": { - "symfony/framework-bundle": "^4.4", - "symfony/dotenv": "^4.4", - "symfony/flex": "^1.11", - - "symfony/event-dispatcher-contracts": "~1.0|~2.0", - "psr/event-dispatcher": "1.0.0", - "symfony/config": "~4.0", - "symfony/dependency-injection": "~4.0", - "symfony/expression-language": "~4.0", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "~4.0", - "symfony/options-resolver": "~4.0", - "symfony/process": "~4.0", - "symfony/property-access": "~4.0", - "symfony/serializer": "~4.0", - "symfony/validator": "~4.0", - "symfony/yaml": "~4.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4|^5.0", - "phpunit/phpunit": "~6.4", - "phpstan/phpstan": "*", - "phpstan/phpstan-symfony": "*", - "phpstan/extension-installer": "*" - }, - "autoload": { - "psr-4": { - "App\\": "src/", - "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" - } - }, - "autoload-dev": { - "psr-4": { - "App\\Tests\\": "tests/" - } - }, - "scripts": { - "auto-scripts": { - "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" - }, - "post-install-cmd": [ - "@auto-scripts" - ], - "post-update-cmd": [ - "@auto-scripts" - ] - }, - "config": { - "allow-plugins": { - "phpstan/extension-installer": true, - "symfony/flex": true - } - } -} diff --git a/Resources/tests/environment/sf4/config/bundles.php b/Resources/tests/environment/sf4/config/bundles.php deleted file mode 100644 index d1a265ef..00000000 --- a/Resources/tests/environment/sf4/config/bundles.php +++ /dev/null @@ -1,7 +0,0 @@ - ['all' => true], - CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], - Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], -]; diff --git a/Resources/tests/environment/sf4/config/packages/framework.yaml b/Resources/tests/environment/sf4/config/packages/framework.yaml deleted file mode 100644 index 5a1678d2..00000000 --- a/Resources/tests/environment/sf4/config/packages/framework.yaml +++ /dev/null @@ -1,10 +0,0 @@ -framework: - secret: '%env(APP_SECRET)%' - - serializer: - enabled: true - - #esi: true - #fragments: true - php_errors: - log: true diff --git a/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml b/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml deleted file mode 100644 index a03e25d8..00000000 --- a/Resources/tests/environment/sf4/config/packages/test/cleverage_process.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/Resources/tests/environment/sf4/phpunit.xml.dist b/Resources/tests/environment/sf4/phpunit.xml.dist deleted file mode 100644 index fbdc9945..00000000 --- a/Resources/tests/environment/sf4/phpunit.xml.dist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - /src-cleverage_process/Tests - - - diff --git a/composer.json b/composer.json index 1fa67ca9..0e94b35f 100644 --- a/composer.json +++ b/composer.json @@ -37,29 +37,29 @@ } }, "require": { - "php": ">=7.2", + "php": ">=8.1", "ext-json": "*", "ext-dom": "*", "ext-intl": "*", - "symfony/event-dispatcher-contracts": "~1.0|~2.0", - "psr/event-dispatcher": "1.0.0", + "ext-mbstring": "*", + "symfony/event-dispatcher": "^5.4|^6.0", "psr/cache": "^1|^2|^3", - "symfony/config": "~3.0|~4.0|~5.0", - "symfony/dependency-injection": "~3.0|~4.0|~5.0", - "symfony/framework-bundle": "~3.0|~4.0|~5.0", - "symfony/expression-language": "~3.0|~4.0|~5.0", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", "symfony/monolog-bundle": "~3.3", - "symfony/console": "~3.0|~4.0|~5.0", - "symfony/options-resolver": "~3.0|~4.0|~5.0", - "symfony/process": "~3.0|~4.0|~5.0", - "symfony/property-access": "~3.0|~4.0|~5.0", - "symfony/serializer": "~3.0|~4.0|~5.0", - "symfony/validator": "~3.0|~4.0|~5.0", - "symfony/yaml": "~3.0|~4.0|~5.0" + "symfony/console": "^5.4|^6.0", + "symfony/options-resolver": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" }, "require-dev": { "roave/security-advisories": "dev-latest", - "phpunit/phpunit": "~6.4", + "phpunit/phpunit": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", "phpstan/extension-installer": "*" From d68650a521495e26955b9db619fc43025ba1b825 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:36:16 +0100 Subject: [PATCH 153/304] phpstan level 1 --- DependencyInjection/Configuration.php | 16 ++----- EventDispatcher/BackcompatEventDispatcher.php | 44 ------------------- Resources/config/services/command.yml | 2 +- Resources/config/services/event.yml | 2 +- Resources/config/services/manager.yml | 2 +- Resources/config/services/task.yml | 2 +- Task/Process/CommandRunnerTask.php | 3 +- Transformer/Xml/XpathEvaluatorTransformer.php | 4 +- Validator/ConstraintLoader.php | 5 +-- composer.json | 4 +- phpstan.neon | 2 + 11 files changed, 17 insertions(+), 69 deletions(-) delete mode 100644 EventDispatcher/BackcompatEventDispatcher.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 57aad899..9cfba742 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -46,7 +46,7 @@ public function __construct($root = 'clever_age_process') */ public function getConfigTreeBuilder() { - [$treeBuilder, $rootNode] = $this->createTreeBuilder($this->root); + [$treeBuilder, $rootNode] = $this->createTreeBuilder(); $definition = $rootNode->children(); // Default error strategy $definition->enumNode('default_error_strategy') @@ -224,18 +224,10 @@ protected function deprecateNode(NodeDefinition $node, string $package, string $ * * @return array A tuple containing [TreeBuilder, NodeDefinition] */ - protected function createTreeBuilder(string $root): array + protected function createTreeBuilder(): array { - $treeBuilderReflection = new \ReflectionClass(TreeBuilder::class); - $treeBuilderConstructReflection = $treeBuilderReflection->getConstructor(); - - if ($treeBuilderConstructReflection && $treeBuilderConstructReflection->getNumberOfParameters() > 0) { - $treeBuilder = new TreeBuilder($this->root); - $rootNode = $treeBuilder->getRootNode(); - } else { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root($this->root); - } + $treeBuilder = new TreeBuilder($this->root); + $rootNode = $treeBuilder->getRootNode(); return [$treeBuilder, $rootNode]; } diff --git a/EventDispatcher/BackcompatEventDispatcher.php b/EventDispatcher/BackcompatEventDispatcher.php deleted file mode 100644 index 9ff83377..00000000 --- a/EventDispatcher/BackcompatEventDispatcher.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -class BackcompatEventDispatcher implements PsrEventDispatcherInterface -{ - /** @var EventDispatcherInterface */ - private $dispatcher; - - public function __construct(EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - } - - public function dispatch($event, string $eventName = null) - { - if($this->dispatcher instanceof ContractsEventDispatcherInterface) { - // This should match most recent Sf version - $this->dispatcher->dispatch($event, $eventName); - } else { - // Back-compatibility with Sf3 style dispatcher - $this->dispatcher->dispatch($eventName, $event); - } - } -} diff --git a/Resources/config/services/command.yml b/Resources/config/services/command.yml index eecb9004..65e75535 100644 --- a/Resources/config/services/command.yml +++ b/Resources/config/services/command.yml @@ -4,5 +4,5 @@ services: autowire: true autoconfigure: true bind: - $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' + $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' $container: '@service_container' diff --git a/Resources/config/services/event.yml b/Resources/config/services/event.yml index 6c1a9dac..b5a218a1 100644 --- a/Resources/config/services/event.yml +++ b/Resources/config/services/event.yml @@ -1,5 +1,5 @@ services: - CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher: + Symfony\Contracts\EventDispatcher\EventDispatcherInterface: public: false autowire: true diff --git a/Resources/config/services/manager.yml b/Resources/config/services/manager.yml index 2aa51fdb..8ba5e8e6 100644 --- a/Resources/config/services/manager.yml +++ b/Resources/config/services/manager.yml @@ -3,7 +3,7 @@ services: autowire: true public: false arguments: - $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' + $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' $container: '@service_container' CleverAge\ProcessBundle\Context\ContextualOptionResolver: diff --git a/Resources/config/services/task.yml b/Resources/config/services/task.yml index 98c9804a..983e442a 100644 --- a/Resources/config/services/task.yml +++ b/Resources/config/services/task.yml @@ -7,4 +7,4 @@ services: tags: - { name: monolog.logger, channel: cleverage_process_task } bind: - $eventDispatcher: '@CleverAge\ProcessBundle\EventDispatcher\BackcompatEventDispatcher' + $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' diff --git a/Task/Process/CommandRunnerTask.php b/Task/Process/CommandRunnerTask.php index 499ec68c..6b0a79fe 100644 --- a/Task/Process/CommandRunnerTask.php +++ b/Task/Process/CommandRunnerTask.php @@ -47,9 +47,8 @@ public function execute(ProcessState $state): void $options['env'], $state->getInput(), $options['timeout'], - $options['options'] ); - $process->inheritEnvironmentVariables(true); + $process->setOptions($options); $process->mustRun(); $state->setOutput($process->getOutput()); } diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php index 53404f6b..dbfb985c 100644 --- a/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -92,7 +92,7 @@ public function transform($value, array $options = []) $query = $options['query']; if (\is_array($query)) { - $result = \array_map(function ($subquery) use ($xpath, $value, $options) { + $result = \array_map(function ($subquery) use ($xpath, $value) { return $this->query($xpath, $subquery['subquery'], $value, $subquery); }, $query); } else { @@ -138,7 +138,7 @@ public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $op // Convert results to text if ($options['unwrap_value']) { - $results = \array_map(function (\DOMNode $item) use ($query, $options) { + $results = \array_map(function (\DOMNode $item) use ($query) { if ($item instanceof \DOMAttr) { return $item->value; } diff --git a/Validator/ConstraintLoader.php b/Validator/ConstraintLoader.php index 765caf13..2aa21432 100644 --- a/Validator/ConstraintLoader.php +++ b/Validator/ConstraintLoader.php @@ -15,10 +15,7 @@ class ConstraintLoader extends AbstractLoader { - /** - * @return bool - */ - public function loadClassMetadata(ClassMetadata $metadata) + public function loadClassMetadata(ClassMetadata $metadata): bool { return false; } diff --git a/composer.json b/composer.json index 0e94b35f..1e8a5ede 100644 --- a/composer.json +++ b/composer.json @@ -46,6 +46,7 @@ "psr/cache": "^1|^2|^3", "symfony/config": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", "symfony/framework-bundle": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/monolog-bundle": "~3.3", @@ -55,7 +56,8 @@ "symfony/property-access": "^5.4|^6.0", "symfony/serializer": "^5.4|^6.0", "symfony/validator": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0", + "league/flysystem-bundle": "^3.1" }, "require-dev": { "roave/security-advisories": "dev-latest", diff --git a/phpstan.neon b/phpstan.neon index 0489d450..12b90523 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,4 +4,6 @@ parameters: - . excludePaths: - vendor/* + - Resources/tests/* + - Tests/* - rector.php From f5cfa247028100467a1253a6eefa2250333f603c Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:39:18 +0100 Subject: [PATCH 154/304] add rector --- composer.json | 3 ++- rector.php | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 rector.php diff --git a/composer.json b/composer.json index 1e8a5ede..476e203a 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,8 @@ "phpunit/phpunit": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", - "phpstan/extension-installer": "*" + "phpstan/extension-installer": "*", + "rector/rector": "*" }, "suggest": { "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..390b8b48 --- /dev/null +++ b/rector.php @@ -0,0 +1,36 @@ +paths([ + __DIR__ . '/Command', + __DIR__ . '/Configuration', + __DIR__ . '/Context', + __DIR__ . '/DependencyInjection', + __DIR__ . '/Event', + __DIR__ . '/EventDispatcher', + __DIR__ . '/EventListener', + __DIR__ . '/Exception', + __DIR__ . '/ExpressionLanguage', + __DIR__ . '/Filesystem', + __DIR__ . '/Logger', + __DIR__ . '/Manager', + __DIR__ . '/Model', + __DIR__ . '/Registry', + __DIR__ . '/Resources', + __DIR__ . '/Task', + __DIR__ . '/Tests', + __DIR__ . '/Transformer', + __DIR__ . '/Validator', + ]); + + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_81, + SymfonyLevelSetList::UP_TO_SYMFONY_54 + ]); +}; From ff8c4f16882b343efd81ae7462cd68243356310a Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:41:58 +0100 Subject: [PATCH 155/304] phpstan level 2 --- Task/Validation/ValidatorTask.php | 2 +- phpstan.neon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index 16c6bb10..7c2d364d 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -61,7 +61,7 @@ public function execute(ProcessState $state) ); if (0 < $violations->count()) { - /** @var $violation ConstraintViolationInterface */ + /** @var ConstraintViolationInterface $violation */ foreach ($violations as $violation) { $invalidValue = $violation->getInvalidValue(); diff --git a/phpstan.neon b/phpstan.neon index 12b90523..5d2e301a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 1 + level: 2 paths: - . excludePaths: From c2bf920f75821d177a125bd83e741a53d4741898 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:48:49 +0100 Subject: [PATCH 156/304] rector --- Configuration/ProcessConfiguration.php | 36 ++++--------------- Configuration/TaskConfiguration.php | 12 ++----- .../Compiler/RegistryCompilerPass.php | 14 +------- DependencyInjection/Configuration.php | 6 +--- Exception/TransformerException.php | 8 ++--- Filesystem/CsvFile.php | 7 +--- Filesystem/CsvResource.php | 18 ++-------- rector.php | 11 +++--- 8 files changed, 23 insertions(+), 89 deletions(-) diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index f452148e..63cd03ff 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -21,27 +21,9 @@ */ class ProcessConfiguration { - /** @var string */ - protected $code; - /** @var array */ protected $options = []; - /** @var TaskConfiguration */ - protected $entryPoint; - - /** @var TaskConfiguration */ - protected $endPoint; - - /** @var string */ - protected $description; - - /** @var string */ - protected $help; - - /** @var bool */ - protected $public; - /** @var TaskConfiguration[] */ protected $taskConfigurations; @@ -62,23 +44,17 @@ class ProcessConfiguration * @param bool $public */ public function __construct( - $code, + protected $code, array $taskConfigurations, array $options = [], - $entryPoint = null, - $endPoint = null, - $description = '', - $help = '', - $public = true + protected $entryPoint = null, + protected $endPoint = null, + protected $description = '', + protected $help = '', + protected $public = true ) { - $this->code = $code; $this->taskConfigurations = $taskConfigurations; $this->options = $options; - $this->entryPoint = $entryPoint; - $this->endPoint = $endPoint; - $this->description = $description; - $this->public = $public; - $this->help = $help; } /** diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index cbb47591..b90e4150 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -25,12 +25,6 @@ class TaskConfiguration public const STRATEGY_SKIP = 'skip'; public const STRATEGY_STOP = 'stop'; - /** @var string */ - protected $code; - - /** @var string */ - protected $serviceReference; - /** @var TaskInterface */ protected $task; @@ -85,8 +79,8 @@ class TaskConfiguration * @param string $logLevel */ public function __construct( - $code, - $serviceReference, + protected $code, + protected $serviceReference, array $options, string $description = '', string $help = '', @@ -95,8 +89,6 @@ public function __construct( string $errorStrategy = self::STRATEGY_SKIP, string $logLevel = LogLevel::CRITICAL ) { - $this->code = $code; - $this->serviceReference = $serviceReference; $this->options = $options; $this->description = $description; $this->help = $help; diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/DependencyInjection/Compiler/RegistryCompilerPass.php index be19999f..620c823c 100644 --- a/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -24,25 +24,13 @@ */ class RegistryCompilerPass implements CompilerPassInterface { - /** @var string */ - protected $registry; - - /** @var string */ - protected $tag; - - /** @var string */ - protected $method; - /** * @param string $registry * @param string $tag * @param string $method */ - public function __construct($registry, $tag, $method) + public function __construct(protected $registry, protected $tag, protected $method) { - $this->registry = $registry; - $this->tag = $tag; - $this->method = $method; } /** diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 9cfba742..3c534722 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -28,15 +28,11 @@ */ class Configuration implements ConfigurationInterface { - /** @var string */ - protected $root; - /** * @param string $root */ - public function __construct($root = 'clever_age_process') + public function __construct(protected $root = 'clever_age_process') { - $this->root = $root; } /** diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index e9a2c9c5..62568b0b 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -18,19 +18,15 @@ */ class TransformerException extends \RuntimeException implements ProcessExceptionInterface { - /** @var string */ - protected $transformerCode; - /** @var string */ protected $targetProperty; /** * {@inheritDoc} + * @param string $transformerCode */ - public function __construct($transformerCode, $code = 0, \Throwable $previous = null) + public function __construct(protected $transformerCode, $code = 0, \Throwable $previous = null) { - $this->transformerCode = $transformerCode; - parent::__construct('', $code, $previous); $this->updateMessage(); } diff --git a/Filesystem/CsvFile.php b/Filesystem/CsvFile.php index e14eecd4..2177184a 100644 --- a/Filesystem/CsvFile.php +++ b/Filesystem/CsvFile.php @@ -18,9 +18,6 @@ */ class CsvFile extends CsvResource { - /** @var string */ - protected $filePath; - /** * @param string $filePath Also accept a resource * @param string $delimiter CSV delimiter @@ -33,15 +30,13 @@ class CsvFile extends CsvResource * @throws \UnexpectedValueException */ public function __construct( - $filePath, + protected $filePath, $delimiter = ',', $enclosure = '"', $escape = '\\', array $headers = null, $mode = 'rb' ) { - $this->filePath = $filePath; - if (!\in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'])) { $dirname = \dirname($this->filePath); if (!@mkdir($dirname, 0755, true) && !is_dir($dirname)) { diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index b660d0de..899abdbd 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -18,15 +18,6 @@ */ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterface { - /** @var string */ - protected $delimiter; - - /** @var string */ - protected $enclosure; - - /** @var string */ - protected $escape; - /** @var resource */ protected $handler; @@ -62,18 +53,15 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf */ public function __construct( $resource, - $delimiter = ',', - $enclosure = '"', - $escape = '\\', + protected $delimiter = ',', + protected $enclosure = '"', + protected $escape = '\\', array $headers = null ) { if (!\is_resource($resource)) { $type = \gettype($resource); throw new \UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); } - $this->delimiter = $delimiter; - $this->enclosure = $enclosure; - $this->escape = $escape; $this->handler = $resource; $this->headers = $this->parseHeaders($headers); diff --git a/rector.php b/rector.php index 390b8b48..197e6545 100644 --- a/rector.php +++ b/rector.php @@ -3,8 +3,7 @@ declare(strict_types=1); use Rector\Config\RectorConfig; -use Rector\Set\ValueObject\LevelSetList; -use Rector\Symfony\Set\SymfonyLevelSetList; +use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ @@ -29,8 +28,12 @@ __DIR__ . '/Validator', ]); - $rectorConfig->sets([ + $rectorConfig->rules([ + ClassPropertyAssignToConstructorPromotionRector::class + ]); + + /*$rectorConfig->sets([ LevelSetList::UP_TO_PHP_81, SymfonyLevelSetList::UP_TO_SYMFONY_54 - ]); + ]);*/ }; From 1f0daeca112c0b82f1af6bab5e5c69a881c70d06 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:49:00 +0100 Subject: [PATCH 157/304] rector --- Event/ProcessEvent.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Event/ProcessEvent.php b/Event/ProcessEvent.php index 6c5fb303..1b480176 100644 --- a/Event/ProcessEvent.php +++ b/Event/ProcessEvent.php @@ -25,12 +25,6 @@ class ProcessEvent extends GenericEvent /** @var string */ protected $processCode; - /** @var mixed */ - protected $processInput; - - /** @var mixed */ - protected $processOutput; - /** @var array */ protected $processContext; @@ -48,14 +42,12 @@ class ProcessEvent extends GenericEvent */ public function __construct( string $processCode, - $processInput = null, + protected $processInput = null, array $processContext = [], - $processOutput = null, + protected $processOutput = null, \Throwable $processError = null ) { $this->processCode = $processCode; - $this->processInput = $processInput; - $this->processOutput = $processOutput; $this->processContext = $processContext; $this->processError = $processError; } From 8696283df9a7bc8c0bdf28ab26aa00fd7b4be22d Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:49:04 +0100 Subject: [PATCH 158/304] rector --- Event/ConsoleProcessEvent.php | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 5a707692..6c5aae31 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -20,32 +20,16 @@ class ConsoleProcessEvent extends GenericEvent { const EVENT_CLI_INIT = 'cleverage_process.cli.init'; - /** @var InputInterface */ - private $consoleInput; - - /** @var OutputInterface */ - private $consoleOutput; - - /** @var mixed */ - private $processInput; - - /** @var array */ - private $processContext; - /** * ConsoleProcessEvent constructor. * - * @param InputInterface $input - * @param OutputInterface $output + * @param InputInterface $consoleInput + * @param OutputInterface $consoleOutput * @param mixed $processInput * @param array $processContext */ - public function __construct(InputInterface $input, OutputInterface $output, $processInput, array $processContext) + public function __construct(private InputInterface $consoleInput, private OutputInterface $consoleOutput, private $processInput, private array $processContext) { - $this->consoleInput = $input; - $this->consoleOutput = $output; - $this->processInput = $processInput; - $this->processContext = $processContext; } From 46d6a265b63057a6ce535b0eefb9f050e479f8be Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:53:33 +0100 Subject: [PATCH 159/304] rector --- Configuration/ProcessConfiguration.php | 36 +--------- Configuration/TaskConfiguration.php | 73 +-------------------- DependencyInjection/Configuration.php | 27 ++------ Exception/TransformerException.php | 9 ++- Filesystem/CsvResource.php | 91 +++++++++----------------- Filesystem/WritableFileInterface.php | 2 - rector.php | 18 +++-- 7 files changed, 56 insertions(+), 200 deletions(-) diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index 63cd03ff..a3659081 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -36,7 +36,6 @@ class ProcessConfiguration /** * @param string $code * @param TaskConfiguration[] $taskConfigurations - * @param array $options * @param string $entryPoint * @param string $endPoint * @param string $description @@ -57,17 +56,11 @@ public function __construct( $this->options = $options; } - /** - * @return string - */ public function getCode(): string { return $this->code; } - /** - * @return array - */ public function getOptions(): array { return $this->options; @@ -75,8 +68,6 @@ public function getOptions(): array /** * @throws MissingTaskConfigurationException - * - * @return TaskConfiguration|null */ public function getEntryPoint(): ?TaskConfiguration { @@ -89,8 +80,6 @@ public function getEntryPoint(): ?TaskConfiguration /** * @throws MissingTaskConfigurationException - * - * @return TaskConfiguration|null */ public function getEndPoint(): ?TaskConfiguration { @@ -101,33 +90,21 @@ public function getEndPoint(): ?TaskConfiguration return $this->getTaskConfiguration($this->endPoint); } - /** - * @return string - */ public function getDescription(): string { return $this->description; } - /** - * @return string - */ public function getHelp(): string { return $this->help; } - /** - * @return bool - */ public function isPublic(): bool { return $this->public; } - /** - * @return bool - */ public function isPrivate(): bool { return !$this->public; @@ -142,11 +119,9 @@ public function getTaskConfigurations(): array } /** - * @param string $taskCode * * @throws MissingTaskConfigurationException * - * @return TaskConfiguration */ public function getTaskConfiguration(string $taskCode): TaskConfiguration { @@ -163,8 +138,6 @@ public function getTaskConfiguration(string $taskCode): TaskConfiguration * If one task depend from another, it should come after * * @throws MissingTaskConfigurationException - * - * @return array */ public function getDependencyGroups(): array { @@ -198,8 +171,6 @@ public function getDependencyGroups(): array * If one task depend from another, it should come after * * @throws MissingTaskConfigurationException - * - * @return array */ public function getMainTaskGroup(): array { @@ -272,10 +243,7 @@ public function checkCircularDependencies(): void /** * Cross all relations of a task to find all dependencies, and append them to the given array * - * @param TaskConfiguration $taskConfig - * @param array $dependencies * - * @return array */ protected function buildDependencies(TaskConfiguration $taskConfig, array &$dependencies = []): array { @@ -304,11 +272,9 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe /** * Sort the tasks by dependencies * - * @param array $dependencies * * @throws MissingTaskConfigurationException * - * @return array */ protected function sortDependencies(array $dependencies): array { @@ -318,7 +284,7 @@ protected function sortDependencies(array $dependencies): array try { $this->checkCircularDependencies(); - } catch (CircularProcessException $e) { + } catch (CircularProcessException) { // Skipping the sort phase, it will throw later, on runtime return $dependencies; } diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index b90e4150..a1f7904c 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -22,8 +22,8 @@ */ class TaskConfiguration { - public const STRATEGY_SKIP = 'skip'; - public const STRATEGY_STOP = 'stop'; + final public const STRATEGY_SKIP = 'skip'; + final public const STRATEGY_STOP = 'stop'; /** @var TaskInterface */ protected $task; @@ -70,13 +70,6 @@ class TaskConfiguration /** * @param string $code * @param string $serviceReference - * @param array $options - * @param string $description - * @param string $help - * @param array $outputs - * @param array $errorOutputs - * @param string $errorStrategy - * @param string $logLevel */ public function __construct( protected $code, @@ -99,17 +92,11 @@ public function __construct( $this->logErrors = $logLevel !== LogLevel::DEBUG; // @deprecated, remove me in next version } - /** - * @return string - */ public function getCode(): string { return $this->code; } - /** - * @return string - */ public function getServiceReference(): string { return $this->serviceReference; @@ -123,33 +110,21 @@ public function getTask(): ?TaskInterface return $this->task; } - /** - * @param TaskInterface $task - */ public function setTask(TaskInterface $task) { $this->task = $task; } - /** - * @return string - */ public function getDescription(): string { return $this->description; } - /** - * @return string - */ public function getHelp(): string { return $this->help; } - /** - * @return array - */ public function getOptions(): array { return $this->options; @@ -157,11 +132,10 @@ public function getOptions(): array /** * @param string $code - * @param mixed $default * * @return mixed */ - public function getOption($code, $default = null) + public function getOption($code, mixed $default = null) { if (array_key_exists($code, $this->options)) { return $this->options[$code]; @@ -170,16 +144,12 @@ public function getOption($code, $default = null) return $default; } - /** - * @return array - */ public function getOutputs(): array { return $this->outputs; } /** - * @return array * @deprecated Use getErrorOutputs method instead * */ @@ -190,25 +160,16 @@ public function getErrors(): array return $this->getErrorOutputs(); } - /** - * @return array - */ public function getErrorOutputs(): array { return $this->errorOutputs; } - /** - * @return ProcessState - */ public function getState(): ProcessState { return $this->state; } - /** - * @param ProcessState $state - */ public function setState(ProcessState $state) { $this->state = $state; @@ -222,9 +183,6 @@ public function getNextTasksConfigurations(): array return $this->nextTasksConfigurations; } - /** - * @param TaskConfiguration $nextTaskConfiguration - */ public function addNextTaskConfiguration(TaskConfiguration $nextTaskConfiguration) { $this->nextTasksConfigurations[] = $nextTaskConfiguration; @@ -238,9 +196,6 @@ public function getPreviousTasksConfigurations(): array return $this->previousTasksConfigurations; } - /** - * @param TaskConfiguration $previousTaskConfiguration - */ public function addPreviousTaskConfiguration(TaskConfiguration $previousTaskConfiguration) { $this->previousTasksConfigurations[] = $previousTaskConfiguration; @@ -254,33 +209,21 @@ public function getErrorTasksConfigurations(): array return $this->errorTasksConfigurations; } - /** - * @param TaskConfiguration $errorTaskConfiguration - */ public function addErrorTaskConfiguration(TaskConfiguration $errorTaskConfiguration) { $this->errorTasksConfigurations[] = $errorTaskConfiguration; } - /** - * @return bool - */ public function isInErrorBranch(): bool { return $this->inErrorBranch; } - /** - * @param bool $inErrorBranch - */ public function setInErrorBranch(bool $inErrorBranch) { $this->inErrorBranch = $inErrorBranch; } - /** - * @return bool - */ public function isRoot(): bool { return empty($this->getPreviousTasksConfigurations()) && !$this->isInErrorBranch(); @@ -289,7 +232,6 @@ public function isRoot(): bool /** * Check task ancestors to find if it have a given task as parent * - * @param TaskConfiguration $taskConfig * * @return bool */ @@ -316,9 +258,7 @@ public function hasAncestor(TaskConfiguration $taskConfig) /** * Check task ancestors to find if it have a given task as child * - * @param TaskConfiguration $taskConfig * @param bool $checkErrors - * * @return bool */ public function hasDescendant(TaskConfiguration $taskConfig, $checkErrors = true) @@ -358,24 +298,17 @@ public function hasDescendant(TaskConfiguration $taskConfig, $checkErrors = true return false; } - /** - * @return string - */ public function getErrorStrategy(): string { return $this->errorStrategy; } - /** - * @return string - */ public function getLogLevel(): string { return $this->logLevel; } /** - * @return bool * @deprecated Use getLogLevel instead * */ diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3c534722..951db4d7 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -10,6 +10,8 @@ namespace CleverAge\ProcessBundle\DependencyInjection; +use RuntimeException; +use ReflectionMethod; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use Psr\Log\LogLevel; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; @@ -38,7 +40,7 @@ public function __construct(protected $root = 'clever_age_process') /** * {@inheritdoc} * - * @throws \RuntimeException + * @throws RuntimeException */ public function getConfigTreeBuilder() { @@ -62,8 +64,6 @@ public function getConfigTreeBuilder() /** * "generic_transformers" root configuration - * - * @param NodeBuilder $definition */ protected function appendRootTransformersConfigDefinition(NodeBuilder $definition) { @@ -84,8 +84,6 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio /** * Single transformer configuration - * - * @param NodeBuilder $definition */ protected function appendTransformerConfigDefinition(NodeBuilder $definition) { @@ -97,8 +95,6 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition) /** * "configurations" root configuration * @TODO rename this root as "processes" - * - * @param NodeBuilder $definition */ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) { @@ -117,9 +113,6 @@ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) $this->appendProcessConfigDefinition($processListDefinition); } - /** - * @param NodeBuilder $definition - */ protected function appendProcessConfigDefinition(NodeBuilder $definition) { $definition @@ -146,9 +139,6 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition) $this->appendTaskConfigDefinition($taskListDefinition); } - /** - * @param NodeBuilder $definition - */ protected function appendTaskConfigDefinition(NodeBuilder $definition) { $logLevels = [ @@ -181,9 +171,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) $definition->arrayNode($nodeName) ->beforeNormalization() ->ifString()->then( - function ($item) { - return [$item]; - } + fn($item) => [$item] )->end() ->prototype('scalar'); } @@ -194,15 +182,10 @@ function ($item) { * Provides compatibility with Sf3, 4 and 5 * * @TODO remove this once support for Symfony 3 and 4 is dropped - * - * @param NodeDefinition $node - * @param string $package - * @param string $version - * @param string $message */ protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message) { - $deprecationMethodReflection = new \ReflectionMethod(NodeDefinition::class, 'setDeprecated'); + $deprecationMethodReflection = new ReflectionMethod(NodeDefinition::class, 'setDeprecated'); if ($deprecationMethodReflection->getNumberOfParameters() === 1) { $node->setDeprecated("Since {$package} {$version}: {$message}"); } else { diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index 62568b0b..fd7efbc5 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -10,13 +10,15 @@ namespace CleverAge\ProcessBundle\Exception; +use RuntimeException; +use Throwable; /** * Runtime error that should wrap any Transformation error * * @author Valentin Clavreul * @author Vincent Chalnot */ -class TransformerException extends \RuntimeException implements ProcessExceptionInterface +class TransformerException extends RuntimeException implements ProcessExceptionInterface { /** @var string */ protected $targetProperty; @@ -25,15 +27,12 @@ class TransformerException extends \RuntimeException implements ProcessException * {@inheritDoc} * @param string $transformerCode */ - public function __construct(protected $transformerCode, $code = 0, \Throwable $previous = null) + public function __construct(protected $transformerCode, $code = 0, Throwable $previous = null) { parent::__construct('', $code, $previous); $this->updateMessage(); } - /** - * @param string $targetProperty - */ public function setTargetProperty(string $targetProperty): void { $this->targetProperty = $targetProperty; diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index 899abdbd..70bf3d46 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -10,6 +10,9 @@ namespace CleverAge\ProcessBundle\Filesystem; +use UnexpectedValueException; +use RuntimeException; +use LogicException; /** * Read and write CSV resources through a simple API. * @@ -49,7 +52,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf * @param string $escape * @param array $headers Leave null to read the headers from the file * - * @throws \UnexpectedValueException + * @throws UnexpectedValueException */ public function __construct( $resource, @@ -60,7 +63,7 @@ public function __construct( ) { if (!\is_resource($resource)) { $type = \gettype($resource); - throw new \UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); + throw new UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); } $this->handler = $resource; @@ -68,25 +71,16 @@ public function __construct( $this->headerCount = \count($this->headers); } - /** - * @return string - */ public function getDelimiter(): string { return $this->delimiter; } - /** - * @return string - */ public function getEnclosure(): string { return $this->enclosure; } - /** - * @return string - */ public function getEscape(): string { return $this->escape; @@ -108,8 +102,7 @@ public function getHandler() * This can be very slow. * * @return int - *@throws \RuntimeException - * + * @throws RuntimeException */ public function getLineCount(): int { @@ -148,7 +141,7 @@ public function getHeaderCount(): int /** * Write headers to the file * - * @throws \RuntimeException + * @throws RuntimeException */ public function writeHeaders(): void { @@ -161,14 +154,14 @@ public function writeHeaders(): void public function getLineNumber(): int { if ($this->seekCalled) { - throw new \LogicException('Cannot get current line number after calling "seek": the line number is lost'); + throw new LogicException('Cannot get current line number after calling "seek": the line number is lost'); } return $this->lineNumber; } /** - * @throws \RuntimeException + * @throws RuntimeException * * @return bool */ @@ -184,11 +177,9 @@ public function isEndOfFile(): bool * * @param null|int $length * - * @throws \RuntimeException - * - * @return array|false + * @throws RuntimeException */ - public function readRaw($length = null) + public function readRaw($length = null): array|false { $this->assertOpened(); ++$this->lineNumber; @@ -199,8 +190,8 @@ public function readRaw($length = null) /** * @param int|null $length * - * @throws \UnexpectedValueException - * @throws \RuntimeException + * @throws UnexpectedValueException + * @throws RuntimeException * * @return array */ @@ -218,19 +209,19 @@ public function readLine($length = null): ?array return null; } $message = "Unable to parse data {$filePosition} for {$this->getResourceName()}"; - throw new \UnexpectedValueException($message); + throw new UnexpectedValueException($message); } $count = \count($values); if ($count !== $this->headerCount) { $message = "Number of columns not matching {$filePosition} for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; - throw new \UnexpectedValueException($message); + throw new UnexpectedValueException($message); } $combined = array_combine($this->headers, $values); if (false === $combined) { - throw new \RuntimeException('Cannot combine headers with values'); + throw new RuntimeException('Cannot combine headers with values'); } return $combined; @@ -239,11 +230,8 @@ public function readLine($length = null): ?array /** * Warning, this function will return exactly the same value as the fgetcsv() function. * - * @param array $fields - * - * @throws \RuntimeException * - * @return int + * @throws RuntimeException */ public function writeRaw(array $fields): int { @@ -256,7 +244,7 @@ public function writeRaw(array $fields): int /** * @param array $fields * - * @throws \RuntimeException + * @throws RuntimeException * * @return int */ @@ -266,21 +254,21 @@ public function writeLine(array $fields): int if ($count !== $this->headerCount) { $message = "Trying to write an invalid number of columns for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; - throw new \UnexpectedValueException($message); + throw new UnexpectedValueException($message); } $parsedFields = []; foreach ($this->headers as $column) { if (!array_key_exists($column, $fields)) { $message = "Missing column {$column} in given fields for {$this->getResourceName()}"; - throw new \UnexpectedValueException($message); + throw new UnexpectedValueException($message); } $parsedFields[$column] = $fields[$column]; } $length = $this->writeRaw($parsedFields); if (false === $length) { - throw new \RuntimeException("Unable to write data to {$this->getResourceName()}"); + throw new RuntimeException("Unable to write data to {$this->getResourceName()}"); } return $length; @@ -289,13 +277,13 @@ public function writeLine(array $fields): int /** * This methods rewinds the file to the first line of data, skipping the headers. * - * @throws \RuntimeException + * @throws RuntimeException */ public function rewind(): void { $this->assertOpened(); if (!rewind($this->handler)) { - throw new \RuntimeException("Unable to rewind '{$this->getResourceName()}'"); + throw new RuntimeException("Unable to rewind '{$this->getResourceName()}'"); } $this->lineNumber = 1; if (!$this->manualHeaders) { @@ -304,7 +292,7 @@ public function rewind(): void } /** - * @throws \RuntimeException + * @throws RuntimeException * * @return int */ @@ -318,7 +306,7 @@ public function tell(): int /** * @param int $offset * - * @throws \RuntimeException + * @throws RuntimeException * * @return int */ @@ -330,9 +318,6 @@ public function seek($offset): int return fseek($this->handler, $offset); } - /** - * @return bool - */ public function close(): bool { if ($this->closed) { @@ -344,17 +329,11 @@ public function close(): bool return $this->closed; } - /** - * @return bool - */ public function isManualHeaders(): bool { return $this->manualHeaders; } - /** - * @return bool - */ public function isClosed(): bool { return $this->closed; @@ -369,21 +348,18 @@ public function __destruct() } /** - * @throws \RuntimeException + * @throws RuntimeException */ protected function assertOpened(): void { if ($this->closed) { - throw new \RuntimeException("{$this->getResourceName()} was closed earlier"); + throw new RuntimeException("{$this->getResourceName()} was closed earlier"); } } /** - * @param array $headers - * - * @throws \UnexpectedValueException * - * @return array + * @throws UnexpectedValueException */ protected function parseHeaders(array $headers = null): array { @@ -391,23 +367,23 @@ protected function parseHeaders(array $headers = null): array if (null === $headers) { $autoHeaders = $this->readRaw(); if (false === $autoHeaders || 0 === \count($autoHeaders)) { - throw new \UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); + throw new UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any $bom = pack('H*', 'EFBBBF'); - $autoHeaders[0] = preg_replace("/^{$bom}/", '', $autoHeaders[0]); + $autoHeaders[0] = preg_replace("/^{$bom}/", '', (string) $autoHeaders[0]); return $autoHeaders; } $this->manualHeaders = true; if (null === $headers || !\is_array($headers)) { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } if (0 === \count($headers)) { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Empty headers for {$this->getResourceName()}, you need to pass the headers manually" ); } @@ -415,9 +391,6 @@ protected function parseHeaders(array $headers = null): array return $headers; } - /** - * @return string - */ protected function getResourceName(): string { return "CSV resource '{$this->handler}'"; diff --git a/Filesystem/WritableFileInterface.php b/Filesystem/WritableFileInterface.php index 35285319..fdfa4bca 100644 --- a/Filesystem/WritableFileInterface.php +++ b/Filesystem/WritableFileInterface.php @@ -16,8 +16,6 @@ interface WritableFileInterface extends FileStreamInterface { /** - * @param array $fields - * * @return int */ public function writeLine(array $fields): int; diff --git a/rector.php b/rector.php index 197e6545..9d1db6ed 100644 --- a/rector.php +++ b/rector.php @@ -3,9 +3,15 @@ declare(strict_types=1); use Rector\Config\RectorConfig; -use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; +use Rector\Core\ValueObject\PhpVersion; +use Rector\Set\ValueObject\LevelSetList; return static function (RectorConfig $rectorConfig): void { + + $rectorConfig->parallel(); + $rectorConfig->importNames(); + $rectorConfig->importShortClasses(); + $rectorConfig->paths([ __DIR__ . '/Command', __DIR__ . '/Configuration', @@ -28,12 +34,10 @@ __DIR__ . '/Validator', ]); - $rectorConfig->rules([ - ClassPropertyAssignToConstructorPromotionRector::class + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_81, + //SymfonyLevelSetList::UP_TO_SYMFONY_54 ]); - /*$rectorConfig->sets([ - LevelSetList::UP_TO_PHP_81, - SymfonyLevelSetList::UP_TO_SYMFONY_54 - ]);*/ + $rectorConfig->phpVersion(PhpVersion::PHP_81); }; From d80b26656b4aac837636c8d71bbe401cf49297de Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 10:57:34 +0100 Subject: [PATCH 160/304] rector --- Command/ExecuteProcessCommand.php | 43 +++++++------------------ DependencyInjection/Configuration.php | 2 +- Event/ConsoleProcessEvent.php | 18 ++--------- Event/ProcessEvent.php | 45 +++++---------------------- Filesystem/CsvResource.php | 11 +++---- rector.php | 2 ++ 6 files changed, 27 insertions(+), 94 deletions(-) diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index 103354fa..e411fe45 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -10,12 +10,12 @@ namespace CleverAge\ProcessBundle\Command; +use Exception; use CleverAge\ProcessBundle\Event\ConsoleProcessEvent; use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -32,27 +32,13 @@ */ class ExecuteProcessCommand extends Command { - public const OUTPUT_STDOUT = '-'; + final public const OUTPUT_STDOUT = '-'; - public const OUTPUT_FORMAT_DUMP = 'dump'; - public const OUTPUT_FORMAT_JSON = 'json-stream'; + final public const OUTPUT_FORMAT_DUMP = 'dump'; + final public const OUTPUT_FORMAT_JSON = 'json-stream'; - /** @var ProcessManager */ - protected $processManager; - - /** @var EventDispatcherInterface */ - protected $eventDispatcher; - - /** - * ExecuteProcessCommand constructor. - * - * @param ProcessManager $processManager - * @param EventDispatcherInterface $eventDispatcher - */ - public function __construct(ProcessManager $processManager, EventDispatcherInterface $eventDispatcher) + public function __construct(protected ProcessManager $processManager, protected EventDispatcherInterface $eventDispatcher) { - $this->processManager = $processManager; - $this->eventDispatcher = $eventDispatcher; parent::__construct(); } @@ -92,7 +78,7 @@ protected function configure() * @param InputInterface $input * @param OutputInterface $output * - * @throws \Exception + * @throws Exception * * @return int|null */ @@ -132,13 +118,11 @@ protected function execute(InputInterface $input, OutputInterface $output) } /** - * @param InputInterface $input * * @throws InvalidArgumentException - * - * @return array + * @return array */ - protected function parseContextValues(InputInterface $input) + protected function parseContextValues(InputInterface $input): array { $parser = new Parser(); @@ -146,7 +130,7 @@ protected function parseContextValues(InputInterface $input) $contextValues = $input->getOption('context'); $context = []; foreach ($contextValues as $contextValue) { - preg_match($pattern, $contextValue, $parts); + preg_match($pattern, (string) $contextValue, $parts); if (3 !== \count($parts) || $parts[0] !== $contextValue) { throw new \InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); @@ -157,12 +141,7 @@ protected function parseContextValues(InputInterface $input) return $context; } - /** - * @param mixed $data - * @param InputInterface $input - * @param OutputInterface $output - */ - protected function handleOutputData($data, InputInterface $input, OutputInterface $output) + protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output) { // Skip all if undefined if (!$input->getOption('output-format')) { @@ -175,7 +154,7 @@ protected function handleOutputData($data, InputInterface $input, OutputInterfac if ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP && class_exists(VarDumper::class)) { VarDumper::dump($data); // @todo remove this please } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { - $output->writeln(json_encode($data)); + $output->writeln(json_encode($data, JSON_THROW_ON_ERROR)); } else { throw new \InvalidArgumentException( sprintf( diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 951db4d7..4c0f213c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -171,7 +171,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) $definition->arrayNode($nodeName) ->beforeNormalization() ->ifString()->then( - fn($item) => [$item] + fn($item): array => [$item] )->end() ->prototype('scalar'); } diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 6c5aae31..2273fbaa 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -18,32 +18,21 @@ */ class ConsoleProcessEvent extends GenericEvent { - const EVENT_CLI_INIT = 'cleverage_process.cli.init'; + final public const EVENT_CLI_INIT = 'cleverage_process.cli.init'; /** * ConsoleProcessEvent constructor. - * - * @param InputInterface $consoleInput - * @param OutputInterface $consoleOutput - * @param mixed $processInput - * @param array $processContext */ - public function __construct(private InputInterface $consoleInput, private OutputInterface $consoleOutput, private $processInput, private array $processContext) + public function __construct(private readonly InputInterface $consoleInput, private readonly OutputInterface $consoleOutput, private readonly mixed $processInput, private readonly array $processContext) { } - /** - * @return InputInterface - */ public function getConsoleInput(): InputInterface { return $this->consoleInput; } - /** - * @return OutputInterface - */ public function getConsoleOutput(): OutputInterface { return $this->consoleOutput; @@ -57,9 +46,6 @@ public function getProcessInput() return $this->processInput; } - /** - * @return array - */ public function getProcessContext(): array { return $this->processContext; diff --git a/Event/ProcessEvent.php b/Event/ProcessEvent.php index 1b480176..3318eba0 100644 --- a/Event/ProcessEvent.php +++ b/Event/ProcessEvent.php @@ -10,6 +10,7 @@ namespace CleverAge\ProcessBundle\Event; +use Throwable; /** * Event object for process start/stop/fail * @@ -18,43 +19,17 @@ class ProcessEvent extends GenericEvent { - const EVENT_PROCESS_STARTED = 'cleverage_process.start'; - const EVENT_PROCESS_ENDED = 'cleverage_process.end'; - const EVENT_PROCESS_FAILED = 'cleverage_process.fail'; - - /** @var string */ - protected $processCode; - - /** @var array */ - protected $processContext; - - /** @var \Throwable|null */ - protected $processError; + final public const EVENT_PROCESS_STARTED = 'cleverage_process.start'; + final public const EVENT_PROCESS_ENDED = 'cleverage_process.end'; + final public const EVENT_PROCESS_FAILED = 'cleverage_process.fail'; /** * ProcessEvent constructor. - * - * @param string $processCode - * @param mixed $processInput - * @param array $processContext - * @param mixed $processOutput - * @param \Throwable|null $processError */ - public function __construct( - string $processCode, - protected $processInput = null, - array $processContext = [], - protected $processOutput = null, - \Throwable $processError = null - ) { - $this->processCode = $processCode; - $this->processContext = $processContext; - $this->processError = $processError; + public function __construct(protected string $processCode, protected mixed $processInput = null, protected array $processContext = [], protected mixed $processOutput = null, protected ?Throwable $processError = null) + { } - /** - * @return string - */ public function getProcessCode(): string { return $this->processCode; @@ -76,18 +51,12 @@ public function getProcessOutput() return $this->processOutput; } - /** - * @return array - */ public function getProcessContext(): array { return $this->processContext; } - /** - * @return \Throwable|null - */ - public function getProcessError(): ?\Throwable + public function getProcessError(): ?Throwable { return $this->processError; } diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index 70bf3d46..d229cb11 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -27,20 +27,17 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf /** @var int|null */ protected $lineCount; - /** @var array */ - protected $headers; + protected array $headers; /** @var bool */ protected $manualHeaders = false; - /** @var int */ - protected $headerCount; + protected int $headerCount; /** @var int */ protected $lineNumber = 1; - /** @var bool */ - protected $closed; + protected bool $closed; /** @var bool */ protected $seekCalled = false; @@ -50,7 +47,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf * @param string $delimiter CSV delimiter * @param string $enclosure * @param string $escape - * @param array $headers Leave null to read the headers from the file + * @param mixed[]|null $headers Leave null to read the headers from the file * * @throws UnexpectedValueException */ diff --git a/rector.php b/rector.php index 9d1db6ed..2f32a6fb 100644 --- a/rector.php +++ b/rector.php @@ -5,6 +5,7 @@ use Rector\Config\RectorConfig; use Rector\Core\ValueObject\PhpVersion; use Rector\Set\ValueObject\LevelSetList; +use Rector\Set\ValueObject\SetList; return static function (RectorConfig $rectorConfig): void { @@ -35,6 +36,7 @@ ]); $rectorConfig->sets([ + SetList::TYPE_DECLARATION, LevelSetList::UP_TO_PHP_81, //SymfonyLevelSetList::UP_TO_SYMFONY_54 ]); From ef37240729ff247eeae66d48ffb0d83d84082175 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 11:21:19 +0100 Subject: [PATCH 161/304] ajout ecs + refacto docker --- Dockerfile | 16 ++------- Makefile | 11 +++--- Resources/tests/environment/sf5/composer.json | 35 ++++++++++--------- composer.json | 4 ++- ecs.php | 29 +++++++++++++++ phpstan.neon | 1 + rector.php | 24 +++---------- 7 files changed, 63 insertions(+), 57 deletions(-) create mode 100644 ecs.php diff --git a/Dockerfile b/Dockerfile index e971b585..5ed590e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,10 @@ -ARG PHP_VERSION=7.2 +ARG PHP_VERSION=8.1 FROM php:${PHP_VERSION}-cli # Basic tools RUN apt-get update RUN apt-get install -y wget git zip unzip -# Blackfire install -ARG BLACKFIRE_PHP_VERSION=72 -ARG BLACKFIRE_PROBE_VERSION=1.29.1 -ARG BLACKFIRE_AGENT_VERSION=1.30.0 -RUN curl -o $(php -i | grep -P "^extension_dir " | sed "s/^.* => //g")/blackfire.so -D - -L -s https://packages.blackfire.io/binaries/blackfire-php/${BLACKFIRE_PROBE_VERSION}/blackfire-php-linux_amd64-php-${BLACKFIRE_PHP_VERSION}.so -RUN curl -o /usr/bin/blackfire-agent -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-agent-linux_amd64 -RUN chmod +x /usr/bin/blackfire-agent -RUN curl -o /usr/bin/blackfire -L https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_AGENT_VERSION}/blackfire-cli-linux_amd64 -RUN chmod +x /usr/bin/blackfire -RUN docker-php-ext-enable blackfire - # Composer install COPY --from=composer:latest /usr/bin/composer /usr/bin/composer @@ -24,7 +13,7 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" COPY Resources/tests/environment/php/conf.ini "$PHP_INI_DIR/conf.d/" # Basic sample symfony app install -ARG SF_ENV=sf4 +ARG SF_ENV=sf5 ENV APP_ENV test RUN mkdir /app WORKDIR /app @@ -33,6 +22,7 @@ COPY Resources/tests/environment/${SF_ENV}/composer.json /app RUN composer install # Additionnal config files for a test env +COPY phpstan.neon /app/ COPY Resources/tests/environment/${SF_ENV} /app/ # Drop the process-bundle sources into this folder diff --git a/Makefile b/Makefile index f8f4b1ac..def010bf 100644 --- a/Makefile +++ b/Makefile @@ -7,19 +7,13 @@ include .env endif # Default image to use for tests -SF_ENV=sf4 +SF_ENV=sf5 LOCAL_DOCKER_TAG=cleverage_process:test DOCKER_RUN=docker run -it --rm \ --mount type=bind,src=$$(pwd),dst=/src-cleverage_process pull: pull/$(SF_ENV) -pull/sf3: - docker pull cleverage/process-bundle:sf3 - -pull/sf4: - docker pull cleverage/process-bundle:sf4 - pull/sf5: docker pull cleverage/process-bundle:sf5 @@ -66,3 +60,6 @@ vendor/%: docker container create --name cleverage_process_bundle_tmp cleverage/process-bundle:$(@F) docker cp cleverage_process_bundle_tmp:/app/vendor vendor-$(@F) docker container rm cleverage_process_bundle_tmp + +linter: + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) /bin/bash -c "vendor/bin/phpstan" \ No newline at end of file diff --git a/Resources/tests/environment/sf5/composer.json b/Resources/tests/environment/sf5/composer.json index 78c50e4b..16c2a7d5 100644 --- a/Resources/tests/environment/sf5/composer.json +++ b/Resources/tests/environment/sf5/composer.json @@ -2,27 +2,27 @@ "type": "project", "license": "proprietary", "require": { - "symfony/framework-bundle": "^5.0", - "symfony/dotenv": "^5.0", + "symfony/framework-bundle": "^5.4", + "symfony/dotenv": "^5.4", "symfony/flex": "^1.11", - - "symfony/event-dispatcher-contracts": "~1.0|~2.0", - "psr/event-dispatcher": "1.0.0", - "symfony/config": "~5.0", - "symfony/dependency-injection": "~5.0", - "symfony/expression-language": "~5.0", + "symfony/event-dispatcher": "^5.4", + "symfony/config": "^5.4", + "symfony/dependency-injection": "^5.4", + "symfony/expression-language": "^5.4", "symfony/monolog-bundle": "~3.3", - "symfony/console": "~5.0", - "symfony/options-resolver": "~5.0", - "symfony/process": "~5.0", - "symfony/property-access": "~5.0", - "symfony/serializer": "~5.0", - "symfony/validator": "~5.0", - "symfony/yaml": "~5.0" + "symfony/console": "^5.4", + "symfony/form": "^5.4", + "symfony/options-resolver": "^5.4", + "symfony/process": "^5.4", + "symfony/property-access": "^5.4", + "symfony/runtime": "^5.4", + "symfony/serializer": "^5.4", + "symfony/validator": "^5.4", + "symfony/yaml": "^5.4" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4|^5.0", - "phpunit/phpunit": "~6.4", + "symfony/phpunit-bridge": "^5.4", + "phpunit/phpunit": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", "phpstan/extension-installer": "*" @@ -52,6 +52,7 @@ }, "config": { "allow-plugins": { + "symfony/runtime": true, "phpstan/extension-installer": true, "symfony/flex": true } diff --git a/composer.json b/composer.json index 476e203a..e8ac257e 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,9 @@ "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", "phpstan/extension-installer": "*", - "rector/rector": "*" + "rector/rector": "*", + "symplify/easy-coding-standard": "*", + "symplify/phpstan-rules": "*" }, "suggest": { "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", diff --git a/ecs.php b/ecs.php new file mode 100644 index 00000000..4bc43fd2 --- /dev/null +++ b/ecs.php @@ -0,0 +1,29 @@ +rule(LineLengthFixer::class); + + $ecsConfig->sets([ + SetList::CLEAN_CODE, + SetList::SYMPLIFY, + SetList::COMMON, + SetList::PSR_12, + SetList::DOCTRINE_ANNOTATIONS, + ]); + + $ecsConfig->paths([ + __DIR__, + ]); + + $ecsConfig->skip([ + __DIR__ . 'vendor', + AssignmentInConditionSniff::class + ]); +}; diff --git a/phpstan.neon b/phpstan.neon index 5d2e301a..d6056437 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,3 +7,4 @@ parameters: - Resources/tests/* - Tests/* - rector.php + - var/* \ No newline at end of file diff --git a/rector.php b/rector.php index 2f32a6fb..1738573e 100644 --- a/rector.php +++ b/rector.php @@ -14,25 +14,11 @@ $rectorConfig->importShortClasses(); $rectorConfig->paths([ - __DIR__ . '/Command', - __DIR__ . '/Configuration', - __DIR__ . '/Context', - __DIR__ . '/DependencyInjection', - __DIR__ . '/Event', - __DIR__ . '/EventDispatcher', - __DIR__ . '/EventListener', - __DIR__ . '/Exception', - __DIR__ . '/ExpressionLanguage', - __DIR__ . '/Filesystem', - __DIR__ . '/Logger', - __DIR__ . '/Manager', - __DIR__ . '/Model', - __DIR__ . '/Registry', - __DIR__ . '/Resources', - __DIR__ . '/Task', - __DIR__ . '/Tests', - __DIR__ . '/Transformer', - __DIR__ . '/Validator', + __DIR__, + ]); + + $rectorConfig->skip([ + __DIR__ . '/vendor' ]); $rectorConfig->sets([ From a833456ef8e7fde65dd29c25d7700cc9c07d3580 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 13:05:12 +0100 Subject: [PATCH 162/304] ecs/rector/phpstan --- CleverAgeProcessBundle.php | 23 +- Command/ExecuteProcessCommand.php | 73 ++-- Command/ListProcessCommand.php | 135 +++----- Command/ProcessHelpCommand.php | 222 +++++-------- Configuration/ProcessConfiguration.php | 77 ++--- Configuration/TaskConfiguration.php | 103 ++---- Context/ContextualOptionResolver.php | 29 +- .../CleverAgeProcessExtension.php | 38 +-- .../Compiler/CheckSerializerCompilerPass.php | 14 +- .../Compiler/RegistryCompilerPass.php | 32 +- DependencyInjection/Configuration.php | 101 +++--- Event/ConsoleProcessEvent.php | 17 +- Event/EventDispatcherTaskEvent.php | 34 +- Event/GenericEvent.php | 12 +- Event/ProcessEvent.php | 24 +- EventListener/DataQueueEventListener.php | 25 +- Exception/CircularProcessException.php | 13 +- .../InvalidProcessConfigurationException.php | 23 +- Exception/MissingProcessException.php | 14 +- .../MissingTaskConfigurationException.php | 14 +- Exception/MissingTransformerException.php | 14 +- Exception/MultiBranchProcessException.php | 18 +- Exception/ProcessExceptionInterface.php | 12 +- Exception/TransformerException.php | 29 +- ExpressionLanguage/PhpFunctionProvider.php | 25 +- Filesystem/CsvFile.php | 47 ++- Filesystem/CsvResource.php | 128 +++---- Filesystem/FileStreamInterface.php | 15 +- Filesystem/JsonStreamFile.php | 48 ++- Filesystem/SeekableFileInterface.php | 14 +- Filesystem/StructuredFileInterface.php | 11 +- Filesystem/WritableFileInterface.php | 8 +- .../WritableStructuredFileInterface.php | 7 +- Filesystem/XmlFile.php | 31 +- Logger/AbstractLogger.php | 22 +- Logger/AbstractProcessor.php | 49 +-- Logger/ProcessLogger.php | 8 +- Logger/ProcessProcessor.php | 11 +- Logger/TaskLogger.php | 12 +- Logger/TaskProcessor.php | 13 +- Logger/TransformerProcessor.php | 13 +- Makefile | 6 +- Manager/ProcessManager.php | 314 ++++++------------ Model/AbstractConfigurableTask.php | 37 +-- Model/BlockingTaskInterface.php | 11 +- Model/FinalizableTaskInterface.php | 11 +- Model/FlushableTaskInterface.php | 11 +- Model/InitializableTaskInterface.php | 11 +- Model/IterableTaskInterface.php | 10 +- Model/ProcessHistory.php | 115 +++---- Model/ProcessState.php | 243 +++++--------- Model/SubprocessInstance.php | 115 ++----- Model/TaskInterface.php | 11 +- Registry/ProcessConfigurationRegistry.php | 68 ++-- Registry/TransformerRegistry.php | 26 +- .../tests/environment/sf5/config/bundles.php | 18 +- Task/AbstractIterableOutputTask.php | 43 +-- Task/AggregateIterableTask.php | 26 +- Task/ArrayMergeTask.php | 36 +- Task/ColumnAggregatorTask.php | 52 ++- Task/ConstantIterableOutputTask.php | 35 +- Task/ConstantOutputTask.php | 31 +- Task/CounterTask.php | 29 +- Task/Debug/DebugTask.php | 13 +- Task/Debug/DieTask.php | 12 +- Task/Debug/ErrorForwarderTask.php | 13 +- Task/Debug/MemInfoDumpTask.php | 33 +- Task/DummyTask.php | 13 +- Task/Event/EventDispatcherTask.php | 47 +-- Task/File/Csv/AbstractCsvResourceTask.php | 50 +-- Task/File/Csv/AbstractCsvTask.php | 38 +-- Task/File/Csv/CsvReaderTask.php | 78 ++--- Task/File/Csv/CsvSplitterTask.php | 69 +--- Task/File/Csv/CsvWriterTask.php | 66 +--- Task/File/Csv/InputCsvReaderTask.php | 33 +- Task/File/FileFetchTask.php | 125 +++---- Task/File/FileMoverTask.php | 52 +-- Task/File/FileReaderTask.php | 31 +- Task/File/FileRemoverTask.php | 16 +- Task/File/FileWriterTask.php | 34 +- Task/File/FolderBrowserTask.php | 69 ++-- Task/File/InputFolderBrowserTask.php | 38 +-- Task/File/JsonStream/JsonStreamReaderTask.php | 23 +- Task/File/Xml/XmlReaderTask.php | 45 +-- Task/File/Xml/XmlWriterTask.php | 49 ++- Task/File/YamlReaderTask.php | 50 +-- Task/File/YamlWriterTask.php | 39 +-- Task/FilterTask.php | 31 +- Task/GroupByAggregateIterableTask.php | 48 +-- Task/InputAggregatorTask.php | 72 ++-- Task/InputIteratorTask.php | 26 +- Task/IterableBatchTask.php | 77 ++--- Task/ObjectUpdaterTask.php | 40 +-- Task/Process/CommandRunnerTask.php | 32 +- Task/Process/ProcessExecutorTask.php | 70 +--- Task/Process/ProcessLauncherTask.php | 142 +++----- Task/PropertyGetterTask.php | 49 +-- Task/PropertySetterTask.php | 50 +-- Task/Reporting/AdvancedStatCounterTask.php | 72 ++-- Task/Reporting/LoggerTask.php | 48 +-- Task/Reporting/StatCounterTask.php | 34 +- Task/RowAggregatorTask.php | 43 +-- Task/Serialization/DenormalizerTask.php | 64 +--- Task/Serialization/DeserializerTask.php | 48 +-- Task/Serialization/NormalizerTask.php | 59 +--- Task/Serialization/SerializerTask.php | 55 +-- Task/SimpleBatchTask.php | 43 +-- Task/SkipEmptyTask.php | 10 +- Task/SplitJoinLineTask.php | 48 +-- Task/StopTask.php | 13 +- Task/TransformerTask.php | 62 +--- Task/Validation/ValidatorTask.php | 53 +-- Tests/AbstractProcessTest.php | 64 ++-- Tests/BasicTest.php | 18 +- Tests/BlockingTaskTest.php | 18 +- Tests/CircularProcessTest.php | 13 +- Tests/ContextTest.php | 64 +++- Tests/EmptyProcessTest.php | 7 +- Tests/ExceptionManagementTest.php | 25 +- Tests/FlushableTaskTest.php | 25 +- Tests/IterableTaskTest.php | 12 +- Tests/MultiBranchProcessTest.php | 66 ++-- Tests/MultiWorkflowTest.php | 7 +- Tests/ProcessManagerTest.php | 35 +- Tests/Task/ColumnAggregatorTaskTest.php | 28 +- Tests/Task/FilterTaskTest.php | 8 +- Tests/Task/ProcessExecutorTaskTest.php | 9 +- Tests/Task/StopTaskTest.php | 7 +- Tests/Task/TransformerTaskTest.php | 19 +- Tests/Task/ValidatorTaskTest.php | 8 +- .../ArrayFilterTransformerTest.php | 49 ++- Tests/Transformer/CallbackTransformerTest.php | 18 +- Tests/Transformer/DateTransformersTest.php | 26 +- Tests/Transformer/GenericTransformersTest.php | 27 +- Tests/Transformer/HashTransformerTest.php | 11 +- Tests/Transformer/MappingTransformerTest.php | 82 +++-- Tests/Transformer/RulesTransformerTest.php | 11 +- .../Transformer/TransformerExceptionTest.php | 15 +- .../Transformer/TypeSetterTransformerTest.php | 13 +- Tests/Transformer/UnsetTransformerTest.php | 42 ++- .../XpathEvaluatorTransformerTest.php | 48 +-- Transformer/ArrayElementTransformer.php | 29 +- Transformer/ArrayFilterTransformer.php | 29 +- Transformer/ArrayFirstTransformer.php | 33 +- Transformer/ArrayLastTransformer.php | 15 +- Transformer/ArrayMapTransformer.php | 49 +-- Transformer/ArrayUnsetTransformer.php | 19 +- Transformer/CachedTransformer.php | 74 ++--- Transformer/CallbackTransformer.php | 39 +-- Transformer/CastTransformer.php | 30 +- Transformer/ConditionTrait.php | 59 ++-- .../ConfigurableTransformerInterface.php | 14 +- Transformer/ConstantTransformer.php | 24 +- Transformer/ConvertValueTransformer.php | 62 ++-- Transformer/DateFormatTransformer.php | 38 +-- Transformer/DateParserTransformer.php | 32 +- Transformer/DebugTransformer.php | 15 +- Transformer/DefaultTransformer.php | 21 +- Transformer/DenormalizeTransformer.php | 60 +--- Transformer/EvaluatorTransformer.php | 56 +--- Transformer/ExplodeTransformer.php | 33 +- .../ExpressionLanguageMapTransformer.php | 77 ++--- Transformer/GenericTransformer.php | 69 ++-- Transformer/HashTransformer.php | 25 +- Transformer/ImplodeTransformer.php | 30 +- Transformer/MappingTransformer.php | 109 ++---- Transformer/MultiReplaceTransformer.php | 14 +- Transformer/NormalizeTransformer.php | 53 +-- Transformer/PregFilterTransformer.php | 36 +- Transformer/PropertyAccessorTransformer.php | 63 +--- .../RecursivePropertySetterTransformer.php | 77 ++--- Transformer/RulesTransformer.php | 70 ++-- Transformer/SlugifyTransformer.php | 34 +- Transformer/SprintfTransformer.php | 27 +- Transformer/TransformerInterface.php | 11 +- Transformer/TransformerTrait.php | 105 +++--- Transformer/TrimTransformer.php | 37 +-- Transformer/TypeSetterTransformer.php | 39 +-- Transformer/UnsetTransformer.php | 30 +- Transformer/WrapperTransformer.php | 40 +-- Transformer/Xml/XpathEvaluatorTransformer.php | 90 +++-- Validator/ConstraintLoader.php | 11 +- ecs.php | 9 +- phpstan.neon | 1 + rector.php | 12 +- 185 files changed, 2752 insertions(+), 4965 deletions(-) diff --git a/CleverAgeProcessBundle.php b/CleverAgeProcessBundle.php index 3b5b930f..f93be4bc 100644 --- a/CleverAgeProcessBundle.php +++ b/CleverAgeProcessBundle.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot - * @author Madeline Veyrenc - */ class CleverAgeProcessBundle extends Bundle { /** * Adding compiler passes to inject services into registry - * - * @param ContainerBuilder $container */ public function build(ContainerBuilder $container): void { $container->addCompilerPass( - new RegistryCompilerPass( - TransformerRegistry::class, - 'cleverage.transformer', - 'addTransformer' - ) + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), + PassConfig::TYPE_BEFORE_OPTIMIZATION, + 0 ); - $container->addCompilerPass(new CheckSerializerCompilerPass()); + $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); } } diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index e411fe45..dfc23204 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ExecuteProcessCommand extends Command { final public const OUTPUT_STDOUT = '-'; final public const OUTPUT_FORMAT_DUMP = 'dump'; + final public const OUTPUT_FORMAT_JSON = 'json-stream'; - public function __construct(protected ProcessManager $processManager, protected EventDispatcherInterface $eventDispatcher) - { + public function __construct( + protected ProcessManager $processManager, + protected EventDispatcherInterface $eventDispatcher + ) { parent::__construct(); } - /** - * {@inheritdoc} - * - * @throws InvalidArgumentException - */ protected function configure() { $this->setName('cleverage:process:execute'); @@ -74,34 +71,22 @@ protected function configure() $this->addOption('output-format', 't', InputOption::VALUE_OPTIONAL, 'Output format'); } - /** - * @param InputInterface $input - * @param OutputInterface $output - * - * @throws Exception - * - * @return int|null - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $inputData = $input->getOption('input'); if ($input->getOption('input-from-stdin')) { $inputData = ''; - while (!feof(STDIN)) { + while (! feof(STDIN)) { $inputData .= fread(STDIN, 8192); } } $context = $this->parseContextValues($input); - $this->eventDispatcher->dispatch( - new ConsoleProcessEvent($input, $output, $inputData, $context), - ConsoleProcessEvent::EVENT_CLI_INIT - ); + $this->eventDispatcher->dispatch(new ConsoleProcessEvent($input, $output, $inputData, $context)); - /** @noinspection ForeachSourceInspection */ foreach ($input->getArgument('processCodes') as $code) { - if (!$output->isQuiet()) { + if (! $output->isQuiet()) { $output->writeln("Starting process '{$code}'..."); } @@ -109,17 +94,15 @@ protected function execute(InputInterface $input, OutputInterface $output) $returnValue = $this->processManager->execute($code, $inputData, $context); $this->handleOutputData($returnValue, $input, $output); - if (!$output->isQuiet()) { + if (! $output->isQuiet()) { $output->writeln("Process '{$code}' executed successfully"); } } - return 0; + return Command::SUCCESS; } /** - * - * @throws InvalidArgumentException * @return array */ protected function parseContextValues(InputInterface $input): array @@ -131,9 +114,9 @@ protected function parseContextValues(InputInterface $input): array $context = []; foreach ($contextValues as $contextValue) { preg_match($pattern, (string) $contextValue, $parts); - if (3 !== \count($parts) + if (\count($parts) !== 3 || $parts[0] !== $contextValue) { - throw new \InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); + throw new InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); } $context[$parts[1]] = $parser->parse($parts[2]); } @@ -144,7 +127,7 @@ protected function parseContextValues(InputInterface $input): array protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output) { // Skip all if undefined - if (!$input->getOption('output-format')) { + if (! $input->getOption('output-format')) { return; } @@ -156,18 +139,15 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { $output->writeln(json_encode($data, JSON_THROW_ON_ERROR)); } else { - throw new \InvalidArgumentException( - sprintf( - "Cannot handle data output with format '%s'", - $input->getOption('output-format') - ) + throw new InvalidArgumentException( + sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) ); } } } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { // JsonStreamFile::writeLine only takes an array... // TODO how to handle other cases ? - if(\is_array($data)) { + if (\is_array($data)) { $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); $outputFile->writeLine($data); } @@ -176,11 +156,8 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { - throw new \InvalidArgumentException( - sprintf( - "Cannot handle data output with format '%s'", - $input->getOption('output-format') - ) + throw new InvalidArgumentException( + sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) ); } } diff --git a/Command/ListProcessCommand.php b/Command/ListProcessCommand.php index 69b1fee5..76af0cc9 100644 --- a/Command/ListProcessCommand.php +++ b/Command/ListProcessCommand.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ListProcessCommand extends Command { - /** @var ProcessConfigurationRegistry */ - protected $processConfigRegistry; + protected static $defaultDescription = 'List defined process'; + + public function __construct( + protected ProcessConfigurationRegistry $processConfigRegistry + ) { + parent::__construct(); + } /** - * @param ProcessConfigurationRegistry $processConfigRegistry + * Counter callback for public processes * - * @throws LogicException + * @param int $sum */ - public function __construct(ProcessConfigurationRegistry $processConfigRegistry) + public function publicProcessCounter($sum, ProcessConfiguration $processConfiguration): int { - $this->processConfigRegistry = $processConfigRegistry; - parent::__construct(); + return $sum + ($processConfiguration->isPublic() ? 1 : 0); } /** - * {@inheritdoc} - * @throws InvalidArgumentException + * Counter callback for private processes + * + * @param int $sum + */ + public function privateProcessCounter($sum, ProcessConfiguration $processConfiguration): int + { + return $sum + ($processConfiguration->isPrivate() ? 1 : 0); + } + + /** + * Sorter callback for process codes */ + public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b): int + { + return $a->getCode() <=> $b->getCode(); + } + + /** + * Filter callback to find max message length + * + * @param int $max + */ + public function maxMessageLengthFilter($max, array $message): int + { + return \max($max, strlen($this->filterOutTags($message['output']))); + } + protected function configure() { $this->setName('cleverage:process:list'); - $this->setDescription('List defined process'); $this->addOption('all', 'a', InputOption::VALUE_NONE, 'Shows all processes (including hidden ones)'); } - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $processConfigurations = $this->processConfigRegistry->getProcessConfigurations(); - \usort($processConfigurations, [$this, 'processSorter']); + \usort($processConfigurations, $this->processSorter(...)); - $publicCount = \array_reduce($processConfigurations, [$this, 'publicProcessCounter'], 0); - $privateCount = \array_reduce($processConfigurations, [$this, 'privateProcessCounter'], 0); + $publicCount = \array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); + $privateCount = \array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); $output->writeln( "There are {$publicCount} process configurations defined (and {$privateCount} private) :" ); @@ -84,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } // Add process descriptions at a fixed position - $maxMessageLength = \array_reduce($messages, [$this, 'maxMessageLengthFilter'], 0); + $maxMessageLength = \array_reduce($messages, $this->maxMessageLengthFilter(...), 0); $outputMessages = []; foreach ($messages as $message) { /** @var ProcessConfiguration $processConfiguration */ @@ -104,72 +126,13 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln($message); } - return 0; - } - - /** - * Counter callback for public processes - * - * @param int $sum - * @param ProcessConfiguration $processConfiguration - * - * @return int - */ - public function publicProcessCounter($sum, ProcessConfiguration $processConfiguration): int - { - return $sum + ($processConfiguration->isPublic() ? 1 : 0); - } - - /** - * Counter callback for private processes - * - * @param int $sum - * @param ProcessConfiguration $processConfiguration - * - * @return int - */ - public function privateProcessCounter($sum, ProcessConfiguration $processConfiguration): int - { - return $sum + ($processConfiguration->isPrivate() ? 1 : 0); - } - - /** - * Sorter callback for process codes - * - * @param ProcessConfiguration $a - * @param ProcessConfiguration $b - * - * @return int - */ - public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b): int - { - if ($a->getCode() === $b->getCode()) { - return 0; - } - - return ($a->getCode() < $b->getCode()) ? -1 : 1; - } - - /** - * Filter callback to find max message length - * - * @param int $max - * @param array $message - * - * @return int - */ - public function maxMessageLengthFilter($max, array $message): int - { - return \max($max, strlen($this->filterOutTags($message['output']))); + return Command::SUCCESS; } /** * Returns a padded message (without counting metadata) * - * @param string $message * @param int $length - * - * @return string */ protected function padMessage(string $message, $length = 80): string { @@ -183,10 +146,6 @@ protected function padMessage(string $message, $length = 80): string /** * Filter out tags used in console outputs - * - * @param string $string - * - * @return string */ protected function filterOutTags(string $string): string { diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index e76b76ed..5634af13 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -1,4 +1,7 @@ - */ class ProcessHelpCommand extends Command { protected const CHAR_DOWN = '│'; + protected const CHAR_MERGE = '┘'; + protected const CHAR_MULTIMERGE = '┴─'; + protected const CHAR_JUMP = '┿─'; + protected const CHAR_HORIZ = '──'; + protected const CHAR_MULTIEXPAND = '┬─'; + protected const CHAR_EXPAND = '┐'; + protected const CHAR_RECEIVE = '├─'; + protected const CHAR_NODE = '■'; protected const BRANCH_SIZE = 2; - protected const INDENT_SIZE = 4; - /** @var ProcessConfigurationRegistry */ - protected $processConfigRegistry; + protected const INDENT_SIZE = 4; - /** @var ContainerInterface */ - protected $container; + protected static $defaultDescription = 'Describe the process'; - /** - * @param ProcessConfigurationRegistry $processConfigRegistry - * @param ContainerInterface $container - * - * @throws LogicException - */ - public function __construct(ProcessConfigurationRegistry $processConfigRegistry, ContainerInterface $container) - { - $this->processConfigRegistry = $processConfigRegistry; - $this->container = $container; + public function __construct( + protected ProcessConfigurationRegistry $processConfigRegistry, + protected ContainerInterface $container + ) { parent::__construct(); } - /** - * {@inheritdoc} - * - * @throws InvalidArgumentException - */ protected function configure() { $this->setName('cleverage:process:help'); - $this->setDescription('Describe the process'); $this->addArgument('process_code', InputArgument::REQUIRED, 'The code of the process'); } - /** - * {@inheritdoc} - * - * @throws NotFoundExceptionInterface - * @throws ContainerExceptionInterface - * @throws \UnexpectedValueException - * @throws InvalidArgumentException - * @throws MissingProcessException - * @throws MissingTaskConfigurationException - * @throws \InvalidArgumentException - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { - $output->getFormatter()->setStyle('fire', new OutputFormatterStyle('red')); + $output->getFormatter() + ->setStyle('fire', new OutputFormatterStyle('red')); $processCode = $input->getArgument('process_code'); $process = $this->processConfigRegistry->getProcessConfiguration($processCode); $output->writeln('Process: '); - $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); + $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $processCode); $output->writeln(''); if ($process->getDescription()) { $output->writeln('Description:'); - $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); + $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $process->getDescription()); $output->writeln(''); } @@ -116,7 +96,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('Help:'); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { - $output->writeln(str_repeat(' ', self::INDENT_SIZE).$helpLine); + $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $helpLine); } $output->writeln(''); } @@ -135,21 +115,16 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->resolveBranchOutput($branches, $nextTaskCode, $process, $output); // Remove the task from the remaining list - $remainingTasks = array_filter( - $remainingTasks, - static function ($task) use ($nextTaskCode) { - return $task !== $nextTaskCode; - } - ); + $remainingTasks = array_filter($remainingTasks, static fn ($task): bool => $task !== $nextTaskCode); } $branches = array_filter($branches); - if (!empty($branches)) { - $branchStr = '['.implode(', ', $branches).']'; + if (! empty($branches)) { + $branchStr = '[' . implode(', ', $branches) . ']'; $output->writeln("All branches are not resolved : {$branchStr}"); } - return 0; + return Command::SUCCESS; } /** @@ -157,11 +132,8 @@ static function ($task) use ($nextTaskCode) { * * @param array $branches * @param array $taskList - * @param ProcessConfiguration $process - * - * @return int|null|string */ - protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process) + protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process): int|null|string { // Get resolvable tasks $taskCandidates = []; @@ -174,9 +146,11 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ // Check if task has all necessary ancestors in branches $hasAllAncestors = array_reduce( $task->getPreviousTasksConfigurations(), - static function ($result, TaskConfiguration $prevTask) use ($branches) { - return $result && \in_array($prevTask->getCode(), $branches, true); - }, + static fn ($result, TaskConfiguration $prevTask): bool => $result && \in_array( + $prevTask->getCode(), + $branches, + true + ), true ); @@ -186,7 +160,7 @@ static function ($result, TaskConfiguration $prevTask) use ($branches) { } if (empty($taskCandidates)) { - throw new \UnexpectedValueException('Cannot find a task to output'); + throw new UnexpectedValueException('Cannot find a task to output'); } // Try to find the task the most on the right @@ -198,14 +172,16 @@ static function ($result, TaskConfiguration $prevTask) use ($branches) { $key = array_search($prevTask->getCode(), $branches, true); // Should never be non-numeric... - if (!is_numeric($key)) { - throw new \UnexpectedValueException('Invalid key type'); + if (! is_numeric($key)) { + throw new UnexpectedValueException('Invalid key type'); } $weight += $key; } - if (!empty($task->getPreviousTasksConfigurations())) { - $weight /= \count($task->getPreviousTasksConfigurations()); + if (! empty($task->getPreviousTasksConfigurations())) { + $weight /= is_countable($task->getPreviousTasksConfigurations()) ? \count( + $task->getPreviousTasksConfigurations() + ) : 0; } $taskWeights[$taskCandidate] = $weight; @@ -215,14 +191,9 @@ static function ($result, TaskConfiguration $prevTask) use ($branches) { $bestCandidate = key($taskWeights); $bestWeight = $taskWeights[$bestCandidate]; - $equalWeights = array_filter( - $taskWeights, - static function ($item) use ($bestWeight) { - return $item == $bestWeight; - } - ); + $equalWeights = array_filter($taskWeights, static fn ($item): bool => $item === $bestWeight); - if (1 === count($equalWeights)) { + if (count($equalWeights) === 1) { return $bestCandidate; } @@ -240,8 +211,6 @@ static function ($item) use ($bestWeight) { /** * Get the number of children (error or not) of a task * - * @param TaskConfiguration $task - * * @return int */ protected function getTaskChildrenCount(TaskConfiguration $task) @@ -259,14 +228,11 @@ protected function getTaskChildrenCount(TaskConfiguration $task) return $count; } - /** * Merge needed branches, display a task node, split following needed branches * * @param array $branches * @param string $taskCode - * @param ProcessConfiguration $process - * @param OutputInterface $output */ protected function resolveBranchOutput( &$branches, @@ -289,8 +255,9 @@ protected function resolveBranchOutput( // Check previous branches if (empty($previousTasks)) { $branches[] = $task->getCode(); - } elseif (1 === \count($previousTasks)) { - $prevTask = current($previousTasks)->getCode(); + } elseif (\count($previousTasks) === 1) { + $prevTask = current($previousTasks) + ->getCode(); foreach (array_reverse($branches, true) as $i => $branchTask) { if ($branchTask === $prevTask) { $branches[$i] = $taskCode; @@ -308,7 +275,7 @@ protected function resolveBranchOutput( } } - if (!$foundBranch) { + if (! $foundBranch) { $output->writeln( "Could not find previous branch : {$taskCode} depends on {$prevTask->getCode()}" ); @@ -322,7 +289,7 @@ protected function resolveBranchOutput( $gapTo = null; foreach ($branchesToMerge as $i) { $gapTo = $i; - if (null !== $gapFrom) { + if ($gapFrom !== null) { for ($j = $gapFrom + 1; $j < $gapTo; ++$j) { $gapBranches[] = $j; } @@ -336,24 +303,22 @@ protected function resolveBranchOutput( } // Merge branches - if (!empty($branchesToMerge)) { + if (! empty($branchesToMerge)) { $this->writeBranches($output, $branches); $this->writeBranches( $output, $branches, '', - static function ($taskCode, $i) use ($branchesToMerge, $gapBranches, $origin) { - return \in_array($i, $branchesToMerge, true) - || \in_array($i, $gapBranches, true) - || $i === $origin; - }, - static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { + static fn ($taskCode, $i): bool => \in_array($i, $branchesToMerge, true) + || \in_array($i, $gapBranches, true) + || $i === $origin, + static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): string { if ($i === $origin) { return self::CHAR_RECEIVE; } if (\in_array($i, $gapBranches, true)) { - if (null !== $branches[$i]) { + if ($branches[$i] !== null) { return self::CHAR_JUMP; } @@ -378,7 +343,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { - if (null !== $branchTask) { + if ($branchTask !== null) { $branches = \array_slice($branches, 0, $i + 1); break; } @@ -394,17 +359,15 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches) { $output, $branches, $this->getTaskDescription($task), - static function ($branchTask, $i) use ($taskCode) { - return $branchTask === $taskCode; - }, + static fn ($branchTask, $i): bool => $branchTask === $taskCode, $nodeStr ); // Write task help message if ($output->isVerbose() && $task->getHelp()) { - $helpLines = array_filter(explode("\n", $task->getHelp())); + $helpLines = array_filter(explode("\n", (string) $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE)."{$helpLine}"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; $this->writeBranches($output, $branches, $helpMessage); } } @@ -412,9 +375,7 @@ static function ($branchTask, $i) use ($taskCode) { // Check next tasks $nextTasks = array_unique( array_map( - static function (TaskConfiguration $task) { - return $task->getCode(); - }, + static fn (TaskConfiguration $task): string => $task->getCode(), array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) ) ); @@ -425,8 +386,8 @@ static function (TaskConfiguration $task) { $expandBranches = []; foreach ($nextTasks as $nextTask) { $index = array_search(null, $branches, true); - if (false !== $index && $index >= $origin) { - /** @var $index int */ + if ($index !== false && $index >= $origin) { + /** @var int $index */ $branches[$index] = $taskCode; $expandBranches[] = $index; } else { @@ -452,15 +413,13 @@ static function (TaskConfiguration $task) { $output, $branches, '', - static function ($branchTask, $i) use ($origin, $final) { - return $i >= $origin && $i <= $final; - }, - static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) { + static fn ($branchTask, $i): bool => $i >= $origin && $i <= $final, + static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final): string { if ($i === $origin) { return self::CHAR_RECEIVE; } if (\in_array($i, $gapBranches, true)) { - if (null !== $branches[$i]) { + if ($branches[$i] !== null) { return self::CHAR_JUMP; } @@ -485,7 +444,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { - if (null !== $branchTask) { + if ($branchTask !== null) { $branches = \array_slice($branches, 0, $i + 1); break; } @@ -495,35 +454,36 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) } /** - * @param OutputInterface $output * @param array $branches * @param string $comment * @param callable $match - * @param string|callable $char - * - * @throws \InvalidArgumentException */ - protected function writeBranches(OutputInterface $output, $branches, $comment = '', $match = null, $char = null) - { + protected function writeBranches( + OutputInterface $output, + $branches, + string|iterable $comment = '', + $match = null, + string|callable $char = null + ) { $output->write(str_repeat(' ', self::INDENT_SIZE)); // Merge lines foreach ($branches as $i => $branchTask) { $str = ''; - if (null !== $match && $match($branchTask, $i)) { + if ($match !== null && $match($branchTask, $i)) { if (\is_string($char)) { $str = $char; } elseif (\is_callable($char)) { $str = $char($branchTask, $i); } else { - throw new \InvalidArgumentException('Char must be string|callable'); + throw new InvalidArgumentException('Char must be string|callable'); } - } elseif (null !== $branchTask) { + } elseif ($branchTask !== null) { $str = self::CHAR_DOWN; } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', $str)); + $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } @@ -533,12 +493,6 @@ protected function writeBranches(OutputInterface $output, $branches, $comment = } /** - * @param TaskConfiguration $task - * - * @throws NotFoundExceptionInterface - * @throws ContainerExceptionInterface - * @throws \UnexpectedValueException - * * @return string */ protected function getTaskDescription(TaskConfiguration $task) @@ -565,11 +519,11 @@ protected function getTaskDescription(TaskConfiguration $task) } if (\count($interfaces)) { - $description .= ' ('.implode(', ', $interfaces).')'; + $description .= ' (' . implode(', ', $interfaces) . ')'; } if (\count($subprocess)) { - $description .= ' {'.implode(', ', $subprocess).'}'; + $description .= ' {' . implode(', ', $subprocess) . '}'; } if ($task->getDescription()) { @@ -580,12 +534,6 @@ protected function getTaskDescription(TaskConfiguration $task) } /** - * @param TaskConfiguration $taskConfiguration - * - * @throws NotFoundExceptionInterface - * @throws ContainerExceptionInterface - * @throws \UnexpectedValueException - * * @return mixed */ protected function getTaskService(TaskConfiguration $taskConfiguration) @@ -594,17 +542,17 @@ protected function getTaskService(TaskConfiguration $taskConfiguration) // @todo Refactor this using a Registry with this feature: // https://symfony.com/doc/current/service_container/service_subscribers_locators.html $serviceReference = $taskConfiguration->getServiceReference(); - if (0 === strpos($serviceReference, '@')) { - $task = $this->container->get(ltrim($serviceReference, '@')); + if (str_starts_with((string) $serviceReference, '@')) { + $task = $this->container->get(ltrim((string) $serviceReference, '@')); } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" ); } - if (!$task instanceof TaskInterface) { - throw new \UnexpectedValueException( + if (! $task instanceof TaskInterface) { + throw new UnexpectedValueException( "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" ); } diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index a3659081..d0a48e29 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ProcessConfiguration { - /** @var array */ - protected $options = []; - - /** @var TaskConfiguration[] */ - protected $taskConfigurations; - - /** @var array */ + /** + * @var array + */ protected $dependencyGroups; - /** @var array */ + /** + * @var array + */ protected $mainTaskGroup; /** @@ -44,16 +42,14 @@ class ProcessConfiguration */ public function __construct( protected $code, - array $taskConfigurations, - array $options = [], + protected array $taskConfigurations, + protected array $options = [], protected $entryPoint = null, protected $endPoint = null, protected $description = '', protected $help = '', protected $public = true ) { - $this->taskConfigurations = $taskConfigurations; - $this->options = $options; } public function getCode(): string @@ -66,24 +62,18 @@ public function getOptions(): array return $this->options; } - /** - * @throws MissingTaskConfigurationException - */ public function getEntryPoint(): ?TaskConfiguration { - if (null === $this->entryPoint) { + if ($this->entryPoint === null) { return null; } return $this->getTaskConfiguration($this->entryPoint); } - /** - * @throws MissingTaskConfigurationException - */ public function getEndPoint(): ?TaskConfiguration { - if (null === $this->endPoint) { + if ($this->endPoint === null) { return null; } @@ -107,7 +97,7 @@ public function isPublic(): bool public function isPrivate(): bool { - return !$this->public; + return ! $this->public; } /** @@ -118,14 +108,9 @@ public function getTaskConfigurations(): array return $this->taskConfigurations; } - /** - * - * @throws MissingTaskConfigurationException - * - */ public function getTaskConfiguration(string $taskCode): TaskConfiguration { - if (!array_key_exists($taskCode, $this->taskConfigurations)) { + if (! array_key_exists($taskCode, $this->taskConfigurations)) { throw MissingTaskConfigurationException::create($taskCode); } @@ -136,12 +121,10 @@ public function getTaskConfiguration(string $taskCode): TaskConfiguration * Group all task by dependencies * * If one task depend from another, it should come after - * - * @throws MissingTaskConfigurationException */ public function getDependencyGroups(): array { - if (null === $this->dependencyGroups) { + if ($this->dependencyGroups === null) { $this->dependencyGroups = []; foreach ($this->getTaskConfigurations() as $taskConfiguration) { $isInBranch = false; @@ -152,7 +135,7 @@ public function getDependencyGroups(): array } } - if (!$isInBranch) { + if (! $isInBranch) { $dependencies = $this->buildDependencies($taskConfiguration); $dependencies = $this->sortDependencies($dependencies); @@ -169,12 +152,10 @@ public function getDependencyGroups(): array * It may be defined by the entry_point, or the end_point or simply the first task * * If one task depend from another, it should come after - * - * @throws MissingTaskConfigurationException */ public function getMainTaskGroup(): array { - if (null === $this->mainTaskGroup) { + if ($this->mainTaskGroup === null) { $this->mainTaskGroup = []; $mainTask = $this->getMainTask(); @@ -192,27 +173,23 @@ public function getMainTaskGroup(): array /** * Get the most important task (may be the entry or end task, or simply the first) * Used to check which tree should be used - * - * @throws MissingTaskConfigurationException - * - * @return TaskConfiguration */ public function getMainTask(): ?TaskConfiguration { $entryTask = $this->getEntryPoint(); // If there's no entry point, we might use the end point - if (!$entryTask) { + if (! $entryTask) { $entryTask = $this->getEndPoint(); } // By default use the first defined task - if (!$entryTask) { + if (! $entryTask) { $entryTask = reset($this->taskConfigurations); } // May happen with an empty array - if($entryTask === false) { + if ($entryTask === false) { return null; } @@ -221,8 +198,6 @@ public function getMainTask(): ?TaskConfiguration /** * Assert the process does not contain circular dependencies - * - * @throws CircularProcessException */ public function checkCircularDependencies(): void { @@ -242,15 +217,13 @@ public function checkCircularDependencies(): void /** * Cross all relations of a task to find all dependencies, and append them to the given array - * - * */ protected function buildDependencies(TaskConfiguration $taskConfig, array &$dependencies = []): array { $code = $taskConfig->getCode(); // May have been added by previous task - if (!\in_array($code, $dependencies, true)) { + if (! \in_array($code, $dependencies, true)) { $dependencies[] = $code; foreach ($taskConfig->getPreviousTasksConfigurations() as $previousTasksConfig) { @@ -271,10 +244,6 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe /** * Sort the tasks by dependencies - * - * - * @throws MissingTaskConfigurationException - * */ protected function sortDependencies(array $dependencies): array { diff --git a/Configuration/TaskConfiguration.php b/Configuration/TaskConfiguration.php index a1f7904c..97c6e553 100644 --- a/Configuration/TaskConfiguration.php +++ b/Configuration/TaskConfiguration.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class TaskConfiguration { final public const STRATEGY_SKIP = 'skip'; - final public const STRATEGY_STOP = 'stop'; - - /** @var TaskInterface */ - protected $task; - - /** @var array */ - protected $options = []; - - /** @var string */ - protected $description = ''; - /** @var string */ - protected $help = ''; - - /** @var array */ - protected $outputs = []; + final public const STRATEGY_STOP = 'stop'; - /** @var array */ - protected $errorOutputs = []; + protected ?TaskInterface $task = null; - /** @var ProcessState */ - protected $state; + protected ProcessState $state; - /** @var TaskConfiguration[] */ + /** + * @var TaskConfiguration[] + */ protected $nextTasksConfigurations = []; - /** @var TaskConfiguration[] */ + /** + * @var TaskConfiguration[] + */ protected $previousTasksConfigurations = []; - /** @var TaskConfiguration[] */ + /** + * @var TaskConfiguration[] + */ protected $errorTasksConfigurations = []; - /** @var bool */ + /** + * @var bool + */ protected $inErrorBranch = false; - /** @var string */ - protected $errorStrategy; - - /** @var string */ - protected $logLevel; - - /** @var bool */ - protected $logErrors; + protected bool $logErrors; /** * @param string $code @@ -74,21 +59,14 @@ class TaskConfiguration public function __construct( protected $code, protected $serviceReference, - array $options, - string $description = '', - string $help = '', - array $outputs = [], - array $errorOutputs = [], - string $errorStrategy = self::STRATEGY_SKIP, - string $logLevel = LogLevel::CRITICAL + protected array $options, + protected string $description = '', + protected string $help = '', + protected array $outputs = [], + protected array $errorOutputs = [], + protected string $errorStrategy = self::STRATEGY_SKIP, + protected string $logLevel = LogLevel::CRITICAL ) { - $this->options = $options; - $this->description = $description; - $this->help = $help; - $this->outputs = $outputs; - $this->errorOutputs = $errorOutputs; - $this->errorStrategy = $errorStrategy; - $this->logLevel = $logLevel; $this->logErrors = $logLevel !== LogLevel::DEBUG; // @deprecated, remove me in next version } @@ -102,15 +80,12 @@ public function getServiceReference(): string return $this->serviceReference; } - /** - * @return TaskInterface - */ public function getTask(): ?TaskInterface { return $this->task; } - public function setTask(TaskInterface $task) + public function setTask(TaskInterface $task): void { $this->task = $task; } @@ -151,7 +126,6 @@ public function getOutputs(): array /** * @deprecated Use getErrorOutputs method instead - * */ public function getErrors(): array { @@ -170,7 +144,7 @@ public function getState(): ProcessState return $this->state; } - public function setState(ProcessState $state) + public function setState(ProcessState $state): void { $this->state = $state; } @@ -183,7 +157,7 @@ public function getNextTasksConfigurations(): array return $this->nextTasksConfigurations; } - public function addNextTaskConfiguration(TaskConfiguration $nextTaskConfiguration) + public function addNextTaskConfiguration(self $nextTaskConfiguration): void { $this->nextTasksConfigurations[] = $nextTaskConfiguration; } @@ -196,7 +170,7 @@ public function getPreviousTasksConfigurations(): array return $this->previousTasksConfigurations; } - public function addPreviousTaskConfiguration(TaskConfiguration $previousTaskConfiguration) + public function addPreviousTaskConfiguration(self $previousTaskConfiguration): void { $this->previousTasksConfigurations[] = $previousTaskConfiguration; } @@ -209,7 +183,7 @@ public function getErrorTasksConfigurations(): array return $this->errorTasksConfigurations; } - public function addErrorTaskConfiguration(TaskConfiguration $errorTaskConfiguration) + public function addErrorTaskConfiguration(self $errorTaskConfiguration): void { $this->errorTasksConfigurations[] = $errorTaskConfiguration; } @@ -219,23 +193,20 @@ public function isInErrorBranch(): bool return $this->inErrorBranch; } - public function setInErrorBranch(bool $inErrorBranch) + public function setInErrorBranch(bool $inErrorBranch): void { $this->inErrorBranch = $inErrorBranch; } public function isRoot(): bool { - return empty($this->getPreviousTasksConfigurations()) && !$this->isInErrorBranch(); + return empty($this->getPreviousTasksConfigurations()) && ! $this->isInErrorBranch(); } /** * Check task ancestors to find if it have a given task as parent - * - * - * @return bool */ - public function hasAncestor(TaskConfiguration $taskConfig) + public function hasAncestor(self $taskConfig): bool { foreach ($this->getPreviousTasksConfigurations() as $previousTaskConfig) { // Avoid errors for direct ancestors @@ -259,9 +230,8 @@ public function hasAncestor(TaskConfiguration $taskConfig) * Check task ancestors to find if it have a given task as child * * @param bool $checkErrors - * @return bool */ - public function hasDescendant(TaskConfiguration $taskConfig, $checkErrors = true) + public function hasDescendant(self $taskConfig, $checkErrors = true): bool { foreach ($this->getNextTasksConfigurations() as $nextTaskConfig) { // Avoid errors for direct descendant @@ -310,7 +280,6 @@ public function getLogLevel(): string /** * @deprecated Use getLogLevel instead - * */ public function isLogErrors(): bool { diff --git a/Context/ContextualOptionResolver.php b/Context/ContextualOptionResolver.php index 095e08e6..59939011 100644 --- a/Context/ContextualOptionResolver.php +++ b/Context/ContextualOptionResolver.php @@ -1,4 +1,7 @@ - - * @author Madeline Veyrenc - */ class ContextualOptionResolver { /** * Basic value inference * Replaces "{{ key }}" by context[key] * - * @param string|array $value - * @param array $context - * * @return mixed */ - public function contextualizeOption($value, array $context) + public function contextualizeOption(string|array $value, array $context) { // Recursively parse options if (\is_array($value)) { @@ -46,13 +40,7 @@ public function contextualizeOption($value, array $context) } // Else use a replace to insert a string value into another - return preg_replace_callback( - $pattern, - static function ($matches) use ($context) { - return $context[$matches[1]]; - }, - $value - ); + return preg_replace_callback($pattern, static fn ($matches) => $context[$matches[1]], $value); } return $value; @@ -60,11 +48,6 @@ static function ($matches) use ($context) { /** * Replace all contextualized values from options - * - * @param array $options - * @param array $context - * - * @return array */ public function contextualizeOptions(array $options, array $context): array { diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index 880191fe..d4c4d8e8 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -1,5 +1,7 @@ - * @author Vincent Chalnot - * @author Madeline Veyrenc */ class CleverAgeProcessExtension extends Extension { - /** - * @param array $configs - * @param ContainerBuilder $container - * - * @throws \Exception - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { // Get the path of the service folder wherever the bundle is installed - $reflection = new \ReflectionClass($this); - $serviceFolderPath = \dirname($reflection->getFileName(), 2).'/Resources/config/services'; + $reflection = new ReflectionClass($this); + $serviceFolderPath = \dirname($reflection->getFileName(), 2) . '/Resources/config/services'; $this->findServices($container, $serviceFolderPath); $configuration = new Configuration(); @@ -56,32 +49,21 @@ public function load(array $configs, ContainerBuilder $container) $transformerDefinition = new Definition(GenericTransformer::class); $transformerDefinition->setAutowired(true); $transformerDefinition->setPublic(false); - $transformerDefinition->addMethodCall( - 'initialize', - [ - $transformerCode, - $transformerConfig, - ] - ); + $transformerDefinition->addMethodCall('initialize', [$transformerCode, $transformerConfig]); $transformerDefinition->addTag('cleverage.transformer'); - $container->setDefinition(GenericTransformer::class."\\".$transformerCode, $transformerDefinition); + $container->setDefinition(GenericTransformer::class . '\\' . $transformerCode, $transformerDefinition); } } /** * Recursively import config files into container - * - * @param ContainerBuilder $container - * @param string $path - * @param string $extension - * - * @throws \Exception */ protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yml') { $finder = new Finder(); - $finder->in($path)->name('*.'.$extension)->files(); + $finder->in($path) + ->name('*.' . $extension)->files(); $loader = new YamlFileLoader($container, new FileLocator($path)); foreach ($finder as $file) { $loader->load($file->getFilename()); diff --git a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 168ef4b8..4dd382cf 100644 --- a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -1,4 +1,7 @@ - */ class CheckSerializerCompilerPass implements CompilerPassInterface { - const MSG = 'The Symfony serializer component do not seem enabled, consider toggling framework.serializer.enable (see https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled)'; + final public const MSG = 'The Symfony serializer component do not seem enabled, consider toggling framework.serializer.enable (see https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled)'; - /** - * {@inheritDoc} - */ public function process(ContainerBuilder $container) { - if (!$container->has('serializer') && !$container->has(DenormalizerInterface::class)) { + if (! $container->has('serializer') && ! $container->has(DenormalizerInterface::class)) { throw new AutowiringFailedException('serializer', self::MSG); } } diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/DependencyInjection/Compiler/RegistryCompilerPass.php index 620c823c..0ca13ee0 100644 --- a/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class RegistryCompilerPass implements CompilerPassInterface { @@ -29,22 +27,19 @@ class RegistryCompilerPass implements CompilerPassInterface * @param string $tag * @param string $method */ - public function __construct(protected $registry, protected $tag, protected $method) - { + public function __construct( + protected $registry, + protected $tag, + protected $method + ) { } /** * Inject tagged services into defined registry - * - * @param ContainerBuilder $container - * - * @throws InvalidArgumentException - * @throws \UnexpectedValueException - * @throws ServiceNotFoundException */ - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { - if (!$container->has($this->registry)) { + if (! $container->has($this->registry)) { return; } @@ -52,10 +47,7 @@ public function process(ContainerBuilder $container) $taggedServices = $container->findTaggedServiceIds($this->tag); foreach ($taggedServices as $id => $tags) { - $definition->addMethodCall( - $this->method, - [new Reference($id)] - ); + $definition->addMethodCall($this->method, [new Reference($id)]); } } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4c0f213c..eda04bd7 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class Configuration implements ConfigurationInterface { /** * @param string $root */ - public function __construct(protected $root = 'clever_age_process') - { + public function __construct( + protected $root = 'clever_age_process' + ) { } - /** - * {@inheritdoc} - * - * @throws RuntimeException - */ public function getConfigTreeBuilder() { [$treeBuilder, $rootNode] = $this->createTreeBuilder(); $definition = $rootNode->children(); // Default error strategy $definition->enumNode('default_error_strategy') - ->values( - [ - TaskConfiguration::STRATEGY_SKIP, - TaskConfiguration::STRATEGY_STOP, - ] - ) + ->values([TaskConfiguration::STRATEGY_SKIP, TaskConfiguration::STRATEGY_STOP]) ->isRequired(); $this->appendRootProcessConfigDefinition($definition); @@ -88,8 +77,14 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio protected function appendTransformerConfigDefinition(NodeBuilder $definition) { $definition - ->arrayNode('contextual_options')->prototype('variable')->end()->end() - ->arrayNode('transformers')->prototype('variable')->end()->end(); + ->arrayNode('contextual_options') + ->prototype('variable') + ->end() + ->end() + ->arrayNode('transformers') + ->prototype('variable') + ->end() + ->end(); } /** @@ -116,12 +111,25 @@ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) protected function appendProcessConfigDefinition(NodeBuilder $definition) { $definition - ->scalarNode('entry_point')->defaultNull()->end() - ->scalarNode('end_point')->defaultNull()->end() - ->scalarNode('description')->defaultValue('')->end() - ->scalarNode('help')->defaultValue('')->end() - ->scalarNode('public')->defaultTrue()->end() - ->arrayNode('options')->prototype('variable')->end()->end(); + ->scalarNode('entry_point') + ->defaultNull() + ->end() + ->scalarNode('end_point') + ->defaultNull() + ->end() + ->scalarNode('description') + ->defaultValue('') + ->end() + ->scalarNode('help') + ->defaultValue('') + ->end() + ->scalarNode('public') + ->defaultTrue() + ->end() + ->arrayNode('options') + ->prototype('variable') + ->end() + ->end(); /** @var ArrayNodeDefinition $tasksArrayDefinition */ $tasksArrayDefinition = $definition @@ -152,14 +160,23 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) LogLevel::DEBUG, ]; - $definition->scalarNode('service')->isRequired(); - $definition->scalarNode('description')->defaultValue(''); - $definition->scalarNode('help')->defaultValue(''); - $definition->arrayNode('options')->prototype('variable')->end(); - $definition->scalarNode('error_strategy')->defaultNull(); - $definition->enumNode('log_level')->values($logLevels)->defaultValue(LogLevel::CRITICAL); - - $logErrorNode = $definition->booleanNode('log_errors')->defaultTrue(); + $definition->scalarNode('service') + ->isRequired(); + $definition->scalarNode('description') + ->defaultValue(''); + $definition->scalarNode('help') + ->defaultValue(''); + $definition->arrayNode('options') + ->prototype('variable') + ->end(); + $definition->scalarNode('error_strategy') + ->defaultNull(); + $definition->enumNode('log_level') + ->values($logLevels) + ->defaultValue(LogLevel::CRITICAL); + + $logErrorNode = $definition->booleanNode('log_errors') + ->defaultTrue(); $this->deprecateNode( $logErrorNode, 'cleverage/process-bundle', @@ -170,9 +187,8 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) foreach (['outputs', 'errors', 'error_outputs'] as $nodeName) { $definition->arrayNode($nodeName) ->beforeNormalization() - ->ifString()->then( - fn($item): array => [$item] - )->end() + ->ifString() + ->then(fn ($item): array => [$item])->end() ->prototype('scalar'); } } @@ -185,12 +201,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) */ protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message) { - $deprecationMethodReflection = new ReflectionMethod(NodeDefinition::class, 'setDeprecated'); - if ($deprecationMethodReflection->getNumberOfParameters() === 1) { - $node->setDeprecated("Since {$package} {$version}: {$message}"); - } else { - $node->setDeprecated($package, $version, $message); - } + $node->setDeprecated($package, $version, $message); } /** @@ -199,8 +210,6 @@ protected function deprecateNode(NodeDefinition $node, string $package, string $ * * @TODO remove this once support for Symfony 3 and 4 is dropped * - * @param string $root - * * @return array A tuple containing [TreeBuilder, NodeDefinition] */ protected function createTreeBuilder(): array diff --git a/Event/ConsoleProcessEvent.php b/Event/ConsoleProcessEvent.php index 2273fbaa..3b577896 100644 --- a/Event/ConsoleProcessEvent.php +++ b/Event/ConsoleProcessEvent.php @@ -1,4 +1,7 @@ -consoleInput; diff --git a/Event/EventDispatcherTaskEvent.php b/Event/EventDispatcherTaskEvent.php index c4dff488..5b48d56d 100644 --- a/Event/EventDispatcherTaskEvent.php +++ b/Event/EventDispatcherTaskEvent.php @@ -1,4 +1,7 @@ - - */ class EventDispatcherTaskEvent extends GenericEvent { - /** - * @var ProcessState - */ - protected $state; - - /** - * @param ProcessState $state - */ - public function __construct(ProcessState $state) - { - $this->state = $state; + public function __construct( + protected ProcessState $state + ) { } - /** - * @return ProcessState - */ - public function getState() + public function getState(): ProcessState { return $this->state; } - /** - * @param ProcessState $state - */ - public function setState($state) + public function setState(ProcessState $state): void { $this->state = $state; } diff --git a/Event/GenericEvent.php b/Event/GenericEvent.php index 65a5f296..788ce05b 100644 --- a/Event/GenericEvent.php +++ b/Event/GenericEvent.php @@ -1,4 +1,7 @@ - */ class ProcessEvent extends GenericEvent { - final public const EVENT_PROCESS_STARTED = 'cleverage_process.start'; + final public const EVENT_PROCESS_ENDED = 'cleverage_process.end'; + final public const EVENT_PROCESS_FAILED = 'cleverage_process.fail'; - /** - * ProcessEvent constructor. - */ - public function __construct(protected string $processCode, protected mixed $processInput = null, protected array $processContext = [], protected mixed $processOutput = null, protected ?Throwable $processError = null) - { + public function __construct( + protected string $processCode, + protected mixed $processInput = null, + protected array $processContext = [], + protected mixed $processOutput = null, + protected ?Throwable $processError = null + ) { } public function getProcessCode(): string @@ -60,5 +65,4 @@ public function getProcessError(): ?Throwable { return $this->processError; } - } diff --git a/EventListener/DataQueueEventListener.php b/EventListener/DataQueueEventListener.php index 49f8ac14..036f73f8 100644 --- a/EventListener/DataQueueEventListener.php +++ b/EventListener/DataQueueEventListener.php @@ -1,4 +1,7 @@ - */ class DataQueueEventListener { - /** @var \SplQueue[] */ - protected $queues = []; - /** - * @param EventDispatcherTaskEvent $event + * @var SplQueue[] */ - public function pushData(EventDispatcherTaskEvent $event) + protected $queues = []; + + public function pushData(EventDispatcherTaskEvent $event): void { $queue = $this->getQueue($event->getState()->getProcessConfiguration()->getCode()); $queue->push(clone $event->getState()); @@ -35,13 +36,11 @@ public function pushData(EventDispatcherTaskEvent $event) /** * @param string $processName - * - * @return \SplQueue */ - public function getQueue($processName): \SplQueue + public function getQueue($processName): SplQueue { - if (!array_key_exists($processName, $this->queues)) { - $this->queues[$processName] = new \SplQueue(); + if (! array_key_exists($processName, $this->queues)) { + $this->queues[$processName] = new SplQueue(); } return $this->queues[$processName]; diff --git a/Exception/CircularProcessException.php b/Exception/CircularProcessException.php index 5ca9a0bf..58d6d1c8 100644 --- a/Exception/CircularProcessException.php +++ b/Exception/CircularProcessException.php @@ -1,4 +1,7 @@ -getCode()}' is not in main task list : {$taskListStr} (from process: {$processConfiguration->getCode()})" ); } - /** - * @param ProcessConfiguration $processConfiguration - * @param TaskConfiguration $taskConfig - * - * @return InvalidProcessConfigurationException - */ public static function createEntryPointHasAncestors( ProcessConfiguration $processConfiguration, TaskConfiguration $taskConfig diff --git a/Exception/MissingProcessException.php b/Exception/MissingProcessException.php index 2ef4a1b7..0e9ad2ac 100644 --- a/Exception/MissingProcessException.php +++ b/Exception/MissingProcessException.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ -class MissingProcessException extends \UnexpectedValueException implements ProcessExceptionInterface +class MissingProcessException extends UnexpectedValueException implements ProcessExceptionInterface { /** * @param string $code - * - * @return MissingProcessException */ public static function create($code): self { diff --git a/Exception/MissingTaskConfigurationException.php b/Exception/MissingTaskConfigurationException.php index 912cbae6..f6b93a00 100644 --- a/Exception/MissingTaskConfigurationException.php +++ b/Exception/MissingTaskConfigurationException.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ -class MissingTaskConfigurationException extends \UnexpectedValueException implements ProcessExceptionInterface +class MissingTaskConfigurationException extends UnexpectedValueException implements ProcessExceptionInterface { /** * @param string $code - * - * @return MissingTaskConfigurationException */ public static function create($code): self { diff --git a/Exception/MissingTransformerException.php b/Exception/MissingTransformerException.php index b47d1f12..6abaef7f 100644 --- a/Exception/MissingTransformerException.php +++ b/Exception/MissingTransformerException.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ -class MissingTransformerException extends \UnexpectedValueException implements ProcessExceptionInterface +class MissingTransformerException extends UnexpectedValueException implements ProcessExceptionInterface { /** * @param string $code - * - * @return MissingTransformerException */ public static function create($code): self { diff --git a/Exception/MultiBranchProcessException.php b/Exception/MultiBranchProcessException.php index 736a25dd..6d10cbcd 100644 --- a/Exception/MultiBranchProcessException.php +++ b/Exception/MultiBranchProcessException.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ -interface ProcessExceptionInterface extends \Throwable +interface ProcessExceptionInterface extends Throwable { } diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index fd7efbc5..68f95fb3 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class TransformerException extends RuntimeException implements ProcessExceptionInterface { - /** @var string */ + /** + * @var string + */ protected $targetProperty; /** - * {@inheritDoc} * @param string $transformerCode */ - public function __construct(protected $transformerCode, $code = 0, Throwable $previous = null) - { + public function __construct( + protected $transformerCode, + $code = 0, + Throwable $previous = null + ) { parent::__construct('', $code, $previous); $this->updateMessage(); } @@ -48,13 +53,11 @@ protected function updateMessage() $this->transformerCode ); } else { - $m = sprintf( - "Transformation '%s' have failed", - $this->transformerCode - ); + $m = sprintf("Transformation '%s' have failed", $this->transformerCode); } if ($this->getPrevious()) { - $m .= ": {$this->getPrevious()->getMessage()}"; + $m .= ": {$this->getPrevious() + ->getMessage()}"; } $this->message = $m; } diff --git a/ExpressionLanguage/PhpFunctionProvider.php b/ExpressionLanguage/PhpFunctionProvider.php index 6e60b7af..fa84ab60 100644 --- a/ExpressionLanguage/PhpFunctionProvider.php +++ b/ExpressionLanguage/PhpFunctionProvider.php @@ -1,4 +1,7 @@ - */ class PhpFunctionProvider implements ExpressionFunctionProviderInterface { - /** @var array */ - protected $functions; - - /** - * PhpFunctionProvider constructor. - * - * @param array $functions - */ - public function __construct(array $functions) - { - $this->functions = $functions; + public function __construct( + protected array $functions + ) { } /** @@ -38,8 +31,6 @@ public function __construct(array $functions) */ public function getFunctions() { - return array_map(function ($func) { - return ExpressionFunction::fromPhp($func); - }, $this->functions); + return array_map(fn ($func): ExpressionFunction => ExpressionFunction::fromPhp($func), $this->functions); } } diff --git a/Filesystem/CsvFile.php b/Filesystem/CsvFile.php index 2177184a..9dca8beb 100644 --- a/Filesystem/CsvFile.php +++ b/Filesystem/CsvFile.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CsvFile extends CsvResource { /** - * @param string $filePath Also accept a resource - * @param string $delimiter CSV delimiter - * @param string $enclosure - * @param string $escape - * @param array $headers Leave null to read the headers from the file - * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) - * - * @throws \RuntimeException - * @throws \UnexpectedValueException + * @param string $filePath Also accept a resource + * @param string $delimiter CSV delimiter + * @param string $enclosure + * @param string $escape + * @param mixed[]|null $headers Leave null to read the headers from the file + * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) */ public function __construct( protected $filePath, @@ -35,24 +35,24 @@ public function __construct( $enclosure = '"', $escape = '\\', array $headers = null, - $mode = 'rb' + string $mode = 'rb' ) { - if (!\in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'])) { + if (! \in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { $dirname = \dirname($this->filePath); - if (!@mkdir($dirname, 0755, true) && !is_dir($dirname)) { - throw new \RuntimeException(sprintf('Directory "%s" was not created', $dirname)); + if (! @mkdir($dirname, 0755, true) && ! is_dir($dirname)) { + throw new RuntimeException(sprintf('Directory "%s" was not created', $dirname)); } } $resource = fopen($filePath, $mode); - if (false === $resource) { - throw new \UnexpectedValueException("Unable to open file: '{$filePath}' in {$mode} mode"); + if ($resource === false) { + throw new UnexpectedValueException("Unable to open file: '{$filePath}' in {$mode} mode"); } // All modes allowing file reading, binary safe modes are handled by stripping out the b during test $readAllowedModes = ['r', 'r+', 'w+', 'a+', 'x+', 'c+']; - if (null === $headers && !\in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { + if ($headers === null && ! \in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { // Cannot read headers if the file was just created - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } @@ -62,17 +62,12 @@ public function __construct( /** * Will return a resource if the file was created using a resource - * - * @return string|resource */ public function getFilePath(): string { return $this->filePath; } - /** - * @return string - */ protected function getResourceName(): string { return "CSV file '{$this->filePath}'"; diff --git a/Filesystem/CsvResource.php b/Filesystem/CsvResource.php index d229cb11..eace7964 100644 --- a/Filesystem/CsvResource.php +++ b/Filesystem/CsvResource.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterface { - /** @var resource */ + /** + * @var resource + */ protected $handler; - /** @var int|null */ + /** + * @var int|null + */ protected $lineCount; protected array $headers; - /** @var bool */ + /** + * @var bool + */ protected $manualHeaders = false; protected int $headerCount; - /** @var int */ + /** + * @var int + */ protected $lineNumber = 1; protected bool $closed; - /** @var bool */ + /** + * @var bool + */ protected $seekCalled = false; /** @@ -48,8 +59,6 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf * @param string $enclosure * @param string $escape * @param mixed[]|null $headers Leave null to read the headers from the file - * - * @throws UnexpectedValueException */ public function __construct( $resource, @@ -58,7 +67,7 @@ public function __construct( protected $escape = '\\', array $headers = null ) { - if (!\is_resource($resource)) { + if (! \is_resource($resource)) { $type = \gettype($resource); throw new UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); } @@ -68,6 +77,14 @@ public function __construct( $this->headerCount = \count($this->headers); } + /** + * Closes the resource when the object is destroyed. + */ + public function __destruct() + { + $this->close(); + } + public function getDelimiter(): string { return $this->delimiter; @@ -97,16 +114,13 @@ public function getHandler() * Warning! This method will rewind the file to the beginning before and after counting the lines! * Do not use in the middle of a process. * This can be very slow. - * - * @return int - * @throws RuntimeException */ public function getLineCount(): int { - if (null === $this->lineCount) { + if ($this->lineCount === null) { $this->rewind(); $line = 0; - while (!$this->isEndOfFile()) { + while (! $this->isEndOfFile()) { if ($this->readRaw()) { ++$line; } @@ -119,17 +133,11 @@ public function getLineCount(): int return $this->lineCount; } - /** - * @return array - */ public function getHeaders(): array { return $this->headers; } - /** - * @return int - */ public function getHeaderCount(): int { return $this->headerCount; @@ -137,17 +145,12 @@ public function getHeaderCount(): int /** * Write headers to the file - * - * @throws RuntimeException */ public function writeHeaders(): void { $this->writeRaw($this->headers); } - /** - * {@inheritDoc} - */ public function getLineNumber(): int { if ($this->seekCalled) { @@ -157,11 +160,6 @@ public function getLineNumber(): int return $this->lineNumber; } - /** - * @throws RuntimeException - * - * @return bool - */ public function isEndOfFile(): bool { $this->assertOpened(); @@ -173,8 +171,6 @@ public function isEndOfFile(): bool * Warning, this function will return exactly the same value as the fgetcsv() function. * * @param null|int $length - * - * @throws RuntimeException */ public function readRaw($length = null): array|false { @@ -187,9 +183,6 @@ public function readRaw($length = null): array|false /** * @param int|null $length * - * @throws UnexpectedValueException - * @throws RuntimeException - * * @return array */ public function readLine($length = null): ?array @@ -201,7 +194,7 @@ public function readLine($length = null): ?array } $values = $this->readRaw($length); - if (false === $values) { + if ($values === false) { if ($this->isEndOfFile()) { return null; } @@ -217,7 +210,7 @@ public function readLine($length = null): ?array } $combined = array_combine($this->headers, $values); - if (false === $combined) { + if ($combined === false) { throw new RuntimeException('Cannot combine headers with values'); } @@ -226,9 +219,6 @@ public function readLine($length = null): ?array /** * Warning, this function will return exactly the same value as the fgetcsv() function. - * - * - * @throws RuntimeException */ public function writeRaw(array $fields): int { @@ -238,13 +228,6 @@ public function writeRaw(array $fields): int return fputcsv($this->handler, $fields, $this->delimiter, $this->enclosure, $this->escape); } - /** - * @param array $fields - * - * @throws RuntimeException - * - * @return int - */ public function writeLine(array $fields): int { $count = \count($fields); @@ -256,7 +239,7 @@ public function writeLine(array $fields): int $parsedFields = []; foreach ($this->headers as $column) { - if (!array_key_exists($column, $fields)) { + if (! array_key_exists($column, $fields)) { $message = "Missing column {$column} in given fields for {$this->getResourceName()}"; throw new UnexpectedValueException($message); } @@ -264,7 +247,7 @@ public function writeLine(array $fields): int } $length = $this->writeRaw($parsedFields); - if (false === $length) { + if ($length === false) { throw new RuntimeException("Unable to write data to {$this->getResourceName()}"); } @@ -273,26 +256,19 @@ public function writeLine(array $fields): int /** * This methods rewinds the file to the first line of data, skipping the headers. - * - * @throws RuntimeException */ public function rewind(): void { $this->assertOpened(); - if (!rewind($this->handler)) { + if (! rewind($this->handler)) { throw new RuntimeException("Unable to rewind '{$this->getResourceName()}'"); } $this->lineNumber = 1; - if (!$this->manualHeaders) { + if (! $this->manualHeaders) { $this->readRaw(); // skip headers if not manual headers } } - /** - * @throws RuntimeException - * - * @return int - */ public function tell(): int { $this->assertOpened(); @@ -302,10 +278,6 @@ public function tell(): int /** * @param int $offset - * - * @throws RuntimeException - * - * @return int */ public function seek($offset): int { @@ -336,17 +308,11 @@ public function isClosed(): bool return $this->closed; } - /** - * Closes the resource when the object is destroyed. - */ - public function __destruct() + public function getFilePath(): string { - $this->close(); + return ''; } - /** - * @throws RuntimeException - */ protected function assertOpened(): void { if ($this->closed) { @@ -354,16 +320,12 @@ protected function assertOpened(): void } } - /** - * - * @throws UnexpectedValueException - */ protected function parseHeaders(array $headers = null): array { // If headers are not passed in the constructor but file is readable, try to read headers from file - if (null === $headers) { + if ($headers === null) { $autoHeaders = $this->readRaw(); - if (false === $autoHeaders || 0 === \count($autoHeaders)) { + if ($autoHeaders === false || \count($autoHeaders) === 0) { throw new UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any @@ -374,12 +336,12 @@ protected function parseHeaders(array $headers = null): array } $this->manualHeaders = true; - if (null === $headers || !\is_array($headers)) { + if ($headers === null || ! \is_array($headers)) { throw new UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } - if (0 === \count($headers)) { + if (\count($headers) === 0) { throw new UnexpectedValueException( "Empty headers for {$this->getResourceName()}, you need to pass the headers manually" ); diff --git a/Filesystem/FileStreamInterface.php b/Filesystem/FileStreamInterface.php index 61e029cc..117ae72a 100644 --- a/Filesystem/FileStreamInterface.php +++ b/Filesystem/FileStreamInterface.php @@ -1,4 +1,7 @@ -file = new \SplFileObject($filename, $mode); + $this->file = new SplFileObject($filename, $mode); // Useful to skip empty trailing lines - $this->file->setFlags(\SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); + $this->file->setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); } /** * Warning! This method will rewind the file to the beginning before and after counting the lines! - * - * @throws \RuntimeException - * - * @return int */ public function getLineCount(): int { - if (null === $this->lineCount) { + if ($this->lineCount === null) { $this->rewind(); $line = 0; - while (!$this->isEndOfFile()) { + while (! $this->isEndOfFile()) { ++$line; $this->file->next(); } @@ -62,17 +65,11 @@ public function getLineCount(): int return $this->lineCount; } - /** - * {@inheritDoc} - */ public function getLineNumber(): int { return $this->lineNumber; } - /** - * @return bool - */ public function isEndOfFile(): bool { return $this->file->eof(); @@ -82,8 +79,6 @@ public function isEndOfFile(): bool * Return an array containing current data and moving the file pointer * * @param null $length - * - * @return array|null */ public function readLine($length = null): ?array { @@ -94,17 +89,12 @@ public function readLine($length = null): ?array $rawLine = $this->file->fgets(); $this->lineNumber++; - return json_decode($rawLine, true); + return json_decode($rawLine, true, 512, JSON_THROW_ON_ERROR); } - /** - * @param array $item - * - * @return int - */ public function writeLine(array $item): int { - $this->file->fwrite(json_encode($item).PHP_EOL); + $this->file->fwrite(json_encode($item, JSON_THROW_ON_ERROR) . PHP_EOL); $this->lineNumber++; return $this->lineNumber; diff --git a/Filesystem/SeekableFileInterface.php b/Filesystem/SeekableFileInterface.php index c385a7ed..8b570e4f 100644 --- a/Filesystem/SeekableFileInterface.php +++ b/Filesystem/SeekableFileInterface.php @@ -1,4 +1,7 @@ - */ class XmlFile { - /** @var \SplFileObject */ - protected $file; - - /** - * XmlFile constructor. - * - * @param string $path - * @param string $mode - */ + protected SplFileObject $file; + public function __construct(string $path, string $mode = 'rb') { - $this->file = new \SplFileObject($path, $mode); + $this->file = new SplFileObject($path, $mode); } - public function read(): \DOMDocument + public function read(): DOMDocument { - $dom = new \DOMDocument(); + $dom = new DOMDocument(); $this->file->rewind(); $fileSize = $this->file->getSize(); $fileContent = $this->file->fread($fileSize); @@ -42,13 +41,13 @@ public function read(): \DOMDocument return $dom; } - public function write(\DOMDocument $dom) + public function write(DOMDocument $dom) { $content = $dom->saveXML(); $result = $this->file->fwrite($content); if ($result === null) { - throw new \RuntimeException("Could not write content to file"); + throw new RuntimeException('Could not write content to file'); } } } diff --git a/Logger/AbstractLogger.php b/Logger/AbstractLogger.php index eae8cc7d..f607a489 100644 --- a/Logger/AbstractLogger.php +++ b/Logger/AbstractLogger.php @@ -1,4 +1,7 @@ -logger = $logger; + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * {@inheritDoc} - */ public function log($level, $message, array $context = []): void { $this->logger->log($level, $message, $context); diff --git a/Logger/AbstractProcessor.php b/Logger/AbstractProcessor.php index 740ec4ad..d2ec2f9f 100644 --- a/Logger/AbstractProcessor.php +++ b/Logger/AbstractProcessor.php @@ -1,4 +1,7 @@ - - */ class AbstractProcessor { - /** @var ProcessManager */ - protected $processManager; - - /** - * @param ProcessManager $processManager - */ - public function __construct(ProcessManager $processManager) - { - $this->processManager = $processManager; + public function __construct( + protected ProcessManager $processManager + ) { } /** - * @param array $record - * * @return array */ public function __invoke(array $record) @@ -48,11 +40,6 @@ public function __invoke(array $record) return $record; } - /** - * @param array $record - * - * @return array - */ protected function normalizeRecordData(array $record): array { $newRecord = []; @@ -63,15 +50,10 @@ protected function normalizeRecordData(array $record): array return $newRecord; } - /** - * @param array $record - * - * @return void - */ protected function addProcessInfoToRecord(array &$record): void { $processHistory = $this->processManager->getProcessHistory(); - if (!$processHistory) { + if (! $processHistory) { return; } @@ -80,22 +62,17 @@ protected function addProcessInfoToRecord(array &$record): void $this->addToRecord($record, 'process_context', $processHistory->getContext()); } - /** - * @param array $record - * - * @return void - */ protected function addTaskInfoToRecord(array &$record): void { $taskConfiguration = $this->processManager->getTaskConfiguration(); - if (!$taskConfiguration) { + if (! $taskConfiguration) { return; } $this->addToRecord($record, 'task_code', $taskConfiguration->getCode()); $this->addToRecord($record, 'task_service', $taskConfiguration->getServiceReference()); $state = $taskConfiguration->getState(); - if (!$state) { + if (! $state) { return; } if ($state->hasErrorOutput()) { @@ -108,13 +85,9 @@ protected function addTaskInfoToRecord(array &$record): void } /** - * @param array $record * @param string $name - * @param mixed $data - * - * @return void */ - protected function addToRecord(array &$record, $name, $data): void + protected function addToRecord(array &$record, $name, mixed $data): void { $record[$name] = $data; } diff --git a/Logger/ProcessLogger.php b/Logger/ProcessLogger.php index 099a8024..1e350415 100644 --- a/Logger/ProcessLogger.php +++ b/Logger/ProcessLogger.php @@ -1,4 +1,7 @@ - - */ class ProcessLogger extends AbstractLogger { } diff --git a/Logger/ProcessProcessor.php b/Logger/ProcessProcessor.php index 2fa87f34..1c2ea6b4 100644 --- a/Logger/ProcessProcessor.php +++ b/Logger/ProcessProcessor.php @@ -1,4 +1,7 @@ - - */ class ProcessProcessor extends AbstractProcessor { } diff --git a/Logger/TaskLogger.php b/Logger/TaskLogger.php index 1e7dad26..b5176467 100644 --- a/Logger/TaskLogger.php +++ b/Logger/TaskLogger.php @@ -1,4 +1,7 @@ - - */ class TaskLogger extends AbstractLogger { - } diff --git a/Logger/TaskProcessor.php b/Logger/TaskProcessor.php index d6cbaf06..3c695955 100644 --- a/Logger/TaskProcessor.php +++ b/Logger/TaskProcessor.php @@ -1,4 +1,7 @@ - - */ class TaskProcessor extends AbstractProcessor { /** - * @param array $record - * * @return array */ public function __invoke(array $record) diff --git a/Logger/TransformerProcessor.php b/Logger/TransformerProcessor.php index 8517671c..4aff866d 100644 --- a/Logger/TransformerProcessor.php +++ b/Logger/TransformerProcessor.php @@ -1,4 +1,7 @@ - - */ class TransformerProcessor extends AbstractProcessor { /** - * @param array $record - * * @return array */ public function __invoke(array $record) diff --git a/Makefile b/Makefile index def010bf..f25e19ac 100644 --- a/Makefile +++ b/Makefile @@ -61,5 +61,7 @@ vendor/%: docker cp cleverage_process_bundle_tmp:/app/vendor vendor-$(@F) docker container rm cleverage_process_bundle_tmp -linter: - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) /bin/bash -c "vendor/bin/phpstan" \ No newline at end of file +linter/local: + vendor/bin/rector process + vendor/bin/ecs check --fix + vendor/bin/phpstan diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index 66294acd..c9680ff6 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ProcessManager { protected const EXECUTE_PROCESS = 1; - protected const EXECUTE_PROCEED = 2; - protected const EXECUTE_FLUSH = 4; - - /** @var ContainerInterface */ - protected $container; - - /** @var ProcessLogger */ - protected $processLogger; - /** @var TaskLogger */ - protected $taskLogger; + protected const EXECUTE_PROCEED = 2; - /** @var ProcessConfigurationRegistry */ - protected $processConfigurationRegistry; + protected const EXECUTE_FLUSH = 4; - /** @var TaskConfiguration */ + /** + * @var TaskConfiguration + */ protected $blockingTaskConfiguration; - /** @var ContextualOptionResolver */ - protected $contextualOptionResolver; - - /** @var TaskConfiguration[] */ + /** + * @var TaskConfiguration[] + */ protected $processedIterables = []; - /** @var TaskConfiguration[] */ + /** + * @var TaskConfiguration[] + */ protected $processedBlockings = []; - /** @var ProcessHistory */ - protected $processHistory; - - /** @var TaskConfiguration */ - protected $taskConfiguration; + protected ?ProcessHistory $processHistory = null; - /** @var EventDispatcherInterface */ - protected $eventDispatcher; + protected ?TaskConfiguration $taskConfiguration = null; - /** - * ProcessManager constructor. - * - * @param ContainerInterface $container - * @param ProcessLogger $processLogger - * @param TaskLogger $taskLogger - * @param ProcessConfigurationRegistry $processConfigurationRegistry - * @param ContextualOptionResolver $contextualOptionResolver - * @param EventDispatcherInterface $eventDispatcher - */ public function __construct( - ContainerInterface $container, - ProcessLogger $processLogger, - TaskLogger $taskLogger, - ProcessConfigurationRegistry $processConfigurationRegistry, - ContextualOptionResolver $contextualOptionResolver, - EventDispatcherInterface $eventDispatcher + protected ContainerInterface $container, + protected ProcessLogger $processLogger, + protected TaskLogger $taskLogger, + protected ProcessConfigurationRegistry $processConfigurationRegistry, + protected ContextualOptionResolver $contextualOptionResolver, + protected EventDispatcherInterface $eventDispatcher ) { - $this->container = $container; - $this->processLogger = $processLogger; - $this->taskLogger = $taskLogger; - $this->processConfigurationRegistry = $processConfigurationRegistry; - $this->contextualOptionResolver = $contextualOptionResolver; - $this->eventDispatcher = $eventDispatcher; } - /** - * @return ProcessHistory|null - */ public function getProcessHistory(): ?ProcessHistory { return $this->processHistory; } - /** - * @return TaskConfiguration|null - */ public function getTaskConfiguration(): ?TaskConfiguration { return $this->taskConfiguration; @@ -126,34 +91,25 @@ public function getTaskConfiguration(): ?TaskConfiguration * This method decorates the real execution to add event & error handling * @see ProcessManager::doExecute * - * @param string $processCode - * @param null $input - * @param array $context + * @param null $input * * @return mixed */ - public function execute(string $processCode, $input = null, array $context = []) + public function execute(string $processCode, mixed $input = null, array $context = []) { try { - $this->eventDispatcher->dispatch( - new ProcessEvent($processCode, $input, $context), - ProcessEvent::EVENT_PROCESS_STARTED - ); + $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context)); $this->processLogger->debug('Process start'); $result = $this->doExecute($processCode, $input, $context); $this->processLogger->debug('Process end'); - $this->eventDispatcher->dispatch( - new ProcessEvent($processCode, $input, $context, $result), - ProcessEvent::EVENT_PROCESS_ENDED - ); - } catch (\Throwable $error) { - $this->processLogger->critical('Critical process failure', ['error' => $error->getMessage()]); - $this->eventDispatcher->dispatch( - new ProcessEvent($processCode, $input, $context, null, $error), - ProcessEvent::EVENT_PROCESS_FAILED - ); + $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context, $result)); + } catch (Throwable $error) { + $this->processLogger->critical('Critical process failure', [ + 'error' => $error->getMessage(), + ]); + $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context, null, $error)); throw $error; } @@ -164,13 +120,9 @@ public function execute(string $processCode, $input = null, array $context = []) /** * Real process execution, with a given input and context * - * @param string $processCode - * @param mixed $input - * @param array $context - * * @return mixed */ - protected function doExecute(string $processCode, $input = null, array $context = []) + protected function doExecute(string $processCode, mixed $input = null, array $context = []) { $parentProcessHistory = $this->processHistory; $processConfiguration = $this->processConfigurationRegistry->getProcessConfiguration($processCode); @@ -185,7 +137,9 @@ protected function doExecute(string $processCode, $input = null, array $context // If defined, set the input of a task if ($processConfiguration->getEntryPoint()) { - $processConfiguration->getEntryPoint()->getState()->setInput($input); + $processConfiguration->getEntryPoint() + ->getState() + ->setInput($input); } elseif ($input !== null) { $this->processLogger->warning('Process has no entry point for input'); } @@ -210,7 +164,9 @@ protected function doExecute(string $processCode, $input = null, array $context // If defined, return the output of a task $returnValue = null; if ($processConfiguration->getEndPoint()) { - $returnValue = $processConfiguration->getEndPoint()->getState()->getOutput(); + $returnValue = $processConfiguration->getEndPoint() + ->getState() + ->getOutput(); } $this->processHistory = $parentProcessHistory; @@ -220,13 +176,6 @@ protected function doExecute(string $processCode, $input = null, array $context /** * Resolve a task, by checking if parents are resolved and processing roots and BlockingTasks - * - * @param TaskConfiguration $taskConfiguration - * - * @throws \RuntimeException - * @throws \UnexpectedValueException - * - * @return bool */ protected function resolve(TaskConfiguration $taskConfiguration): bool { @@ -240,14 +189,14 @@ protected function resolve(TaskConfiguration $taskConfiguration): bool // Resolve parents first $allParentsResolved = true; foreach ($taskConfiguration->getPreviousTasksConfigurations() as $previousTasksConfiguration) { - if (!$previousTasksConfiguration->getState()->isResolved()) { + if (! $previousTasksConfiguration->getState()->isResolved()) { $isResolved = $this->resolve($previousTasksConfiguration); $allParentsResolved = $allParentsResolved && $isResolved; } } - if (!$allParentsResolved) { - throw new \UnexpectedValueException('Cannot resolve all parents'); + if (! $allParentsResolved) { + throw new UnexpectedValueException('Cannot resolve all parents'); } $state->setStatus(ProcessState::STATUS_PROCESSING); @@ -274,20 +223,15 @@ protected function resolve(TaskConfiguration $taskConfiguration): bool /** * Fetch task service and run additional setup for InitializableTasks - * - * @param TaskConfiguration $taskConfiguration - * - * @throws ServiceNotFoundException - * @throws ServiceCircularReferenceException - * @throws \UnexpectedValueException - * @throws \RuntimeException */ protected function initialize(TaskConfiguration $taskConfiguration): void { $this->taskConfiguration = $taskConfiguration; if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP - && \count($taskConfiguration->getErrorOutputs()) > 0) { + && (is_countable($taskConfiguration->getErrorOutputs()) ? \count( + $taskConfiguration->getErrorOutputs() + ) : 0) > 0) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); @@ -295,17 +239,17 @@ protected function initialize(TaskConfiguration $taskConfiguration): void // @todo Refactor this using a Registry with this feature: // https://symfony.com/doc/current/service_container/service_subscribers_locators.html $serviceReference = $taskConfiguration->getServiceReference(); - if (0 === strpos($serviceReference, '@')) { - $task = $this->container->get(ltrim($serviceReference, '@')); + if (str_starts_with((string) $serviceReference, '@')) { + $task = $this->container->get(ltrim((string) $serviceReference, '@')); } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" ); } - if (!$task instanceof TaskInterface) { - throw new \UnexpectedValueException( + if (! $task instanceof TaskInterface) { + throw new UnexpectedValueException( "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" ); } @@ -315,8 +259,10 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $state = $taskConfiguration->getState(); try { $task->initialize($state); - } catch (\Throwable $e) { - $logContext = ['exception' => $e]; + } catch (Throwable $e) { + $logContext = [ + 'exception' => $e, + ]; $this->taskLogger->critical($e->getMessage(), $logContext); $state->stop($e); } @@ -326,12 +272,6 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = null; } - /** - * @param TaskConfiguration $taskConfiguration - * @param int $executionFlag - * - * @throws \RuntimeException - */ protected function process(TaskConfiguration $taskConfiguration, int $executionFlag = self::EXECUTE_PROCESS): void { $this->taskConfiguration = $taskConfiguration; @@ -360,10 +300,12 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF if ($state->isStopped()) { $exception = $state->getException(); if ($exception) { - $m = "Process {$state->getProcessConfiguration()->getCode()} has failed"; - $m .= " during process {$state->getTaskConfiguration()->getCode()}"; + $m = "Process {$state->getProcessConfiguration() + ->getCode()} has failed"; + $m .= " during process {$state->getTaskConfiguration() + ->getCode()}"; $m .= " with message: '{$exception->getMessage()}'.\n"; - throw new \RuntimeException($m, -1, $exception); + throw new RuntimeException($m, -1, $exception); } return; @@ -372,8 +314,8 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF // Run child items only if the state is not "skipped" and task is not blocking $task = $taskConfiguration->getTask(); $shouldContinue = - (!$task instanceof BlockingTaskInterface || self::EXECUTE_PROCEED === $executionFlag) - && !$state->isSkipped(); + (! $task instanceof BlockingTaskInterface || $executionFlag === self::EXECUTE_PROCEED) + && ! $state->isSkipped(); if ($shouldContinue) { if ($task instanceof IterableTaskInterface) { @@ -398,13 +340,13 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF if ($task instanceof IterableTaskInterface) { // Check if task has more items $hasMoreItem = $task->next($state); - if (!$hasMoreItem) { - if (!$this->hasProcessedIterable($taskConfiguration)) { + if (! $hasMoreItem) { + if (! $this->hasProcessedIterable($taskConfiguration)) { return; // This means the task is empty } // This means we are over iterating this task so we can remove it from registry $this->removeProcessedIterable($taskConfiguration); - if (self::EXECUTE_FLUSH !== $executionFlag) { + if ($executionFlag !== self::EXECUTE_FLUSH) { // This task is now finished, we may flush it to test if there is anything lasting $this->flush($taskConfiguration); } @@ -418,49 +360,45 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF $this->taskConfiguration = null; } - /** - * @param TaskConfiguration $taskConfiguration - * @param int $executionFlag - */ protected function processExecution(TaskConfiguration $taskConfiguration, int $executionFlag): void { $task = $taskConfiguration->getTask(); - if (null === $task) { - throw new \RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); + if ($task === null) { + throw new RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); } $state = $taskConfiguration->getState(); try { - if (self::EXECUTE_PROCESS === $executionFlag) { + if ($executionFlag === self::EXECUTE_PROCESS) { $state->reset(false); $this->processLogger->debug("Processing task {$taskConfiguration->getCode()}"); $task->execute($state); if ($task instanceof BlockingTaskInterface) { $this->addProcessedBlocking($taskConfiguration); } - } elseif (self::EXECUTE_PROCEED === $executionFlag) { + } elseif ($executionFlag === self::EXECUTE_PROCEED) { $state->reset(true); - if (!$task instanceof BlockingTaskInterface) { + if (! $task instanceof BlockingTaskInterface) { // This exception should never be thrown - throw new \UnexpectedValueException("Task {$taskConfiguration->getCode()} is not blocking"); + throw new UnexpectedValueException("Task {$taskConfiguration->getCode()} is not blocking"); } $this->processLogger->debug("Proceeding task {$taskConfiguration->getCode()}"); $task->proceed($state); $this->removeProcessedBlocking($taskConfiguration); - } elseif (self::EXECUTE_FLUSH === $executionFlag) { + } elseif ($executionFlag === self::EXECUTE_FLUSH) { $state->reset(true); - if (!$task instanceof FlushableTaskInterface) { + if (! $task instanceof FlushableTaskInterface) { // This exception should never be thrown - throw new \UnexpectedValueException("Task {$taskConfiguration->getCode()} is not flushable"); + throw new UnexpectedValueException("Task {$taskConfiguration->getCode()} is not flushable"); } $this->processLogger->debug("Flushing task {$taskConfiguration->getCode()}"); $task->flush($state); } else { - throw new \UnexpectedValueException("Unknown execution flag: {$executionFlag}"); + throw new UnexpectedValueException("Unknown execution flag: {$executionFlag}"); } $exception = $state->getException(); - } catch (\Throwable $e) { + } catch (Throwable $e) { $exception = $e; } @@ -472,7 +410,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e $state->getErrorContext() ); $state->setException($exception); - if (!$state->hasErrorOutput()) { + if (! $state->hasErrorOutput()) { $state->setErrorOutput($state->getInput()); } if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { @@ -480,7 +418,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e } elseif ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { $state->stop($exception); } else { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Unknown error strategy '{$taskConfiguration->getErrorStrategy()}'" ); } @@ -489,10 +427,6 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e /** * Browse all children for FlushableTask until a BlockingTask is found - * - * @param TaskConfiguration $taskConfiguration - * - * @throws \RuntimeException */ protected function flush(TaskConfiguration $taskConfiguration): void { @@ -516,11 +450,6 @@ protected function flush(TaskConfiguration $taskConfiguration): void } } - /** - * @param TaskConfiguration $taskConfiguration - * - * @throws \RuntimeException - */ protected function finalize(TaskConfiguration $taskConfiguration): void { $task = $taskConfiguration->getTask(); @@ -529,8 +458,10 @@ protected function finalize(TaskConfiguration $taskConfiguration): void $state = $taskConfiguration->getState(); try { $task->finalize($taskConfiguration->getState()); - } catch (\Throwable $e) { - $logContext = ['exception' => $e]; + } catch (Throwable $e) { + $logContext = [ + 'exception' => $e, + ]; $this->taskLogger->critical($e->getMessage(), $logContext); $state->stop($e); } @@ -539,15 +470,6 @@ protected function finalize(TaskConfiguration $taskConfiguration): void } } - /** - * @param ProcessConfiguration $processConfiguration - * @param array $context - * - * @throws \RuntimeException - * @throws \InvalidArgumentException - * - * @return ProcessHistory - */ protected function initializeStates( ProcessConfiguration $processConfiguration, array $context = [] @@ -566,20 +488,17 @@ protected function initializeStates( return $processHistory; } - /** - * @param TaskConfiguration $previousTaskConfiguration - * @param TaskConfiguration $nextTaskConfiguration - * @param bool $isError - */ protected function prepareNextProcess( TaskConfiguration $previousTaskConfiguration, TaskConfiguration $nextTaskConfiguration, - $isError = false + bool $isError = false ): void { if ($isError) { - $input = $previousTaskConfiguration->getState()->getErrorOutput(); + $input = $previousTaskConfiguration->getState() + ->getErrorOutput(); } else { - $input = $previousTaskConfiguration->getState()->getOutput(); + $input = $previousTaskConfiguration->getState() + ->getOutput(); } $nextState = $nextTaskConfiguration->getState(); @@ -589,10 +508,6 @@ protected function prepareNextProcess( /** * Save the state of the import process - * - * @param ProcessState $state - * - * @throws \RuntimeException */ protected function handleState(ProcessState $state): void { @@ -602,10 +517,6 @@ protected function handleState(ProcessState $state): void } } - /** - * @param ProcessHistory $history - * - */ protected function endProcess(ProcessHistory $history): void { // Do not change state if already set @@ -623,13 +534,6 @@ protected function endProcess(ProcessHistory $history): void /** * Validate a process - * - * @param ProcessConfiguration $processConfiguration - * - * @throws \RuntimeException - * @throws InvalidProcessConfigurationException - * @throws CircularProcessException - * @throws MissingTaskConfigurationException */ protected function checkProcess(ProcessConfiguration $processConfiguration): void { @@ -642,10 +546,12 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check multi-branch processes foreach ($taskConfigurations as $taskConfiguration) { - if (!\in_array($taskConfiguration->getCode(), $mainTaskList, true)) { + if (! \in_array($taskConfiguration->getCode(), $mainTaskList, true)) { // We won't throw an error to ease development... but there must be some kind of warning $state = $taskConfiguration->getState(); - $logContext = ['main_task_list' => $mainTaskList]; + $logContext = [ + 'main_task_list' => $mainTaskList, + ]; $this->processLogger->warning( "Task '{$taskConfiguration->getCode()}' is unreachable, check that it's referenced in some other task output or in the main entry point", $logContext @@ -656,18 +562,24 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check coherence for entry/end points $processConfiguration->getEndPoint(); - if ($entryPoint && !\in_array($entryPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $entryPoint, $mainTaskList); + if ($entryPoint && ! \in_array($entryPoint->getCode(), $mainTaskList, true)) { + throw InvalidProcessConfigurationException::createNotInMain( + $processConfiguration, + $entryPoint, + $mainTaskList + ); } - if ($endPoint && !\in_array($endPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $endPoint, $mainTaskList); + if ($endPoint && ! \in_array($endPoint->getCode(), $mainTaskList, true)) { + throw InvalidProcessConfigurationException::createNotInMain( + $processConfiguration, + $endPoint, + $mainTaskList + ); } } /** * When an iterable task returns at least one element, it gets added here - * - * @param TaskConfiguration $taskConfiguration */ protected function addProcessedIterable(TaskConfiguration $taskConfiguration): void { @@ -676,10 +588,6 @@ protected function addProcessedIterable(TaskConfiguration $taskConfiguration): v /** * If true this means that the tasks returned an element at least once - * - * @param TaskConfiguration $taskConfiguration - * - * @return bool */ protected function hasProcessedIterable(TaskConfiguration $taskConfiguration): bool { @@ -688,8 +596,6 @@ protected function hasProcessedIterable(TaskConfiguration $taskConfiguration): b /** * Once everything was flushed, the task is resolved and can be removed from the stack - * - * @param TaskConfiguration $taskConfiguration */ protected function removeProcessedIterable(TaskConfiguration $taskConfiguration): void { @@ -698,8 +604,6 @@ protected function removeProcessedIterable(TaskConfiguration $taskConfiguration) /** * Add blocking tasks that were just processed - * - * @param TaskConfiguration $taskConfiguration */ protected function addProcessedBlocking(TaskConfiguration $taskConfiguration): void { @@ -708,10 +612,6 @@ protected function addProcessedBlocking(TaskConfiguration $taskConfiguration): v /** * If true this means the task was processed normally but was never run with proceed - * - * @param TaskConfiguration $taskConfiguration - * - * @return bool */ protected function hasProcessedBlocking(TaskConfiguration $taskConfiguration): bool { @@ -720,8 +620,6 @@ protected function hasProcessedBlocking(TaskConfiguration $taskConfiguration): b /** * Once a blocking task has been proceeded, we can remove it from the stack - * - * @param TaskConfiguration $taskConfiguration */ protected function removeProcessedBlocking(TaskConfiguration $taskConfiguration): void { diff --git a/Model/AbstractConfigurableTask.php b/Model/AbstractConfigurableTask.php index cdac8a8c..140317a4 100644 --- a/Model/AbstractConfigurableTask.php +++ b/Model/AbstractConfigurableTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ abstract class AbstractConfigurableTask implements InitializableTaskInterface { - /** @var array */ + /** + * @var array + */ protected $options; /** * Only validate the options at initialization, ensuring that the task will not fail at runtime - * - * @param ProcessState $state - * - * @throws ExceptionInterface */ - public function initialize(ProcessState $state) + public function initialize(ProcessState $state): void { $this->getOptions($state); } /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * * @return array */ protected function getOptions(ProcessState $state) { - if (null === $this->options) { + if ($this->options === null) { $resolver = new OptionsResolver(); $this->configureOptions($resolver); $this->options = $resolver->resolve($state->getContextualizedOptions()); @@ -55,26 +49,19 @@ protected function getOptions(ProcessState $state) } /** - * @param ProcessState $state * @param string $code * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * * @return mixed */ protected function getOption(ProcessState $state, $code) { $options = $this->getOptions($state); - if (!array_key_exists($code, $options)) { - throw new \InvalidArgumentException("Missing option {$code}"); + if (! array_key_exists($code, $options)) { + throw new InvalidArgumentException("Missing option {$code}"); } return $options[$code]; } - /** - * @param OptionsResolver $resolver - */ abstract protected function configureOptions(OptionsResolver $resolver); } diff --git a/Model/BlockingTaskInterface.php b/Model/BlockingTaskInterface.php index a13fef89..0c7ea685 100644 --- a/Model/BlockingTaskInterface.php +++ b/Model/BlockingTaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface BlockingTaskInterface extends TaskInterface { - /** - * @param ProcessState $state - */ public function proceed(ProcessState $state); } diff --git a/Model/FinalizableTaskInterface.php b/Model/FinalizableTaskInterface.php index a553bbbb..f109f1bf 100644 --- a/Model/FinalizableTaskInterface.php +++ b/Model/FinalizableTaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface FinalizableTaskInterface extends TaskInterface { - /** - * @param ProcessState $state - */ public function finalize(ProcessState $state); } diff --git a/Model/FlushableTaskInterface.php b/Model/FlushableTaskInterface.php index f9f37d92..d222f75d 100644 --- a/Model/FlushableTaskInterface.php +++ b/Model/FlushableTaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface FlushableTaskInterface extends TaskInterface { - /** - * @param ProcessState $state - */ public function flush(ProcessState $state); } diff --git a/Model/InitializableTaskInterface.php b/Model/InitializableTaskInterface.php index 320883df..8f0f0dbc 100644 --- a/Model/InitializableTaskInterface.php +++ b/Model/InitializableTaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface InitializableTaskInterface extends TaskInterface { - /** - * @param ProcessState $state - */ public function initialize(ProcessState $state); } diff --git a/Model/IterableTaskInterface.php b/Model/IterableTaskInterface.php index 1aa38878..2881b9a3 100644 --- a/Model/IterableTaskInterface.php +++ b/Model/IterableTaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface IterableTaskInterface extends TaskInterface { @@ -23,8 +23,6 @@ interface IterableTaskInterface extends TaskInterface * return true if the task has a next element * return false if the task has terminated it's iteration * - * @param ProcessState $state - * * @return bool */ public function next(ProcessState $state); diff --git a/Model/ProcessHistory.php b/Model/ProcessHistory.php index e8d92786..0e444d30 100644 --- a/Model/ProcessHistory.php +++ b/Model/ProcessHistory.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ -class ProcessHistory +class ProcessHistory implements Stringable { - public const STATE_STARTED = 'started'; - public const STATE_SUCCESS = 'success'; - public const STATE_FAILED = 'failed'; + final public const STATE_STARTED = 'started'; - /** - * @var int - */ - protected $id; + final public const STATE_SUCCESS = 'success'; - /** - * @var string - */ - protected $processCode; + final public const STATE_FAILED = 'failed'; - /** - * @var array - */ - protected $context; + protected float $id; - /** - * @var \DateTime - */ - protected $startDate; + protected string $processCode; + + protected DateTime $startDate; /** - * @var \DateTime + * @var DateTime */ protected $endDate; @@ -54,61 +44,52 @@ class ProcessHistory */ protected $state = self::STATE_STARTED; - /** - * @param ProcessConfiguration $processConfiguration - * @param array $context - */ - public function __construct(ProcessConfiguration $processConfiguration, array $context = []) - { + public function __construct( + ProcessConfiguration $processConfiguration, + protected array $context = [] + ) { $this->id = microtime(true); $this->processCode = $processConfiguration->getCode(); - $this->startDate = new \DateTime(); - $this->context = $context; + $this->startDate = new DateTime(); } - /** - * @return int - */ - public function getId() + public function __toString(): string + { + $reference = $this->getProcessCode() . '[' . $this->getState() . ']'; + $time = $this->getStartDate() + ->format(DateTime::ATOM); + + return $reference . ': ' . $time; + } + + public function getId(): float { return $this->id; } - /** - * @return string - */ public function getProcessCode(): string { return $this->processCode; } - /** - * @return array - */ public function getContext(): array { return $this->context; } - /** - * @return \DateTime - */ - public function getStartDate(): \DateTime + public function getStartDate(): DateTime { return $this->startDate; } /** - * @return \DateTime + * @return DateTime */ public function getEndDate() { return $this->endDate; } - /** - * @return string - */ public function getState(): string { return $this->state; @@ -117,35 +98,30 @@ public function getState(): string /** * Set the process as failed */ - public function setFailed() + public function setFailed(): void { - $this->endDate = new \DateTime(); + $this->endDate = new DateTime(); $this->state = self::STATE_FAILED; } /** * Set the process as succeded */ - public function setSuccess() + public function setSuccess(): void { - $this->endDate = new \DateTime(); + $this->endDate = new DateTime(); $this->state = self::STATE_SUCCESS; } /** * Is true when the process is running - * - * @return bool */ - public function isStarted() + public function isStarted(): bool { return $this->state === self::STATE_STARTED; } - /** - * @return bool - */ - public function isFailed() + public function isFailed(): bool { return $this->state === self::STATE_FAILED; } @@ -158,20 +134,11 @@ public function isFailed() public function getDuration() { if ($this->getEndDate()) { - return $this->getEndDate()->getTimestamp() - $this->getStartDate()->getTimestamp(); + return $this->getEndDate() + ->getTimestamp() - $this->getStartDate() + ->getTimestamp(); } return null; } - - /** - * @return string - */ - public function __toString() - { - $reference = $this->getProcessCode().'['.$this->getState().']'; - $time = $this->getStartDate()->format(\DateTime::ATOM); - - return $reference.': '.$time; - } } diff --git a/Model/ProcessState.php b/Model/ProcessState.php index 2ccc01a9..2f1d18b8 100644 --- a/Model/ProcessState.php +++ b/Model/ProcessState.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ProcessState { - public const STATUS = [self::STATUS_NEW, self::STATUS_PENDING, self::STATUS_PROCESSING, self::STATUS_RESOLVED]; - public const STATUS_NEW = 'new'; - public const STATUS_PENDING = 'pending'; - public const STATUS_PROCESSING = 'processing'; - public const STATUS_RESOLVED = 'resolved'; + final public const STATUS = [ + self::STATUS_NEW, + self::STATUS_PENDING, + self::STATUS_PROCESSING, + self::STATUS_RESOLVED, + ]; - /** @var ProcessConfiguration */ - protected $processConfiguration; + final public const STATUS_NEW = 'new'; - /** @var ProcessHistory */ - protected $processHistory; + final public const STATUS_PENDING = 'pending'; - /** @var TaskConfiguration */ - protected $taskConfiguration; + final public const STATUS_PROCESSING = 'processing'; - /** @var mixed */ + final public const STATUS_RESOLVED = 'resolved'; + + protected TaskConfiguration $taskConfiguration; + + /** + * @var mixed + */ protected $input; - /** @var mixed */ + /** + * @var mixed + */ protected $output; - /** @var mixed */ + /** + * @var mixed + */ protected $errorOutput; - /** @var boolean */ + /** + * @var boolean + */ protected $hasErrorOutput = false; - /** @var bool */ + /** + * @var bool + */ protected $stopped = false; - /** @var \Throwable */ - protected $exception; + protected ?Throwable $exception = null; - /** @var array */ + /** + * @var array + */ protected $errorContext = []; - /** @var int */ + /** + * @var int + */ protected $returnCode; - /** @var bool */ - protected $skipped; + protected bool $skipped; - /** @var array */ + /** + * @var array + */ protected $context; - /** @var ContextualOptionResolver */ + /** + * @var ContextualOptionResolver + */ protected $contextualOptionResolver; - /** @var array */ + /** + * @var array + */ protected $contextualizedOptions; - /** @var ProcessState|null */ - protected $previousState; - - /** @var string */ - protected $status = self::STATUS_NEW; + protected ?\CleverAge\ProcessBundle\Model\ProcessState $previousState = null; /** - * @param ProcessConfiguration $processConfiguration - * @param ProcessHistory $processHistory + * @var string */ - public function __construct(ProcessConfiguration $processConfiguration, ProcessHistory $processHistory) - { - $this->processConfiguration = $processConfiguration; - $this->processHistory = $processHistory; + protected $status = self::STATUS_NEW; + + public function __construct( + protected ProcessConfiguration $processConfiguration, + protected ProcessHistory $processHistory + ) { } - /** - * @param ContextualOptionResolver $contextualOptionResolver - */ public function setContextualOptionResolver(ContextualOptionResolver $contextualOptionResolver): void { $this->contextualOptionResolver = $contextualOptionResolver; @@ -99,10 +116,8 @@ public function setContextualOptionResolver(ContextualOptionResolver $contextual /** * Clone the current object and keep a back reference - * - * @return ProcessState */ - public function duplicate(): ProcessState + public function duplicate(): self { $newState = clone $this; $newState->setPreviousState($this); @@ -130,33 +145,21 @@ public function reset($cleanInput): void } } - /** - * @return ProcessConfiguration - */ public function getProcessConfiguration(): ProcessConfiguration { return $this->processConfiguration; } - /** - * @return ProcessHistory - */ public function getProcessHistory(): ProcessHistory { return $this->processHistory; } - /** - * @return TaskConfiguration - */ public function getTaskConfiguration(): TaskConfiguration { return $this->taskConfiguration; } - /** - * @param TaskConfiguration $taskConfiguration - */ public function setTaskConfiguration(TaskConfiguration $taskConfiguration): void { $this->taskConfiguration = $taskConfiguration; @@ -170,10 +173,7 @@ public function getInput() return $this->input; } - /** - * @param mixed $input - */ - public function setInput($input): void + public function setInput(mixed $input): void { $this->input = $input; } @@ -186,10 +186,7 @@ public function getOutput() return $this->output; } - /** - * @param mixed $output - */ - public function setOutput($output): void + public function setOutput(mixed $output): void { $this->output = $output; } @@ -207,11 +204,9 @@ public function getError() } /** - * @param mixed $error - * * @deprecated Use setErrorOutput instead */ - public function setError($error): void + public function setError(mixed $error): void { @trigger_error('Deprecated method, use setErrorOutput instead', E_USER_DEPRECATED); @@ -219,8 +214,6 @@ public function setError($error): void } /** - * @return bool - * * @deprecated Use hasErrorOutput instead */ public function hasError(): bool @@ -238,27 +231,18 @@ public function getErrorOutput() return $this->errorOutput; } - /** - * @param mixed $errorOutput - */ - public function setErrorOutput($errorOutput): void + public function setErrorOutput(mixed $errorOutput): void { $this->hasErrorOutput = true; $this->errorOutput = $errorOutput; } - /** - * @return bool - */ public function hasErrorOutput(): bool { return $this->hasErrorOutput; } - /** - * @param \Throwable $e - */ - public function stop(\Throwable $e = null): void + public function stop(Throwable $e = null): void { if ($e) { $this->setException($e); @@ -266,182 +250,118 @@ public function stop(\Throwable $e = null): void $this->setStopped(true); } - /** - * @return boolean - */ public function isStopped(): bool { return $this->stopped; } - /** - * @param boolean $stopped - */ public function setStopped(bool $stopped): void { $this->stopped = $stopped; } - /** - * @return \Throwable|null - */ - public function getException(): ?\Throwable + public function getException(): ?Throwable { return $this->exception; } - /** - * @param \Throwable|null $exception - */ - public function setException(\Throwable $exception = null): void + public function setException(Throwable $exception = null): void { $this->exception = $exception; } - /** - * @return array - */ public function getErrorContext(): array { return $this->errorContext; } - /** - * @param array $errorContext - */ public function setErrorContext(array $errorContext): void { $this->errorContext = $errorContext; } - /** - * @param string|int $key - * @param string|int|array $value - */ - public function addErrorContextValue($key, $value): void + public function addErrorContextValue(string|int $key, string|int|array $value): void { $this->errorContext[$key] = $value; } - /** - * @param string|int $key - */ - public function removeErrorContext($key): void + public function removeErrorContext(string|int $key): void { unset($this->errorContext[$key]); } - /** - * @return int - */ public function getReturnCode(): int { - if (null !== $this->returnCode) { + if ($this->returnCode !== null) { return $this->returnCode; } return 0; } - /** - * @param int $returnCode - */ public function setReturnCode(int $returnCode): void { $this->returnCode = $returnCode; } - /** - * @return bool - */ public function isSkipped(): bool { return $this->skipped; } - /** - * @param bool $skipped - */ public function setSkipped(bool $skipped): void { $this->skipped = $skipped; } - /** - * @return ProcessState|null - */ - public function getPreviousState(): ?ProcessState + public function getPreviousState(): ?self { return $this->previousState; } - /** - * @param ProcessState $previousState - */ - public function setPreviousState($previousState): void + public function setPreviousState(?self $previousState): void { $this->previousState = $previousState; } - /** - * @return string - */ public function getStatus(): string { return $this->status; } - /** - * @param string $status - * - * @throws \UnexpectedValueException - */ public function setStatus(string $status): void { - if (!\in_array($status, self::STATUS, true)) { - throw new \UnexpectedValueException("Unknown status {$status}"); + if (! \in_array($status, self::STATUS, true)) { + throw new UnexpectedValueException("Unknown status {$status}"); } $this->status = $status; } - /** - * @return bool - */ public function isResolved(): bool { return $this->status === self::STATUS_RESOLVED; } - /** - * @return array - */ public function getContext(): array { return $this->context; } - /** - * @param array $context - * - * @throws \RuntimeException - */ public function setContext(array $context): void { if ($this->context) { - throw new \RuntimeException('Once defined, context is immutable'); + throw new RuntimeException('Once defined, context is immutable'); } $this->context = $context; } - /** - * @return array|null - */ public function getContextualizedOptions(): ?array { - if (!$this->contextualizedOptions) { - $options = $this->getTaskConfiguration()->getOptions(); + if (! $this->contextualizedOptions) { + $options = $this->getTaskConfiguration() + ->getOptions(); $this->contextualizedOptions = $this->contextualOptionResolver->contextualizeOptions( $options, $this->context @@ -453,11 +373,10 @@ public function getContextualizedOptions(): ?array /** * @param string $code - * @param mixed $default * * @return mixed */ - public function getContextualizedOption($code, $default = null) + public function getContextualizedOption($code, mixed $default = null) { $contextualizedOptions = $this->getContextualizedOptions(); if (array_key_exists($code, $contextualizedOptions)) { @@ -468,8 +387,6 @@ public function getContextualizedOption($code, $default = null) } /** - * @return array - * * @deprecated Use monolog processors instead */ public function getLogContext(): array diff --git a/Model/SubprocessInstance.php b/Model/SubprocessInstance.php index 09364244..1c606882 100644 --- a/Model/SubprocessInstance.php +++ b/Model/SubprocessInstance.php @@ -1,4 +1,7 @@ -processCode = $processCode; - $this->input = $input; - $this->context = $context; - $resolver = new OptionsResolver(); $this->configureOptions($resolver); $this->options = $resolver->resolve($options); - $this->consolePath = $kernel->getProjectDir().'/bin/console'; + $this->consolePath = $kernel->getProjectDir() . '/bin/console'; $this->environment = $kernel->getEnvironment(); - $this->bufferPath = $kernel->getProjectDir().'/var/cdm_buffer_'.uniqid().'.json-stream'; // Todo use param ? - $this->logDir = $kernel->getLogDir().'/process'; + $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid() . '.json-stream'; // Todo use param ? + $this->logDir = $kernel->getLogDir() . '/process'; } - /** * Prepare the process before start * @@ -91,28 +66,22 @@ public function buildProcess() 'nohup', $pathFinder->find(), $this->consolePath, - '--env='.$this->environment, + '--env=' . $this->environment, 'cleverage:process:execute', '--input-from-stdin', ]; $fs = new Filesystem(); $fs->mkdir($this->logDir); - if (!$fs->exists($this->consolePath)) { - throw new \RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); + if (! $fs->exists($this->consolePath)) { + throw new RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); } if ($this->options[self::OPTION_JSON_BUFFERING]) { - $arguments = array_merge( - $arguments, - [ - '--output='.$this->bufferPath, - '--output-format=json-stream', - ] - ); + $arguments = array_merge($arguments, ['--output=' . $this->bufferPath, '--output-format=json-stream']); } - if (!empty($this->context)) { + if (! empty($this->context)) { foreach ($this->context as $key => $value) { $arguments[] = sprintf('--context=%s:%s', $key, $value); } @@ -120,15 +89,7 @@ public function buildProcess() $arguments[] = $this->processCode; - $this->process = new Process($arguments, null, null, $this->input); - - if (method_exists(Process::class, 'fromShellCommandline')) { - $this->process = Process::fromShellCommandline($this->process->getCommandLine(), null, null, $this->input); - } else { - $this->process->setCommandLine($this->process->getCommandLine()); - $this->process->inheritEnvironmentVariables(); - } - + $this->process = Process::fromShellCommandline($this->process->getCommandLine(), null, null, $this->input); $this->process->enableOutput(); return $this; @@ -139,7 +100,7 @@ public function buildProcess() * * @return $this */ - public function start() + public function start(): static { $this->process->start(); @@ -149,60 +110,40 @@ public function start() /** * Stop the process * - * @param int $timeout - * * @return $this */ - public function stop($timeout = 10) + public function stop(float $timeout = 10): static { $this->process->stop($timeout); return $this; } - /** - * @return Process - */ public function getProcess(): Process { return $this->process; } - /** - * @return string - */ public function getProcessCode(): string { return $this->processCode; } - /** - * @return string|null - */ public function getInput(): ?string { return $this->input; } - /** - * @return array - */ public function getOptions(): array { return $this->options; } - /** - * @return array - */ public function getContext(): array { return $this->context; } - /** - * @return string|null - */ public function getResult(): ?string { $fs = new Filesystem(); @@ -215,10 +156,8 @@ public function getResult(): ?string /** * Available options for process launcher - * - * @param OptionsResolver $resolver */ - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault(self::OPTION_JSON_BUFFERING, false); $resolver->setAllowedTypes(self::OPTION_JSON_BUFFERING, 'bool'); diff --git a/Model/TaskInterface.php b/Model/TaskInterface.php index 096107c6..9b95bd9a 100644 --- a/Model/TaskInterface.php +++ b/Model/TaskInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface TaskInterface { - /** - * @param ProcessState $state - */ public function execute(ProcessState $state); } diff --git a/Registry/ProcessConfigurationRegistry.php b/Registry/ProcessConfigurationRegistry.php index 49212f5f..6b02d8cf 100644 --- a/Registry/ProcessConfigurationRegistry.php +++ b/Registry/ProcessConfigurationRegistry.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ProcessConfigurationRegistry { - /** @var array */ - protected $rawConfiguration; - - /** @var string */ - protected $defaultErrorStrategy; - - /** @var ProcessConfiguration[] */ - protected $processConfigurations = []; - /** - * @param array $rawConfiguration - * @param string $defaultErrorStrategy + * @var ProcessConfiguration[] */ - public function __construct(array $rawConfiguration, string $defaultErrorStrategy) - { - $this->rawConfiguration = $rawConfiguration; - $this->defaultErrorStrategy = $defaultErrorStrategy; + protected $processConfigurations = []; + + public function __construct( + protected array $rawConfiguration, + protected string $defaultErrorStrategy + ) { } - /** - * @param string $processCode - * - * @return ProcessConfiguration - * @throws MissingProcessException - * - */ public function getProcessConfiguration(string $processCode): ProcessConfiguration { - if (!$this->hasProcessConfiguration($processCode)) { + if (! $this->hasProcessConfiguration($processCode)) { throw MissingProcessException::create($processCode); } $this->resolveConfiguration($processCode); @@ -74,19 +60,11 @@ public function getProcessConfigurations(): array return $this->processConfigurations; } - /** - * @param string $processCode - * - * @return bool - */ public function hasProcessConfiguration(string $processCode): bool { return array_key_exists($processCode, $this->rawConfiguration); } - /** - * @param string $processCode - */ protected function resolveConfiguration(string $processCode): void { if (array_key_exists($processCode, $this->processConfigurations)) { @@ -97,11 +75,13 @@ protected function resolveConfiguration(string $processCode): void $taskConfigurations = []; /** @noinspection ForeachSourceInspection */ foreach ($rawProcessConfiguration['tasks'] as $taskCode => $rawTaskConfiguration) { - if (\count($rawTaskConfiguration['errors']) > 0) { - if (\count($rawTaskConfiguration['error_outputs']) > 0) { + if ((is_countable($rawTaskConfiguration['errors']) ? \count($rawTaskConfiguration['errors']) : 0) > 0) { + if ((is_countable($rawTaskConfiguration['error_outputs']) ? \count( + $rawTaskConfiguration['error_outputs'] + ) : 0) > 0) { $m = "Don't define both 'errors' and 'error_outputs' for task {$taskCode}, these options "; $m .= "are the same, 'errors' is deprecated, just use the new one 'error_outputs'"; - throw new \LogicException($m); + throw new LogicException($m); } $rawTaskConfiguration['error_outputs'] = $rawTaskConfiguration['errors']; } @@ -161,14 +141,16 @@ protected function resolveConfiguration(string $processCode): void // #106 - entry point should not have an ancestor if ($processConfig->getEntryPoint() && $processConfig->getEntryPoint()->getPreviousTasksConfigurations()) { - throw InvalidProcessConfigurationException::createEntryPointHasAncestors($processConfig, $processConfig->getEntryPoint()); + throw InvalidProcessConfigurationException::createEntryPointHasAncestors( + $processConfig, + $processConfig->getEntryPoint() + ); } $this->processConfigurations[$processCode] = $processConfig; } /** - * @param TaskConfiguration $taskConfig * @param bool $isErrorBranch */ protected function markErrorBranch(TaskConfiguration $taskConfig, $isErrorBranch = true): void diff --git a/Registry/TransformerRegistry.php b/Registry/TransformerRegistry.php index fa1bf245..367ef488 100644 --- a/Registry/TransformerRegistry.php +++ b/Registry/TransformerRegistry.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class TransformerRegistry { - /** @var TransformerInterface[] */ - protected $transformers = []; - /** - * @param TransformerInterface $transformer + * @var TransformerInterface[] */ + protected $transformers = []; + public function addTransformer(TransformerInterface $transformer) { if (array_key_exists($transformer->getCode(), $this->transformers)) { - throw new \UnexpectedValueException("Transformer {$transformer->getCode()} is already defined"); + throw new UnexpectedValueException("Transformer {$transformer->getCode()} is already defined"); } $this->transformers[$transformer->getCode()] = $transformer; } @@ -46,13 +46,11 @@ public function getTransformers() /** * @param string $code * - * @throws MissingTransformerException - * * @return TransformerInterface */ public function getTransformer($code) { - if (!$this->hasTransformer($code)) { + if (! $this->hasTransformer($code)) { throw MissingTransformerException::create($code); } @@ -61,10 +59,8 @@ public function getTransformer($code) /** * @param string $code - * - * @return bool */ - public function hasTransformer($code) + public function hasTransformer($code): bool { return array_key_exists($code, $this->transformers); } diff --git a/Resources/tests/environment/sf5/config/bundles.php b/Resources/tests/environment/sf5/config/bundles.php index d1a265ef..ef87cf11 100644 --- a/Resources/tests/environment/sf5/config/bundles.php +++ b/Resources/tests/environment/sf5/config/bundles.php @@ -1,7 +1,19 @@ ['all' => true], - CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], - Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + FrameworkBundle::class => [ + 'all' => true, + ], + CleverAgeProcessBundle::class => [ + 'all' => true, + ], + MonologBundle::class => [ + 'all' => true, + ], ]; diff --git a/Task/AbstractIterableOutputTask.php b/Task/AbstractIterableOutputTask.php index 9bf4a9f8..98f570a8 100644 --- a/Task/AbstractIterableOutputTask.php +++ b/Task/AbstractIterableOutputTask.php @@ -1,5 +1,7 @@ - * @author Vincent Chalnot */ abstract class AbstractIterableOutputTask extends AbstractConfigurableTask implements IterableTaskInterface { - /** @var \Iterator */ - protected $iterator; - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface + * @var Iterator */ - public function execute(ProcessState $state) + protected $iterator; + + public function execute(ProcessState $state): void { $this->handleIteratorFromInput($state); @@ -53,20 +49,18 @@ public function execute(ProcessState $state) * return true if the task has a next element * return false if the task has terminated it's iteration * - * @param ProcessState $state - * * @return bool */ public function next(ProcessState $state) { - if (!$this->iterator) { + if (! $this->iterator) { return false; } $this->iterator->next(); $state->removeErrorContext('iterator_key'); - if (!$this->iterator->valid()) { + if (! $this->iterator->valid()) { // Reset the iterator to allow the following iteration $this->iterator = null; @@ -78,12 +72,10 @@ public function next(ProcessState $state) /** * Create or recreate an iterator from input - * - * @param ProcessState $state */ protected function handleIteratorFromInput(ProcessState $state) { - if ($this->iterator instanceof \Iterator) { + if ($this->iterator instanceof Iterator) { if ($this->iterator->valid()) { return; // No action needed, execution is in progress } @@ -92,8 +84,8 @@ protected function handleIteratorFromInput(ProcessState $state) } // This should never be reached - if (null !== $this->iterator) { - throw new \UnexpectedValueException( + if ($this->iterator !== null) { + throw new UnexpectedValueException( "At this point iterator should have been null, maybe it's a wrong type..." ); } @@ -110,10 +102,5 @@ protected function configureOptions(OptionsResolver $resolver) { } - /** - * @param ProcessState $state - * - * @return \Iterator - */ - abstract protected function initializeIterator(ProcessState $state): \Iterator; + abstract protected function initializeIterator(ProcessState $state): Iterator; } diff --git a/Task/AggregateIterableTask.php b/Task/AggregateIterableTask.php index 4319b20f..adb61a9d 100644 --- a/Task/AggregateIterableTask.php +++ b/Task/AggregateIterableTask.php @@ -1,4 +1,7 @@ - */ class AggregateIterableTask implements BlockingTaskInterface { - /** @var array */ - protected $result = []; - /** - * @param ProcessState $state - * - * @throws ExceptionInterface + * @var array */ - public function execute(ProcessState $state) + protected $result = []; + + public function execute(ProcessState $state): void { $this->result[] = $state->getInput(); } - /** - * @param ProcessState $state - */ - public function proceed(ProcessState $state) + public function proceed(ProcessState $state): void { - if (0 === \count($this->result)) { + if (\count($this->result) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/Task/ArrayMergeTask.php b/Task/ArrayMergeTask.php index 458031d9..86e96226 100644 --- a/Task/ArrayMergeTask.php +++ b/Task/ArrayMergeTask.php @@ -1,4 +1,7 @@ -getInput(); - if (!\is_array($input)) { - throw new \UnexpectedValueException('Input must be an array'); + if (! \is_array($input)) { + throw new UnexpectedValueException('Input must be an array'); } $mergeFunction = $this->getOption($state, 'merge_function'); - if (!\in_array($mergeFunction, self::MERGE_FUNC, true)) { - throw new \InvalidArgumentException("Unknown merge function {$mergeFunction}"); + if (! \in_array($mergeFunction, self::MERGE_FUNC, true)) { + throw new InvalidArgumentException("Unknown merge function {$mergeFunction}"); } $this->mergedOutput = $mergeFunction($this->mergedOutput, $input); } - /** - * @param ProcessState $state - */ - public function proceed(ProcessState $state) + public function proceed(ProcessState $state): void { $state->setOutput($this->mergedOutput); } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('merge_function', 'array_merge'); diff --git a/Task/ColumnAggregatorTask.php b/Task/ColumnAggregatorTask.php index 0d0fba86..46b4701f 100644 --- a/Task/ColumnAggregatorTask.php +++ b/Task/ColumnAggregatorTask.php @@ -1,4 +1,7 @@ - */ class ColumnAggregatorTask extends AbstractConfigurableTask implements BlockingTaskInterface { @@ -32,25 +34,13 @@ class ColumnAggregatorTask extends AbstractConfigurableTask implements BlockingT */ protected $result = []; - /** @var LoggerInterface */ - protected $logger; - - - /** - * ColumnAggregatorTask constructor. - * - * @param PropertyAccessorInterface $accessor - * @param LoggerInterface $logger - */ - public function __construct(PropertyAccessorInterface $accessor, LoggerInterface $logger) - { + public function __construct( + PropertyAccessorInterface $accessor, + protected LoggerInterface $logger + ) { $this->accessor = $accessor; - $this->logger = $logger; } - /** - * @param ProcessState $state - */ public function execute(ProcessState $state) { $input = $state->getInput(); @@ -59,12 +49,15 @@ public function execute(ProcessState $state) $missingColumns = []; foreach ($columns as $column) { - if (!isset($input[$column])) { + if (! isset($input[$column])) { $missingColumns[] = $column; continue; } - if ($this->checkCondition(['input_column_value' => $input[$column], 'input' => $input], $conditions)) { + if ($this->checkCondition([ + 'input_column_value' => $input[$column], + 'input' => $input, + ], $conditions)) { $this->addValueToAggregationGroup( $column, $input, @@ -74,35 +67,31 @@ public function execute(ProcessState $state) } } - if (!empty($missingColumns)) { + if (! empty($missingColumns)) { $colStr = implode(', ', $missingColumns); $message = "Missing columns [{$colStr}] in input"; if ($this->getOption($state, 'ignore_missing')) { $this->logger->warning($message); } else { - throw new \UnexpectedValueException($message); + throw new UnexpectedValueException($message); } } } - /** - * @param ProcessState $state - */ - public function proceed(ProcessState $state) + public function proceed(ProcessState $state): void { $state->setOutput($this->result); } /** * @param string $column - * @param mixed $input * @param string $referenceKey * @param string $aggregationKey */ - protected function addValueToAggregationGroup($column, $input, $referenceKey, $aggregationKey) + protected function addValueToAggregationGroup($column, mixed $input, $referenceKey, $aggregationKey) { - if (!isset($this->result[$column])) { + if (! isset($this->result[$column])) { $this->result[$column] = [ $referenceKey => $column, $aggregationKey => [], @@ -112,9 +101,6 @@ protected function addValueToAggregationGroup($column, $input, $referenceKey, $a $this->result[$column][$aggregationKey][] = $input; } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('columns'); diff --git a/Task/ConstantIterableOutputTask.php b/Task/ConstantIterableOutputTask.php index 79b47ffd..93c66284 100644 --- a/Task/ConstantIterableOutputTask.php +++ b/Task/ConstantIterableOutputTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ConstantIterableOutputTask extends AbstractIterableOutputTask { - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'output', - ] - ); + $resolver->setRequired(['output']); $resolver->setAllowedTypes('output', ['array']); } - /** - * {@inheritdoc} - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - */ - protected function initializeIterator(ProcessState $state): \Iterator + protected function initializeIterator(ProcessState $state): Iterator { - return new \ArrayIterator($this->getOption($state, 'output')); + return new ArrayIterator($this->getOption($state, 'output')); } } diff --git a/Task/ConstantOutputTask.php b/Task/ConstantOutputTask.php index 3d762f3c..fc19319c 100644 --- a/Task/ConstantOutputTask.php +++ b/Task/ConstantOutputTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ConstantOutputTask extends AbstractConfigurableTask { - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $state->setOutput($this->getOption($state, 'output')); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'output', - ] - ); + $resolver->setRequired(['output']); } } diff --git a/Task/CounterTask.php b/Task/CounterTask.php index c526a915..d54ace90 100644 --- a/Task/CounterTask.php +++ b/Task/CounterTask.php @@ -1,4 +1,7 @@ - */ class CounterTask extends AbstractConfigurableTask implements FlushableTaskInterface { - /** @var int */ - protected $counter = 0; - /** - * @param ProcessState $state + * @var int */ + protected $counter = 0; + public function execute(ProcessState $state): void { $this->counter++; $modulo = $this->getOption($state, 'flush_every'); - if (0 === $this->counter % $modulo) { + if ($this->counter % $modulo === 0) { $state->setOutput($this->counter); } else { $state->setSkipped(true); @@ -42,29 +42,20 @@ public function execute(ProcessState $state): void /** * Condition is inversed during flush - * - * @param ProcessState $state */ public function flush(ProcessState $state): void { $modulo = $this->getOption($state, 'flush_every'); - if (0 === $this->counter % $modulo) { + if ($this->counter % $modulo === 0) { $state->setSkipped(true); } else { $state->setOutput($this->counter); } } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'flush_every', - ] - ); + $resolver->setRequired(['flush_every']); $resolver->setAllowedTypes('flush_every', ['int']); } } diff --git a/Task/Debug/DebugTask.php b/Task/Debug/DebugTask.php index b0789674..761da86b 100644 --- a/Task/Debug/DebugTask.php +++ b/Task/Debug/DebugTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class DebugTask implements TaskInterface { - /** - * @param ProcessState $state - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { if (class_exists(VarDumper::class)) { VarDumper::dump($state->getInput()); diff --git a/Task/Debug/DieTask.php b/Task/Debug/DieTask.php index 3ded8829..42a05739 100644 --- a/Task/Debug/DieTask.php +++ b/Task/Debug/DieTask.php @@ -1,4 +1,7 @@ - */ class DieTask implements TaskInterface { - /** - * @param ProcessState $state - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): never { die(); } diff --git a/Task/Debug/ErrorForwarderTask.php b/Task/Debug/ErrorForwarderTask.php index 79d5782a..d04251f5 100644 --- a/Task/Debug/ErrorForwarderTask.php +++ b/Task/Debug/ErrorForwarderTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ErrorForwarderTask implements TaskInterface { - /** - * {@inheritdoc} - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $state->setSkipped(true); $state->setErrorOutput($state->getInput()); diff --git a/Task/Debug/MemInfoDumpTask.php b/Task/Debug/MemInfoDumpTask.php index 839a033a..22529f39 100644 --- a/Task/Debug/MemInfoDumpTask.php +++ b/Task/Debug/MemInfoDumpTask.php @@ -1,4 +1,7 @@ - */ class MemInfoDumpTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** - * @param LoggerInterface $logger - */ - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { if (function_exists('meminfo_dump')) { gc_collect_cycles(); @@ -48,16 +40,9 @@ public function execute(ProcessState $state) } } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'file_path', - ] - ); + $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); } } diff --git a/Task/DummyTask.php b/Task/DummyTask.php index dde67358..59d9db61 100644 --- a/Task/DummyTask.php +++ b/Task/DummyTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class DummyTask implements TaskInterface { - /** - * @param ProcessState $state - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $state->setOutput($state->getInput()); } diff --git a/Task/Event/EventDispatcherTask.php b/Task/Event/EventDispatcherTask.php index 16312ef0..7cc159e1 100644 --- a/Task/Event/EventDispatcherTask.php +++ b/Task/Event/EventDispatcherTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot - * @author Madeline Veyrenc */ class EventDispatcherTask extends AbstractConfigurableTask { - /** @var EventDispatcherInterface */ - protected $eventDispatcher; - - /** - * @param EventDispatcherInterface $eventDispatcher - */ - public function __construct(EventDispatcherInterface $eventDispatcher) - { - $this->eventDispatcher = $eventDispatcher; + public function __construct( + protected EventDispatcherInterface $eventDispatcher + ) { } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); if ($options['passive']) { @@ -54,22 +39,12 @@ public function execute(ProcessState $state) $event = new EventDispatcherTaskEvent($state); - $this->eventDispatcher->dispatch($event, $options['event_name']); + $this->eventDispatcher->dispatch($event); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'event_name', - ] - ); + $resolver->setRequired(['event_name']); $resolver->setDefault('passive', true); $resolver->setAllowedTypes('event_name', ['string']); $resolver->setAllowedTypes('passive', ['boolean']); diff --git a/Task/File/Csv/AbstractCsvResourceTask.php b/Task/File/Csv/AbstractCsvResourceTask.php index af78f8bc..e68f1520 100644 --- a/Task/File/Csv/AbstractCsvResourceTask.php +++ b/Task/File/Csv/AbstractCsvResourceTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ abstract class AbstractCsvResourceTask extends AbstractConfigurableTask implements FinalizableTaskInterface { - /** @var CsvResource */ - protected $csv; - /** - * @param ProcessState $state + * @var CsvResource */ - public function finalize(ProcessState $state) + protected $csv; + + public function finalize(ProcessState $state): void { if ($this->csv instanceof CsvResource) { $this->csv->close(); } } - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws ExceptionInterface - * @throws \RuntimeException - */ protected function initFile(ProcessState $state) { if ($this->csv) { @@ -63,22 +52,14 @@ protected function initFile(ProcessState $state) ); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults( - [ - 'delimiter' => ';', - 'enclosure' => '"', - 'escape' => '\\', - 'headers' => null, - ] - ); + $resolver->setDefaults([ + 'delimiter' => ';', + 'enclosure' => '"', + 'escape' => '\\', + 'headers' => null, + ]); $resolver->setAllowedTypes('delimiter', ['string']); $resolver->setAllowedTypes('enclosure', ['string']); $resolver->setAllowedTypes('escape', ['string']); @@ -86,9 +67,6 @@ protected function configureOptions(OptionsResolver $resolver) } /** - * @param ProcessState $state - * @param array $options - * * @return array */ abstract protected function getHeaders(ProcessState $state, array $options); diff --git a/Task/File/Csv/AbstractCsvTask.php b/Task/File/Csv/AbstractCsvTask.php index 9ff30134..3e2ab668 100644 --- a/Task/File/Csv/AbstractCsvTask.php +++ b/Task/File/Csv/AbstractCsvTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ abstract class AbstractCsvTask extends AbstractCsvResourceTask { - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws ExceptionInterface - * @throws \RuntimeException - */ protected function initFile(ProcessState $state) { if ($this->csv) { @@ -50,26 +40,14 @@ protected function initFile(ProcessState $state) ); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); - $resolver->setRequired( - [ - 'file_path', - ] - ); + $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); - $resolver->setDefaults( - [ - 'mode' => 'rb', - ] - ); + $resolver->setDefaults([ + 'mode' => 'rb', + ]); $resolver->setAllowedTypes('mode', ['string']); } } diff --git a/Task/File/Csv/CsvReaderTask.php b/Task/File/Csv/CsvReaderTask.php index 19fc8b03..cb57628d 100644 --- a/Task/File/Csv/CsvReaderTask.php +++ b/Task/File/Csv/CsvReaderTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CsvReaderTask extends AbstractCsvTask implements IterableTaskInterface { - /** @var LoggerInterface */ - protected $logger; - - /** - * @param LoggerInterface $logger - */ - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \RuntimeException - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * @throws \LogicException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { - $output = null; if ($this->csv instanceof CsvFile && $this->csv->getFilePath() !== $this->getOption($state, 'file_path')) { $this->csv = null; } - if (!$this->csv instanceof CsvFile) { + if (! $this->csv instanceof CsvFile) { $this->initFile($state); } $lineNumber = $this->csv->getLineNumber(); $output = $this->csv->readLine(); - if (null === $output) { + if ($output === null) { if ($this->getOption($state, 'log_empty_lines')) { $logContext = [ 'csv_file' => $this->csv->getFilePath(), @@ -83,51 +65,29 @@ public function execute(ProcessState $state) * Moves the internal pointer to the next element, * return true if the task has a next element * return false if the task has terminated it's iteration - * - * @param ProcessState $state - * - * @throws \LogicException - * @throws \UnexpectedValueException - * @throws \RuntimeException - * - * @return bool */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { - if (!$this->csv instanceof CsvFile) { - throw new \LogicException('No CSV File initialized'); + if (! $this->csv instanceof CsvFile) { + throw new LogicException('No CSV File initialized'); } $state->removeErrorContext('csv_file'); $state->removeErrorContext('csv_line'); - return !$this->csv->isEndOfFile(); + return ! $this->csv->isEndOfFile(); } - /** - * @param ProcessState $state - * @param array $options - * - * @return array - */ - protected function getHeaders(ProcessState $state, array $options) + protected function getHeaders(ProcessState $state, array $options): array { return $options['headers']; } - /** - * @param OptionsResolver $resolver - * - * @throws UndefinedOptionsException - * @throws AccessException - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); - $resolver->setDefaults( - [ - 'log_empty_lines' => false, - ] - ); + $resolver->setDefaults([ + 'log_empty_lines' => false, + ]); } } diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index e76c7485..97b97196 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -1,4 +1,7 @@ -getOptions($state); - if (null === $this->csv) { + if ($this->csv === null) { $headers = $this->getHeaders($state, $options); $csv = new CsvFile( $options['file_path'], @@ -59,17 +50,11 @@ public function execute(ProcessState $state) * return true if the task has a next element * return false if the task has terminated it's iteration * - * @param ProcessState $state - * - * @throws \LogicException - * @throws \UnexpectedValueException - * @throws \RuntimeException - * * @return bool */ public function next(ProcessState $state) { - if (!$this->csv instanceof CsvResource) { + if (! $this->csv instanceof CsvResource) { return false; } @@ -79,15 +64,10 @@ public function next(ProcessState $state) $this->csv = null; } - return !$endOfFile; + return ! $endOfFile; } - /** - * @param ProcessState $state - * - * @throws IOException - */ - public function finalize(ProcessState $state) + public function finalize(ProcessState $state): void { if ($this->csv instanceof CsvResource) { $this->csv->close(); @@ -96,21 +76,16 @@ public function finalize(ProcessState $state) } /** - * @param CsvFile $csv * @param int $maxLines * - * @throws \RuntimeException - * @throws \LogicException - * @throws \UnexpectedValueException - * * @return string */ protected function splitCsv(CsvFile $csv, $maxLines) { - $tmpFilePath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_'.uniqid('process', false).'.csv'; + $tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php_' . uniqid('process', false) . '.csv'; $tmpFile = fopen($tmpFilePath, 'wb+'); - if (false === $tmpFile) { - throw new \RuntimeException("Unable to open temporary file {$tmpFilePath}"); + if ($tmpFile === false) { + throw new RuntimeException("Unable to open temporary file {$tmpFilePath}"); } $splitCsv = new CsvResource( $tmpFile, @@ -121,9 +96,9 @@ protected function splitCsv(CsvFile $csv, $maxLines) ); $splitCsv->writeHeaders(); - while ($splitCsv->getLineNumber() < $maxLines && !$csv->isEndOfFile()) { + while ($splitCsv->getLineNumber() < $maxLines && ! $csv->isEndOfFile()) { $raw = $csv->readRaw(); - if (false === $raw) { + if ($raw === false) { continue; // This is probably an empty line, no harm to skip it } $splitCsv->writeRaw($raw); @@ -133,19 +108,11 @@ protected function splitCsv(CsvFile $csv, $maxLines) return $tmpFilePath; } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); - $resolver->setDefaults( - [ - 'max_lines' => 1000, - ] - ); + $resolver->setDefaults([ + 'max_lines' => 1000, + ]); } } diff --git a/Task/File/Csv/CsvWriterTask.php b/Task/File/Csv/CsvWriterTask.php index ca89eb8e..dfe40dd9 100644 --- a/Task/File/Csv/CsvWriterTask.php +++ b/Task/File/Csv/CsvWriterTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot - * * @property CsvFile $csv */ class CsvWriterTask extends AbstractCsvTask implements BlockingTaskInterface { - /** - * @param ProcessState $state - * - * @throws \RuntimeException - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { - if (!$this->csv instanceof CsvFile) { + if (! $this->csv instanceof CsvFile) { $this->initFile($state); - if ($this->getOption($state, 'write_headers') && 0 === filesize($this->csv->getFilePath())) { + if ($this->getOption($state, 'write_headers') && filesize($this->csv->getFilePath()) === 0) { $this->csv->writeHeaders(); } } $this->csv->writeLine($this->getInput($state)); } - /** - * @param ProcessState $state - */ - public function proceed(ProcessState $state) + public function proceed(ProcessState $state): void { if ($this->csv) { $state->setOutput($this->csv->getFilePath()); } } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); - $resolver->setDefaults( - [ - 'mode' => 'wb', - 'split_character' => '|', - 'write_headers' => true, - ] - ); + $resolver->setDefaults([ + 'mode' => 'wb', + 'split_character' => '|', + 'write_headers' => true, + ]); $resolver->setNormalizer( 'file_path', - static function (Options $options, $value) { + static function (Options $options, $value): string { $value = strtr( $value, [ @@ -94,19 +73,13 @@ static function (Options $options, $value) { } /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * * @return array */ protected function getInput(ProcessState $state) { $input = $state->getInput(); - if (!\is_array($input)) { - throw new \UnexpectedValueException('Input value is not an array'); + if (! \is_array($input)) { + throw new UnexpectedValueException('Input value is not an array'); } $splitCharacter = $this->getOption($state, 'split_character'); @@ -121,15 +94,12 @@ protected function getInput(ProcessState $state) } /** - * @param ProcessState $state - * @param array $options - * * @return array */ protected function getHeaders(ProcessState $state, array $options) { $headers = $options['headers']; - if (null === $headers) { + if ($headers === null) { $headers = array_keys($state->getInput()); } diff --git a/Task/File/Csv/InputCsvReaderTask.php b/Task/File/Csv/InputCsvReaderTask.php index 1e449649..99849a35 100644 --- a/Task/File/Csv/InputCsvReaderTask.php +++ b/Task/File/Csv/InputCsvReaderTask.php @@ -1,4 +1,7 @@ -getInput()) { + if ($state->getInput() !== null) { $options['file_path'] = $this->getFilePath($options, $state->getInput()); } return $options; } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); @@ -58,19 +48,14 @@ protected function configureOptions(OptionsResolver $resolver) /** * If there is no base_path, then the given path from input should be absolute - * - * @param array $options - * @param string $input - * - * @return string */ - protected function getFilePath(array $options, string $input) + protected function getFilePath(array $options, string $input): string { $basePath = $options['base_path']; - if ('' !== $basePath) { - $basePath = rtrim($options['base_path'], '/').'/'; + if ($basePath !== '') { + $basePath = rtrim((string) $options['base_path'], '/') . '/'; } - return $basePath.$input; + return $basePath . $input; } } diff --git a/Task/File/FileFetchTask.php b/Task/File/FileFetchTask.php index fd27ecc2..7026286e 100644 --- a/Task/File/FileFetchTask.php +++ b/Task/File/FileFetchTask.php @@ -1,4 +1,7 @@ - */ class FileFetchTask extends AbstractConfigurableTask implements IterableTaskInterface { + protected Filesystem $sourceFS; - /** @var MountManager */ - protected $mountManager; - - /** @var FilesystemInterface */ - protected $sourceFS; + protected Filesystem $destinationFS; - /** @var FilesystemInterface */ - protected $destinationFS; + protected array $matchingFiles = []; - /** @var array */ - protected $matchingFiles = []; - - /** - * @param MountManager|null $mountManager - */ - public function __construct(MountManager $mountManager = null) - { - $this->mountManager = $mountManager; + public function __construct( + protected ?MountManager $mountManager = null + ) { } - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * @throws FilesystemNotFoundException - */ - public function initialize(ProcessState $state) + public function initialize(ProcessState $state): void { - if (!$this->mountManager) { + if (! $this->mountManager) { throw new ServiceNotFoundException('MountManager service not found, you need to install FlySystemBundle'); } // Configure options parent::initialize($state); - $this->sourceFS = $this->mountManager->getFilesystem($this->getOption($state, 'source_filesystem')); + $this->sourceFS = $this->mountManager->get($this->getOption($state, 'source_filesystem')); $this->destinationFS = $this->mountManager->getFilesystem($this->getOption($state, 'destination_filesystem')); } - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * @throws \UnexpectedValueException - * @throws FilesystemNotFoundException - * @throws FileNotFoundException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $this->findMatchingFiles($state); $file = current($this->matchingFiles); - if (!$file) { + if (! $file) { $state->setSkipped(true); return; @@ -96,82 +73,59 @@ public function execute(ProcessState $state) } /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws ExceptionInterface - * @throws \InvalidArgumentException - * * @return bool|mixed */ - public function next(ProcessState $state) + public function next(ProcessState $state): mixed { $this->findMatchingFiles($state); return next($this->matchingFiles); } - /** - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - * @throws ExceptionInterface - */ - protected function findMatchingFiles(ProcessState $state) + protected function findMatchingFiles(ProcessState $state): void { $filePattern = $this->getOption($state, 'file_pattern'); if ($filePattern) { foreach ($this->sourceFS->listContents('/') as $file) { - if ('file' === $file['type'] - && preg_match($filePattern, $file['path']) - && !\in_array($file['path'], $this->matchingFiles, true)) { + if ($file['type'] === 'file' + && preg_match($filePattern, (string) $file['path']) + && ! in_array($file['path'], $this->matchingFiles, true)) { $this->matchingFiles[] = $file['path']; } } } else { $input = $state->getInput(); - if (!$input) { - throw new \UnexpectedValueException('No pattern neither input provided for the Task'); + if (! $input) { + throw new UnexpectedValueException('No pattern neither input provided for the Task'); } - if (\is_array($input)) { + if (is_array($input)) { foreach ($input as $file) { - if (!\in_array($file, $this->matchingFiles, true)) { + if (! in_array($file, $this->matchingFiles, true)) { $this->matchingFiles[] = $file; } } - } elseif (!\in_array($input, $this->matchingFiles, true)) { + } elseif (! in_array($input, $this->matchingFiles, true)) { $this->matchingFiles[] = $input; } } } - /** - * @param ProcessState $state - * @param string $filename - * @param bool $removeSource - * - * @throws FileNotFoundException - * @throws ExceptionInterface - * @throws FilesystemNotFoundException - * @throws \InvalidArgumentException - * - * @return mixed - */ - protected function doFileCopy(ProcessState $state, $filename, $removeSource) + protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null { $prefixFrom = $this->getOption($state, 'source_filesystem'); $prefixTo = $this->getOption($state, 'destination_filesystem'); - $buffer = $this->mountManager->getFilesystem($prefixFrom)->readStream($filename); + $buffer = $this->mountManager->getFilesystem($prefixFrom) + ->readStream($filename); - if (false === $buffer) { + if ($buffer === false) { return false; } - $result = $this->mountManager->getFilesystem($prefixTo)->putStream($filename, $buffer); + $result = $this->mountManager->getFilesystem($prefixTo) + ->putStream($filename, $buffer); - if (\is_resource($buffer)) { + if (is_resource($buffer)) { fclose($buffer); } @@ -182,9 +136,6 @@ protected function doFileCopy(ProcessState $state, $filename, $removeSource) return $result ? $filename : null; } - /** - * {@inheritdoc} - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired(['source_filesystem', 'destination_filesystem']); diff --git a/Task/File/FileMoverTask.php b/Task/File/FileMoverTask.php index f4633f47..6365acb1 100644 --- a/Task/File/FileMoverTask.php +++ b/Task/File/FileMoverTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class FileMoverTask extends AbstractConfigurableTask { - /** - * @param ProcessState $state - * - * @throws IOException - * @throws ExceptionInterface - * @throws \UnexpectedValueException - */ public function execute(ProcessState $state) { $options = $this->getOptions($state); $fs = new Filesystem(); $file = $state->getInput(); - if (!$fs->exists($file)) { - throw new \UnexpectedValueException("File does not exists: '{$file}'"); + if (! $fs->exists($file)) { + throw new UnexpectedValueException("File does not exists: '{$file}'"); } $dest = $options['destination']; if (is_dir($dest)) { - $dest = rtrim($dest, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.basename($file); + $dest = rtrim((string) $dest, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename((string) $file); } if ($options['autoincrement']) { $dest = $this->makeFilenameUnique($dest); @@ -53,26 +43,14 @@ public function execute(ProcessState $state) $state->setOutput($dest); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'destination', - ] - ); + $resolver->setRequired(['destination']); $resolver->setAllowedTypes('destination', ['string']); - $resolver->setDefaults( - [ - 'overwrite' => false, - 'autoincrement' => false, - ] - ); + $resolver->setDefaults([ + 'overwrite' => false, + 'autoincrement' => false, + ]); $resolver->setAllowedTypes('overwrite', ['boolean']); $resolver->setAllowedTypes('autoincrement', ['boolean']); } @@ -88,10 +66,10 @@ protected function makeFilenameUnique($dest) $i = 1; while ($fs->exists($dest)) { if (preg_match('/^(.*?)(-\d+)?(\.[^.]*)$/', $dest, $matches)) { - $dest = $matches[1].'-'.$i.$matches[3]; + $dest = $matches[1] . '-' . $i . $matches[3]; ++$i; } else { - $dest .= '-'.$i; // Fallback brutal mode + $dest .= '-' . $i; // Fallback brutal mode } } diff --git a/Task/File/FileReaderTask.php b/Task/File/FileReaderTask.php index 480b8887..964c43c2 100644 --- a/Task/File/FileReaderTask.php +++ b/Task/File/FileReaderTask.php @@ -1,4 +1,7 @@ - */ class FileReaderTask extends AbstractConfigurableTask { - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws IOException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $state->setOutput(file_get_contents($options['filename'])); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'filename', - ] - ); + $resolver->setRequired(['filename']); $resolver->setAllowedTypes('filename', ['string']); } } diff --git a/Task/File/FileRemoverTask.php b/Task/File/FileRemoverTask.php index 09c53a58..e0527d6b 100644 --- a/Task/File/FileRemoverTask.php +++ b/Task/File/FileRemoverTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class FileRemoverTask implements TaskInterface { - /** - * @param ProcessState $state - * - * @throws IOException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $fs = new Filesystem(); $fs->remove($state->getInput()); diff --git a/Task/File/FileWriterTask.php b/Task/File/FileWriterTask.php index b93941c6..64516de2 100644 --- a/Task/File/FileWriterTask.php +++ b/Task/File/FileWriterTask.php @@ -1,4 +1,7 @@ - - */ class FileWriterTask extends AbstractConfigurableTask { - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws IOException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -42,19 +30,9 @@ public function execute(ProcessState $state) $state->setOutput($options['filename']); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'filename', - ] - ); + $resolver->setRequired(['filename']); $resolver->setAllowedTypes('filename', ['string']); } } diff --git a/Task/File/FolderBrowserTask.php b/Task/File/FolderBrowserTask.php index af20fde7..e918cade 100644 --- a/Task/File/FolderBrowserTask.php +++ b/Task/File/FolderBrowserTask.php @@ -1,4 +1,7 @@ -logger = $logger; + protected $files; + + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - * - * @throws \LogicException - * @throws \InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); - if (null === $this->files) { + if ($this->files === null) { $finder = new Finder(); $finder->files(); if ($options['name_pattern']) { @@ -63,7 +53,7 @@ public function execute(ProcessState $state) $this->files->rewind(); } - if (!$this->files->valid()) { + if (! $this->files->valid()) { $this->logger->log($options['empty_log_level'], "No item found in path {$options['folder_path']}"); $state->setSkipped(true); $state->setErrorOutput($options['folder_path']); @@ -83,13 +73,11 @@ public function execute(ProcessState $state) * return true if the task has a next element * return false if the task has terminated it's iteration * - * @param ProcessState $state - * * @return bool */ public function next(ProcessState $state) { - if (!$this->files) { + if (! $this->files) { return false; } $this->files->next(); @@ -98,43 +86,30 @@ public function next(ProcessState $state) return $this->files->valid(); } - /** - * @param OptionsResolver $resolver - * - * @throws InvalidConfigurationException - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'folder_path', - ] - ); + $resolver->setRequired(['folder_path']); $resolver->setAllowedTypes('folder_path', ['string']); /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'folder_path', static function (Options $options, $value) { - if (!is_dir($value)) { + if (! is_dir($value)) { throw new InvalidConfigurationException( "Folder path does not exists or is not a folder: '{$value}'" ); } - if (!is_readable($value)) { + if (! is_readable($value)) { throw new InvalidConfigurationException("Folder path is not readable: '{$value}'"); } return $value; } ); - $resolver->setDefaults( - [ - 'name_pattern' => null, - 'empty_log_level' => LogLevel::WARNING, - ] - ); + $resolver->setDefaults([ + 'name_pattern' => null, + 'empty_log_level' => LogLevel::WARNING, + ]); $resolver->setAllowedTypes('name_pattern', ['null', 'string', 'array']); $resolver->setAllowedValues( 'empty_log_level', diff --git a/Task/File/InputFolderBrowserTask.php b/Task/File/InputFolderBrowserTask.php index 7f445df8..ba75c17a 100644 --- a/Task/File/InputFolderBrowserTask.php +++ b/Task/File/InputFolderBrowserTask.php @@ -1,4 +1,7 @@ -folderPath = null; $state->setSkipped(true); } - /** - * {@inheritDoc} - */ public function initialize(ProcessState $state): void { parent::getOptions($state); } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); $resolver->remove(['folder_path']); - $resolver->setDefaults( - [ - 'base_folder_path' => '', - ] - ); + $resolver->setDefaults([ + 'base_folder_path' => '', + ]); $resolver->setAllowedTypes('base_folder_path', ['string']); } - /** - * {@inheritDoc} - */ protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); if ($state->getInput()) { - $folderPath = $options['base_folder_path'].$state->getInput(); + $folderPath = $options['base_folder_path'] . $state->getInput(); if ($this->folderPath && $folderPath !== $this->folderPath) { - throw new \LogicException( + throw new LogicException( "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" ); } $this->folderPath = $folderPath; } - if (!is_dir($this->folderPath)) { + if (! is_dir($this->folderPath)) { throw new InvalidConfigurationException( "Folder path does not exists or is not a folder: '{$this->folderPath}'" ); } - if (!is_readable($this->folderPath)) { + if (! is_readable($this->folderPath)) { throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); } $options['folder_path'] = $this->folderPath; diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/Task/File/JsonStream/JsonStreamReaderTask.php index 5a52168f..0447fafc 100644 --- a/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/Task/File/JsonStream/JsonStreamReaderTask.php @@ -1,4 +1,7 @@ -file) { + if ($this->file === null) { $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); } @@ -36,7 +36,6 @@ public function execute(ProcessState $state) } else { $state->setSkipped(true); } - } public function next(ProcessState $state) @@ -46,13 +45,11 @@ public function next(ProcessState $state) $this->file = null; } - return !$eof; + return ! $eof; } protected function getFilePath(ProcessState $state) { return $state->getInput(); } - - } diff --git a/Task/File/Xml/XmlReaderTask.php b/Task/File/Xml/XmlReaderTask.php index ad87875b..b292055a 100644 --- a/Task/File/Xml/XmlReaderTask.php +++ b/Task/File/Xml/XmlReaderTask.php @@ -1,4 +1,7 @@ - */ class XmlReaderTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** - * XmlReaderTask constructor. - * - * @param LoggerInterface $logger - */ - public function __construct(LoggerInterface $logger) + public function __construct( + protected LoggerInterface $logger + ) { + } + + public function execute(ProcessState $state): void { - $this->logger = $logger; + if ($state->getInput() !== null) { + $this->logger->warning('Input has been ignored for XMLReaderTask'); + } + + $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); + $state->setOutput($file->read()); } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('file_path'); @@ -47,17 +47,4 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setDefault('mode', 'rb'); $resolver->setAllowedTypes('mode', 'string'); } - - /** - * {@inheritDoc} - */ - public function execute(ProcessState $state) - { - if ($state->getInput() !== null) { - $this->logger->warning('Input has been ignored for XMLReaderTask'); - } - - $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); - $state->setOutput($file->read()); - } } diff --git a/Task/File/Xml/XmlWriterTask.php b/Task/File/Xml/XmlWriterTask.php index 7607fda6..4d1892de 100644 --- a/Task/File/Xml/XmlWriterTask.php +++ b/Task/File/Xml/XmlWriterTask.php @@ -1,4 +1,7 @@ - */ class XmlWriterTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; + public function __construct( + protected LoggerInterface $logger + ) { + } - /** - * XmlReaderTask constructor. - * - * @param LoggerInterface $logger - */ - public function __construct(LoggerInterface $logger) + public function execute(ProcessState $state) { - $this->logger = $logger; + $input = $state->getInput(); + if (! $input instanceof DOMDocument) { + throw new UnexpectedValueException('Input must be a \DOMDocument'); + } + + $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); + $file->write($input); + $state->setOutput($this->getOption($state, 'file_path')); } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('file_path'); @@ -47,19 +51,4 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setDefault('mode', 'wb'); $resolver->setAllowedTypes('mode', 'string'); } - - /** - * {@inheritDoc} - */ - public function execute(ProcessState $state) - { - $input = $state->getInput(); - if (!$input instanceof \DOMDocument) { - throw new \UnexpectedValueException('Input must be a \DOMDocument'); - } - - $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); - $file->write($input); - $state->setOutput($this->getOption($state, 'file_path')); - } } diff --git a/Task/File/YamlReaderTask.php b/Task/File/YamlReaderTask.php index 61de6e8a..286f1a55 100644 --- a/Task/File/YamlReaderTask.php +++ b/Task/File/YamlReaderTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class YamlReaderTask extends AbstractIterableOutputTask { - /** - * @param OptionsResolver $resolver - * - * @throws UndefinedOptionsException - * @throws AccessException - * @throws \UnexpectedValueException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'file_path', - ] - ); + $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); $resolver->setNormalizer( 'file_path', static function (Options $options, $value) { - if (!file_exists($value)) { - throw new \UnexpectedValueException("File not found: {$value}"); + if (! file_exists($value)) { + throw new UnexpectedValueException("File not found: {$value}"); } return $value; @@ -55,23 +44,14 @@ static function (Options $options, $value) { ); } - /** - * @param ProcessState $state - * - * @throws \InvalidArgumentException - * @throws ParseException - * @throws ExceptionInterface - * - * @return \Iterator - */ - protected function initializeIterator(ProcessState $state): \Iterator + protected function initializeIterator(ProcessState $state): Iterator { $filePath = $this->getOption($state, 'file_path'); $content = Yaml::parseFile($filePath); - if (!\is_array($content)) { - throw new \InvalidArgumentException("File content is not an array: {$filePath}"); + if (! \is_array($content)) { + throw new InvalidArgumentException("File content is not an array: {$filePath}"); } - return new \ArrayIterator($content); + return new ArrayIterator($content); } } diff --git a/Task/File/YamlWriterTask.php b/Task/File/YamlWriterTask.php index d69f1ac3..bc46b6d6 100644 --- a/Task/File/YamlWriterTask.php +++ b/Task/File/YamlWriterTask.php @@ -1,4 +1,7 @@ - */ class YamlWriterTask extends AbstractConfigurableTask { - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws IOException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); file_put_contents($options['file_path'], Yaml::dump($state->getInput(), $options['inline'])); $state->setOutput($options['file_path']); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'file_path', - ] - ); + $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); - $resolver->setDefaults( - [ - 'inline' => 4, - ] - ); + $resolver->setDefaults([ + 'inline' => 4, + ]); $resolver->setAllowedTypes('inline', ['integer']); } } diff --git a/Task/FilterTask.php b/Task/FilterTask.php index 80eb7725..46df9723 100644 --- a/Task/FilterTask.php +++ b/Task/FilterTask.php @@ -1,4 +1,7 @@ -accessor = new PropertyAccessor(); } - /** - * {@inheritDoc} - * - * @throws ExceptionInterface - * @throws UnexpectedTypeException - * @throws InvalidArgumentException - * @throws AccessException - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); - if (!$this->checkCondition($input, $this->getOptions($state))) { + if (! $this->checkCondition($input, $this->getOptions($state))) { $state->setErrorOutput($input); $state->setSkipped(true); @@ -61,9 +47,6 @@ public function execute(ProcessState $state) $state->setOutput($input); } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver) { $this->configureConditionOptions($resolver); diff --git a/Task/GroupByAggregateIterableTask.php b/Task/GroupByAggregateIterableTask.php index c334cd11..619e7ad4 100644 --- a/Task/GroupByAggregateIterableTask.php +++ b/Task/GroupByAggregateIterableTask.php @@ -1,42 +1,38 @@ - */ class GroupByAggregateIterableTask extends AbstractConfigurableTask implements BlockingTaskInterface { - /** @var string */ - const GROUP_BY_OPTION = 'group_by_accessors'; - - /** @var array */ - protected $result; - - /** @var PropertyAccessorInterface */ - protected $accessor; + /** + * @var string + */ + final public const GROUP_BY_OPTION = 'group_by_accessors'; /** - * @param PropertyAccessorInterface $accessor + * @var array */ - public function __construct(PropertyAccessorInterface $accessor) - { + protected $result; + + public function __construct( + protected PropertyAccessorInterface $accessor + ) { $this->result = []; - $this->accessor = $accessor; } - /** - * {@inheritDoc} - */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -47,7 +43,7 @@ public function execute(ProcessState $state): void foreach ($groupByAccessors as $groupByAccessor) { try { $keyParts[] = $this->accessor->getValue($input, $groupByAccessor); - } catch (\Exception $e) { + } catch (Exception $e) { $state->addErrorContextValue('property', $groupByAccessor); $state->setException($e); @@ -59,28 +55,18 @@ public function execute(ProcessState $state): void $this->result[$key] = $input; } - /** - * {@inheritDoc} - */ public function proceed(ProcessState $state): void { - if (0 === \count($this->result)) { + if (\count($this->result) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->result); } } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - self::GROUP_BY_OPTION, - ] - ); + $resolver->setRequired([self::GROUP_BY_OPTION]); $resolver->setAllowedTypes(self::GROUP_BY_OPTION, ['array']); } } diff --git a/Task/InputAggregatorTask.php b/Task/InputAggregatorTask.php index 0ea77c4f..079d3059 100644 --- a/Task/InputAggregatorTask.php +++ b/Task/InputAggregatorTask.php @@ -1,4 +1,7 @@ -getPreviousState(); - if (!$previousState || !$previousState->getTaskConfiguration()) { - throw new \UnexpectedValueException('This task cannot be used without a previous task'); + if (! $previousState || ! $previousState->getTaskConfiguration()) { + throw new UnexpectedValueException('This task cannot be used without a previous task'); } $inputCode = $this->getInputCode($state); @@ -51,7 +49,7 @@ public function execute(ProcessState $state) if ($this->getOption($state, 'clean_input_on_override')) { $this->inputs = []; } else { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output" ); } @@ -64,7 +62,7 @@ public function execute(ProcessState $state) $keepInputs = $this->getOption($state, 'keep_inputs'); // Only clear inputs that are not in the keep_inputs option foreach ($this->inputs as $inputCode => $value) { - if (null !== $keepInputs && \in_array($inputCode, $keepInputs, true)) { + if ($keepInputs !== null && \in_array($inputCode, $keepInputs, true)) { continue; } unset($this->inputs[$inputCode]); @@ -74,21 +72,13 @@ public function execute(ProcessState $state) } } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('input_codes'); - $resolver->setDefaults( - [ - 'clean_input_on_override' => true, - 'keep_inputs' => null, - ] - ); + $resolver->setDefaults([ + 'clean_input_on_override' => true, + 'keep_inputs' => null, + ]); $resolver->setAllowedTypes('input_codes', 'array'); $resolver->setAllowedTypes('clean_input_on_override', 'boolean'); $resolver->setAllowedTypes('keep_inputs', ['null', 'array']); @@ -97,24 +87,19 @@ protected function configureOptions(OptionsResolver $resolver) /** * Map the previous task code to an input code * - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - * @throws \UnexpectedValueException - * * @return string */ protected function getInputCode(ProcessState $state) { $previousState = $state->getPreviousState(); - if (!$previousState) { - throw new \RuntimeException('No previous state for current task'); + if (! $previousState) { + throw new RuntimeException('No previous state for current task'); } - $previousTaskCode = $previousState->getTaskConfiguration()->getCode(); + $previousTaskCode = $previousState->getTaskConfiguration() + ->getCode(); $inputCodes = $this->getOption($state, 'input_codes'); - if (!array_key_exists($previousTaskCode, $inputCodes)) { - throw new \UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); + if (! array_key_exists($previousTaskCode, $inputCodes)) { + throw new UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); } return $inputCodes[$previousTaskCode]; @@ -122,19 +107,12 @@ protected function getInputCode(ProcessState $state) /** * Check if the received inputs match the defined mappings - * - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - * - * @return bool */ - protected function isResolved(ProcessState $state) + protected function isResolved(ProcessState $state): bool { $inputCodes = $this->getOption($state, 'input_codes'); foreach ($inputCodes as $inputCode) { - if (!array_key_exists($inputCode, $this->inputs)) { + if (! array_key_exists($inputCode, $this->inputs)) { return false; } } diff --git a/Task/InputIteratorTask.php b/Task/InputIteratorTask.php index a9e661fa..9a8fbec8 100644 --- a/Task/InputIteratorTask.php +++ b/Task/InputIteratorTask.php @@ -1,4 +1,7 @@ - */ class InputIteratorTask extends AbstractIterableOutputTask { - /** - * @inheritDoc - */ - protected function initializeIterator(ProcessState $state): \Iterator + protected function initializeIterator(ProcessState $state): Iterator { $input = $state->getInput(); - if ($input instanceof \Iterator) { + if ($input instanceof Iterator) { return $input; } - if ($input instanceof \IteratorAggregate) { + if ($input instanceof IteratorAggregate) { return $input->getIterator(); } if (\is_array($input)) { - return new \ArrayIterator($input); + return new ArrayIterator($input); } - throw new \UnexpectedValueException('Cannot create iterator from input'); + throw new UnexpectedValueException('Cannot create iterator from input'); } } diff --git a/Task/IterableBatchTask.php b/Task/IterableBatchTask.php index 78e35d31..f0403c23 100644 --- a/Task/IterableBatchTask.php +++ b/Task/IterableBatchTask.php @@ -1,4 +1,7 @@ - */ class IterableBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { - - /** @var \SplQueue */ + /** + * @var SplQueue + */ protected $outputQueue; - /** @var bool */ - protected $flushMode = false; - - /** @var LoggerInterface */ - protected $logger; - /** - * IterableBatchTask constructor. - * - * @param LoggerInterface $logger + * @var bool */ - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; + protected $flushMode = false; + + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - */ - public function initialize(ProcessState $state) + public function initialize(ProcessState $state): void { parent::initialize($state); - $this->outputQueue = new \SplQueue(); + $this->outputQueue = new SplQueue(); } - - /** - * @param ProcessState $state - */ - public function flush(ProcessState $state) + public function flush(ProcessState $state): void { $this->flushMode = true; if ($this->outputQueue->isEmpty()) { @@ -70,23 +58,17 @@ public function flush(ProcessState $state) } } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $batchCount = $this->getOption($state, 'batch_count'); // Register new input - if (!$this->flushMode) { + if (! $this->flushMode) { $this->outputQueue->enqueue($this->processInput($state)); } // Detect flushing - if (null !== $batchCount && \count($this->outputQueue) >= $batchCount) { + if ($batchCount !== null && \count($this->outputQueue) >= $batchCount) { $this->flushMode = true; } @@ -99,32 +81,23 @@ public function execute(ProcessState $state) } /** - * @param ProcessState $state - * * @return bool */ public function next(ProcessState $state) { // Stop flushing once over - if (!\count($this->outputQueue)) { + if (! \count($this->outputQueue)) { $this->flushMode = false; } return $this->flushMode; } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults( - [ - 'batch_count' => 10, - ] - ); + $resolver->setDefaults([ + 'batch_count' => 10, + ]); $resolver->setAllowedTypes('batch_count', 'integer'); } @@ -132,8 +105,6 @@ protected function configureOptions(OptionsResolver $resolver) /** * Override this method to add a custom processing behavior * - * @param ProcessState $state - * * @return mixed */ protected function processInput(ProcessState $state) diff --git a/Task/ObjectUpdaterTask.php b/Task/ObjectUpdaterTask.php index 53ec1902..d5835892 100644 --- a/Task/ObjectUpdaterTask.php +++ b/Task/ObjectUpdaterTask.php @@ -1,4 +1,7 @@ - */ class ObjectUpdaterTask extends AbstractConfigurableTask { - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param PropertyAccessorInterface $accessor - */ - public function __construct(PropertyAccessorInterface $accessor) - { - $this->accessor = $accessor; + public function __construct( + protected PropertyAccessorInterface $accessor + ) { } - /** - * @param ProcessState $state - */ public function execute(ProcessState $state): void { $input = $state->getInput(); - if (!array_key_exists('object', $input)) { - throw new \UnexpectedValueException("Missing 'object' key in input array"); + if (! array_key_exists('object', $input)) { + throw new UnexpectedValueException("Missing 'object' key in input array"); } - if (!array_key_exists('value', $input)) { - throw new \UnexpectedValueException("Missing 'value' key in input array"); + if (! array_key_exists('value', $input)) { + throw new UnexpectedValueException("Missing 'value' key in input array"); } $this->accessor->setValue($input['object'], $this->getOption($state, 'property_path'), $input['value']); $state->setOutput($input['object']); } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'property_path', - ] - ); + $resolver->setRequired(['property_path']); } } diff --git a/Task/Process/CommandRunnerTask.php b/Task/Process/CommandRunnerTask.php index 6b0a79fe..fbd8f61d 100644 --- a/Task/Process/CommandRunnerTask.php +++ b/Task/Process/CommandRunnerTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CommandRunnerTask extends AbstractConfigurableTask { - /** @var KernelInterface */ - protected $kernel; - - /** - * @param KernelInterface $kernel - */ - public function __construct(KernelInterface $kernel) - { - $this->kernel = $kernel; + public function __construct( + protected KernelInterface $kernel + ) { } - /** - * @inheritDoc - */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -53,16 +44,9 @@ public function execute(ProcessState $state): void $state->setOutput($process->getOutput()); } - /** - * @inheritDoc - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'commandline', - ] - ); + $resolver->setRequired(['commandline']); $resolver->setAllowedTypes('commandline', ['string', 'array']); $resolver->setDefaults( [ diff --git a/Task/Process/ProcessExecutorTask.php b/Task/Process/ProcessExecutorTask.php index e80bcee6..5e294bb5 100644 --- a/Task/Process/ProcessExecutorTask.php +++ b/Task/Process/ProcessExecutorTask.php @@ -1,4 +1,7 @@ -processManager = $processManager; - $this->processRegistry = $processRegistry; - $this->logger = $logger; } - /** - * {@inheritdoc} - * - * @throws \InvalidArgumentException - * @throws ExceptionInterface - * @throws \Exception - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); $process = $this->getOption($state, 'process'); - $output = $this->processManager->execute( - $process, - $input, - $this->getOption($state, 'context') - ); + $output = $this->processManager->execute($process, $input, $this->getOption($state, 'context')); $state->setOutput($output); } - /** - * {@inheritdoc} - * - * @throws \InvalidArgumentException - */ - public function initialize(ProcessState $state) + public function initialize(ProcessState $state): void { parent::initialize($state); $this->process = $this->getOption($state, 'process'); } - /** - * {@inheritdoc} - * - * @throws InvalidConfigurationException - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('process'); - $resolver->setDefaults( - [ - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'context' => [], + ]); $resolver->addAllowedTypes('process', 'string'); $resolver->setAllowedTypes('context', ['array']); $resolver->setNormalizer( 'process', function (Options $options, $processCode) { - if (!$this->processRegistry->hasProcessConfiguration($processCode)) { + if (! $this->processRegistry->hasProcessConfiguration($processCode)) { throw new InvalidConfigurationException("Unknown process {$processCode}"); } diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index fbf17bfa..cb809c6e 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { - /** @var LoggerInterface */ - protected $logger; - - /** @var ProcessConfigurationRegistry */ - protected $processRegistry; - - /** @var KernelInterface */ - protected $kernel; - - /** @var SubprocessInstance[] */ + /** + * @var SubprocessInstance[] + */ protected $launchedProcesses = []; - /** @var \SplQueue */ - protected $finishedBuffers; - - /** @var bool */ - protected $flushMode = false; + protected SplQueue $finishedBuffers; /** - * @param LoggerInterface $logger - * @param ProcessConfigurationRegistry $processRegistry - * @param KernelInterface $kernel + * @var bool */ + protected $flushMode = false; + public function __construct( - LoggerInterface $logger, - ProcessConfigurationRegistry $processRegistry, - KernelInterface $kernel + protected LoggerInterface $logger, + protected ProcessConfigurationRegistry $processRegistry, + protected KernelInterface $kernel ) { - $this->logger = $logger; - $this->processRegistry = $processRegistry; - $this->kernel = $kernel; - - $this->finishedBuffers = new \SplQueue(); + $this->finishedBuffers = new SplQueue(); } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { // TODO still not perfect, optimize and secure it $this->handleProcesses($state); // Handler processes first - if (!$this->flushMode) { + if (! $this->flushMode) { $this->handleInput($state); $state->setSkipped(true); - } elseif (!$this->finishedBuffers->isEmpty()) { + } elseif (! $this->finishedBuffers->isEmpty()) { $state->setOutput($this->finishedBuffers->dequeue()); // After dequeue, stop flush @@ -94,28 +73,22 @@ public function execute(ProcessState $state) } } - /** - * @param ProcessState $state - */ - public function flush(ProcessState $state) + public function flush(ProcessState $state): void { $this->flushMode = true; - if (!$this->finishedBuffers->isEmpty()) { + if (! $this->finishedBuffers->isEmpty()) { $state->setOutput($this->finishedBuffers->dequeue()); } else { $state->setSkipped(true); } // After dequeue, stop flush - if ($this->finishedBuffers->isEmpty() && !count($this->launchedProcesses)) { + if ($this->finishedBuffers->isEmpty() && ! count($this->launchedProcesses)) { $this->flushMode = false; } } /** - * @param ProcessState $state - * - * @throws ExceptionInterface * @return bool */ public function next(ProcessState $state) @@ -139,11 +112,6 @@ public function next(ProcessState $state) return false; } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - */ protected function handleInput(ProcessState $state) { $options = $this->getOptions($state); @@ -156,7 +124,8 @@ protected function handleInput(ProcessState $state) $this->launchedProcesses[] = $process; $logContext = [ - 'input' => $process->getProcess()->getInput(), + 'input' => $process->getProcess() + ->getInput(), ]; $this->logger->debug("Running command: {$process->getProcess()->getCommandLine()}", $logContext); @@ -165,14 +134,11 @@ protected function handleInput(ProcessState $state) } /** - * @param ProcessState $state - * - * @throws ExceptionInterface * @return SubprocessInstance */ protected function launchProcess(ProcessState $state) { - $input = null !== $state->getInput() ? (string) $state->getInput() : null; + $input = $state->getInput() !== null ? (string) $state->getInput() : null; $subprocess = new SubprocessInstance( $this->kernel, @@ -184,37 +150,38 @@ protected function launchProcess(ProcessState $state) ] ); - return $subprocess->buildProcess()->start(); + return $subprocess->buildProcess() + ->start(); } - /** - * @param ProcessState $state - * - * @throws RuntimeException - */ protected function handleProcesses(ProcessState $state) { foreach ($this->launchedProcesses as $key => $process) { - if (!$process->getProcess()->isTerminated()) { + if (! $process->getProcess()->isTerminated()) { // @todo handle incremental error output properly, specially for terminal where logs are lost - echo $process->getProcess()->getIncrementalErrorOutput(); + echo $process->getProcess() + ->getIncrementalErrorOutput(); continue; } $logContext = [ - 'cmd' => $process->getProcess()->getCommandLine(), - 'input' => $process->getProcess()->getInput(), - 'exit_code' => $process->getProcess()->getExitCode(), - 'exit_code_text' => $process->getProcess()->getExitCodeText(), + 'cmd' => $process->getProcess() + ->getCommandLine(), + 'input' => $process->getProcess() + ->getInput(), + 'exit_code' => $process->getProcess() + ->getExitCode(), + 'exit_code_text' => $process->getProcess() + ->getExitCodeText(), ]; $this->logger->debug('Command terminated', $logContext); unset($this->launchedProcesses[$key]); - if (0 !== $process->getProcess()->getExitCode()) { + if ($process->getProcess()->getExitCode() !== 0) { $this->logger->critical($process->getProcess()->getErrorOutput(), $logContext); $this->killProcesses(); - throw new \RuntimeException("Sub-process has failed: {$process->getProcess()->getExitCodeText()}"); + throw new RuntimeException("Sub-process has failed: {$process->getProcess()->getExitCodeText()}"); } $result = $process->getResult(); @@ -224,25 +191,14 @@ protected function handleProcesses(ProcessState $state) } } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - * @throws InvalidConfigurationException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'process', - ] - ); + $resolver->setRequired(['process']); /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'process', function (Options $options, $value) { - if (!$this->processRegistry->hasProcessConfiguration($value)) { + if (! $this->processRegistry->hasProcessConfiguration($value)) { throw new InvalidConfigurationException("Unknown process {$value}"); } @@ -265,9 +221,7 @@ function (Options $options, $value) { $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); $resolver->setAllowedTypes('sleep_on_finalize_interval', ['integer', 'double']); - $microsecondNormalizer = function (Options $options, $value) { - return (int)($value * 1000000); - }; + $microsecondNormalizer = fn (Options $options, $value): int => (int) ($value * 1_000_000); $resolver->setNormalizer('sleep_interval', $microsecondNormalizer); $resolver->setNormalizer('sleep_interval_after_launch', $microsecondNormalizer); $resolver->setNormalizer('sleep_on_finalize_interval', $microsecondNormalizer); @@ -278,10 +232,10 @@ function (Options $options, $value) { $resolver->setAllowedTypes('process_options', ['array']); $resolver->setNormalizer( 'process_options', - static function (Options $options, $value) { - if (!empty($value)) { + static function (Options $options, $value): int|float|string|bool|null { + if (! empty($value)) { // Todo deprecation trigger - throw new \InvalidArgumentException('Deprecated option, please contact support for help'); + throw new InvalidArgumentException('Deprecated option, please contact support for help'); } return $value; diff --git a/Task/PropertyGetterTask.php b/Task/PropertyGetterTask.php index aa346296..5a3c94b7 100644 --- a/Task/PropertyGetterTask.php +++ b/Task/PropertyGetterTask.php @@ -1,4 +1,7 @@ - */ class PropertyGetterTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - */ - public function __construct(LoggerInterface $logger, PropertyAccessorInterface $accessor) - { - $this->logger = $logger; - $this->accessor = $accessor; + public function __construct( + protected LoggerInterface $logger, + protected PropertyAccessorInterface $accessor + ) { } - /** - * @param ProcessState $state - * - * @throws \Exception - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $input = $state->getInput(); @@ -54,7 +39,7 @@ public function execute(ProcessState $state) try { $output = $this->accessor->getValue($input, $property); - } catch (\Exception $e) { + } catch (Exception $e) { $state->addErrorContextValue('property', $property); $state->setException($e); @@ -64,19 +49,9 @@ public function execute(ProcessState $state) $state->setOutput($output); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'property', - ] - ); + $resolver->setRequired(['property']); $resolver->setAllowedTypes('property', ['string']); } } diff --git a/Task/PropertySetterTask.php b/Task/PropertySetterTask.php index 07c85f76..f5eb5026 100644 --- a/Task/PropertySetterTask.php +++ b/Task/PropertySetterTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class PropertySetterTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - */ - public function __construct(LoggerInterface $logger, PropertyAccessorInterface $accessor) - { - $this->logger = $logger; - $this->accessor = $accessor; + public function __construct( + protected LoggerInterface $logger, + protected PropertyAccessorInterface $accessor + ) { } - /** - * @param ProcessState $state - * - * @throws \Exception - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $input = $state->getInput(); @@ -55,7 +39,7 @@ public function execute(ProcessState $state) foreach ($options['values'] as $key => $value) { try { $this->accessor->setValue($input, $key, $value); - } catch (\Exception $e) { + } catch (Exception $e) { $state->addErrorContextValue('property', $key); $state->addErrorContextValue('value', $value); $state->setException($e); @@ -67,19 +51,9 @@ public function execute(ProcessState $state) $state->setOutput($input); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'values', - ] - ); + $resolver->setRequired(['values']); $resolver->setAllowedTypes('values', ['array']); } } diff --git a/Task/Reporting/AdvancedStatCounterTask.php b/Task/Reporting/AdvancedStatCounterTask.php index 4e6bfbb2..52d4a73b 100644 --- a/Task/Reporting/AdvancedStatCounterTask.php +++ b/Task/Reporting/AdvancedStatCounterTask.php @@ -1,4 +1,7 @@ -logger = $logger; + protected $preInitCounter = 0; + + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { - $now = new \DateTime(); - if (!$this->startedAt) { + $now = new DateTime(); + if (! $this->startedAt) { $this->startedAt = $now; $this->lastUpdate = $now; } @@ -65,7 +62,7 @@ public function execute(ProcessState $state) return; } - if ($this->counter > 0 && 0 === $this->counter % $this->getOption($state, 'show_every')) { + if ($this->counter > 0 && $this->counter % $this->getOption($state, 'show_every') === 0) { $diff = $now->diff($this->lastUpdate); $fullText = "Last iteration {$diff->format('%H:%I:%S')} ago"; $items = $this->getOption($state, 'num_items') * $this->counter; @@ -75,7 +72,8 @@ public function execute(ProcessState $state) $rate = number_format($items / $seconds, 2, ',', ' '); } $fullText .= " - {$rate} items/s - {$items} items processed"; - $fullText .= " in {$now->diff($this->startedAt)->format('%H:%I:%S')}"; + $fullText .= " in {$now->diff($this->startedAt) + ->format('%H:%I:%S')}"; $this->lastUpdate = $now; $this->logger->info($fullText); @@ -85,21 +83,13 @@ public function execute(ProcessState $state) $this->counter++; } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults( - [ - 'num_items' => 1, - 'skip_first' => 0, - 'show_every' => 1, - ] - ); + $resolver->setDefaults([ + 'num_items' => 1, + 'skip_first' => 0, + 'show_every' => 1, + ]); $resolver->setAllowedTypes('num_items', ['int']); $resolver->setAllowedTypes('skip_first', ['int']); $resolver->setAllowedTypes('show_every', ['int']); diff --git a/Task/Reporting/LoggerTask.php b/Task/Reporting/LoggerTask.php index 2f790312..dbcf045d 100644 --- a/Task/Reporting/LoggerTask.php +++ b/Task/Reporting/LoggerTask.php @@ -1,4 +1,7 @@ - */ class LoggerTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** @var PropertyAccessorInterface */ - protected $accessor; - /** - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - * * @internal param LoggerInterface $logger */ public function __construct( - LoggerInterface $logger, - PropertyAccessorInterface $accessor + protected LoggerInterface $logger, + protected PropertyAccessorInterface $accessor ) { - $this->logger = $logger; - $this->accessor = $accessor; } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \Symfony\Component\PropertyAccess\Exception\AccessException - * @throws \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException - * @throws UnexpectedTypeException - * @throws CircularReferenceException - * @throws InvalidArgumentException - * @throws LogicException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $context = []; @@ -78,12 +50,6 @@ public function execute(ProcessState $state) $state->setOutput($state->getInput()); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults( diff --git a/Task/Reporting/StatCounterTask.php b/Task/Reporting/StatCounterTask.php index 53a777ab..64fad0e4 100644 --- a/Task/Reporting/StatCounterTask.php +++ b/Task/Reporting/StatCounterTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class StatCounterTask implements FinalizableTaskInterface { - /** @var LoggerInterface */ - protected $logger; - - /** @var int */ - protected $counter = 0; - /** - * @param LoggerInterface $logger + * @var int */ - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; + protected $counter = 0; + + public function __construct( + protected LoggerInterface $logger + ) { } - /** - * @param ProcessState $state - */ - public function finalize(ProcessState $state) + public function finalize(ProcessState $state): void { $this->logger->info("Processed item count: {$this->counter}"); } - /** - * @param ProcessState $state - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $this->counter++; } diff --git a/Task/RowAggregatorTask.php b/Task/RowAggregatorTask.php index 132483a0..a697ec34 100644 --- a/Task/RowAggregatorTask.php +++ b/Task/RowAggregatorTask.php @@ -1,4 +1,7 @@ -logger = $logger; + public function __construct( + protected LoggerInterface $logger + ) { } /** * Store inputs and once everything has been received, pass to next task * Once an output has been generated this task is reset, and may wait for another loop - * - * @param ProcessState $state - * - * @throws \UnexpectedValueException - * @throws \InvalidArgumentException - * @throws ExceptionInterface */ public function execute(ProcessState $state) { @@ -62,7 +50,7 @@ public function execute(ProcessState $state) $aggregateColumns = $this->getOption($state, 'aggregate_columns'); $aggregationKey = $this->getOption($state, 'aggregation_key'); - if (!array_key_exists($aggregateBy, $input)) { + if (! array_key_exists($aggregateBy, $input)) { throw new InvalidProcessConfigurationException( "Array aggregator exception: missing column '{$aggregateBy}'" ); @@ -70,7 +58,7 @@ public function execute(ProcessState $state) $inputAggregateBy = $input[$aggregateBy]; - if (!array_key_exists($inputAggregateBy, $this->result)) { + if (! array_key_exists($inputAggregateBy, $this->result)) { $this->result[$inputAggregateBy] = $input; foreach ($aggregateColumns as $aggregateColumn) { if (array_key_exists($aggregateColumn, $this->result[$inputAggregateBy])) { @@ -81,7 +69,7 @@ public function execute(ProcessState $state) $inputAggregateColumns = []; foreach ($aggregateColumns as $aggregateColumn) { - if (!array_key_exists($aggregateColumn, $input)) { + if (! array_key_exists($aggregateColumn, $input)) { throw new InvalidProcessConfigurationException( "Array aggregator exception: missing column {$aggregateColumn}" ); @@ -91,20 +79,11 @@ public function execute(ProcessState $state) $this->result[$inputAggregateBy][$aggregationKey][] = $inputAggregateColumns; } - /** - * @param ProcessState $state - */ - public function proceed(ProcessState $state) + public function proceed(ProcessState $state): void { $state->setOutput(array_values($this->result)); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('aggregate_by'); diff --git a/Task/Serialization/DenormalizerTask.php b/Task/Serialization/DenormalizerTask.php index 3fe38766..79bf33ac 100644 --- a/Task/Serialization/DenormalizerTask.php +++ b/Task/Serialization/DenormalizerTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class DenormalizerTask extends AbstractConfigurableTask { - /** @var DenormalizerInterface */ - protected $denormalizer; - - /** - * @param DenormalizerInterface $denormalizer - */ - public function __construct(DenormalizerInterface $denormalizer) - { - $this->denormalizer = $denormalizer; + public function __construct( + protected DenormalizerInterface $denormalizer + ) { } - /** - * @param ProcessState $state - * - * @throws UnexpectedValueException - * @throws RuntimeException - * @throws LogicException - * @throws InvalidArgumentException - * @throws ExtraAttributesException - * @throws BadMethodCallException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $normalizedData = $this->denormalizer->denormalize( @@ -66,26 +40,14 @@ public function execute(ProcessState $state) $state->setOutput($normalizedData); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'class', - ] - ); + $resolver->setRequired(['class']); $resolver->setAllowedTypes('class', ['string']); - $resolver->setDefaults( - [ - 'format' => null, - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'format' => null, + 'context' => [], + ]); $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } diff --git a/Task/Serialization/DeserializerTask.php b/Task/Serialization/DeserializerTask.php index f8be4034..2ee80ac3 100644 --- a/Task/Serialization/DeserializerTask.php +++ b/Task/Serialization/DeserializerTask.php @@ -1,4 +1,6 @@ - - */ class DeserializerTask extends AbstractConfigurableTask { - /** @var SerializerInterface */ - protected $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) - { - $this->serializer = $serializer; + public function __construct( + protected SerializerInterface $serializer + ) { } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -52,26 +37,13 @@ public function execute(ProcessState $state): void $state->setOutput($serializeData); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'type', - 'format', - ] - ); + $resolver->setRequired(['type', 'format']); $resolver->setAllowedTypes('type', ['string']); $resolver->setAllowedTypes('format', ['string']); - $resolver->setDefaults( - [ - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'context' => [], + ]); } } diff --git a/Task/Serialization/NormalizerTask.php b/Task/Serialization/NormalizerTask.php index bdf711fd..438b57ca 100644 --- a/Task/Serialization/NormalizerTask.php +++ b/Task/Serialization/NormalizerTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class NormalizerTask extends AbstractConfigurableTask { - /** @var NormalizerInterface */ - protected $normalizer; - - /** - * @param NormalizerInterface $normalizer - */ - public function __construct(NormalizerInterface $normalizer) - { - $this->normalizer = $normalizer; + public function __construct( + protected NormalizerInterface $normalizer + ) { } - /** - * @param ProcessState $state - * - * @throws LogicException - * @throws InvalidArgumentException - * @throws CircularReferenceException - * @throws ExceptionInterface - */ public function execute(ProcessState $state) { $options = $this->getOptions($state); - if (!$this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { - throw new \UnexpectedValueException('Given value is not normalizable for format '.$options['format']); + if (! $this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { + throw new UnexpectedValueException('Given value is not normalizable for format ' . $options['format']); } $normalizedData = $this->normalizer->normalize( @@ -64,24 +45,12 @@ public function execute(ProcessState $state) $state->setOutput($normalizedData); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'format', - ] - ); + $resolver->setRequired(['format']); $resolver->setAllowedTypes('format', ['string']); - $resolver->setDefaults( - [ - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'context' => [], + ]); } } diff --git a/Task/Serialization/SerializerTask.php b/Task/Serialization/SerializerTask.php index ddfc0c3d..43a685e2 100644 --- a/Task/Serialization/SerializerTask.php +++ b/Task/Serialization/SerializerTask.php @@ -1,4 +1,6 @@ - - */ class SerializerTask extends AbstractConfigurableTask { - /** @var SerializerInterface */ - protected $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) - { - $this->serializer = $serializer; + public function __construct( + protected SerializerInterface $serializer + ) { } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); - $serializeData = $this->serializer->serialize( - $state->getInput(), - $options['format'], - $options['context'] - ); + $serializeData = $this->serializer->serialize($state->getInput(), $options['format'], $options['context']); $state->setOutput($serializeData); } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'format', - ] - ); + $resolver->setRequired(['format']); $resolver->setAllowedTypes('format', ['string']); - $resolver->setDefaults( - [ - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'context' => [], + ]); } } diff --git a/Task/SimpleBatchTask.php b/Task/SimpleBatchTask.php index 25f2b201..b573a0e1 100644 --- a/Task/SimpleBatchTask.php +++ b/Task/SimpleBatchTask.php @@ -1,4 +1,7 @@ - */ class SimpleBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface { - /** @var array */ - protected $elements = []; - /** - * @param ProcessState $state + * @var array */ - public function flush(ProcessState $state) + protected $elements = []; + + public function flush(ProcessState $state): void { - if (0 === \count($this->elements)) { + if (\count($this->elements) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->elements); @@ -40,18 +38,12 @@ public function flush(ProcessState $state) } } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \InvalidArgumentException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $batchCount = $this->getOption($state, 'batch_count'); $this->elements[] = $state->getInput(); - if (null !== $batchCount && \count($this->elements) >= $batchCount) { + if ($batchCount !== null && \count($this->elements) >= $batchCount) { $state->setOutput($this->elements); $this->elements = []; } else { @@ -59,17 +51,10 @@ public function execute(ProcessState $state) } } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - */ protected function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults( - [ - 'batch_count' => 10, - ] - ); + $resolver->setDefaults([ + 'batch_count' => 10, + ]); } } diff --git a/Task/SkipEmptyTask.php b/Task/SkipEmptyTask.php index 727c4438..5f2d0ff9 100644 --- a/Task/SkipEmptyTask.php +++ b/Task/SkipEmptyTask.php @@ -1,4 +1,7 @@ -setOutput($state->getInput()); if (empty($state->getInput())) { diff --git a/Task/SplitJoinLineTask.php b/Task/SplitJoinLineTask.php index 620be258..ab3265e4 100644 --- a/Task/SplitJoinLineTask.php +++ b/Task/SplitJoinLineTask.php @@ -1,4 +1,7 @@ - */ class SplitJoinLineTask extends AbstractIterableOutputTask { - /** - * {@inheritdoc} - */ public function next(ProcessState $state): bool { $valid = parent::next($state); - if (!$valid) { + if (! $valid) { $this->iterator = null; } return $valid; } - /** - * @param OptionsResolver $resolver - */ protected function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'split_columns', - 'join_column', - ] - ); + $resolver->setRequired(['split_columns', 'join_column']); $resolver->setAllowedTypes('split_columns', ['array']); $resolver->setAllowedTypes('join_column', ['string']); - $resolver->setDefaults( - [ - 'split_character' => ',', - ] - ); + $resolver->setDefaults([ + 'split_character' => ',', + ]); } - /** - * @param ProcessState $state - * - * @return \Iterator - */ - protected function initializeIterator(ProcessState $state): \Iterator + protected function initializeIterator(ProcessState $state): Iterator { $originalLine = $state->getInput(); $options = $this->getOptions($state); @@ -70,10 +56,10 @@ protected function initializeIterator(ProcessState $state): \Iterator $outputLines = []; foreach ($options['split_columns'] as $column) { - if (!array_key_exists($column, $originalLine)) { - throw new \UnexpectedValueException("Missing column {$column}"); + if (! array_key_exists($column, $originalLine)) { + throw new UnexpectedValueException("Missing column {$column}"); } - $columnValues = explode($options['split_character'], $originalLine[$column]); + $columnValues = explode($options['split_character'], (string) $originalLine[$column]); foreach ($columnValues as $columnValue) { $outputLine = $lineCopy; $outputLine[$options['join_column']] = $columnValue; @@ -81,6 +67,6 @@ protected function initializeIterator(ProcessState $state): \Iterator } } - return new \ArrayIterator($outputLines); + return new ArrayIterator($outputLines); } } diff --git a/Task/StopTask.php b/Task/StopTask.php index c23995ec..911e4d49 100644 --- a/Task/StopTask.php +++ b/Task/StopTask.php @@ -1,4 +1,7 @@ -setStopped(true); - $state->getProcessHistory()->setFailed(); + $state->getProcessHistory() + ->setFailed(); } } diff --git a/Task/TransformerTask.php b/Task/TransformerTask.php index 5a911898..b714a32e 100644 --- a/Task/TransformerTask.php +++ b/Task/TransformerTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class TransformerTask extends AbstractConfigurableTask { use TransformerTrait; - /** @var LoggerInterface */ - protected $logger; - - /** @var TransformerInterface */ - protected $transformer; - /** - * @param LoggerInterface $logger - * @param TransformerRegistry $transformerRegistry - * + * @var TransformerInterface */ - public function __construct(LoggerInterface $logger, TransformerRegistry $transformerRegistry) - { - $this->logger = $logger; + protected $transformer; + + public function __construct( + protected LoggerInterface $logger, + TransformerRegistry $transformerRegistry + ) { $this->transformerRegistry = $transformerRegistry; } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws MissingTransformerException - * @throws \UnexpectedValueException - * @throws AccessException - * @throws InvalidOptionsException - * @throws MissingOptionsException - * @throws NoSuchOptionException - * @throws OptionDefinitionException - * @throws UndefinedOptionsException - */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $output = null; $options = $this->getOptions($state); @@ -83,18 +57,6 @@ public function execute(ProcessState $state) $state->setOutput($output); } - /** - * @param OptionsResolver $resolver - * - * @throws UndefinedOptionsException - * @throws OptionDefinitionException - * @throws NoSuchOptionException - * @throws MissingOptionsException - * @throws InvalidOptionsException - * @throws AccessException - * @throws MissingTransformerException - * @throws ExceptionInterface - */ protected function configureOptions(OptionsResolver $resolver) { $this->configureTransformersOptions($resolver); diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index 7c2d364d..bd259716 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ValidatorTask extends AbstractConfigurableTask { - /** @var LoggerInterface */ - protected $logger; - - /** @var ValidatorInterface */ - protected $validator; - - /** - * @param LoggerInterface $logger - * @param ValidatorInterface $validator - */ - public function __construct(LoggerInterface $logger, ValidatorInterface $validator) - { - $this->logger = $logger; - $this->validator = $validator; + public function __construct( + protected LoggerInterface $logger, + protected ValidatorInterface $validator + ) { } - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @throws \UnexpectedValueException - */ public function execute(ProcessState $state) { $options = $this->getOptions($state); - $violations = $this->validator->validate( - $state->getInput(), - $options['constraints'], - $options['groups'] - ); + $violations = $this->validator->validate($state->getInput(), $options['constraints'], $options['groups']); - if (0 < $violations->count()) { + if ($violations->count() > 0) { /** @var ConstraintViolationInterface $violation */ foreach ($violations as $violation) { $invalidValue = $violation->getInvalidValue(); @@ -82,15 +62,12 @@ public function execute(ProcessState $state) return; } - throw new \UnexpectedValueException("{$violations->count()} constraint violations detected on validation"); + throw new UnexpectedValueException("{$violations->count()} constraint violations detected on validation"); } $state->setOutput($state->getInput()); } - /** - * {@inheritDoc} - */ protected function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('log_errors', LogLevel::CRITICAL); @@ -112,7 +89,7 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer( 'log_errors', static function (Options $options, $value) { - if (true === $value) { + if ($value === true) { return LogLevel::CRITICAL; } @@ -127,8 +104,8 @@ static function (Options $options, $value) { $resolver->setAllowedTypes('constraints', ['null', 'array']); $resolver->setNormalizer( 'constraints', - static function (Options $options, $constraints) { - if (null === $constraints) { + static function (Options $options, $constraints): ?array { + if ($constraints === null) { return null; } diff --git a/Tests/AbstractProcessTest.php b/Tests/AbstractProcessTest.php index dc972a1d..bb2997e8 100644 --- a/Tests/AbstractProcessTest.php +++ b/Tests/AbstractProcessTest.php @@ -1,4 +1,7 @@ -processManager = $this->getContainer()->get(ProcessManager::class); - $this->processConfigurationRegistry = $this->getContainer()->get(ProcessConfigurationRegistry::class); - $this->transformerRegistry = $this->getContainer()->get(TransformerRegistry::class); + $this->processManager = $this->getContainer() + ->get(ProcessManager::class); + $this->processConfigurationRegistry = $this->getContainer() + ->get(ProcessConfigurationRegistry::class); + $this->transformerRegistry = $this->getContainer() + ->get(TransformerRegistry::class); } /** * Assert that an array of values match what's been registered in the standard queue * It can also match task codes using the checkTask flag - * - * @param array $expected - * @param string $processName - * @param bool $checkTask */ protected function assertDataQueue(array $expected, string $processName, bool $checkTask = true) { - $dataQueueListener = $this->getContainer()->get(DataQueueEventListener::class); + $dataQueueListener = $this->getContainer() + ->get(DataQueueEventListener::class); $actualQueue = $dataQueueListener->getQueue($processName); self::assertCount(\count($expected), $actualQueue, 'Event count does not match'); @@ -72,7 +80,9 @@ protected function assertDataQueue(array $expected, string $processName, bool $c if (array_key_exists('task', $expected[$key])) { self::assertEquals( $expected[$key]['task'], - $value->getPreviousState()->getTaskConfiguration()->getCode(), + $value->getPreviousState() + ->getTaskConfiguration() + ->getCode(), "Task #{$key} does not match" ); } @@ -89,13 +99,11 @@ protected function assertDataQueue(array $expected, string $processName, bool $c * Returns the booted symfony container * * Compatibility backport for symfony/phpunit-bridge that should work with v3 or v4 - * - * @return ContainerInterface */ protected function getContainer(): ContainerInterface { - if (isset(self::$container)) { - return self::$container; + if (isset(self::getContainer())) { + return self::getContainer(); } $container = self::$kernel->getContainer(); @@ -106,15 +114,8 @@ protected function getContainer(): ContainerInterface /** * Helper method to configure options and test a transformation - * - * @param string $transformerCode - * @param mixed $expected - * @param mixed $value - * @param array $options - * - * @throws ExceptionInterface */ - protected function assertTransformation(string $transformerCode, $expected, $value, array $options = []) + protected function assertTransformation(string $transformerCode, mixed $expected, mixed $value, array $options = []) { $result = $this->transform($transformerCode, $value, $options); self::assertEquals($expected, $result); @@ -123,14 +124,9 @@ protected function assertTransformation(string $transformerCode, $expected, $val /** * Transform some value using referenced transformer with given options * - * @param string $transformerCode - * @param mixed $value - * @param array $options - * * @return mixed - * @throws ExceptionInterface */ - protected function transform(string $transformerCode, $value, array $options = []) + protected function transform(string $transformerCode, mixed $value, array $options = []) { $transformer = $this->transformerRegistry->getTransformer($transformerCode); diff --git a/Tests/BasicTest.php b/Tests/BasicTest.php index 184b4009..c365d557 100644 --- a/Tests/BasicTest.php +++ b/Tests/BasicTest.php @@ -1,5 +1,8 @@ -processManager->execute('test.unknown_test'); } @@ -30,7 +32,7 @@ public function testUnknownProcess() /** * Check that a known process can be executed and return defined output */ - public function testSimpleProcess() + public function testSimpleProcess(): void { $result = $this->processManager->execute('test.simple_process', 'success'); @@ -40,7 +42,7 @@ public function testSimpleProcess() /** * Assert that the error branch is not called */ - public function testErrorProcess() + public function testErrorProcess(): void { $this->processManager->execute('test.error_process'); $this->assertDataQueue( @@ -65,7 +67,7 @@ public function testErrorProcess() /** * Assert that the error branch is called, and blocking task are correctly working */ - public function testErrorProcessBlocking() + public function testErrorProcessBlocking(): void { $this->processManager->execute('test.error_process_with_blocking'); $this->assertDataQueue( @@ -94,7 +96,7 @@ public function testErrorProcessBlocking() /** * @expectedException \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException */ - public function testFailingEntryPointWithAncestors() + public function testFailingEntryPointWithAncestors(): void { $this->processManager->execute('test.entry_point_with_ancestor'); } @@ -102,7 +104,7 @@ public function testFailingEntryPointWithAncestors() /** * Check that the use of a string in task "outputs" or "errors" is possible */ - public function testStringOutput() + public function testStringOutput(): void { $result = $this->processManager->execute('test.string_outputs', 'success'); self::assertEquals('success', $result); diff --git a/Tests/BlockingTaskTest.php b/Tests/BlockingTaskTest.php index 15697c95..2830d600 100644 --- a/Tests/BlockingTaskTest.php +++ b/Tests/BlockingTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.simple_blocking'); self::assertEquals([1, 2, 3], $result); } - public function testBlockingSolo() + public function testBlockingSolo(): void { $result = $this->processManager->execute('test.blocking_solo', 'success'); self::assertEquals(['success'], $result); } - public function testMultipleBlockingSolo() + public function testMultipleBlockingSolo(): void { $result = $this->processManager->execute('test.multiple_blocking_solo', 'success'); @@ -43,7 +45,7 @@ public function testMultipleBlockingSolo() * - a subsequent blocking task will be proceeded at least once * - a subsequent blocking task will be proceeded at most once */ - public function testMultipleBlocking() + public function testMultipleBlocking(): void { $result = $this->processManager->execute('test.multiple_blocking'); @@ -54,7 +56,7 @@ public function testMultipleBlocking() * Assert when there is multiple iterations before a blocking that all are successfully resolved, and the blocking * is executed only once */ - public function testMultipleIterationBlocking() + public function testMultipleIterationBlocking(): void { $this->processManager->execute('test.multiple_iteration_blocking'); @@ -72,7 +74,7 @@ public function testMultipleIterationBlocking() /** * Assert that if a blocking is never executed, it will automatically skip subsequent tasks */ - public function testBlockingEmptyData() + public function testBlockingEmptyData(): void { $this->processManager->execute('test.blocking_empty_data'); diff --git a/Tests/CircularProcessTest.php b/Tests/CircularProcessTest.php index be5f1eaa..b0ccc108 100644 --- a/Tests/CircularProcessTest.php +++ b/Tests/CircularProcessTest.php @@ -1,5 +1,8 @@ -processManager->execute('test.circular_process'); } @@ -27,7 +30,7 @@ public function testCircularProcess() /** * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException */ - public function testReversedCircularProcess() + public function testReversedCircularProcess(): void { $this->processManager->execute('test.circular_process.reversed'); } @@ -35,7 +38,7 @@ public function testReversedCircularProcess() /** * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException */ - public function testSelfCircularProcess() + public function testSelfCircularProcess(): void { $this->processManager->execute('test.circular_process.self'); } @@ -45,7 +48,7 @@ public function testSelfCircularProcess() * * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException */ - public function testLongCircularProcess() + public function testLongCircularProcess(): void { $this->processManager->execute('test.circular_process.long'); } diff --git a/Tests/ContextTest.php b/Tests/ContextTest.php index cefde99b..5c97d8cd 100644 --- a/Tests/ContextTest.php +++ b/Tests/ContextTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.context', 'ko', ['value' => 'ok']); + $result = $this->processManager->execute('test.context', 'ko', [ + 'value' => 'ok', + ]); self::assertEquals('ok', $result); - $result = $this->processManager->execute('test.context.sub_value', null, ['value' => 'ok']); + $result = $this->processManager->execute('test.context.sub_value', null, [ + 'value' => 'ok', + ]); - self::assertEquals(['key' => 'ok'], $result); + self::assertEquals([ + 'key' => 'ok', + ], $result); } /** * Assert a value can correctly passed and merged into a string, through context */ - public function testContextMergedValue() + public function testContextMergedValue(): void { - $result = $this->processManager->execute('test.context.merged_value', null, ['value' => 'ok']); + $result = $this->processManager->execute('test.context.merged_value', null, [ + 'value' => 'ok', + ]); self::assertEquals('value is ok', $result); } @@ -42,12 +53,15 @@ public function testContextMergedValue() /** * Assert 2 values can correctly passed and merged into a string, through context */ - public function testContextMultiValue() + public function testContextMultiValue(): void { $result = $this->processManager->execute( 'test.context.multi_values', null, - ['value1' => 'red', 'value2' => 'dead'] + [ + 'value1' => 'red', + 'value2' => 'dead', + ] ); self::assertEquals('red is dead', $result); @@ -58,30 +72,48 @@ public function testContextMultiValue() * * @expectedException \RuntimeException */ - public function testContextCannotMergeValue() + public function testContextCannotMergeValue(): void { $this->processManager->execute( 'test.context.merged_value', null, - ['value' => ['another_key' => 'another_value']] + [ + 'value' => [ + 'another_key' => 'another_value', + ], + ] ); } /** * Assert a complex value can correctly passed through context */ - public function testComplexContext() + public function testComplexContext(): void { - $result = $this->processManager->execute('test.context', null, ['value' => ['another_key' => 'another_value']]); + $result = $this->processManager->execute('test.context', null, [ + 'value' => [ + 'another_key' => 'another_value', + ], + ]); - self::assertEquals(['another_key' => 'another_value'], $result); + self::assertEquals([ + 'another_key' => 'another_value', + ], $result); $result = $this->processManager->execute( 'test.context.sub_value', null, - ['value' => ['another_key' => 'another_value']] + [ + 'value' => [ + 'another_key' => 'another_value', + ], + ] ); - self::assertEquals(['key' => ['another_key' => 'another_value']], $result); + self::assertEquals([ + 'key' => [ + 'another_key' => 'another_value', + ], + ], $result); } } diff --git a/Tests/EmptyProcessTest.php b/Tests/EmptyProcessTest.php index 6880fb13..ba77fd3a 100644 --- a/Tests/EmptyProcessTest.php +++ b/Tests/EmptyProcessTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.empty_process'); self::assertTrue(true, 'There was an exception'); diff --git a/Tests/ExceptionManagementTest.php b/Tests/ExceptionManagementTest.php index 1bafa2e9..18428e74 100644 --- a/Tests/ExceptionManagementTest.php +++ b/Tests/ExceptionManagementTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.exception_management.set_exception_in_the_middle'); - self::assertEquals( - [ - 'abc', - 'bcd', - 'cde', - 'def', - ], - $result['success'] - ); + self::assertEquals(['abc', 'bcd', 'cde', 'def'], $result['success']); - self::assertEquals( - [ - 1, - ], - $result['errors'] - ); + self::assertEquals([1], $result['errors']); } } diff --git a/Tests/FlushableTaskTest.php b/Tests/FlushableTaskTest.php index b8b63ff3..5848aa67 100644 --- a/Tests/FlushableTaskTest.php +++ b/Tests/FlushableTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.simple_flushable'); @@ -27,10 +27,7 @@ public function testSimpleFlushable() self::assertEquals([3], $result[1]); } - /** - * @throws \Exception - */ - public function testSingleFlushable() + public function testSingleFlushable(): void { $result = $this->processManager->execute('test.single_flushable'); @@ -38,10 +35,7 @@ public function testSingleFlushable() self::assertEquals([1], $result[0]); } - /** - * @throws \Exception - */ - public function testSimpleFlushableNoIterable() + public function testSimpleFlushableNoIterable(): void { $result = $this->processManager->execute('test.simple_flushable_no_iterable'); @@ -49,10 +43,7 @@ public function testSimpleFlushableNoIterable() self::assertEquals([1], $result[0]); } - /** - * @throws \Exception - */ - public function testIterableFlushable() + public function testIterableFlushable(): void { $result = $this->processManager->execute('test.iterable_flushable'); diff --git a/Tests/IterableTaskTest.php b/Tests/IterableTaskTest.php index 521b60fa..38761e5c 100644 --- a/Tests/IterableTaskTest.php +++ b/Tests/IterableTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.iterable_process'); @@ -66,7 +69,7 @@ public function testIterableProcess() * Assert 2 iterators can run alone, without a subsequent blocking task * Assert \CleverAge\ProcessBundle\Task\InputIteratorTask can correctly reset */ - public function testDoubleIterableAlone() + public function testDoubleIterableAlone(): void { $this->processManager->execute('test.double_iterable_alone'); @@ -93,11 +96,10 @@ public function testDoubleIterableAlone() ); } - /** * Assert the SplitJoinLineTask works the way it's supposed to */ - public function testSplitJoinLine() + public function testSplitJoinLine(): void { $this->processManager->execute('test.split_join_iterable'); diff --git a/Tests/MultiBranchProcessTest.php b/Tests/MultiBranchProcessTest.php index 062ea9d0..b857db40 100644 --- a/Tests/MultiBranchProcessTest.php +++ b/Tests/MultiBranchProcessTest.php @@ -1,5 +1,8 @@ -processManager->execute('test.multi_branch_process_first'); - $this->assertDataQueue( + $this->assertDataQueue([ [ - [ - 'task' => 'data1', - 'value' => 'ok', - ], + 'task' => 'data1', + 'value' => 'ok', ], - 'test.multi_branch_process_first' - ); + ], 'test.multi_branch_process_first'); $this->processManager->execute('test.multi_branch_process_entry'); - $this->assertDataQueue( + $this->assertDataQueue([ [ - [ - 'task' => 'data2', - 'value' => 'ok', - ], + 'task' => 'data2', + 'value' => 'ok', ], - 'test.multi_branch_process_entry' - ); + ], 'test.multi_branch_process_entry'); $this->processManager->execute('test.multi_branch_process_entry_reversed'); - $this->assertDataQueue( + $this->assertDataQueue([ [ - [ - 'task' => 'data2', - 'value' => 'ok', - ], + 'task' => 'data2', + 'value' => 'ok', ], - 'test.multi_branch_process_entry' - ); + ], 'test.multi_branch_process_entry'); $this->processManager->execute('test.multi_branch_process_end'); - $this->assertDataQueue( + $this->assertDataQueue([ [ - [ - 'task' => 'data2', - 'value' => 'ok', - ], + 'task' => 'data2', + 'value' => 'ok', ], - 'test.multi_branch_process_end' - ); + ], 'test.multi_branch_process_end'); $this->processManager->execute('test.multi_branch_process_entry_end'); - $this->assertDataQueue( + $this->assertDataQueue([ [ - [ - 'task' => 'data2', - 'value' => 'ok', - ], + 'task' => 'data2', + 'value' => 'ok', ], - 'test.multi_branch_process_entry_end' - ); + ], 'test.multi_branch_process_entry_end'); } - public function testMainGroupOrder() + public function testMainGroupOrder(): void { $process = $this->processConfigurationRegistry->getProcessConfiguration('test.multi_branch_process_first'); self::assertEquals( @@ -122,7 +110,7 @@ public function testMainGroupOrder() * * @expectedException \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException */ - public function testMultiBranchProcessError() + public function testMultiBranchProcessError(): void { $this->processManager->execute('test.multi_branch_process_entry_end_error'); } diff --git a/Tests/MultiWorkflowTest.php b/Tests/MultiWorkflowTest.php index 912c7916..6b9b93e9 100644 --- a/Tests/MultiWorkflowTest.php +++ b/Tests/MultiWorkflowTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.multi_workflow_process'); diff --git a/Tests/ProcessManagerTest.php b/Tests/ProcessManagerTest.php index ca6e70ef..42c49450 100644 --- a/Tests/ProcessManagerTest.php +++ b/Tests/ProcessManagerTest.php @@ -1,4 +1,7 @@ -prophesize(EventDispatcherInterface::class); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_STARTED]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ + new TypeToken(ProcessEvent::class), + ProcessEvent::EVENT_PROCESS_STARTED, + ]); $dispatchStartProphecy->shouldBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_ENDED]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ + new TypeToken(ProcessEvent::class), + ProcessEvent::EVENT_PROCESS_ENDED, + ]); $dispatchStartProphecy->shouldBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); - $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [new TypeToken(ProcessEvent::class), ProcessEvent::EVENT_PROCESS_FAILED]); + $dispatchStartProphecy = new MethodProphecy($edProphecy, 'dispatch', [ + new TypeToken(ProcessEvent::class), + ProcessEvent::EVENT_PROCESS_FAILED, + ]); $dispatchStartProphecy->shouldNotBeCalled(); $edProphecy->addMethodProphecy($dispatchStartProphecy); @@ -43,10 +54,14 @@ public function testProcessEvents() $eventDispatcher = $edProphecy->reveal(); $processManager = new ProcessManager( $this->getContainer(), - $this->getContainer()->get(ProcessLogger::class), - $this->getContainer()->get(TaskLogger::class), - $this->getContainer()->get(ProcessConfigurationRegistry::class), - $this->getContainer()->get(ContextualOptionResolver::class), + $this->getContainer() + ->get(ProcessLogger::class), + $this->getContainer() + ->get(TaskLogger::class), + $this->getContainer() + ->get(ProcessConfigurationRegistry::class), + $this->getContainer() + ->get(ContextualOptionResolver::class), $eventDispatcher ); diff --git a/Tests/Task/ColumnAggregatorTaskTest.php b/Tests/Task/ColumnAggregatorTaskTest.php index 8639330d..8639380c 100644 --- a/Tests/Task/ColumnAggregatorTaskTest.php +++ b/Tests/Task/ColumnAggregatorTaskTest.php @@ -1,4 +1,7 @@ - 'A', 'col2' => 'val1']; - $input2 = ['col1' => 'B', 'col2' => 'val2']; - $input3 = ['col1' => 'A', 'col2' => 'val3']; - $input4 = ['col1' => 'B', 'col2' => 'val4']; + $input1 = [ + 'col1' => 'A', + 'col2' => 'val1', + ]; + $input2 = [ + 'col1' => 'B', + 'col2' => 'val2', + ]; + $input3 = [ + 'col1' => 'A', + 'col2' => 'val3', + ]; + $input4 = [ + 'col1' => 'B', + 'col2' => 'val4', + ]; $input = [$input1, $input2, $input3, $input4]; self::assertEquals( @@ -45,6 +60,5 @@ public function testSimpleColumnAggregation() ], $this->processManager->execute('test.column_aggregator_task.simple', $input) ); - } } diff --git a/Tests/Task/FilterTaskTest.php b/Tests/Task/FilterTaskTest.php index 6715f7b1..ebd9b8bd 100644 --- a/Tests/Task/FilterTaskTest.php +++ b/Tests/Task/FilterTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.process_execute_task'); self::assertEquals([1, 2, 3, 4], $result); @@ -31,7 +34,7 @@ public function testExecutor() * * @expectedException \RuntimeException */ - public function testExecutorError() + public function testExecutorError(): void { $this->processManager->execute('test.process_execute_task.error'); } diff --git a/Tests/Task/StopTaskTest.php b/Tests/Task/StopTaskTest.php index d1478d02..167426c7 100644 --- a/Tests/Task/StopTaskTest.php +++ b/Tests/Task/StopTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.task.stop_task.iterable_interruption'); diff --git a/Tests/Task/TransformerTaskTest.php b/Tests/Task/TransformerTaskTest.php index 4213c45a..55ef5aa9 100644 --- a/Tests/Task/TransformerTaskTest.php +++ b/Tests/Task/TransformerTaskTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.transformer_task.simple', 'value'); - self::assertEquals(['field' => 'value'], $result); + self::assertEquals([ + 'field' => 'value', + ], $result); } /** @@ -32,7 +37,7 @@ public function testSimpleMapping() * * @expectedException \RuntimeException */ - public function testMissingMapping() + public function testMissingMapping(): void { $this->processManager->execute('test.transformer_task.error', 'value'); } @@ -40,10 +45,12 @@ public function testMissingMapping() /** * Assert we can use multiple times the same sub-transformer using # suffixes */ - public function testMultiSubtransformers() + public function testMultiSubtransformers(): void { $result = $this->processManager->execute('test.transformer_task.multi_subtransformers', [3, null, 4, 2]); - self::assertEquals(['field' => [2, 4, 3]], $result); + self::assertEquals([ + 'field' => [2, 4, 3], + ], $result); } } diff --git a/Tests/Task/ValidatorTaskTest.php b/Tests/Task/ValidatorTaskTest.php index b21f3771..a464bc8e 100644 --- a/Tests/Task/ValidatorTaskTest.php +++ b/Tests/Task/ValidatorTaskTest.php @@ -1,4 +1,7 @@ - 42, @@ -30,5 +33,4 @@ public function testSimpleValidation() $result = $this->processManager->execute('test.validator_task', $input); self::assertEquals($input, $result); } - } diff --git a/Tests/Transformer/ArrayFilterTransformerTest.php b/Tests/Transformer/ArrayFilterTransformerTest.php index 091871bc..65644b89 100644 --- a/Tests/Transformer/ArrayFilterTransformerTest.php +++ b/Tests/Transformer/ArrayFilterTransformerTest.php @@ -1,4 +1,7 @@ - 1, 'filter_value' => 'X'], - ['data' => 2, 'filter_value' => 'Y'], - ['data' => 3], - ['data' => 4, 'filter_value' => 'X'], - ['data' => 5, 'filter_value' => 'Y'], - ['data' => 6], + [ + 'data' => 1, + 'filter_value' => 'X', + ], + [ + 'data' => 2, + 'filter_value' => 'Y', + ], + [ + 'data' => 3, + ], + [ + 'data' => 4, + 'filter_value' => 'X', + ], + [ + 'data' => 5, + 'filter_value' => 'Y', + ], + [ + 'data' => 6, + ], ]; $result = $this->processManager->execute('test.array_filter_transformer.simple', $input); $nativeResult = array_filter( $input, - static function ($item) { - return isset($item['filter_value']) && 'X' === $item['filter_value']; - } + static fn ($item): bool => isset($item['filter_value']) && $item['filter_value'] === 'X' ); // Note that to match native function, key are preserved $expectedResult = [ - 0 => ['data' => 1, 'filter_value' => 'X'], - 3 => ['data' => 4, 'filter_value' => 'X'], + 0 => [ + 'data' => 1, + 'filter_value' => 'X', + ], + 3 => [ + 'data' => 4, + 'filter_value' => 'X', + ], ]; self::assertCount(2, $result); diff --git a/Tests/Transformer/CallbackTransformerTest.php b/Tests/Transformer/CallbackTransformerTest.php index 120b7ae3..93b51e0a 100644 --- a/Tests/Transformer/CallbackTransformerTest.php +++ b/Tests/Transformer/CallbackTransformerTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.date_transformers.date_format', '2001-01-01T00:00:00+00:00'); self::assertEquals('2001-01-01', $result); @@ -31,9 +33,9 @@ public function testDateFormatString() /** * Assert a date object can be formatted into a string */ - public function testDateFormatObject() + public function testDateFormatObject(): void { - $date = \DateTime::createFromFormat(DATE_ATOM, '2001-01-02T00:00:00+00:00'); + $date = DateTime::createFromFormat(DATE_ATOM, '2001-01-02T00:00:00+00:00'); $result = $this->processManager->execute('test.date_transformers.date_format', $date); self::assertEquals('2001-01-02', $result); } @@ -41,17 +43,17 @@ public function testDateFormatObject() /** * Assert a date can be parsed using a given format */ - public function testDateParser() + public function testDateParser(): void { - $date = \DateTime::createFromFormat('d/m/Y', '01/01/2001'); + $date = DateTime::createFromFormat('d/m/Y', '01/01/2001'); $result = $this->processManager->execute('test.date_transformers.date_parser', '2001-01-01'); // There could be a 1s difference, depending on execution time... $date->setTime(0, 0); $result->setTime(0, 0); - self::assertInstanceOf(\DateTime::class, $result); - if ($result instanceof \DateTime) { + self::assertInstanceOf(DateTime::class, $result); + if ($result instanceof DateTime) { self::assertEquals($date->getTimestamp(), $result->getTimestamp()); } } @@ -61,7 +63,7 @@ public function testDateParser() * * @expectedException \RuntimeException */ - public function testDateParserError() + public function testDateParserError(): void { $this->processManager->execute('test.date_transformers.date_parser', '2001-01-01T00:00:00+00:00'); } @@ -69,7 +71,7 @@ public function testDateParserError() /** * Assert date parser & formatter can be chained to transform a date string into another */ - public function testDateParseFormat() + public function testDateParseFormat(): void { $result = $this->processManager->execute( 'test.date_transformers.date_parse_format', diff --git a/Tests/Transformer/GenericTransformersTest.php b/Tests/Transformer/GenericTransformersTest.php index e4af6d14..39adf0b2 100644 --- a/Tests/Transformer/GenericTransformersTest.php +++ b/Tests/Transformer/GenericTransformersTest.php @@ -1,33 +1,26 @@ assertTransformation('test.generic_transformers.simple','my_ok', 'my_ok'); - $this->assertTransformation('test.generic_transformers.simple','ok', null); + $this->assertTransformation('test.generic_transformers.simple', 'my_ok', 'my_ok'); + $this->assertTransformation('test.generic_transformers.simple', 'ok', null); } - /** - * @throws ExceptionInterface - */ - public function testContextualOptions() + + public function testContextualOptions(): void { - $this->assertTransformation('test.generic_transformers.contextual_options','my_ok', 'my_ok', [ - 'default_value' => 'ok' + $this->assertTransformation('test.generic_transformers.contextual_options', 'my_ok', 'my_ok', [ + 'default_value' => 'ok', ]); - $this->assertTransformation('test.generic_transformers.contextual_options','ok', null, [ - 'default_value' => 'ok' + $this->assertTransformation('test.generic_transformers.contextual_options', 'ok', null, [ + 'default_value' => 'ok', ]); } - } diff --git a/Tests/Transformer/HashTransformerTest.php b/Tests/Transformer/HashTransformerTest.php index bc1e8aaf..e813339e 100644 --- a/Tests/Transformer/HashTransformerTest.php +++ b/Tests/Transformer/HashTransformerTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.hash_transformer.md5', 'This is a string'); self::assertEquals('41fb5b5ae4d57c5ee528adb00e5e8e74', $result); @@ -31,7 +32,7 @@ public function testMd5Hash() /** * Assert a string can be hash in sha512 */ - public function testSha512Hash() + public function testSha512Hash(): void { $result = $this->processManager->execute('test.hash_transformer.sha512', 'This is a string'); self::assertEquals( diff --git a/Tests/Transformer/MappingTransformerTest.php b/Tests/Transformer/MappingTransformerTest.php index 40dfdbdc..3008482a 100644 --- a/Tests/Transformer/MappingTransformerTest.php +++ b/Tests/Transformer/MappingTransformerTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.mapping_transformer.simple', ['field' => 'value']); + $result = $this->processManager->execute('test.mapping_transformer.simple', [ + 'field' => 'value', + ]); - self::assertEquals(['field2' => 'value'], $result); + self::assertEquals([ + 'field2' => 'value', + ], $result); } /** @@ -33,61 +39,87 @@ public function testSimpleMapping() * * @expectedException \RuntimeException */ - public function testMissingMapping() + public function testMissingMapping(): void { - $this->processManager->execute('test.mapping_transformer.error', ['field' => 'value']); + $this->processManager->execute('test.mapping_transformer.error', [ + 'field' => 'value', + ]); } /** * Assert we can use multiple times the same sub-transformer using # suffixes */ - public function testMultiSubtransformers() + public function testMultiSubtransformers(): void { $result = $this->processManager->execute( 'test.mapping_transformer.multi_subtransformers', - ['field' => [3, null, 4, 2]] + [ + 'field' => [3, null, 4, 2], + ] ); - self::assertEquals(['field2' => [2, 4, 3]], $result); + self::assertEquals([ + 'field2' => [2, 4, 3], + ], $result); } /** * Assert we can use a deep property path as a key to generate a multi-depth array */ - public function testDeepMapping() + public function testDeepMapping(): void { - $result = $this->processManager->execute('test.mapping_transformer.deep_mapping', ['value' => 'ok']); + $result = $this->processManager->execute('test.mapping_transformer.deep_mapping', [ + 'value' => 'ok', + ]); - self::assertEquals(['field1' => ['field2' => ['field3' => 'ok']]], $result); + self::assertEquals([ + 'field1' => [ + 'field2' => [ + 'field3' => 'ok', + ], + ], + ], $result); } /** * Test the '.' source property path */ - public function testFullInput() + public function testFullInput(): void { - $result = $this->processManager->execute('test.mapping_transformer.full_input', ['value' => 'ok']); + $result = $this->processManager->execute('test.mapping_transformer.full_input', [ + 'value' => 'ok', + ]); - self::assertEquals(['out' => ['value' => 'ok']], $result); + self::assertEquals([ + 'out' => [ + 'value' => 'ok', + ], + ], $result); } /** * Test the '.' source property path inside an array of source codes */ - public function testFullInputInArray() + public function testFullInputInArray(): void { - $result = $this->processManager->execute('test.mapping_transformer.full_input_in_array', ['field' => 'ok']); + $result = $this->processManager->execute('test.mapping_transformer.full_input_in_array', [ + 'field' => 'ok', + ]); - self::assertEquals(['out' => [ - 'some_field' => 'ok', - 'full' => ['field' => 'ok'], - ]], $result); + self::assertEquals([ + 'out' => [ + 'some_field' => 'ok', + 'full' => [ + 'field' => 'ok', + ], + ], + ], $result); } /** * Test that a source property can be an array with numeric keys (see commit e141cb61) */ - public function testMultiSourceFieldInSequence() + public function testMultiSourceFieldInSequence(): void { $result = $this->processManager->execute('test.mapping_transformer.multi_source_field_in_sequence', [ 'field1' => 'a', @@ -95,6 +127,8 @@ public function testMultiSourceFieldInSequence() 'field3' => 'c', ]); - self::assertEquals(['out' => ['a', 'b', 'c']], $result); + self::assertEquals([ + 'out' => ['a', 'b', 'c'], + ], $result); } } diff --git a/Tests/Transformer/RulesTransformerTest.php b/Tests/Transformer/RulesTransformerTest.php index 8f61d766..df4ffcc9 100644 --- a/Tests/Transformer/RulesTransformerTest.php +++ b/Tests/Transformer/RulesTransformerTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.rules_transformer.simple', 'ok'); self::assertEquals('result1', $result1); @@ -31,5 +31,4 @@ public function testSimpleRule() $result3 = $this->processManager->execute('test.rules_transformer.simple', 'any'); self::assertEquals('result3', $result3); } - } diff --git a/Tests/Transformer/TransformerExceptionTest.php b/Tests/Transformer/TransformerExceptionTest.php index 96504d55..1f015c6c 100644 --- a/Tests/Transformer/TransformerExceptionTest.php +++ b/Tests/Transformer/TransformerExceptionTest.php @@ -1,4 +1,7 @@ - [ @@ -47,7 +52,7 @@ public function testDeepError() $message = null; try { $this->processManager->execute('test.transformer_exception.deep', $input); - } catch (\RuntimeException $exception) { + } catch (RuntimeException $exception) { $message = $exception->getMessage(); } diff --git a/Tests/Transformer/TypeSetterTransformerTest.php b/Tests/Transformer/TypeSetterTransformerTest.php index 2f778008..a7f4dfdc 100644 --- a/Tests/Transformer/TypeSetterTransformerTest.php +++ b/Tests/Transformer/TypeSetterTransformerTest.php @@ -1,4 +1,7 @@ -processManager->execute('test.type_setter_transformer.int_to_int', 1); self::assertSame(1, $result); @@ -30,7 +32,7 @@ public function testIntToInt() /** * Assert string to int convertion */ - public function testStringToInt() + public function testStringToInt(): void { $result = $this->processManager->execute('test.type_setter_transformer.string_to_int', '1'); self::assertSame(1, $result); @@ -39,10 +41,9 @@ public function testStringToInt() /** * Assert int to string convertion */ - public function testIntToString() + public function testIntToString(): void { $result = $this->processManager->execute('test.type_setter_transformer.int_to_string', 1); self::assertSame('1', $result); } - } diff --git a/Tests/Transformer/UnsetTransformerTest.php b/Tests/Transformer/UnsetTransformerTest.php index 90ac90a6..9f26fbd0 100644 --- a/Tests/Transformer/UnsetTransformerTest.php +++ b/Tests/Transformer/UnsetTransformerTest.php @@ -1,4 +1,7 @@ - 1, @@ -29,13 +31,16 @@ public function testSimpleUnset() 'to_test' => 2, ]; $result = $this->processManager->execute('test.unset_transformer.simple', $input); - self::assertEquals(['other' => 1, 'to_test' => 2], $result); + self::assertEquals([ + 'other' => 1, + 'to_test' => 2, + ], $result); } /** * Assert a few simple condition can trigger unset (or not) */ - public function testConditionalUnset() + public function testConditionalUnset(): void { $input = [ 'other' => 1, @@ -45,21 +50,35 @@ public function testConditionalUnset() // Should unset $result = $this->processManager->execute('test.unset_transformer.condition', $input); - self::assertEquals(['other' => 1, 'to_test' => 2], $result); + self::assertEquals([ + 'other' => 1, + 'to_test' => 2, + ], $result); // No unset $input['to_test'] = 3; $result = $this->processManager->execute('test.unset_transformer.condition', $input); - self::assertEquals(['other' => 1, 'to_unset' => 1, 'to_test' => 3], $result); + self::assertEquals([ + 'other' => 1, + 'to_unset' => 1, + 'to_test' => 3, + ], $result); // Checking null, no unset $result = $this->processManager->execute('test.unset_transformer.condition_null', $input); - self::assertEquals(['other' => 1, 'to_unset' => 1, 'to_test' => 3], $result); + self::assertEquals([ + 'other' => 1, + 'to_unset' => 1, + 'to_test' => 3, + ], $result); // Should unset $input['to_test'] = null; $result = $this->processManager->execute('test.unset_transformer.condition_null', $input); - self::assertEquals(['other' => 1, 'to_test' => null], $result); + self::assertEquals([ + 'other' => 1, + 'to_test' => null, + ], $result); } /** @@ -67,7 +86,7 @@ public function testConditionalUnset() * * @expectedException \RuntimeException */ - public function testWrongUnsetString() + public function testWrongUnsetString(): void { $this->processManager->execute('test.unset_transformer.simple', 'not an array'); } @@ -77,9 +96,8 @@ public function testWrongUnsetString() * * @expectedException \RuntimeException */ - public function testWrongUnsetMissingProperty() + public function testWrongUnsetMissingProperty(): void { $this->processManager->execute('test.unset_transformer.simple', ['no property found']); } - } diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/Tests/Transformer/XpathEvaluatorTransformerTest.php index 5580485f..f373c089 100644 --- a/Tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/Tests/Transformer/XpathEvaluatorTransformerTest.php @@ -1,5 +1,8 @@ -loadXML('ok'); $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ 'query' => '/a/text()', ]); } - public function testAttributeValueQuery() + public function testAttributeValueQuery(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ko'); $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ 'query' => '/node/@data', ]); } - public function testSubQuery() + public function testSubQuery(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ok'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -48,9 +52,9 @@ public function testSubQuery() ]); } - public function testMultiResults() + public function testMultiResults(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -60,13 +64,13 @@ public function testMultiResults() ]); } - public function testMultiResultsAsNodeList() + public function testMultiResultsAsNodeList(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; - /** @var \DOMNodeList $result */ + /** @var DOMNodeList $result */ $result = $this->transform('xpath_evaluator', $node, [ 'query' => './c/text()', 'single_result' => false, @@ -79,24 +83,20 @@ public function testMultiResultsAsNodeList() self::assertEquals('ok3', $result[2]->textContent); } - public function testMultiQuery() + public function testMultiQuery(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; $this->assertTransformation('xpath_evaluator', ['ok1', 'ok2', 'ok3'], $node, [ - 'query' => [ - './c/text()', - './d/text()', - './e/text()', - ], + 'query' => ['./c/text()', './d/text()', './e/text()'], ]); } - public function testMultiQueryWithKey() + public function testMultiQueryWithKey(): void { - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -113,7 +113,7 @@ public function testMultiQueryWithKey() ]); } - public function testOverridableSubqueries() + public function testOverridableSubqueries(): void { $xml = << XML; - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); $domDocument->loadXML($xml); $node = $domDocument->getElementsByTagName('b')[0]; diff --git a/Transformer/ArrayElementTransformer.php b/Transformer/ArrayElementTransformer.php index c0225b72..89611646 100644 --- a/Transformer/ArrayElementTransformer.php +++ b/Transformer/ArrayElementTransformer.php @@ -1,4 +1,7 @@ - */ class ArrayElementTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritdoc} - */ public function transform($value, array $options = []) { return array_values(array_slice($value, $options['index'], 1))[0]; } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'array_element'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'index', - ] - ); + $resolver->setRequired(['index']); $resolver->setAllowedTypes('index', ['integer']); } } diff --git a/Transformer/ArrayFilterTransformer.php b/Transformer/ArrayFilterTransformer.php index 26021410..d0f2a512 100644 --- a/Transformer/ArrayFilterTransformer.php +++ b/Transformer/ArrayFilterTransformer.php @@ -1,4 +1,7 @@ -accessor = $accessor; } /** - * {@inheritdoc} + * @return array */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): array { - if (!(\is_array($value) || $value instanceof \Traversable)) { - throw new \UnexpectedValueException('Given value is not iterable'); + if (! (is_iterable($value))) { + throw new UnexpectedValueException('Given value is not iterable'); } $result = []; @@ -52,18 +51,12 @@ public function transform($value, array $options = []) return $result; } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'array_filter'; } - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $this->configureWrappedConditionOptions('condition', $resolver); } diff --git a/Transformer/ArrayFirstTransformer.php b/Transformer/ArrayFirstTransformer.php index 81ce3a87..ec5c1f57 100644 --- a/Transformer/ArrayFirstTransformer.php +++ b/Transformer/ArrayFirstTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ArrayFirstTransformer implements ConfigurableTransformerInterface { @@ -25,15 +24,12 @@ class ArrayFirstTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options - * - * @throws ExceptionInterface * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - if ($options['allow_not_iterable'] && !is_iterable($value)) { + if ($options['allow_not_iterable'] && ! is_iterable($value)) { return $value; } @@ -42,25 +38,16 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'array_first'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults( - [ - 'allow_not_iterable' => false, - ] - ); + $resolver->setDefaults([ + 'allow_not_iterable' => false, + ]); } } diff --git a/Transformer/ArrayLastTransformer.php b/Transformer/ArrayLastTransformer.php index e2a5e0e5..f0d61f7a 100644 --- a/Transformer/ArrayLastTransformer.php +++ b/Transformer/ArrayLastTransformer.php @@ -1,4 +1,7 @@ - */ class ArrayLastTransformer implements TransformerInterface { - /** - * {@inheritdoc} - */ public function transform($value, array $options = []) { return array_values(array_slice($value, -1))[0]; } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'array_last'; } diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index 0f6615de..edd654ec 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ArrayMapTransformer implements ConfigurableTransformerInterface { use TransformerTrait; - /** - * @param TransformerRegistry $transformerRegistry - */ public function __construct(TransformerRegistry $transformerRegistry) { $this->transformerRegistry = $transformerRegistry; @@ -36,16 +35,13 @@ public function __construct(TransformerRegistry $transformerRegistry) * Must return the transformed $value * * @param array $values - * @param array $options * - * @throws \UnexpectedValueException - * - * @return mixed $value + * @return mixed[] $value */ - public function transform($values, array $options = []) + public function transform($values, array $options = []): array { - if (!\is_array($values) && !$values instanceof \Traversable) { - throw new \UnexpectedValueException('Input value must be an array or traversable'); + if (! \is_array($values) && ! $values instanceof Traversable) { + throw new UnexpectedValueException('Input value must be an array or traversable'); } $results = []; @@ -53,12 +49,12 @@ public function transform($values, array $options = []) foreach ($values as $key => $item) { try { $item = $this->applyTransformers($options['transformers'], $item); - if (null === $item && $options['skip_null']) { + if ($item === null && $options['skip_null']) { continue; } $results[$key] = $item; } catch (TransformerException $exception) { - $exception->setTargetProperty((string)$key); + $exception->setTargetProperty((string) $key); throw $exception; } } @@ -68,30 +64,19 @@ public function transform($values, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'array_map'; } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $this->configureTransformersOptions($resolver); - $resolver->setRequired( - [ - 'transformers', - ] - ); - $resolver->setDefaults( - [ - 'skip_null' => false, - ] - ); + $resolver->setRequired(['transformers']); + $resolver->setDefaults([ + 'skip_null' => false, + ]); $resolver->setAllowedTypes('skip_null', ['boolean']); } } diff --git a/Transformer/ArrayUnsetTransformer.php b/Transformer/ArrayUnsetTransformer.php index 59eb9db0..a710b3bd 100644 --- a/Transformer/ArrayUnsetTransformer.php +++ b/Transformer/ArrayUnsetTransformer.php @@ -1,4 +1,7 @@ -setRequired('key'); diff --git a/Transformer/CachedTransformer.php b/Transformer/CachedTransformer.php index 4e763883..9413b352 100644 --- a/Transformer/CachedTransformer.php +++ b/Transformer/CachedTransformer.php @@ -1,4 +1,7 @@ -transformerRegistry = $transformerRegistry; - $this->cache = $cache; - $this->logger = $logger; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('cache_key'); $resolver->setAllowedTypes('cache_key', 'string'); $resolver->setDefault('ttl', null); - $resolver->setAllowedTypes('ttl', ['null', 'string', \DateTimeInterface::class]); + $resolver->setAllowedTypes('ttl', ['null', 'string', DateTimeInterface::class]); $resolver->setNormalizer( 'ttl', function (Options $options, $value) { @@ -62,7 +51,7 @@ function (Options $options, $value) { * @see https://www.php.net/manual/en/datetime.formats.relative.php */ if (is_string($value)) { - $value = new \DateTime($value); + $value = new DateTime($value); } return $value; @@ -81,24 +70,28 @@ public function transform($value, array $options = []) $cacheItem = $this->cache->getItem($cacheKey); if ($cacheItem->isHit()) { return $cacheItem->get(); - } else { - $newValue = $this->applyTransformers($options['transformers'], $value); - $cacheItem->set($newValue); - if ($options['ttl']) { - $cacheItem->expiresAt($options['ttl']); - } - $success = $this->cache->saveDeferred($cacheItem); - - if (!$success) { - $this->logger->warning('Cannot save cache item', ['cache_key' => $cacheKey]); - } - - return $newValue; } + $newValue = $this->applyTransformers($options['transformers'], $value); + $cacheItem->set($newValue); + if ($options['ttl']) { + $cacheItem->expiresAt($options['ttl']); + } + $success = $this->cache->saveDeferred($cacheItem); + + if (! $success) { + $this->logger->warning('Cannot save cache item', [ + 'cache_key' => $cacheKey, + ]); + } + + return $newValue; } catch (InvalidArgumentException $exception) { $this->logger->warning( 'Cannot get cache item', - ['cache_key' => $cacheKey, 'message' => $exception->getMessage()] + [ + 'cache_key' => $cacheKey, + 'message' => $exception->getMessage(), + ] ); } } @@ -106,20 +99,19 @@ public function transform($value, array $options = []) return $this->applyTransformers($options['transformers'], $value); } - public function getCode() + public function getCode(): string { return 'cached'; } - protected function generateCacheKey($cacheKeyRoot, $value, $options) + protected function generateCacheKey($cacheKeyRoot, $value, $options): bool|string { $value = $this->applyTransformers($options['key_transformers'], $value); - if (!\is_string($value)) { + if (! \is_string($value)) { return false; } return \implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, \rawurlencode($value)]); } - } diff --git a/Transformer/CallbackTransformer.php b/Transformer/CallbackTransformer.php index 47a92512..9e0bb8e8 100644 --- a/Transformer/CallbackTransformer.php +++ b/Transformer/CallbackTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CallbackTransformer implements ConfigurableTransformerInterface { @@ -27,14 +26,13 @@ class CallbackTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - if (count($options['additional_parameters']) - && !count($options['right_parameters'])) { + if ((is_countable($options['additional_parameters']) ? count($options['additional_parameters']) : 0) + && ! (is_countable($options['right_parameters']) ? count($options['right_parameters']) : 0)) { $options['right_parameters'] = $options['additional_parameters']; } @@ -46,35 +44,22 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'callback'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( - [ - 'callback', - ] - ); + $resolver->setRequired(['callback']); $resolver->setAllowedTypes('callback', ['string', 'array']); /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'callback', - static function (Options $options, $value) { - if (!\is_callable($value)) { - throw new InvalidOptionsException( - 'Callback option must be callable' - ); + static function (Options $options, $value): callable { + if (! \is_callable($value)) { + throw new InvalidOptionsException('Callback option must be callable'); } return $value; diff --git a/Transformer/CastTransformer.php b/Transformer/CastTransformer.php index 04487b41..0e6e8151 100644 --- a/Transformer/CastTransformer.php +++ b/Transformer/CastTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class CastTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritdoc} - */ public function transform($value, array $options = []) { settype($value, $options['type']); @@ -31,26 +27,14 @@ public function transform($value, array $options = []) return $value; } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'cast'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'type', - ] - ); + $resolver->setRequired(['type']); $resolver->setAllowedTypes('type', ['string']); } } diff --git a/Transformer/ConditionTrait.php b/Transformer/ConditionTrait.php index ff499c46..af349069 100644 --- a/Transformer/ConditionTrait.php +++ b/Transformer/ConditionTrait.php @@ -1,4 +1,7 @@ - $value) { - if (!$this->checkValue($input, $key, $value)) { + if (! $this->checkValue($input, $key, $value)) { return false; } } foreach ($conditions['empty'] as $key => $value) { - if (!$this->checkEmpty($input, $key)) { + if (! $this->checkEmpty($input, $key)) { return false; } } foreach ($conditions['match_regexp'] as $key => $value) { - if (!$this->checkValue($input, $key, $value, true, true)) { + if (! $this->checkValue($input, $key, $value, true, true)) { return false; } } foreach ($conditions['not_match'] as $key => $value) { - if (!$this->checkValue($input, $key, $value, false)) { + if (! $this->checkValue($input, $key, $value, false)) { return false; } } @@ -66,7 +65,7 @@ protected function checkCondition($input, $conditions) } foreach ($conditions['not_match_regexp'] as $key => $value) { - if (!$this->checkValue($input, $key, $value, false, true)) { + if (! $this->checkValue($input, $key, $value, false, true)) { return false; } } @@ -76,9 +75,6 @@ protected function checkCondition($input, $conditions) /** * Configure available condition rules in a wrapper option - * - * @param string $wrapperKey - * @param OptionsResolver $resolver */ protected function configureWrappedConditionOptions(string $wrapperKey, OptionsResolver $resolver) { @@ -86,7 +82,7 @@ protected function configureWrappedConditionOptions(string $wrapperKey, OptionsR $resolver->setAllowedTypes($wrapperKey, ['array']); $resolver->setNormalizer( $wrapperKey, - function (OptionsResolver $options, $value) { + function (OptionsResolver $options, $value): array { $conditionResolver = new OptionsResolver(); $this->configureConditionOptions($conditionResolver); @@ -97,8 +93,6 @@ function (OptionsResolver $options, $value) { /** * Configure available condition rules - * - * @param OptionsResolver $resolver */ protected function configureConditionOptions(OptionsResolver $resolver) { @@ -119,38 +113,31 @@ protected function configureConditionOptions(OptionsResolver $resolver) * * @param object|array $input * @param string $key - * @param mixed $value * @param bool $shouldMatch * @param bool $regexpMode - * - * @throws UnexpectedTypeException - * @throws AccessException - * @throws InvalidArgumentException - * - * @return bool */ - protected function checkValue($input, $key, $value, $shouldMatch = true, $regexpMode = false) + protected function checkValue($input, $key, mixed $value, $shouldMatch = true, $regexpMode = false): bool { $currentValue = $this->getValue($input, $key); /** @noinspection TypeUnsafeComparisonInspection */ - if ($shouldMatch && !$regexpMode && $currentValue != $value) { + if ($shouldMatch && ! $regexpMode && $currentValue !== $value) { return false; } /** @noinspection TypeUnsafeComparisonInspection */ - if (!$shouldMatch && !$regexpMode && $currentValue == $value) { + if (! $shouldMatch && ! $regexpMode && $currentValue === $value) { return false; } if ($regexpMode) { - $pregMatch = preg_match($value, $currentValue); + $pregMatch = preg_match($value, (string) $currentValue); - if ($shouldMatch && (false === $pregMatch || 0 === $pregMatch)) { + if ($shouldMatch && ($pregMatch === false || $pregMatch === 0)) { return false; } - if (!$shouldMatch && (false === $pregMatch || $pregMatch > 0)) { + if (! $shouldMatch && ($pregMatch === false || $pregMatch > 0)) { return false; } } @@ -163,10 +150,8 @@ protected function checkValue($input, $key, $value, $shouldMatch = true, $regexp * * @param array|object $input * @param string $key - * - * @return bool */ - protected function checkEmpty($input, $key) + protected function checkEmpty($input, $key): bool { $currentValue = $this->getValue($input, $key); @@ -183,7 +168,7 @@ protected function checkEmpty($input, $key) */ protected function getValue($input, $key) { - if ('' === $key) { + if ($key === '') { $currentValue = $input; } elseif ($this->accessor->isReadable($input, $key)) { $currentValue = $this->accessor->getValue($input, $key); diff --git a/Transformer/ConfigurableTransformerInterface.php b/Transformer/ConfigurableTransformerInterface.php index 9ee4568e..4a60d128 100644 --- a/Transformer/ConfigurableTransformerInterface.php +++ b/Transformer/ConfigurableTransformerInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface ConfigurableTransformerInterface extends TransformerInterface { - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ public function configureOptions(OptionsResolver $resolver); } diff --git a/Transformer/ConstantTransformer.php b/Transformer/ConstantTransformer.php index 3c0730ce..00b22e40 100644 --- a/Transformer/ConstantTransformer.php +++ b/Transformer/ConstantTransformer.php @@ -1,4 +1,7 @@ - */ class ConstantTransformer implements ConfigurableTransformerInterface { - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'constant', - ] - ); + $resolver->setRequired(['constant']); } /** * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { @@ -50,8 +40,6 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ public function getCode(): string { diff --git a/Transformer/ConvertValueTransformer.php b/Transformer/ConvertValueTransformer.php index 9c5620cf..a839e072 100644 --- a/Transformer/ConvertValueTransformer.php +++ b/Transformer/ConvertValueTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ConvertValueTransformer implements ConfigurableTransformerInterface { @@ -25,39 +25,34 @@ class ConvertValueTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @throws \UnexpectedValueException - * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - if (null === $value) { + if ($value === null) { return $value; } - if (!is_string($value) && !is_int($value)) { // If not a valid array index - if (!$options['auto_cast']) { + if (! is_string($value) && ! is_int($value)) { // If not a valid array index + if (! $options['auto_cast']) { $type = gettype($value); - throw new \UnexpectedValueException( + throw new UnexpectedValueException( "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" ); } if (is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here - throw new \UnexpectedValueException( - "Unexpected input of type 'array' in convert_value transformer" - ); + throw new UnexpectedValueException("Unexpected input of type 'array' in convert_value transformer"); } $value = (string) $value; // Let's cast it to string } - if (!array_key_exists($value, $options['map'])) { + if (! array_key_exists($value, $options['map'])) { if ($options['keep_missing']) { return $value; } - if (!$options['ignore_missing']) { - throw new \UnexpectedValueException("Missing value in map '{$value}'"); + if (! $options['ignore_missing']) { + throw new UnexpectedValueException("Missing value in map '{$value}'"); } return null; @@ -68,34 +63,21 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'convert_value'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'map', - ] - ); + $resolver->setRequired(['map']); $resolver->setAllowedTypes('map', ['array']); - $resolver->setDefaults( - [ - 'ignore_missing' => false, - 'keep_missing' => false, - 'auto_cast' => false, - ] - ); + $resolver->setDefaults([ + 'ignore_missing' => false, + 'keep_missing' => false, + 'auto_cast' => false, + ]); $resolver->setAllowedTypes('ignore_missing', ['boolean']); $resolver->setAllowedTypes('keep_missing', ['boolean']); $resolver->setAllowedTypes('auto_cast', ['boolean']); diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 485b956a..312dcf73 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -1,4 +1,7 @@ -format($options['format']); if ($result === false) { - @trigger_error('The date cannot be formatted, this will throw an error starting from v4.0', E_USER_DEPRECATED); + @trigger_error( + 'The date cannot be formatted, this will throw an error starting from v4.0', + E_USER_DEPRECATED + ); } return $result; } - /** - * @return string - */ - public function getCode() + public function getCode(): string { return 'date_format'; } - /** - * @param OptionsResolver $resolver - * - * @throws UndefinedOptionsException - * @throws AccessException - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('format'); $resolver->setAllowedTypes('format', 'string'); diff --git a/Transformer/DateParserTransformer.php b/Transformer/DateParserTransformer.php index 586e3205..bb6df2f4 100644 --- a/Transformer/DateParserTransformer.php +++ b/Transformer/DateParserTransformer.php @@ -1,4 +1,7 @@ -setRequired('format'); $resolver->setAllowedTypes('format', 'string'); diff --git a/Transformer/DebugTransformer.php b/Transformer/DebugTransformer.php index bdb774d7..b317cd12 100644 --- a/Transformer/DebugTransformer.php +++ b/Transformer/DebugTransformer.php @@ -1,4 +1,7 @@ - */ class DebugTransformer implements TransformerInterface { - /** - * @inheritDoc - */ public function transform($value, array $options = []) { if (class_exists(VarDumper::class)) { @@ -31,10 +29,7 @@ public function transform($value, array $options = []) return $value; } - /** - * @inheritDoc - */ - public function getCode() + public function getCode(): string { return 'dump'; } diff --git a/Transformer/DefaultTransformer.php b/Transformer/DefaultTransformer.php index e1b6ae81..11dddf88 100644 --- a/Transformer/DefaultTransformer.php +++ b/Transformer/DefaultTransformer.php @@ -1,4 +1,7 @@ -setRequired('value'); } /** * @param mixed $value - * @param array $options * * @return mixed */ public function transform($value, array $options = []) { - if (!$value) { + if (! $value) { return $options['value']; } return $value; } - /** - * @return string - */ - public function getCode() + public function getCode(): string { return 'default'; } diff --git a/Transformer/DenormalizeTransformer.php b/Transformer/DenormalizeTransformer.php index d826ddd6..f0fe6e6b 100644 --- a/Transformer/DenormalizeTransformer.php +++ b/Transformer/DenormalizeTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class DenormalizeTransformer implements ConfigurableTransformerInterface { - /** @var DenormalizerInterface */ - protected $denormalizer; - - /** - * @param DenormalizerInterface $denormalizer - */ - public function __construct(DenormalizerInterface $denormalizer) - { - $this->denormalizer = $denormalizer; + public function __construct( + protected DenormalizerInterface $denormalizer + ) { } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'class', - ] - ); + $resolver->setRequired(['class']); $resolver->setAllowedTypes('class', ['string']); - $resolver->setDefaults( - [ - 'format' => null, - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'format' => null, + 'context' => [], + ]); $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } /** * @param mixed $value - * @param array $options * - * @throws ExceptionInterface * @return mixed|object */ public function transform($value, array $options = []) { - return $this->denormalizer->denormalize( - $value, - $options['class'], - $options['format'], - $options['context'] - ); + return $this->denormalizer->denormalize($value, $options['class'], $options['format'], $options['context']); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'denormalize'; } diff --git a/Transformer/EvaluatorTransformer.php b/Transformer/EvaluatorTransformer.php index bee97819..2d3037ba 100644 --- a/Transformer/EvaluatorTransformer.php +++ b/Transformer/EvaluatorTransformer.php @@ -1,4 +1,7 @@ - - */ class EvaluatorTransformer implements ConfigurableTransformerInterface { + protected ExpressionLanguage $language; - /** @var ExpressionLanguage */ - protected $language; - - /** - * EvaluatorTransformer constructor. - */ public function __construct() { $this->language = new ExpressionLanguage(); } - - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { // Allow to cache the parsing by statically defining variables $resolver->setDefault('variables', null); $resolver->addAllowedTypes('variables', ['null', 'array']); - $resolver->setRequired( - [ - 'expression', - ] - ); + $resolver->setRequired(['expression']); $resolver->setAllowedTypes('expression', ['string', ParsedExpression::class]); $resolver->setNormalizer( 'expression', @@ -73,29 +49,15 @@ function (Options $options, $expression) { /** * @param mixed $value - * @param array $options - * - * @throws UndefinedOptionsException - * @throws OptionDefinitionException - * @throws NoSuchOptionException - * @throws MissingOptionsException - * @throws InvalidOptionsException - * @throws AccessException * * @return string */ public function transform($value, array $options = []) { - return $this->language->evaluate( - $options['expression'], - $value - ); + return $this->language->evaluate($options['expression'], $value); } - /** - * @return string - */ - public function getCode() + public function getCode(): string { return 'evaluator'; } diff --git a/Transformer/ExplodeTransformer.php b/Transformer/ExplodeTransformer.php index 1c32b532..2f496c95 100644 --- a/Transformer/ExplodeTransformer.php +++ b/Transformer/ExplodeTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class ExplodeTransformer implements ConfigurableTransformerInterface { @@ -25,41 +24,29 @@ class ExplodeTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - if (null === $value || '' === $value) { + if ($value === null || $value === '') { return []; } - return explode($options['delimiter'], $value); + return explode($options['delimiter'], (string) $value); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'explode'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'delimiter', - ] - ); + $resolver->setRequired(['delimiter']); $resolver->setAllowedTypes('delimiter', ['string']); } } diff --git a/Transformer/ExpressionLanguageMapTransformer.php b/Transformer/ExpressionLanguageMapTransformer.php index 8a3214d0..0d16cde7 100644 --- a/Transformer/ExpressionLanguageMapTransformer.php +++ b/Transformer/ExpressionLanguageMapTransformer.php @@ -1,4 +1,7 @@ - */ class ExpressionLanguageMapTransformer implements ConfigurableTransformerInterface { - /** @var ExpressionLanguage */ - protected $language; - - /** - * @param ExpressionLanguage $language - */ - public function __construct(ExpressionLanguage $language) - { - $this->language = $language; + public function __construct( + protected ExpressionLanguage $language + ) { } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'map', - ] - ); + $resolver->setRequired(['map']); $resolver->setAllowedTypes('map', ['array']); - $resolver->setDefaults( - [ - 'ignore_missing' => false, - 'keep_missing' => false, - ] - ); + $resolver->setDefaults([ + 'ignore_missing' => false, + 'keep_missing' => false, + ]); $resolver->setAllowedTypes('ignore_missing', ['boolean']); $resolver->setAllowedTypes('keep_missing', ['boolean']); $resolver->setNormalizer( 'map', - function (Options $options, $values) { - if (!is_array($values)) { - throw new \UnexpectedValueException('The map must be an array'); + function (Options $options, $values): array { + if (! is_array($values)) { + throw new UnexpectedValueException('The map must be an array'); } $resolver = new OptionsResolver(); - $resolver->setRequired( - [ - 'condition', - 'output', - ] - ); + $resolver->setRequired(['condition', 'output']); $resolver->setNormalizer( 'condition', - function (Options $options, $value) { - return $this->language->parse($value, ['data']); - } + fn (Options $options, $value): ParsedExpression => $this->language->parse($value, ['data']) ); $resolver->setNormalizer( 'output', - function (Options $options, $value) { - return $this->language->parse($value, ['data']); - } + fn (Options $options, $value): ParsedExpression => $this->language->parse($value, ['data']) ); $parsedValues = []; foreach ($values as $value) { @@ -93,13 +69,14 @@ function (Options $options, $value) { * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - $input = ['data' => $value]; + $input = [ + 'data' => $value, + ]; foreach ($options['map'] as $mapItem) { if ($this->language->evaluate($mapItem['condition'], $input)) { return $this->language->evaluate($mapItem['output'], $input); @@ -109,8 +86,8 @@ public function transform($value, array $options = []) if ($options['keep_missing']) { return $value; } - if (!$options['ignore_missing']) { - throw new \UnexpectedValueException("No expression accepting value '{$value}' in map"); + if (! $options['ignore_missing']) { + throw new UnexpectedValueException("No expression accepting value '{$value}' in map"); } return null; @@ -118,8 +95,6 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ public function getCode(): string { diff --git a/Transformer/GenericTransformer.php b/Transformer/GenericTransformer.php index 5c7dcd71..b6c335b3 100644 --- a/Transformer/GenericTransformer.php +++ b/Transformer/GenericTransformer.php @@ -1,4 +1,7 @@ -contextualOptionResolver = $contextualOptionResolver; + protected $contextualOptions; + + public function __construct( + protected ContextualOptionResolver $contextualOptionResolver, + TransformerRegistry $transformerRegistry + ) { $this->transformerRegistry = $transformerRegistry; } /** * Register the generic options, and load the transformer list - * - * @param string $code - * @param array $options */ - public function initialize(string $code, array $options = []) + public function initialize(string $code, array $options = []): void { $this->transformerCode = $code; $resolver = new OptionsResolver(); @@ -65,14 +64,12 @@ public function initialize(string $code, array $options = []) /** * Called on instance creation - * - * @param OptionsResolver $resolver */ - public function configureInitialOptions(OptionsResolver $resolver) + public function configureInitialOptions(OptionsResolver $resolver): void { $resolver->setDefault('contextual_options', []); $resolver->setAllowedTypes('contextual_options', 'array'); - $resolver->setNormalizer('contextual_options', function (Options $options, $value) { + $resolver->setNormalizer('contextual_options', function (Options $options, $value): array { $configuration = []; foreach ($value as $optionCode => $optionConfig) { $resolver = new OptionsResolver(); @@ -88,8 +85,6 @@ public function configureInitialOptions(OptionsResolver $resolver) /** * Called on process startup, prepare the real transformers - * - * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { @@ -105,9 +100,9 @@ public function configureOptions(OptionsResolver $resolver) // Get the transformer list + apply transformer option resolution by context $this->configureTransformersOptions($resolver); - $resolver->setNormalizer('transformers', function (Options $options, $transformerOptions) { + $resolver->setNormalizer('transformers', function (Options $options, $transformerOptions): array { if ($transformerOptions !== []) { - throw new \InvalidArgumentException('Transformers option should not be used at this point'); + throw new InvalidArgumentException('Transformers option should not be used at this point'); } $transformerOptions = $this->normalizeTransformerOptions($options, $this->preconfiguredTransformerOptions); @@ -117,17 +112,11 @@ public function configureOptions(OptionsResolver $resolver) }); } - /** - * {@inheritDoc} - */ public function transform($value, array $options = []) { return $this->applyTransformers($options['transformers'], $value); } - /** - * {@inheritDoc} - */ public function getCode() { return $this->transformerCode; @@ -135,13 +124,8 @@ public function getCode() /** * Get the real transformer from contextual options + generic definitions - * - * @param Options $options - * @param array $transformerOptions - * - * @return array */ - public function normalizeTransformerOptions(Options $options, $transformerOptions) + public function normalizeTransformerOptions(Options $options, array $transformerOptions): array { $contextualizedOptionValues = []; foreach ($this->contextualOptions as $contextualOption => $contextualOptionConfig) { @@ -153,10 +137,8 @@ public function normalizeTransformerOptions(Options $options, $transformerOption /** * Available options for contextual_options - * - * @param OptionsResolver $resolver */ - public function configureContextualOptions(OptionsResolver $resolver) + public function configureContextualOptions(OptionsResolver $resolver): void { $resolver->setDefault('required', true); $resolver->setAllowedTypes('required', 'bool'); @@ -166,5 +148,4 @@ public function configureContextualOptions(OptionsResolver $resolver) $resolver->setDefault('default_is_null', false); $resolver->setAllowedTypes('default_is_null', 'bool'); } - } diff --git a/Transformer/HashTransformer.php b/Transformer/HashTransformer.php index d4ed5d32..b394c294 100644 --- a/Transformer/HashTransformer.php +++ b/Transformer/HashTransformer.php @@ -1,4 +1,7 @@ - */ class HashTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('algo'); $resolver->setAllowedValues('algo', hash_algos()); @@ -32,19 +30,12 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefault('raw_output', false); } - /** - * {@inheritDoc} - * @throws \UnexpectedValueException - */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): string { - return hash($options['algo'], $value, $options['raw_output']); + return hash((string) $options['algo'], (string) $value, $options['raw_output']); } - /** - * {@inheritDoc} - */ - public function getCode() + public function getCode(): string { return 'hash'; } diff --git a/Transformer/ImplodeTransformer.php b/Transformer/ImplodeTransformer.php index 9bdeaa2b..63e2550e 100644 --- a/Transformer/ImplodeTransformer.php +++ b/Transformer/ImplodeTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot - * @author Corentin Bouix */ class ImplodeTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('separator'); $resolver->setDefault('separator', '|'); $resolver->setAllowedTypes('separator', 'string'); } - /** - * {@inheritDoc} - * @throws \UnexpectedValueException - */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): string { - if (!\is_array($value)) { - throw new \UnexpectedValueException('Given value is not an array'); + if (! \is_array($value)) { + throw new UnexpectedValueException('Given value is not an array'); } return implode($options['separator'], $value); } - /** - * {@inheritDoc} - */ - public function getCode() + public function getCode(): string { return 'implode'; } diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 147755e9..653f684b 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class MappingTransformer implements ConfigurableTransformerInterface { use TransformerTrait; - /** @var LoggerInterface */ - protected $logger; - - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param TransformerRegistry $transformerRegistry - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - */ public function __construct( TransformerRegistry $transformerRegistry, - LoggerInterface $logger, - PropertyAccessorInterface $accessor + protected LoggerInterface $logger, + protected PropertyAccessorInterface $accessor ) { $this->transformerRegistry = $transformerRegistry; - $this->logger = $logger; - $this->accessor = $accessor; } /** * Must return the transformed $value * * @param mixed $input - * @param array $options - * - * @return mixed $value - * @throws \Exception * + * @return mixed */ public function transform($input, array $options = []) { - if (!empty($options['initial_value']) && $options['keep_input']) { + if (! empty($options['initial_value']) && $options['keep_input']) { throw new InvalidOptionsException( 'The options "initial_value" and "keep_input" can\'t be both enabled.' ); @@ -87,7 +66,7 @@ public function transform($input, array $options = []) $ignoreMissingFlag = $mapping['ignore_missing'] || $options['ignore_missing']; // Prepare input value - if (null !== $mapping['constant']) { + if ($mapping['constant'] !== null) { $inputValue = $mapping['constant']; } elseif ($mapping['set_null']) { $inputValue = null; @@ -125,10 +104,14 @@ public function transform($input, array $options = []) $this->logger->debug( 'Transformation exception', [ - 'message' => $exception->getPrevious()->getMessage(), - 'file' => $exception->getPrevious()->getFile(), - 'line' => $exception->getPrevious()->getLine(), - 'trace' => $exception->getPrevious()->getTraceAsString(), + 'message' => $exception->getPrevious() + ->getMessage(), + 'file' => $exception->getPrevious() + ->getFile(), + 'line' => $exception->getPrevious() + ->getLine(), + 'trace' => $exception->getPrevious() + ->getTraceAsString(), ] ); @@ -143,32 +126,16 @@ public function transform($input, array $options = []) } elseif (\is_array($result)) { $result[$targetProperty] = $transformedValue; } else { - throw new \UnexpectedValueException("Property '{$targetProperty}' is not writable"); + throw new UnexpectedValueException("Property '{$targetProperty}' is not writable"); } } return $result; } - /** - * @param OptionsResolver $resolver - * - * @throws OptionDefinitionException - * @throws NoSuchOptionException - * @throws MissingOptionsException - * @throws InvalidOptionsException - * @throws UndefinedOptionsException - * @throws AccessException - * @throws MissingTransformerException - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'mapping', - ] - ); + $resolver->setRequired(['mapping']); $resolver->setAllowedTypes('mapping', ['array']); $resolver->setDefaults( [ @@ -184,15 +151,13 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer( 'mapping', - function (/** @noinspection PhpUnusedParameterInspection */ Options $options, $value) { + function (/** @noinspection PhpUnusedParameterInspection */ Options $options, $value): array { $resolvedMapping = []; $mappingResolver = new OptionsResolver(); $this->configureMappingOptions($mappingResolver); /** @var array $value */ foreach ($value as $property => $mappingConfig) { - $resolvedMapping[$property] = $mappingResolver->resolve( - $mappingConfig ?? [] - ); + $resolvedMapping[$property] = $mappingResolver->resolve($mappingConfig ?? []); } return $resolvedMapping; @@ -202,26 +167,12 @@ function (/** @noinspection PhpUnusedParameterInspection */ Options $options, $v /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'mapping'; } - /** - * @param OptionsResolver $resolver - * - * @throws OptionDefinitionException - * @throws NoSuchOptionException - * @throws MissingOptionsException - * @throws InvalidOptionsException - * @throws UndefinedOptionsException - * @throws AccessException - * @throws MissingTransformerException - * @throws ExceptionInterface - */ protected function configureMappingOptions(OptionsResolver $resolver) { $resolver->setDefaults( @@ -242,14 +193,9 @@ protected function configureMappingOptions(OptionsResolver $resolver) /** * Custom rules to get a value from an input object or array * - * @param mixed $input - * @param string $sourceProperty - * - * @throws RuntimeException - * * @return mixed */ - protected function extractInputValue($input, string $sourceProperty) + protected function extractInputValue(mixed $input, string $sourceProperty) { if ($sourceProperty === '.') { return $input; @@ -263,9 +209,6 @@ protected function extractInputValue($input, string $sourceProperty) * * @TODO WARNING there is no error if framework.property_access.throw_exception_on_invalid_index is false (which is * the default) - * - * @param RuntimeException $missingPropertyError - * @param string $srcKey */ protected function handleInputMissingExceptions(RuntimeException $missingPropertyError, string $srcKey) { diff --git a/Transformer/MultiReplaceTransformer.php b/Transformer/MultiReplaceTransformer.php index 63e28da9..dea49686 100644 --- a/Transformer/MultiReplaceTransformer.php +++ b/Transformer/MultiReplaceTransformer.php @@ -1,4 +1,7 @@ - $replacement) { - $value = str_replace($pattern, $replacement, $value); + foreach ($options['replace_mapping'] as $pattern => $replacement) { + $value = str_replace($pattern, $replacement, (string) $value); } return $value; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('replace_mapping'); $resolver->setAllowedTypes('replace_mapping', 'array'); } - public function getCode() + public function getCode(): string { return 'multi_replace'; } - } diff --git a/Transformer/NormalizeTransformer.php b/Transformer/NormalizeTransformer.php index 8a9c7c04..08ea96c2 100644 --- a/Transformer/NormalizeTransformer.php +++ b/Transformer/NormalizeTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class NormalizeTransformer implements ConfigurableTransformerInterface { - /** @var NormalizerInterface */ - protected $normalizer; - - /** - * @param NormalizerInterface $normalizer - */ - public function __construct(NormalizerInterface $normalizer) - { - $this->normalizer = $normalizer; + public function __construct( + protected NormalizerInterface $normalizer + ) { } - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults( - [ - 'format' => null, - 'context' => [], - ] - ); + $resolver->setDefaults([ + 'format' => null, + 'context' => [], + ]); $resolver->setAllowedTypes('format', ['null', 'string']); $resolver->setAllowedTypes('context', ['array']); } /** * @param mixed $value - * @param array $options * - * @throws ExceptionInterface * @return array|bool|float|int|mixed|string */ public function transform($value, array $options = []) { - return $this->normalizer->normalize( - $value, - $options['format'], - $options['context'] - ); + return $this->normalizer->normalize($value, $options['format'], $options['context']); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'normalize'; } diff --git a/Transformer/PregFilterTransformer.php b/Transformer/PregFilterTransformer.php index d2a52348..6d8aac0e 100644 --- a/Transformer/PregFilterTransformer.php +++ b/Transformer/PregFilterTransformer.php @@ -1,4 +1,7 @@ - - */ class PregFilterTransformer implements ConfigurableTransformerInterface { /** * Must return the transformed $value * * @param mixed $value - * @param array $options - * - * @return mixed $value */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): array|string|null { $pattern = $options['pattern']; $replacement = $options['replacement']; - return preg_filter($pattern, $replacement, $value); + return preg_filter($pattern, (string) $replacement, (string) $value); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'preg_filter'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'pattern', - 'replacement', - ] - ); + $resolver->setRequired(['pattern', 'replacement']); $resolver->setAllowedTypes('pattern', ['string', 'array']); $resolver->setAllowedTypes('replacement', ['string', 'array']); } diff --git a/Transformer/PropertyAccessorTransformer.php b/Transformer/PropertyAccessorTransformer.php index d267b0a6..077825cd 100644 --- a/Transformer/PropertyAccessorTransformer.php +++ b/Transformer/PropertyAccessorTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class PropertyAccessorTransformer implements ConfigurableTransformerInterface { - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param PropertyAccessorInterface $accessor - */ - public function __construct(PropertyAccessorInterface $accessor) - { - $this->accessor = $accessor; + public function __construct( + protected PropertyAccessorInterface $accessor + ) { } /** * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @throws InvalidArgumentException - * @throws AccessException - * @throws UnexpectedTypeException - * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - - if (null === $value && $options['ignore_null']) { + if ($value === null && $options['ignore_null']) { return null; } - if ($options['ignore_missing'] && !$this->accessor->isReadable($value, $options['property_path'])) { + if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $options['property_path'])) { return null; } @@ -64,33 +48,20 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'property_accessor'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'property_path', - ] - ); + $resolver->setRequired(['property_path']); - $resolver->setDefaults( - [ - 'ignore_null' => false, - 'ignore_missing' => false, - ] - ); + $resolver->setDefaults([ + 'ignore_null' => false, + 'ignore_missing' => false, + ]); $resolver->setAllowedTypes('property_path', ['string']); $resolver->setAllowedTypes('ignore_null', ['boolean']); diff --git a/Transformer/RecursivePropertySetterTransformer.php b/Transformer/RecursivePropertySetterTransformer.php index f6578722..f20b6767 100644 --- a/Transformer/RecursivePropertySetterTransformer.php +++ b/Transformer/RecursivePropertySetterTransformer.php @@ -1,4 +1,7 @@ - */ class RecursivePropertySetterTransformer implements ConfigurableTransformerInterface { - /** @var PropertyAccessorInterface */ - protected $accessor; - - /** - * @param PropertyAccessorInterface $accessor - */ - public function __construct(PropertyAccessorInterface $accessor) - { - $this->accessor = $accessor; + public function __construct( + protected PropertyAccessorInterface $accessor + ) { } /** * Must return the transformed $value * * @param mixed $value - * @param array $options - * - * @throws NoSuchPropertyException - * @throws TransformerException - * @throws InvalidArgumentException - * @throws AccessException - * @throws UnexpectedTypeException * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []) { - if (null === $value && $options['ignore_null']) { + if ($value === null && $options['ignore_null']) { return null; } - if ($options['ignore_missing'] && !$this->accessor->isReadable($value, $options['iterator'])) { + if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $options['iterator'])) { return null; } $iterable = $this->accessor->getValue($value, $options['iterator']); - if (!is_iterable($iterable)) { + if (! is_iterable($iterable)) { throw new TransformerException($options['iterator']); } $protertiesToSet = []; foreach ($options['set_properties'] as $propertyName => $propertyValuePath) { $protertiesValue = null; - if ($options['ignore_missing'] && !$this->accessor->isReadable($value, $propertyValuePath)) { + if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $propertyValuePath)) { $protertiesValue = null; } else { $protertiesValue = $this->accessor->getValue($value, $propertyValuePath); - if (null === $protertiesValue && !$options['ignore_null']) { + if ($protertiesValue === null && ! $options['ignore_null']) { throw new TransformerException($propertyValuePath); } } @@ -85,8 +70,10 @@ public function transform($value, array $options = []) try { $this->accessor->setValue($item, $protertyName, $propertyValue); } catch (NoSuchPropertyException $e) { - if ($item instanceof \stdClass) { - $item = (object) array_merge((array) $item, [$protertyName => $propertyValue]); + if ($item instanceof stdClass) { + $item = (object) array_merge((array) $item, [ + $protertyName => $propertyValue, + ]); } else { throw $e; } @@ -99,34 +86,20 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'recursive_property_setter'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'iterator', - 'set_properties', - ] - ); + $resolver->setRequired(['iterator', 'set_properties']); - $resolver->setDefaults( - [ - 'ignore_null' => false, - 'ignore_missing' => false, - ] - ); + $resolver->setDefaults([ + 'ignore_null' => false, + 'ignore_missing' => false, + ]); $resolver->setAllowedTypes('iterator', ['string']); $resolver->setAllowedTypes('set_properties', ['array']); diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php index 30ab9260..9a56ccb5 100644 --- a/Transformer/RulesTransformer.php +++ b/Transformer/RulesTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class RulesTransformer implements ConfigurableTransformerInterface { - use TransformerTrait; - /** @var ExpressionLanguage */ - protected $language; - - /** - * RulesTransformer constructor. - * - * @param TransformerRegistry $transformerRegistry - * @param ExpressionLanguage $language - */ - public function __construct(TransformerRegistry $transformerRegistry, ExpressionLanguage $language) - { - $this->language = $language; + public function __construct( + TransformerRegistry $transformerRegistry, + protected ExpressionLanguage $language + ) { $this->transformerRegistry = $transformerRegistry; } - /** - * {@inheritdoc} - */ public function transform($value, array $options = []) { foreach ($options['rules_set'] as $rule) { @@ -53,26 +42,19 @@ public function transform($value, array $options = []) return null; } elseif ($rule['constant'] !== null) { return $rule['constant']; - } else { - return $this->applyTransformers($rule['transformers'], $value); } + return $this->applyTransformers($rule['transformers'], $value); } } return $value; } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'rules'; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('use_value_as_variables', false); @@ -83,9 +65,8 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setRequired('rules_set'); $resolver->setAllowedTypes('rules_set', 'array'); - $resolver->setNormalizer('rules_set', function (Options $options, $conditionSet) { - - $rules = array_map(function ($item) use ($options) { + $resolver->setNormalizer('rules_set', function (Options $options, $conditionSet): array { + $rules = array_map(function ($item) use ($options): array { $resolver = new OptionsResolver(); $this->configureRuleOptions($resolver, $options['expression_variables']); @@ -97,13 +78,13 @@ public function configureOptions(OptionsResolver $resolver) foreach ($rules as $rule) { if ($rule['default']) { if ($hasFoundDefault) { - throw new \InvalidArgumentException("Rules set cannot have more than 2 default rules"); + throw new InvalidArgumentException('Rules set cannot have more than 2 default rules'); } $hasFoundDefault = true; } if ($hasFoundDefault && $rule['condition'] !== null) { - throw new \InvalidArgumentException("A conditional rule cannot be placed after a default rule"); + throw new InvalidArgumentException('A conditional rule cannot be placed after a default rule'); } } @@ -114,7 +95,6 @@ public function configureOptions(OptionsResolver $resolver) /** * Configure options for one "rule" block * - * @param OptionsResolver $resolver * @param array|null $expressionVariables */ public function configureRuleOptions(OptionsResolver $resolver, $expressionVariables = null) @@ -132,15 +112,16 @@ public function configureRuleOptions(OptionsResolver $resolver, $expressionVaria $expressionNormalizer = function (Options $options, $expression) use ($expressionVariables) { if (is_array($expressionVariables) && $expression !== null) { return $this->language->parse($expression, $expressionVariables); - } else { - return $expression; } + return $expression; }; $resolver->setNormalizer('condition', $expressionNormalizer); $resolver->setNormalizer('default', function (Options $options, $value) { if ($value && $options['condition']) { - throw new \InvalidArgumentException("A rule cannot have a condition and be the default in the same time"); + throw new InvalidArgumentException( + 'A rule cannot have a condition and be the default in the same time' + ); } return $value; @@ -151,22 +132,17 @@ public function configureRuleOptions(OptionsResolver $resolver, $expressionVaria /** * Test if a value match a rule - * - * @param mixed $value - * @param string|ParsedExpression $rule - * @param bool $useValueAsVariable - * - * @return bool */ - protected function matchRule($value, $rule, bool $useValueAsVariable): bool + protected function matchRule(mixed $value, string|ParsedExpression $rule, bool $useValueAsVariable): bool { if ($rule['condition'] !== null) { - $expressionValues = $useValueAsVariable ? $value : ['value' => $value]; + $expressionValues = $useValueAsVariable ? $value : [ + 'value' => $value, + ]; return $this->language->evaluate($rule['condition'], $expressionValues); } return $rule['default']; } - } diff --git a/Transformer/SlugifyTransformer.php b/Transformer/SlugifyTransformer.php index c097b915..60bef40f 100644 --- a/Transformer/SlugifyTransformer.php +++ b/Transformer/SlugifyTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class SlugifyTransformer implements ConfigurableTransformerInterface { @@ -26,20 +26,17 @@ class SlugifyTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options - * - * @return mixed $value */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): string { - /** @var \Transliterator $transliterator */ + /** @var Transliterator $transliterator */ $transliterator = $options['transliterator']; $string = $transliterator->transliterate($value); return trim( preg_replace( $options['replace'], - $options['separator'], + (string) $options['separator'], strtolower(trim(strip_tags($string))) ), $options['separator'] @@ -48,20 +45,13 @@ public function transform($value, array $options = []) /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'slugify'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults( [ @@ -73,9 +63,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer( 'transliterator', - static function (Options $options, $value) { - return \Transliterator::create($value); - } + static fn (Options $options, $value): ?Transliterator => Transliterator::create($value) ); } } diff --git a/Transformer/SprintfTransformer.php b/Transformer/SprintfTransformer.php index e1ed00ba..020c9dd6 100644 --- a/Transformer/SprintfTransformer.php +++ b/Transformer/SprintfTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot - * @author Corentin Bouix */ class SprintfTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('format'); $resolver->setDefault('format', '%s'); $resolver->setAllowedTypes('format', 'string'); } - /** - * {@inheritDoc} - * @throws \UnexpectedValueException - */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): string { - if (!\is_array($value)) { + if (! \is_array($value)) { $value = [$value]; } return vsprintf($options['format'], $value); } - /** - * {@inheritDoc} - */ - public function getCode() + public function getCode(): string { return 'sprintf'; } diff --git a/Transformer/TransformerInterface.php b/Transformer/TransformerInterface.php index 7a0cb343..e18a871d 100644 --- a/Transformer/TransformerInterface.php +++ b/Transformer/TransformerInterface.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ interface TransformerInterface { @@ -22,9 +22,8 @@ interface TransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options * - * @return mixed $value + * @return mixed */ public function transform($value, array $options = []); diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 3f68f7c9..3c6df5e3 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -1,6 +1,7 @@ - */ trait TransformerTrait { - /** @var TransformerRegistry */ + /** + * @var TransformerRegistry + */ protected $transformerRegistry; /** - * @param array $transformers - * @param mixed $value - * + * Transform the list of transformer codes + options into a list of Closure (better performances) + */ + public function normalizeTransformers(Options $options, $transformers): array + { + $transformerClosures = []; + + foreach ($transformers as $origTransformerCode => $transformerOptions) { + $transformerOptionsResolver = new OptionsResolver(); + $transformerCode = $this->getCleanedTransfomerCode($origTransformerCode); + $transformer = $this->transformerRegistry->getTransformer($transformerCode); + $transformerOptions = $this->checkTransformerOptions($transformerOptions, $origTransformerCode); + if ($transformer instanceof ConfigurableTransformerInterface) { + $transformer->configureOptions($transformerOptionsResolver); + $transformerOptions = $transformerOptionsResolver->resolve($transformerOptions); + } elseif (! empty($transformerOptions)) { + throw new InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); + } + + $closure = static fn ($value) => $transformer->transform($value, $transformerOptions); + $transformerClosures[$origTransformerCode] = $closure; + } + + return $transformerClosures; + } + + /** * @return mixed - * @throws TransformerException - * */ - protected function applyTransformers(array $transformers, $value) + protected function applyTransformers(array $transformers, mixed $value) { // Quick return for better perfs if (empty($transformers)) { @@ -46,7 +68,7 @@ protected function applyTransformers(array $transformers, $value) foreach ($transformers as $transformerCode => $transformerClosure) { try { $value = $transformerClosure($value); - } catch (\Throwable $exception) { + } catch (Throwable $exception) { throw new TransformerException($transformerCode, 0, $exception); } } @@ -59,26 +81,20 @@ protected function applyTransformers(array $transformers, $value) * keys This way you can chain multiple times the same transformer. Without this, it would silently call only the * 1st one. * - * @param string $transformerCode - * * @return string * - * @throws MissingTransformerException - * * @example * transformers: * callback#1: * callback: array_filter * callback#2: * callback: array_reverse - * - * */ protected function getCleanedTransfomerCode(string $transformerCode) { $match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts); - if (1 === $match && $this->transformerRegistry->hasTransformer($parts[1])) { + if ($match === 1 && $this->transformerRegistry->hasTransformer($parts[1])) { return $parts[1]; } @@ -86,60 +102,19 @@ protected function getCleanedTransfomerCode(string $transformerCode) } /** - * @param OptionsResolver $resolver * @param string $optionName */ protected function configureTransformersOptions(OptionsResolver $resolver, $optionName = 'transformers') { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); - $resolver->setNormalizer($optionName, \Closure::fromCallable([$this, 'normalizeTransformers'])); - } - - /** - * Transform the list of transformer codes + options into a list of Closure (better performances) - * - * @param Options $options - * @param $transformers - * - * @return \Closure[] - * - * @throws ExceptionInterface - */ - public function normalizeTransformers(Options $options, $transformers) - { - $transformerClosures = []; - - foreach ($transformers as $origTransformerCode => $transformerOptions) { - $transformerOptionsResolver = new OptionsResolver(); - $transformerCode = $this->getCleanedTransfomerCode($origTransformerCode); - $transformer = $this->transformerRegistry->getTransformer($transformerCode); - $transformerOptions = $this->checkTransformerOptions($transformerOptions, $origTransformerCode); - if ($transformer instanceof ConfigurableTransformerInterface) { - $transformer->configureOptions($transformerOptionsResolver); - $transformerOptions = $transformerOptionsResolver->resolve($transformerOptions); - } elseif (!empty($transformerOptions)) { - throw new \InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); - } - - $closure = static function ($value) use ($transformer, $transformerOptions) { - return $transformer->transform($value, $transformerOptions); - }; - $transformerClosures[$origTransformerCode] = $closure; - } - - return $transformerClosures; + $resolver->setNormalizer($optionName, Closure::fromCallable([$this, 'normalizeTransformers'])); } /** * Check the options to always return an array, or fail on unexpected values - * - * @param mixed $transformerOptions - * @param string $transformerCode - * - * @return array */ - private function checkTransformerOptions($transformerOptions, string $transformerCode): array + private function checkTransformerOptions(mixed $transformerOptions, string $transformerCode): array { if (is_array($transformerOptions)) { return $transformerOptions; @@ -148,9 +123,9 @@ private function checkTransformerOptions($transformerOptions, string $transforme return []; } - $type = is_object($transformerOptions) ? get_class($transformerOptions) : gettype($transformerOptions); + $type = get_debug_type($transformerOptions); - throw new \InvalidArgumentException( + throw new InvalidArgumentException( "Options for transformer {$transformerCode} are invalid : found {$type}, expected array or null" ); } diff --git a/Transformer/TrimTransformer.php b/Transformer/TrimTransformer.php index b30d57b9..2430f525 100644 --- a/Transformer/TrimTransformer.php +++ b/Transformer/TrimTransformer.php @@ -1,4 +1,7 @@ - - * @author Vincent Chalnot */ class TrimTransformer implements ConfigurableTransformerInterface { @@ -25,41 +24,29 @@ class TrimTransformer implements ConfigurableTransformerInterface * Must return the transformed $value * * @param mixed $value - * @param array $options - * - * @return mixed $value */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): ?string { - if (null === $value) { + if ($value === null) { return null; } - return trim($value, $options['charlist']); + return trim((string) $value, $options['charlist']); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'trim'; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults( - [ - 'charlist' => " \t\n\r\0\x0B", - ] - ); + $resolver->setDefaults([ + 'charlist' => " \t\n\r\0\x0B", + ]); $resolver->setAllowedTypes('charlist', ['string']); } } diff --git a/Transformer/TypeSetterTransformer.php b/Transformer/TypeSetterTransformer.php index e558f29a..0e33845b 100644 --- a/Transformer/TypeSetterTransformer.php +++ b/Transformer/TypeSetterTransformer.php @@ -1,4 +1,7 @@ - - */ class TypeSetterTransformer implements ConfigurableTransformerInterface { - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('type'); $resolver->setAllowedValues( 'type', - [ - 'boolean', - 'bool', - 'integer', - 'int', - 'float', - 'double', - 'string', - 'array', - 'object', - 'null', - ] + ['boolean', 'bool', 'integer', 'int', 'float', 'double', 'string', 'array', 'object', 'null'] ); $resolver->setAllowedTypes('type', 'string'); } - /** - * {@inheritDoc} - * @throws \UnexpectedValueException - */ public function transform($value, array $options = []) { $return = settype($value, $options['type']); - if (true === $return) { + if ($return === true) { return $value; } throw new TransformerException("Failed to change value type in {$options['type']}"); } - /** - * {@inheritDoc} - */ - public function getCode() + public function getCode(): string { return 'type_setter'; } diff --git a/Transformer/UnsetTransformer.php b/Transformer/UnsetTransformer.php index 966f6dd7..5d6ab8cf 100644 --- a/Transformer/UnsetTransformer.php +++ b/Transformer/UnsetTransformer.php @@ -1,4 +1,7 @@ -accessor = $accessor; } - /** - * {@inheritdoc} - */ public function transform($value, array $options = []) { - if (!\is_array($value)) { - throw new \UnexpectedValueException('Given value must be an array'); + if (! \is_array($value)) { + throw new UnexpectedValueException('Given value must be an array'); } - if (!array_key_exists($options['property'], $value)) { - throw new \UnexpectedValueException("Property {$options['property']} does not exists"); + if (! array_key_exists($options['property'], $value)) { + throw new UnexpectedValueException("Property {$options['property']} does not exists"); } if ($this->checkCondition($value, $options['condition'])) { @@ -48,10 +46,7 @@ public function transform($value, array $options = []) return $value; } - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('property'); $resolver->setAllowedTypes('property', 'string'); @@ -59,10 +54,7 @@ public function configureOptions(OptionsResolver $resolver) $this->configureWrappedConditionOptions('condition', $resolver); } - /** - * {@inheritdoc} - */ - public function getCode() + public function getCode(): string { return 'unset'; } diff --git a/Transformer/WrapperTransformer.php b/Transformer/WrapperTransformer.php index 4b10389a..2335bbd5 100644 --- a/Transformer/WrapperTransformer.php +++ b/Transformer/WrapperTransformer.php @@ -1,4 +1,7 @@ - - */ class WrapperTransformer implements ConfigurableTransformerInterface { - /** * Must return the transformed $value - * - * @param mixed $input - * @param array $options - * - * @return mixed $value */ - public function transform($input, array $options = []) + public function transform(mixed $input, array $options = []): array { - return [$options['wrapper_key'] => $input]; + return [ + $options['wrapper_key'] => $input, + ]; } - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired( - [ - 'wrapper_key', - ] - ); + $resolver->setRequired(['wrapper_key']); $resolver->setAllowedTypes('wrapper_key', ['string', 'int']); } /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode() + public function getCode(): string { return 'wrapper'; } diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/Transformer/Xml/XpathEvaluatorTransformer.php index dbfb985c..561383e9 100644 --- a/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/Transformer/Xml/XpathEvaluatorTransformer.php @@ -1,4 +1,7 @@ -setRequired('query'); $resolver->setAllowedTypes('query', ['string', 'array']); - $resolver->setNormalizer('query', function(Options $options, $value) { + $resolver->setNormalizer('query', function (Options $options, $value): string|array { // Basic case : a single query - if(\is_string($value)) { + if (\is_string($value)) { return $value; } // Complex case : a list of subqueries, each can override root level options - if(\is_array($value)) { + if (\is_array($value)) { $queryOptions = []; $queryResolver = new OptionsResolver(); $this->configureQueryOptions($queryResolver, $options); @@ -42,8 +48,10 @@ public function configureOptions(OptionsResolver $resolver) $queryResolver->setAllowedTypes('subquery', 'string'); foreach ($value as $code => $subquery) { - if(\is_string($subquery)) { - $subquery = ['subquery' => $subquery]; + if (\is_string($subquery)) { + $subquery = [ + 'subquery' => $subquery, + ]; } $queryOptions[$code] = $queryResolver->resolve($subquery); @@ -53,7 +61,7 @@ public function configureOptions(OptionsResolver $resolver) } // This should never be reached - throw new \InvalidArgumentException('Unhandled query'); + throw new InvalidArgumentException('Unhandled query'); }); // Use same options & defaults for root option level and subquery options @@ -63,11 +71,8 @@ public function configureOptions(OptionsResolver $resolver) /** * Configure options about how to handle xpath query results. * Available at root and subquery level. - * - * @param OptionsResolver $resolver - * @param Options|null $parentOptions */ - public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null) + public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null): void { $resolver->setDefault('single_result', $parentOptions ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); @@ -79,22 +84,20 @@ public function configureQueryOptions(OptionsResolver $resolver, Options $parent $resolver->setAllowedTypes('unwrap_value', 'bool'); } - /** - * {@inheritDoc} - */ public function transform($value, array $options = []) { - if (!$value instanceof \DOMNode) { - throw new \UnexpectedValueException("Input should be a " . \DOMNode::class); + if (! $value instanceof DOMNode) { + throw new UnexpectedValueException('Input should be a ' . DOMNode::class); } $xpath = $this->buildXpath($value); $query = $options['query']; if (\is_array($query)) { - $result = \array_map(function ($subquery) use ($xpath, $value) { - return $this->query($xpath, $subquery['subquery'], $value, $subquery); - }, $query); + $result = \array_map( + fn ($subquery) => $this->query($xpath, $subquery['subquery'], $value, $subquery), + $query + ); } else { $result = $this->query($xpath, $query, $value, $options); } @@ -102,35 +105,22 @@ public function transform($value, array $options = []) return $result; } - /** - * {@inheritDoc} - */ - public function getCode() + public function getCode(): string { return 'xpath_evaluator'; } - /** - * @param \DOMNode $node - * - * @return \DOMXPath - */ - public function buildXpath(\DOMNode $node): \DOMXPath + public function buildXpath(DOMNode $node): DOMXPath { - $doc = $node instanceof \DOMDocument ? $node : $node->ownerDocument; + $doc = $node instanceof DOMDocument ? $node : $node->ownerDocument; - return new \DOMXPath($doc); + return new DOMXPath($doc); } /** - * @param \DOMXPath $xpath - * @param string $query - * @param \DOMNode $node - * @param array $options - * * @return mixed */ - public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $options) + public function query(DOMXPath $xpath, string $query, DOMNode $node, array $options) { // TODO check if query is relative ? $nodeList = $xpath->query($query, $node); @@ -138,39 +128,37 @@ public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $op // Convert results to text if ($options['unwrap_value']) { - $results = \array_map(function (\DOMNode $item) use ($query) { - if ($item instanceof \DOMAttr) { + $results = \array_map(function (DOMNode $item) use ($query): string { + if ($item instanceof DOMAttr) { return $item->value; } - if ($item instanceof \DOMText) { + if ($item instanceof DOMText) { // If you have an error, remember that you may need to use the "text()" xpath selector return $item->textContent; } - throw new \UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); + throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); }, $results); } // Unwrap the node list if ($options['single_result']) { if (count($results) > 1) { - throw new \UnexpectedValueException("There is too much results for query '{$query}'"); + throw new UnexpectedValueException("There is too much results for query '{$query}'"); } - if (count($results) === 0 && !$options['ignore_missing']) { - throw new \UnexpectedValueException("There is not enough results for query '{$query}'"); + if (count($results) === 0 && ! $options['ignore_missing']) { + throw new UnexpectedValueException("There is not enough results for query '{$query}'"); } - if(count($results) === 1) { + if (count($results) === 1) { $results = $results[0]; } else { $results = null; } - } return $results; } - } diff --git a/Validator/ConstraintLoader.php b/Validator/ConstraintLoader.php index 2aa21432..eae41577 100644 --- a/Validator/ConstraintLoader.php +++ b/Validator/ConstraintLoader.php @@ -1,4 +1,7 @@ - $childNodes) { - if (is_numeric($name) && \is_array($childNodes) && 1 === \count($childNodes)) { + if (is_numeric($name) && \is_array($childNodes) && \count($childNodes) === 1) { $options = current($childNodes); if (\is_array($options)) { diff --git a/ecs.php b/ecs.php index 4bc43fd2..5aa539a9 100644 --- a/ecs.php +++ b/ecs.php @@ -18,12 +18,7 @@ SetList::DOCTRINE_ANNOTATIONS, ]); - $ecsConfig->paths([ - __DIR__, - ]); + $ecsConfig->paths([__DIR__]); - $ecsConfig->skip([ - __DIR__ . 'vendor', - AssignmentInConditionSniff::class - ]); + $ecsConfig->skip([__DIR__ . 'vendor', AssignmentInConditionSniff::class]); }; diff --git a/phpstan.neon b/phpstan.neon index d6056437..69897602 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,6 +3,7 @@ parameters: paths: - . excludePaths: + - ecs.php - vendor/* - Resources/tests/* - Tests/* diff --git a/rector.php b/rector.php index 1738573e..4f9c066c 100644 --- a/rector.php +++ b/rector.php @@ -6,25 +6,21 @@ use Rector\Core\ValueObject\PhpVersion; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; +use Rector\Symfony\Set\SymfonyLevelSetList; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->parallel(); $rectorConfig->importNames(); $rectorConfig->importShortClasses(); - $rectorConfig->paths([ - __DIR__, - ]); + $rectorConfig->paths([__DIR__]); - $rectorConfig->skip([ - __DIR__ . '/vendor' - ]); + $rectorConfig->skip([__DIR__ . '/vendor']); $rectorConfig->sets([ SetList::TYPE_DECLARATION, LevelSetList::UP_TO_PHP_81, - //SymfonyLevelSetList::UP_TO_SYMFONY_54 + SymfonyLevelSetList::UP_TO_SYMFONY_54, ]); $rectorConfig->phpVersion(PhpVersion::PHP_81); From d1af293d71f90db44e884bde9aa989e7a9077fd5 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 15:21:00 +0100 Subject: [PATCH 163/304] phpstan --- Command/ExecuteProcessCommand.php | 2 +- Command/ProcessHelpCommand.php | 34 +++++------------ Context/ContextualOptionResolver.php | 2 +- .../CleverAgeProcessExtension.php | 2 +- DependencyInjection/Configuration.php | 17 ++++----- Exception/TransformerException.php | 14 ++----- Filesystem/XmlFile.php | 4 +- Manager/ProcessManager.php | 4 +- Model/AbstractConfigurableTask.php | 17 ++------- Model/BlockingTaskInterface.php | 2 +- Model/FinalizableTaskInterface.php | 2 +- Model/FlushableTaskInterface.php | 2 +- Model/InitializableTaskInterface.php | 2 +- Model/ProcessHistory.php | 21 +++-------- Model/TaskInterface.php | 2 +- Registry/TransformerRegistry.php | 18 +++------ Task/AbstractIterableOutputTask.php | 12 ++---- Task/ArrayMergeTask.php | 10 +---- Task/ColumnAggregatorTask.php | 20 ++++------ Task/File/Csv/AbstractCsvResourceTask.php | 7 +--- Task/File/Csv/AbstractCsvTask.php | 2 +- Task/File/Csv/CsvSplitterTask.php | 11 +----- Task/File/Csv/CsvWriterTask.php | 37 ++++++------------- Task/File/Csv/InputCsvReaderTask.php | 7 +--- Task/File/FileFetchTask.php | 21 +++++------ Task/File/FileMoverTask.php | 9 +---- Task/File/FolderBrowserTask.php | 4 +- Task/File/JsonStream/JsonStreamReaderTask.php | 9 ++--- Task/File/Xml/XmlWriterTask.php | 2 +- Task/InputAggregatorTask.php | 7 +--- Task/Process/ProcessLauncherTask.php | 17 +++------ Task/Reporting/AdvancedStatCounterTask.php | 20 ++-------- Task/RowAggregatorTask.php | 2 +- Task/Serialization/NormalizerTask.php | 2 +- Task/Validation/ValidatorTask.php | 2 +- Transformer/ArrayMapTransformer.php | 5 +-- Transformer/CachedTransformer.php | 2 +- Transformer/ConditionTrait.php | 11 ++---- Transformer/DateFormatTransformer.php | 21 +---------- Transformer/MappingTransformer.php | 12 ++---- Transformer/RulesTransformer.php | 4 +- Transformer/TransformerTrait.php | 16 +++----- phpstan.neon | 16 +++++++- 43 files changed, 142 insertions(+), 291 deletions(-) diff --git a/Command/ExecuteProcessCommand.php b/Command/ExecuteProcessCommand.php index dfc23204..25a29ed7 100644 --- a/Command/ExecuteProcessCommand.php +++ b/Command/ExecuteProcessCommand.php @@ -124,7 +124,7 @@ protected function parseContextValues(InputInterface $input): array return $context; } - protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output) + protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output): void { // Skip all if undefined if (! $input->getOption('output-format')) { diff --git a/Command/ProcessHelpCommand.php b/Command/ProcessHelpCommand.php index 5634af13..8fc33eac 100644 --- a/Command/ProcessHelpCommand.php +++ b/Command/ProcessHelpCommand.php @@ -179,9 +179,7 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ } if (! empty($task->getPreviousTasksConfigurations())) { - $weight /= is_countable($task->getPreviousTasksConfigurations()) ? \count( - $task->getPreviousTasksConfigurations() - ) : 0; + $weight /= \count($task->getPreviousTasksConfigurations()); } $taskWeights[$taskCandidate] = $weight; @@ -230,16 +228,13 @@ protected function getTaskChildrenCount(TaskConfiguration $task) /** * Merge needed branches, display a task node, split following needed branches - * - * @param array $branches - * @param string $taskCode */ protected function resolveBranchOutput( - &$branches, - $taskCode, + array &$branches, + string $taskCode, ProcessConfiguration $process, OutputInterface $output - ) { + ): void { $task = $process->getTaskConfiguration($taskCode); $branchesToMerge = []; $gapBranches = []; @@ -453,18 +448,13 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) $this->writeBranches($output, $branches); } - /** - * @param array $branches - * @param string $comment - * @param callable $match - */ protected function writeBranches( OutputInterface $output, - $branches, + array $branches, string|iterable $comment = '', - $match = null, + ?callable $match = null, string|callable $char = null - ) { + ): void { $output->write(str_repeat(' ', self::INDENT_SIZE)); // Merge lines @@ -492,10 +482,7 @@ protected function writeBranches( $output->writeln($comment); } - /** - * @return string - */ - protected function getTaskDescription(TaskConfiguration $task) + protected function getTaskDescription(TaskConfiguration $task): string { $description = $task->getCode(); $interfaces = []; @@ -533,10 +520,7 @@ protected function getTaskDescription(TaskConfiguration $task) return $description; } - /** - * @return mixed - */ - protected function getTaskService(TaskConfiguration $taskConfiguration) + protected function getTaskService(TaskConfiguration $taskConfiguration): mixed { // Duplicate code from \CleverAge\ProcessBundle\Manager\ProcessManager::initialize // @todo Refactor this using a Registry with this feature: diff --git a/Context/ContextualOptionResolver.php b/Context/ContextualOptionResolver.php index 59939011..0e96a040 100644 --- a/Context/ContextualOptionResolver.php +++ b/Context/ContextualOptionResolver.php @@ -21,7 +21,7 @@ class ContextualOptionResolver * * @return mixed */ - public function contextualizeOption(string|array $value, array $context) + public function contextualizeOption(mixed $value, array $context) { // Recursively parse options if (\is_array($value)) { diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/DependencyInjection/CleverAgeProcessExtension.php index d4c4d8e8..4dd6409a 100644 --- a/DependencyInjection/CleverAgeProcessExtension.php +++ b/DependencyInjection/CleverAgeProcessExtension.php @@ -59,7 +59,7 @@ public function load(array $configs, ContainerBuilder $container): void /** * Recursively import config files into container */ - protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yml') + protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yml'): void { $finder = new Finder(); $finder->in($path) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index eda04bd7..47c0f109 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -28,11 +28,8 @@ */ class Configuration implements ConfigurationInterface { - /** - * @param string $root - */ public function __construct( - protected $root = 'clever_age_process' + protected string $root = 'clever_age_process' ) { } @@ -54,7 +51,7 @@ public function getConfigTreeBuilder() /** * "generic_transformers" root configuration */ - protected function appendRootTransformersConfigDefinition(NodeBuilder $definition) + protected function appendRootTransformersConfigDefinition(NodeBuilder $definition): void { /** @var ArrayNodeDefinition $transformersArrayDefinition */ $transformersArrayDefinition = $definition->arrayNode('generic_transformers') @@ -74,7 +71,7 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio /** * Single transformer configuration */ - protected function appendTransformerConfigDefinition(NodeBuilder $definition) + protected function appendTransformerConfigDefinition(NodeBuilder $definition): void { $definition ->arrayNode('contextual_options') @@ -91,7 +88,7 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition) * "configurations" root configuration * @TODO rename this root as "processes" */ - protected function appendRootProcessConfigDefinition(NodeBuilder $definition) + protected function appendRootProcessConfigDefinition(NodeBuilder $definition): void { /** @var ArrayNodeDefinition $configurationsArrayDefinition */ $configurationsArrayDefinition = $definition->arrayNode('configurations') @@ -108,7 +105,7 @@ protected function appendRootProcessConfigDefinition(NodeBuilder $definition) $this->appendProcessConfigDefinition($processListDefinition); } - protected function appendProcessConfigDefinition(NodeBuilder $definition) + protected function appendProcessConfigDefinition(NodeBuilder $definition): void { $definition ->scalarNode('entry_point') @@ -147,7 +144,7 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition) $this->appendTaskConfigDefinition($taskListDefinition); } - protected function appendTaskConfigDefinition(NodeBuilder $definition) + protected function appendTaskConfigDefinition(NodeBuilder $definition): void { $logLevels = [ LogLevel::EMERGENCY, @@ -199,7 +196,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition) * * @TODO remove this once support for Symfony 3 and 4 is dropped */ - protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message) + protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message): void { $node->setDeprecated($package, $version, $message); } diff --git a/Exception/TransformerException.php b/Exception/TransformerException.php index 68f95fb3..6334ca0f 100644 --- a/Exception/TransformerException.php +++ b/Exception/TransformerException.php @@ -21,17 +21,11 @@ */ class TransformerException extends RuntimeException implements ProcessExceptionInterface { - /** - * @var string - */ - protected $targetProperty; + protected string $targetProperty; - /** - * @param string $transformerCode - */ public function __construct( - protected $transformerCode, - $code = 0, + protected string $transformerCode, + int $code = 0, Throwable $previous = null ) { parent::__construct('', $code, $previous); @@ -44,7 +38,7 @@ public function setTargetProperty(string $targetProperty): void $this->updateMessage(); } - protected function updateMessage() + protected function updateMessage(): void { if (isset($this->targetProperty)) { $m = sprintf( diff --git a/Filesystem/XmlFile.php b/Filesystem/XmlFile.php index adf1e407..05a8ffb0 100644 --- a/Filesystem/XmlFile.php +++ b/Filesystem/XmlFile.php @@ -41,12 +41,12 @@ public function read(): DOMDocument return $dom; } - public function write(DOMDocument $dom) + public function write(DOMDocument $dom): void { $content = $dom->saveXML(); $result = $this->file->fwrite($content); - if ($result === null) { + if ($result === false) { throw new RuntimeException('Could not write content to file'); } } diff --git a/Manager/ProcessManager.php b/Manager/ProcessManager.php index c9680ff6..4adb3b9d 100644 --- a/Manager/ProcessManager.php +++ b/Manager/ProcessManager.php @@ -229,9 +229,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = $taskConfiguration; if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP - && (is_countable($taskConfiguration->getErrorOutputs()) ? \count( - $taskConfiguration->getErrorOutputs() - ) : 0) > 0) { + && (\count($taskConfiguration->getErrorOutputs())) > 0) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); diff --git a/Model/AbstractConfigurableTask.php b/Model/AbstractConfigurableTask.php index 140317a4..6a7a938f 100644 --- a/Model/AbstractConfigurableTask.php +++ b/Model/AbstractConfigurableTask.php @@ -21,10 +21,7 @@ */ abstract class AbstractConfigurableTask implements InitializableTaskInterface { - /** - * @var array - */ - protected $options; + protected ?array $options; /** * Only validate the options at initialization, ensuring that the task will not fail at runtime @@ -34,10 +31,7 @@ public function initialize(ProcessState $state): void $this->getOptions($state); } - /** - * @return array - */ - protected function getOptions(ProcessState $state) + protected function getOptions(ProcessState $state): ?array { if ($this->options === null) { $resolver = new OptionsResolver(); @@ -48,12 +42,7 @@ protected function getOptions(ProcessState $state) return $this->options; } - /** - * @param string $code - * - * @return mixed - */ - protected function getOption(ProcessState $state, $code) + protected function getOption(ProcessState $state, string $code): mixed { $options = $this->getOptions($state); if (! array_key_exists($code, $options)) { diff --git a/Model/BlockingTaskInterface.php b/Model/BlockingTaskInterface.php index 0c7ea685..c4124a70 100644 --- a/Model/BlockingTaskInterface.php +++ b/Model/BlockingTaskInterface.php @@ -18,5 +18,5 @@ */ interface BlockingTaskInterface extends TaskInterface { - public function proceed(ProcessState $state); + public function proceed(ProcessState $state): void; } diff --git a/Model/FinalizableTaskInterface.php b/Model/FinalizableTaskInterface.php index f109f1bf..8f47e907 100644 --- a/Model/FinalizableTaskInterface.php +++ b/Model/FinalizableTaskInterface.php @@ -18,5 +18,5 @@ */ interface FinalizableTaskInterface extends TaskInterface { - public function finalize(ProcessState $state); + public function finalize(ProcessState $state): void; } diff --git a/Model/FlushableTaskInterface.php b/Model/FlushableTaskInterface.php index d222f75d..cc4c9d60 100644 --- a/Model/FlushableTaskInterface.php +++ b/Model/FlushableTaskInterface.php @@ -18,5 +18,5 @@ */ interface FlushableTaskInterface extends TaskInterface { - public function flush(ProcessState $state); + public function flush(ProcessState $state): void; } diff --git a/Model/InitializableTaskInterface.php b/Model/InitializableTaskInterface.php index 8f0f0dbc..98212464 100644 --- a/Model/InitializableTaskInterface.php +++ b/Model/InitializableTaskInterface.php @@ -18,5 +18,5 @@ */ interface InitializableTaskInterface extends TaskInterface { - public function initialize(ProcessState $state); + public function initialize(ProcessState $state): void; } diff --git a/Model/ProcessHistory.php b/Model/ProcessHistory.php index 0e444d30..d4f52bf1 100644 --- a/Model/ProcessHistory.php +++ b/Model/ProcessHistory.php @@ -32,17 +32,11 @@ class ProcessHistory implements Stringable protected string $processCode; - protected DateTime $startDate; + protected ?DateTime $startDate; - /** - * @var DateTime - */ - protected $endDate; + protected ?DateTime $endDate = null; - /** - * @var string - */ - protected $state = self::STATE_STARTED; + protected string $state = self::STATE_STARTED; public function __construct( ProcessConfiguration $processConfiguration, @@ -82,10 +76,7 @@ public function getStartDate(): DateTime return $this->startDate; } - /** - * @return DateTime - */ - public function getEndDate() + public function getEndDate(): ?DateTime { return $this->endDate; } @@ -128,10 +119,8 @@ public function isFailed(): bool /** * Get process duration in seconds - * - * @return int|null */ - public function getDuration() + public function getDuration(): ?int { if ($this->getEndDate()) { return $this->getEndDate() diff --git a/Model/TaskInterface.php b/Model/TaskInterface.php index 9b95bd9a..3f3d327c 100644 --- a/Model/TaskInterface.php +++ b/Model/TaskInterface.php @@ -21,5 +21,5 @@ */ interface TaskInterface { - public function execute(ProcessState $state); + public function execute(ProcessState $state): void; } diff --git a/Registry/TransformerRegistry.php b/Registry/TransformerRegistry.php index 367ef488..c67ab73e 100644 --- a/Registry/TransformerRegistry.php +++ b/Registry/TransformerRegistry.php @@ -25,9 +25,9 @@ class TransformerRegistry /** * @var TransformerInterface[] */ - protected $transformers = []; + protected array $transformers = []; - public function addTransformer(TransformerInterface $transformer) + public function addTransformer(TransformerInterface $transformer): void { if (array_key_exists($transformer->getCode(), $this->transformers)) { throw new UnexpectedValueException("Transformer {$transformer->getCode()} is already defined"); @@ -38,17 +38,12 @@ public function addTransformer(TransformerInterface $transformer) /** * @return TransformerInterface[] */ - public function getTransformers() + public function getTransformers(): array { return $this->transformers; } - /** - * @param string $code - * - * @return TransformerInterface - */ - public function getTransformer($code) + public function getTransformer(string $code): TransformerInterface { if (! $this->hasTransformer($code)) { throw MissingTransformerException::create($code); @@ -57,10 +52,7 @@ public function getTransformer($code) return $this->transformers[$code]; } - /** - * @param string $code - */ - public function hasTransformer($code): bool + public function hasTransformer(string $code): bool { return array_key_exists($code, $this->transformers); } diff --git a/Task/AbstractIterableOutputTask.php b/Task/AbstractIterableOutputTask.php index 98f570a8..46916c1a 100644 --- a/Task/AbstractIterableOutputTask.php +++ b/Task/AbstractIterableOutputTask.php @@ -25,10 +25,7 @@ */ abstract class AbstractIterableOutputTask extends AbstractConfigurableTask implements IterableTaskInterface { - /** - * @var Iterator - */ - protected $iterator; + protected ?Iterator $iterator = null; public function execute(ProcessState $state): void { @@ -48,10 +45,8 @@ public function execute(ProcessState $state): void * Moves the internal pointer to the next element, * return true if the task has a next element * return false if the task has terminated it's iteration - * - * @return bool */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { if (! $this->iterator) { return false; @@ -73,7 +68,7 @@ public function next(ProcessState $state) /** * Create or recreate an iterator from input */ - protected function handleIteratorFromInput(ProcessState $state) + protected function handleIteratorFromInput(ProcessState $state): void { if ($this->iterator instanceof Iterator) { if ($this->iterator->valid()) { @@ -84,6 +79,7 @@ protected function handleIteratorFromInput(ProcessState $state) } // This should never be reached + /** @phpstan-ignore-next-line */ if ($this->iterator !== null) { throw new UnexpectedValueException( "At this point iterator should have been null, maybe it's a wrong type..." diff --git a/Task/ArrayMergeTask.php b/Task/ArrayMergeTask.php index 86e96226..565cb01d 100644 --- a/Task/ArrayMergeTask.php +++ b/Task/ArrayMergeTask.php @@ -25,17 +25,11 @@ */ class ArrayMergeTask extends AbstractConfigurableTask implements BlockingTaskInterface { - /** - * @var array - */ protected const MERGE_FUNC = ['array_merge', 'array_merge_recursive', 'array_replace', 'array_replace_recursive']; - /** - * @var array - */ - protected $mergedOutput = []; + protected array $mergedOutput = []; - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); if (! \is_array($input)) { diff --git a/Task/ColumnAggregatorTask.php b/Task/ColumnAggregatorTask.php index 46b4701f..f098d8ac 100644 --- a/Task/ColumnAggregatorTask.php +++ b/Task/ColumnAggregatorTask.php @@ -29,10 +29,7 @@ class ColumnAggregatorTask extends AbstractConfigurableTask implements BlockingT { use ConditionTrait; - /** - * @var array - */ - protected $result = []; + protected array $result = []; public function __construct( PropertyAccessorInterface $accessor, @@ -41,7 +38,7 @@ public function __construct( $this->accessor = $accessor; } - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); $columns = $this->getOption($state, 'columns'); @@ -84,13 +81,12 @@ public function proceed(ProcessState $state): void $state->setOutput($this->result); } - /** - * @param string $column - * @param string $referenceKey - * @param string $aggregationKey - */ - protected function addValueToAggregationGroup($column, mixed $input, $referenceKey, $aggregationKey) - { + protected function addValueToAggregationGroup( + mixed $column, + mixed $input, + string $referenceKey, + string $aggregationKey + ): void { if (! isset($this->result[$column])) { $this->result[$column] = [ $referenceKey => $column, diff --git a/Task/File/Csv/AbstractCsvResourceTask.php b/Task/File/Csv/AbstractCsvResourceTask.php index e68f1520..868720b8 100644 --- a/Task/File/Csv/AbstractCsvResourceTask.php +++ b/Task/File/Csv/AbstractCsvResourceTask.php @@ -24,10 +24,7 @@ */ abstract class AbstractCsvResourceTask extends AbstractConfigurableTask implements FinalizableTaskInterface { - /** - * @var CsvResource - */ - protected $csv; + protected ?CsvResource $csv = null; public function finalize(ProcessState $state): void { @@ -36,7 +33,7 @@ public function finalize(ProcessState $state): void } } - protected function initFile(ProcessState $state) + protected function initFile(ProcessState $state): void { if ($this->csv) { return; diff --git a/Task/File/Csv/AbstractCsvTask.php b/Task/File/Csv/AbstractCsvTask.php index 3e2ab668..1c5263d1 100644 --- a/Task/File/Csv/AbstractCsvTask.php +++ b/Task/File/Csv/AbstractCsvTask.php @@ -23,7 +23,7 @@ */ abstract class AbstractCsvTask extends AbstractCsvResourceTask { - protected function initFile(ProcessState $state) + protected function initFile(ProcessState $state): void { if ($this->csv) { return; diff --git a/Task/File/Csv/CsvSplitterTask.php b/Task/File/Csv/CsvSplitterTask.php index 97b97196..8f02b20c 100644 --- a/Task/File/Csv/CsvSplitterTask.php +++ b/Task/File/Csv/CsvSplitterTask.php @@ -49,10 +49,8 @@ public function execute(ProcessState $state): void * Moves the internal pointer to the next element, * return true if the task has a next element * return false if the task has terminated it's iteration - * - * @return bool */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { if (! $this->csv instanceof CsvResource) { return false; @@ -75,12 +73,7 @@ public function finalize(ProcessState $state): void } } - /** - * @param int $maxLines - * - * @return string - */ - protected function splitCsv(CsvFile $csv, $maxLines) + protected function splitCsv(CsvFile $csv, int $maxLines): string { $tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php_' . uniqid('process', false) . '.csv'; $tmpFile = fopen($tmpFilePath, 'wb+'); diff --git a/Task/File/Csv/CsvWriterTask.php b/Task/File/Csv/CsvWriterTask.php index dfe40dd9..bf61ec82 100644 --- a/Task/File/Csv/CsvWriterTask.php +++ b/Task/File/Csv/CsvWriterTask.php @@ -41,9 +41,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if ($this->csv) { - $state->setOutput($this->csv->getFilePath()); - } + $state->setOutput($this->csv->getFilePath()); } protected function configureOptions(OptionsResolver $resolver) @@ -57,25 +55,18 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer( 'file_path', - static function (Options $options, $value): string { - $value = strtr( - $value, - [ - '{date}' => date('Ymd'), - '{date_time}' => date('Ymd_His'), - '{unique_token}' => uniqid(), - ] - ); - - return $value; - } + static fn (Options $options, $value): string => strtr( + $value, + [ + '{date}' => date('Ymd'), + '{date_time}' => date('Ymd_His'), + '{unique_token}' => uniqid('', true), + ] + ) ); } - /** - * @return array - */ - protected function getInput(ProcessState $state) + protected function getInput(ProcessState $state): array { $input = $state->getInput(); if (! \is_array($input)) { @@ -83,8 +74,7 @@ protected function getInput(ProcessState $state) } $splitCharacter = $this->getOption($state, 'split_character'); - /** @var array $input */ - foreach ($input as $key => &$item) { + foreach ($input as &$item) { if (\is_array($item)) { $item = implode($splitCharacter, $item); } @@ -93,10 +83,7 @@ protected function getInput(ProcessState $state) return $input; } - /** - * @return array - */ - protected function getHeaders(ProcessState $state, array $options) + protected function getHeaders(ProcessState $state, array $options): array { $headers = $options['headers']; if ($headers === null) { diff --git a/Task/File/Csv/InputCsvReaderTask.php b/Task/File/Csv/InputCsvReaderTask.php index 99849a35..09b720c8 100644 --- a/Task/File/Csv/InputCsvReaderTask.php +++ b/Task/File/Csv/InputCsvReaderTask.php @@ -21,12 +21,7 @@ */ class InputCsvReaderTask extends CsvReaderTask { - /** - * @TODO refactor to get file path outside of options - * - * @return array - */ - protected function getOptions(ProcessState $state) + protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); if ($state->getInput() !== null) { diff --git a/Task/File/FileFetchTask.php b/Task/File/FileFetchTask.php index 7026286e..2fca55d7 100644 --- a/Task/File/FileFetchTask.php +++ b/Task/File/FileFetchTask.php @@ -17,6 +17,7 @@ use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; use League\Flysystem\Filesystem; +use League\Flysystem\FilesystemException; use League\Flysystem\MountManager; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -53,8 +54,8 @@ public function initialize(ProcessState $state): void // Configure options parent::initialize($state); - $this->sourceFS = $this->mountManager->get($this->getOption($state, 'source_filesystem')); - $this->destinationFS = $this->mountManager->getFilesystem($this->getOption($state, 'destination_filesystem')); + $this->sourceFS = new Filesystem($this->getOption($state, 'source_filesystem')); + $this->destinationFS = new Filesystem($this->getOption($state, 'destination_filesystem')); } public function execute(ProcessState $state): void @@ -113,24 +114,22 @@ protected function findMatchingFiles(ProcessState $state): void protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null { $prefixFrom = $this->getOption($state, 'source_filesystem'); - $prefixTo = $this->getOption($state, 'destination_filesystem'); - $buffer = $this->mountManager->getFilesystem($prefixFrom) - ->readStream($filename); + $buffer = $this->sourceFS->readStream($filename); - if ($buffer === false) { - return false; + try { + $this->destinationFS->writeStream($filename, $buffer); + $result = true; + } catch (FilesystemException) { + $result = false; } - $result = $this->mountManager->getFilesystem($prefixTo) - ->putStream($filename, $buffer); - if (is_resource($buffer)) { fclose($buffer); } if ($removeSource) { - $this->mountManager->delete(sprintf('%s://%s', $prefixFrom, $filename)); + $this->sourceFS->delete(sprintf('%s://%s', $prefixFrom, $filename)); } return $result ? $filename : null; diff --git a/Task/File/FileMoverTask.php b/Task/File/FileMoverTask.php index 6365acb1..69d67109 100644 --- a/Task/File/FileMoverTask.php +++ b/Task/File/FileMoverTask.php @@ -24,7 +24,7 @@ */ class FileMoverTask extends AbstractConfigurableTask { - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $fs = new Filesystem(); @@ -55,12 +55,7 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('autoincrement', ['boolean']); } - /** - * @param string $dest - * - * @return string - */ - protected function makeFilenameUnique($dest) + protected function makeFilenameUnique(string $dest): string { $fs = new Filesystem(); $i = 1; diff --git a/Task/File/FolderBrowserTask.php b/Task/File/FolderBrowserTask.php index e918cade..63a4f31b 100644 --- a/Task/File/FolderBrowserTask.php +++ b/Task/File/FolderBrowserTask.php @@ -31,9 +31,9 @@ class FolderBrowserTask extends AbstractConfigurableTask implements IterableTaskInterface { /** - * @var Iterator|SplFileInfo[] + * @var Iterator|SplFileInfo[]|null */ - protected $files; + protected Iterator|array|null $files = null; public function __construct( protected LoggerInterface $logger diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/Task/File/JsonStream/JsonStreamReaderTask.php index 0447fafc..a799cf0f 100644 --- a/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/Task/File/JsonStream/JsonStreamReaderTask.php @@ -19,10 +19,7 @@ class JsonStreamReaderTask implements IterableTaskInterface { - /** - * @var JsonStreamFile - */ - protected $file; + protected ?JsonStreamFile $file = null; public function execute(ProcessState $state): void { @@ -38,7 +35,7 @@ public function execute(ProcessState $state): void } } - public function next(ProcessState $state) + public function next(ProcessState $state): bool { $eof = $this->file->isEndOfFile(); if ($eof) { @@ -48,7 +45,7 @@ public function next(ProcessState $state) return ! $eof; } - protected function getFilePath(ProcessState $state) + protected function getFilePath(ProcessState $state): string { return $state->getInput(); } diff --git a/Task/File/Xml/XmlWriterTask.php b/Task/File/Xml/XmlWriterTask.php index 4d1892de..6325227c 100644 --- a/Task/File/Xml/XmlWriterTask.php +++ b/Task/File/Xml/XmlWriterTask.php @@ -31,7 +31,7 @@ public function __construct( ) { } - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); if (! $input instanceof DOMDocument) { diff --git a/Task/InputAggregatorTask.php b/Task/InputAggregatorTask.php index 079d3059..c6e2611b 100644 --- a/Task/InputAggregatorTask.php +++ b/Task/InputAggregatorTask.php @@ -28,16 +28,13 @@ */ class InputAggregatorTask extends AbstractConfigurableTask { - /** - * @var array - */ - protected $inputs = []; + protected array $inputs = []; /** * Store inputs and once everything has been received, pass to next task * Once an output has been generated this task is reset, and may wait for another loop */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $previousState = $state->getPreviousState(); if (! $previousState || ! $previousState->getTaskConfiguration()) { diff --git a/Task/Process/ProcessLauncherTask.php b/Task/Process/ProcessLauncherTask.php index cb809c6e..e7f4ea64 100644 --- a/Task/Process/ProcessLauncherTask.php +++ b/Task/Process/ProcessLauncherTask.php @@ -65,6 +65,7 @@ public function execute(ProcessState $state): void $state->setOutput($this->finishedBuffers->dequeue()); // After dequeue, stop flush + /** @phpstan-ignore-next-line */ if ($this->finishedBuffers->isEmpty()) { $this->flushMode = false; } @@ -88,10 +89,7 @@ public function flush(ProcessState $state): void } } - /** - * @return bool - */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { $this->handleProcesses($state); @@ -112,7 +110,7 @@ public function next(ProcessState $state) return false; } - protected function handleInput(ProcessState $state) + protected function handleInput(ProcessState $state): void { $options = $this->getOptions($state); while (\count($this->launchedProcesses) >= $options['max_processes']) { @@ -133,10 +131,7 @@ protected function handleInput(ProcessState $state) usleep($options['sleep_interval_after_launch']); } - /** - * @return SubprocessInstance - */ - protected function launchProcess(ProcessState $state) + protected function launchProcess(ProcessState $state): SubprocessInstance { $input = $state->getInput() !== null ? (string) $state->getInput() : null; @@ -154,7 +149,7 @@ protected function launchProcess(ProcessState $state) ->start(); } - protected function handleProcesses(ProcessState $state) + protected function handleProcesses(ProcessState $state): void { foreach ($this->launchedProcesses as $key => $process) { if (! $process->getProcess()->isTerminated()) { @@ -246,7 +241,7 @@ static function (Options $options, $value): int|float|string|bool|null { /** * Kill all running processes */ - protected function killProcesses() + protected function killProcesses(): void { foreach ($this->launchedProcesses as $process) { $process->stop(5); diff --git a/Task/Reporting/AdvancedStatCounterTask.php b/Task/Reporting/AdvancedStatCounterTask.php index 52d4a73b..988cfd40 100644 --- a/Task/Reporting/AdvancedStatCounterTask.php +++ b/Task/Reporting/AdvancedStatCounterTask.php @@ -24,25 +24,13 @@ */ class AdvancedStatCounterTask extends AbstractConfigurableTask { - /** - * @var DateTime - */ - protected $startedAt; + protected ?DateTime $startedAt = null; - /** - * @var DateTime - */ - protected $lastUpdate; + protected ?DateTime $lastUpdate = null; - /** - * @var int - */ - protected $counter = 0; + protected int $counter = 0; - /** - * @var int - */ - protected $preInitCounter = 0; + protected int $preInitCounter = 0; public function __construct( protected LoggerInterface $logger diff --git a/Task/RowAggregatorTask.php b/Task/RowAggregatorTask.php index a697ec34..c392a525 100644 --- a/Task/RowAggregatorTask.php +++ b/Task/RowAggregatorTask.php @@ -42,7 +42,7 @@ public function __construct( * Store inputs and once everything has been received, pass to next task * Once an output has been generated this task is reset, and may wait for another loop */ - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $input = $state->getInput(); diff --git a/Task/Serialization/NormalizerTask.php b/Task/Serialization/NormalizerTask.php index 438b57ca..86f9048c 100644 --- a/Task/Serialization/NormalizerTask.php +++ b/Task/Serialization/NormalizerTask.php @@ -29,7 +29,7 @@ public function __construct( ) { } - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); diff --git a/Task/Validation/ValidatorTask.php b/Task/Validation/ValidatorTask.php index bd259716..0fa7a3e6 100644 --- a/Task/Validation/ValidatorTask.php +++ b/Task/Validation/ValidatorTask.php @@ -35,7 +35,7 @@ public function __construct( ) { } - public function execute(ProcessState $state) + public function execute(ProcessState $state): void { $options = $this->getOptions($state); $violations = $this->validator->validate($state->getInput(), $options['constraints'], $options['groups']); diff --git a/Transformer/ArrayMapTransformer.php b/Transformer/ArrayMapTransformer.php index edd654ec..b0a0ddc5 100644 --- a/Transformer/ArrayMapTransformer.php +++ b/Transformer/ArrayMapTransformer.php @@ -34,9 +34,7 @@ public function __construct(TransformerRegistry $transformerRegistry) /** * Must return the transformed $value * - * @param array $values - * - * @return mixed[] $value + * @param mixed $values */ public function transform($values, array $options = []): array { @@ -45,7 +43,6 @@ public function transform($values, array $options = []): array } $results = []; - /** @noinspection ForeachSourceInspection */ foreach ($values as $key => $item) { try { $item = $this->applyTransformers($options['transformers'], $item); diff --git a/Transformer/CachedTransformer.php b/Transformer/CachedTransformer.php index 9413b352..27dae3a7 100644 --- a/Transformer/CachedTransformer.php +++ b/Transformer/CachedTransformer.php @@ -104,7 +104,7 @@ public function getCode(): string return 'cached'; } - protected function generateCacheKey($cacheKeyRoot, $value, $options): bool|string + protected function generateCacheKey(string $cacheKeyRoot, string $value, array $options): bool|string { $value = $this->applyTransformers($options['key_transformers'], $value); diff --git a/Transformer/ConditionTrait.php b/Transformer/ConditionTrait.php index af349069..ff6ab11d 100644 --- a/Transformer/ConditionTrait.php +++ b/Transformer/ConditionTrait.php @@ -21,10 +21,7 @@ */ trait ConditionTrait { - /** - * @var PropertyAccessorInterface - */ - protected $accessor; + protected ?PropertyAccessorInterface $accessor = null; /** * Test the input with the given set of conditions @@ -76,7 +73,7 @@ protected function checkCondition(mixed $input, $conditions): bool /** * Configure available condition rules in a wrapper option */ - protected function configureWrappedConditionOptions(string $wrapperKey, OptionsResolver $resolver) + protected function configureWrappedConditionOptions(string $wrapperKey, OptionsResolver $resolver): void { $resolver->setDefault($wrapperKey, []); $resolver->setAllowedTypes($wrapperKey, ['array']); @@ -94,7 +91,7 @@ function (OptionsResolver $options, $value): array { /** * Configure available condition rules */ - protected function configureConditionOptions(OptionsResolver $resolver) + protected function configureConditionOptions(OptionsResolver $resolver): void { $resolver->setDefault('not_match', []); $resolver->setDefault('match', []); @@ -166,7 +163,7 @@ protected function checkEmpty($input, $key): bool * * @return mixed|null */ - protected function getValue($input, $key) + protected function getValue($input, $key): mixed { if ($key === '') { $currentValue = $input; diff --git a/Transformer/DateFormatTransformer.php b/Transformer/DateFormatTransformer.php index 312dcf73..7e44148f 100644 --- a/Transformer/DateFormatTransformer.php +++ b/Transformer/DateFormatTransformer.php @@ -13,7 +13,6 @@ namespace CleverAge\ProcessBundle\Transformer; -use DateTime; use DateTimeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; @@ -26,18 +25,13 @@ * transformers: * date_format: * format: Y-m-d - * - * @TODO deprecated v4.0 : remove string input - * @TODO deprecated v4.0 : no false output */ class DateFormatTransformer implements ConfigurableTransformerInterface { /** * @param mixed $value - * - * @return mixed|string */ - public function transform($value, array $options = []) + public function transform($value, array $options = []): mixed { if (! $value) { return $value; @@ -45,22 +39,11 @@ public function transform($value, array $options = []) if ($value instanceof DateTimeInterface) { $date = $value; - } elseif (is_string($value)) { - @trigger_error('String input will be deprecated in v4.0', E_USER_DEPRECATED); - $date = new DateTime($value); } else { throw new UnexpectedValueException('Given value cannot be parsed into a date'); } - $result = $date->format($options['format']); - if ($result === false) { - @trigger_error( - 'The date cannot be formatted, this will throw an error starting from v4.0', - E_USER_DEPRECATED - ); - } - - return $result; + return $date->format($options['format']); } public function getCode(): string diff --git a/Transformer/MappingTransformer.php b/Transformer/MappingTransformer.php index 653f684b..65e44d6c 100644 --- a/Transformer/MappingTransformer.php +++ b/Transformer/MappingTransformer.php @@ -43,10 +43,8 @@ public function __construct( * Must return the transformed $value * * @param mixed $input - * - * @return mixed */ - public function transform($input, array $options = []) + public function transform($input, array $options = []): mixed { if (! empty($options['initial_value']) && $options['keep_input']) { throw new InvalidOptionsException( @@ -173,7 +171,7 @@ public function getCode(): string return 'mapping'; } - protected function configureMappingOptions(OptionsResolver $resolver) + protected function configureMappingOptions(OptionsResolver $resolver): void { $resolver->setDefaults( [ @@ -192,10 +190,8 @@ protected function configureMappingOptions(OptionsResolver $resolver) /** * Custom rules to get a value from an input object or array - * - * @return mixed */ - protected function extractInputValue(mixed $input, string $sourceProperty) + protected function extractInputValue(mixed $input, string $sourceProperty): mixed { if ($sourceProperty === '.') { return $input; @@ -210,7 +206,7 @@ protected function extractInputValue(mixed $input, string $sourceProperty) * @TODO WARNING there is no error if framework.property_access.throw_exception_on_invalid_index is false (which is * the default) */ - protected function handleInputMissingExceptions(RuntimeException $missingPropertyError, string $srcKey) + protected function handleInputMissingExceptions(RuntimeException $missingPropertyError, string $srcKey): void { $this->logger->debug( 'Mapping exception', diff --git a/Transformer/RulesTransformer.php b/Transformer/RulesTransformer.php index 9a56ccb5..374c1bc8 100644 --- a/Transformer/RulesTransformer.php +++ b/Transformer/RulesTransformer.php @@ -94,10 +94,8 @@ public function configureOptions(OptionsResolver $resolver) /** * Configure options for one "rule" block - * - * @param array|null $expressionVariables */ - public function configureRuleOptions(OptionsResolver $resolver, $expressionVariables = null) + public function configureRuleOptions(OptionsResolver $resolver, ?array $expressionVariables = null): void { $resolver->setDefaults([ 'condition' => null, diff --git a/Transformer/TransformerTrait.php b/Transformer/TransformerTrait.php index 3c6df5e3..826261c4 100644 --- a/Transformer/TransformerTrait.php +++ b/Transformer/TransformerTrait.php @@ -23,15 +23,12 @@ trait TransformerTrait { - /** - * @var TransformerRegistry - */ - protected $transformerRegistry; + protected ?TransformerRegistry $transformerRegistry = null; /** * Transform the list of transformer codes + options into a list of Closure (better performances) */ - public function normalizeTransformers(Options $options, $transformers): array + public function normalizeTransformers(Options $options, array $transformers): array { $transformerClosures = []; @@ -101,11 +98,10 @@ protected function getCleanedTransfomerCode(string $transformerCode) return $transformerCode; } - /** - * @param string $optionName - */ - protected function configureTransformersOptions(OptionsResolver $resolver, $optionName = 'transformers') - { + protected function configureTransformersOptions( + OptionsResolver $resolver, + string $optionName = 'transformers' + ): void { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); $resolver->setNormalizer($optionName, Closure::fromCallable([$this, 'normalizeTransformers'])); diff --git a/phpstan.neon b/phpstan.neon index 69897602..289e6564 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 2 + level: 6 paths: - . excludePaths: @@ -8,4 +8,16 @@ parameters: - Resources/tests/* - Tests/* - rector.php - - var/* \ No newline at end of file + - var/* + ignoreErrors: + - '#type has no value type specified in iterable type#' + - '#has parameter .* with no value type specified in iterable type#' + - '#has no value type specified in iterable type array#' + - '#configureOptions\(\) has no return type specified.#' + - '#configure\(\) has no return type specified#' + - '#process\(\) has no return type specified#' + - '#should return Iterator but returns Traversable#' + - '#Negated boolean expression is always false#' + checkGenericClassInNonGenericObjectType: false + reportUnmatchedIgnoredErrors: false + inferPrivatePropertyTypeFromConstructor: true \ No newline at end of file From 6ec4a963fca106a7e3100c2f22c727da4cc3a5a5 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 12 Mar 2023 17:38:59 +0100 Subject: [PATCH 164/304] change directory structure --- .travis.yml | 15 --------------- composer.json | 2 +- {Documentation => doc}/01-quick_start.md | 0 {Documentation => doc}/02-task_types.md | 0 {Documentation => doc}/03-custom_tasks.md | 0 {Documentation => doc}/04-advanced_workflow.md | 0 {Documentation => doc}/05-good_practices.md | 0 {Documentation => doc}/06-testing.md | 0 {Documentation => doc}/basic-etl.png | Bin .../changelog/CHANGELOG-2.0-1.1.md | 0 .../changelog/CHANGELOG-3.1.md | 0 .../changelog/CHANGELOG-3.2.md | 0 .../cookbooks/01-common_setup.md | 0 .../cookbooks/memory_usage_graph.md | 0 .../cookbooks/performances_monitoring.md | 0 .../reference/01-process_definition.md | 0 .../reference/02-task_definition.md | 0 .../03-generic_transformers_definition.md | 0 .../reference/tasks/_template.md | 0 .../reference/tasks/aggregate_iterable_task.md | 0 .../tasks/constant_iterable_output_task.md | 0 .../reference/tasks/constant_output_task.md | 0 .../reference/tasks/csv_reader_task.md | 0 .../reference/tasks/csv_writer_task.md | 0 .../reference/tasks/debug_task.md | 0 .../reference/tasks/denormalizer_task.md | 0 .../reference/tasks/dummy_task.md | 0 .../reference/tasks/event_dispatcher_task.md | 0 .../reference/tasks/input_aggregator_task.md | 0 .../reference/tasks/input_iterator_task.md | 0 .../reference/tasks/iterable_batch_task.md | 0 .../reference/tasks/normalizer_task.md | 0 .../reference/tasks/property_getter_task.md | 0 .../reference/tasks/property_setter_task.md | 0 .../reference/tasks/transformer_task.md | 0 .../reference/tasks/xml_reader_task.md | 0 .../reference/tasks/xml_writer_task.md | 0 .../reference/traits/condition_trait.md | 0 .../reference/traits/transformer_trait.md | 0 .../reference/transformers/_template.md | 0 .../transformers/array_filter_transformer.md | 0 .../reference/transformers/date_format.md | 0 .../reference/transformers/date_parser.md | 0 .../transformers/mapping_transformer.md | 0 .../reference/transformers/rules_transformer.md | 0 .../reference/transformers/xpath_evaluator.md | 0 ecs.php | 4 ++-- phpstan.neon | 2 +- rector.php | 4 +--- .../CleverAgeProcessBundle.php | 0 .../Command}/ExecuteProcessCommand.php | 0 {Command => src/Command}/ListProcessCommand.php | 0 {Command => src/Command}/ProcessHelpCommand.php | 0 .../Configuration}/ProcessConfiguration.php | 0 .../Configuration}/TaskConfiguration.php | 0 .../Context}/ContextualOptionResolver.php | 0 .../CleverAgeProcessExtension.php | 0 .../Compiler/CheckSerializerCompilerPass.php | 0 .../Compiler/RegistryCompilerPass.php | 0 .../DependencyInjection}/Configuration.php | 0 {Event => src/Event}/ConsoleProcessEvent.php | 0 .../Event}/EventDispatcherTaskEvent.php | 0 {Event => src/Event}/GenericEvent.php | 0 {Event => src/Event}/ProcessEvent.php | 0 .../EventListener}/DataQueueEventListener.php | 0 .../Exception}/CircularProcessException.php | 0 .../InvalidProcessConfigurationException.php | 0 .../Exception}/MissingProcessException.php | 0 .../MissingTaskConfigurationException.php | 0 .../Exception}/MissingTransformerException.php | 0 .../Exception}/MultiBranchProcessException.php | 0 .../Exception}/ProcessExceptionInterface.php | 0 .../Exception}/TransformerException.php | 0 .../ExpressionLanguage}/PhpFunctionProvider.php | 0 {Filesystem => src/Filesystem}/CsvFile.php | 0 {Filesystem => src/Filesystem}/CsvResource.php | 0 .../Filesystem}/FileStreamInterface.php | 0 .../Filesystem}/JsonStreamFile.php | 0 .../Filesystem}/SeekableFileInterface.php | 0 .../Filesystem}/StructuredFileInterface.php | 0 .../Filesystem}/WritableFileInterface.php | 0 .../WritableStructuredFileInterface.php | 0 {Filesystem => src/Filesystem}/XmlFile.php | 0 {Logger => src/Logger}/AbstractLogger.php | 0 {Logger => src/Logger}/AbstractProcessor.php | 0 {Logger => src/Logger}/ProcessLogger.php | 0 {Logger => src/Logger}/ProcessProcessor.php | 0 {Logger => src/Logger}/TaskLogger.php | 0 {Logger => src/Logger}/TaskProcessor.php | 0 {Logger => src/Logger}/TransformerProcessor.php | 0 {Manager => src/Manager}/ProcessManager.php | 0 .../Model}/AbstractConfigurableTask.php | 0 {Model => src/Model}/BlockingTaskInterface.php | 0 .../Model}/FinalizableTaskInterface.php | 0 {Model => src/Model}/FlushableTaskInterface.php | 0 .../Model}/InitializableTaskInterface.php | 0 {Model => src/Model}/IterableTaskInterface.php | 0 {Model => src/Model}/ProcessHistory.php | 0 {Model => src/Model}/ProcessState.php | 0 {Model => src/Model}/SubprocessInstance.php | 0 {Model => src/Model}/TaskInterface.php | 0 .../Registry}/ProcessConfigurationRegistry.php | 0 .../Registry}/TransformerRegistry.php | 0 .../Resources}/config/services/command.yml | 0 .../Resources}/config/services/event.yml | 0 .../config/services/expression_language.yml | 0 .../Resources}/config/services/logger.yml | 0 .../Resources}/config/services/manager.yml | 0 .../Resources}/config/services/registry.yml | 0 .../Resources}/config/services/task.yml | 0 .../Resources}/config/services/transformer.yml | 0 .../migration/move_doctrine_to_addon.sh | 0 .../migration/move_flysystem_to_addon.sh | 0 .../Resources}/migration/replace_deprecated.sh | 0 {Resources => src/Resources}/tests/config.yml | 0 .../Resources}/tests/environment/README.md | 0 .../Resources}/tests/environment/php/conf.ini | 0 .../tests/environment/sf5/composer.json | 0 .../tests/environment/sf5/config/bundles.php | 0 .../sf5/config/packages/framework.yaml | 0 .../config/packages/test/cleverage_process.yaml | 0 .../tests/environment/sf5/phpunit.xml.dist | 0 .../Resources}/tests/process/blocking_tasks.yml | 0 .../tests/process/circular_process.yml | 0 .../Resources}/tests/process/context.yml | 0 .../Resources}/tests/process/empty_process.yml | 0 .../Resources}/tests/process/error_process.yml | 0 .../tests/process/exception_management.yml | 0 .../Resources}/tests/process/flushable_tasks.yml | 0 .../Resources}/tests/process/help_command.yml | 0 .../tests/process/iterable_process.yml | 0 .../Resources}/tests/process/long_process.yml | 0 .../tests/process/multi_branch_process.yml | 0 .../tests/process/multi_workflow_process.yml | 0 .../Resources}/tests/process/simple_process.yml | 0 .../tests/task/column_aggregator_task.yml | 0 .../Resources}/tests/task/filter_task.yml | 0 .../tests/task/process_execute_task.yml | 0 .../Resources}/tests/task/stop_task.yml | 0 .../Resources}/tests/task/transformer_task.yml | 0 .../Resources}/tests/task/validator_task.yml | 0 .../transfomer/array_filter_transformer.yml | 0 .../tests/transfomer/callback_transformer.yml | 0 .../tests/transfomer/date_transformers.yml | 0 .../tests/transfomer/generic_transformer.yml | 0 .../tests/transfomer/hash_transformer.yml | 0 .../tests/transfomer/mapping_transformer.yml | 0 .../tests/transfomer/rules_transformer.yml | 0 .../tests/transfomer/transformer_exception.yml | 0 .../tests/transfomer/type_setter_transformer.yml | 0 .../tests/transfomer/unset_transformer.yml | 0 .../Task}/AbstractIterableOutputTask.php | 0 {Task => src/Task}/AggregateIterableTask.php | 0 {Task => src/Task}/ArrayMergeTask.php | 0 {Task => src/Task}/ColumnAggregatorTask.php | 0 .../Task}/ConstantIterableOutputTask.php | 0 {Task => src/Task}/ConstantOutputTask.php | 0 {Task => src/Task}/CounterTask.php | 0 {Task => src/Task}/Debug/DebugTask.php | 0 {Task => src/Task}/Debug/DieTask.php | 0 {Task => src/Task}/Debug/ErrorForwarderTask.php | 0 {Task => src/Task}/Debug/MemInfoDumpTask.php | 0 {Task => src/Task}/DummyTask.php | 0 {Task => src/Task}/Event/EventDispatcherTask.php | 0 .../Task}/File/Csv/AbstractCsvResourceTask.php | 0 {Task => src/Task}/File/Csv/AbstractCsvTask.php | 0 {Task => src/Task}/File/Csv/CsvReaderTask.php | 0 {Task => src/Task}/File/Csv/CsvSplitterTask.php | 0 {Task => src/Task}/File/Csv/CsvWriterTask.php | 0 .../Task}/File/Csv/InputCsvReaderTask.php | 0 {Task => src/Task}/File/FileFetchTask.php | 0 {Task => src/Task}/File/FileMoverTask.php | 0 {Task => src/Task}/File/FileReaderTask.php | 0 {Task => src/Task}/File/FileRemoverTask.php | 0 {Task => src/Task}/File/FileWriterTask.php | 0 {Task => src/Task}/File/FolderBrowserTask.php | 0 .../Task}/File/InputFolderBrowserTask.php | 0 .../File/JsonStream/JsonStreamReaderTask.php | 0 {Task => src/Task}/File/Xml/XmlReaderTask.php | 0 {Task => src/Task}/File/Xml/XmlWriterTask.php | 0 {Task => src/Task}/File/YamlReaderTask.php | 0 {Task => src/Task}/File/YamlWriterTask.php | 0 {Task => src/Task}/FilterTask.php | 0 .../Task}/GroupByAggregateIterableTask.php | 0 {Task => src/Task}/InputAggregatorTask.php | 0 {Task => src/Task}/InputIteratorTask.php | 0 {Task => src/Task}/IterableBatchTask.php | 0 {Task => src/Task}/ObjectUpdaterTask.php | 0 {Task => src/Task}/Process/CommandRunnerTask.php | 0 .../Task}/Process/ProcessExecutorTask.php | 0 .../Task}/Process/ProcessLauncherTask.php | 0 {Task => src/Task}/PropertyGetterTask.php | 0 {Task => src/Task}/PropertySetterTask.php | 0 .../Task}/Reporting/AdvancedStatCounterTask.php | 0 {Task => src/Task}/Reporting/LoggerTask.php | 0 {Task => src/Task}/Reporting/StatCounterTask.php | 0 {Task => src/Task}/RowAggregatorTask.php | 0 .../Task}/Serialization/DenormalizerTask.php | 0 .../Task}/Serialization/DeserializerTask.php | 0 .../Task}/Serialization/NormalizerTask.php | 0 .../Task}/Serialization/SerializerTask.php | 0 {Task => src/Task}/SimpleBatchTask.php | 0 {Task => src/Task}/SkipEmptyTask.php | 0 {Task => src/Task}/SplitJoinLineTask.php | 0 {Task => src/Task}/StopTask.php | 0 {Task => src/Task}/TransformerTask.php | 0 {Task => src/Task}/Validation/ValidatorTask.php | 0 .../Transformer}/ArrayElementTransformer.php | 0 .../Transformer}/ArrayFilterTransformer.php | 0 .../Transformer}/ArrayFirstTransformer.php | 0 .../Transformer}/ArrayLastTransformer.php | 0 .../Transformer}/ArrayMapTransformer.php | 0 .../Transformer}/ArrayUnsetTransformer.php | 0 .../Transformer}/CachedTransformer.php | 0 .../Transformer}/CallbackTransformer.php | 0 .../Transformer}/CastTransformer.php | 0 .../Transformer}/ConditionTrait.php | 0 .../ConfigurableTransformerInterface.php | 0 .../Transformer}/ConstantTransformer.php | 0 .../Transformer}/ConvertValueTransformer.php | 0 .../Transformer}/DateFormatTransformer.php | 0 .../Transformer}/DateParserTransformer.php | 0 .../Transformer}/DebugTransformer.php | 0 .../Transformer}/DefaultTransformer.php | 0 .../Transformer}/DenormalizeTransformer.php | 0 .../Transformer}/EvaluatorTransformer.php | 0 .../Transformer}/ExplodeTransformer.php | 0 .../ExpressionLanguageMapTransformer.php | 0 .../Transformer}/GenericTransformer.php | 0 .../Transformer}/HashTransformer.php | 0 .../Transformer}/ImplodeTransformer.php | 0 .../Transformer}/MappingTransformer.php | 0 .../Transformer}/MultiReplaceTransformer.php | 0 .../Transformer}/NormalizeTransformer.php | 0 .../Transformer}/PregFilterTransformer.php | 0 .../Transformer}/PropertyAccessorTransformer.php | 0 .../RecursivePropertySetterTransformer.php | 0 .../Transformer}/RulesTransformer.php | 0 .../Transformer}/SlugifyTransformer.php | 0 .../Transformer}/SprintfTransformer.php | 0 .../Transformer}/TransformerInterface.php | 0 .../Transformer}/TransformerTrait.php | 0 .../Transformer}/TrimTransformer.php | 0 .../Transformer}/TypeSetterTransformer.php | 0 .../Transformer}/UnsetTransformer.php | 0 .../Transformer}/WrapperTransformer.php | 0 .../Xml/XpathEvaluatorTransformer.php | 0 .../Validator}/ConstraintLoader.php | 0 {hooks => src/hooks}/build | 0 {Tests => tests}/AbstractProcessTest.php | 0 {Tests => tests}/BasicTest.php | 0 {Tests => tests}/BlockingTaskTest.php | 0 {Tests => tests}/CircularProcessTest.php | 0 {Tests => tests}/ContextTest.php | 0 {Tests => tests}/EmptyProcessTest.php | 0 {Tests => tests}/ExceptionManagementTest.php | 0 {Tests => tests}/FlushableTaskTest.php | 0 {Tests => tests}/IterableTaskTest.php | 0 {Tests => tests}/MultiBranchProcessTest.php | 0 {Tests => tests}/MultiWorkflowTest.php | 0 {Tests => tests}/ProcessManagerTest.php | 0 .../Task/ColumnAggregatorTaskTest.php | 0 {Tests => tests}/Task/FilterTaskTest.php | 0 .../Task/ProcessExecutorTaskTest.php | 0 {Tests => tests}/Task/StopTaskTest.php | 0 {Tests => tests}/Task/TransformerTaskTest.php | 0 {Tests => tests}/Task/ValidatorTaskTest.php | 0 .../Transformer/ArrayFilterTransformerTest.php | 0 .../Transformer/CallbackTransformerTest.php | 0 .../Transformer/DateTransformersTest.php | 0 .../Transformer/GenericTransformersTest.php | 0 .../Transformer/HashTransformerTest.php | 0 .../Transformer/MappingTransformerTest.php | 0 .../Transformer/RulesTransformerTest.php | 0 .../Transformer/TransformerExceptionTest.php | 0 .../Transformer/TypeSetterTransformerTest.php | 0 .../Transformer/UnsetTransformerTest.php | 0 .../XpathEvaluatorTransformerTest.php | 0 278 files changed, 5 insertions(+), 22 deletions(-) delete mode 100644 .travis.yml rename {Documentation => doc}/01-quick_start.md (100%) rename {Documentation => doc}/02-task_types.md (100%) rename {Documentation => doc}/03-custom_tasks.md (100%) rename {Documentation => doc}/04-advanced_workflow.md (100%) rename {Documentation => doc}/05-good_practices.md (100%) rename {Documentation => doc}/06-testing.md (100%) rename {Documentation => doc}/basic-etl.png (100%) rename {Documentation => doc}/changelog/CHANGELOG-2.0-1.1.md (100%) rename {Documentation => doc}/changelog/CHANGELOG-3.1.md (100%) rename {Documentation => doc}/changelog/CHANGELOG-3.2.md (100%) rename {Documentation => doc}/cookbooks/01-common_setup.md (100%) rename {Documentation => doc}/cookbooks/memory_usage_graph.md (100%) rename {Documentation => doc}/cookbooks/performances_monitoring.md (100%) rename {Documentation => doc}/reference/01-process_definition.md (100%) rename {Documentation => doc}/reference/02-task_definition.md (100%) rename {Documentation => doc}/reference/03-generic_transformers_definition.md (100%) rename {Documentation => doc}/reference/tasks/_template.md (100%) rename {Documentation => doc}/reference/tasks/aggregate_iterable_task.md (100%) rename {Documentation => doc}/reference/tasks/constant_iterable_output_task.md (100%) rename {Documentation => doc}/reference/tasks/constant_output_task.md (100%) rename {Documentation => doc}/reference/tasks/csv_reader_task.md (100%) rename {Documentation => doc}/reference/tasks/csv_writer_task.md (100%) rename {Documentation => doc}/reference/tasks/debug_task.md (100%) rename {Documentation => doc}/reference/tasks/denormalizer_task.md (100%) rename {Documentation => doc}/reference/tasks/dummy_task.md (100%) rename {Documentation => doc}/reference/tasks/event_dispatcher_task.md (100%) rename {Documentation => doc}/reference/tasks/input_aggregator_task.md (100%) rename {Documentation => doc}/reference/tasks/input_iterator_task.md (100%) rename {Documentation => doc}/reference/tasks/iterable_batch_task.md (100%) rename {Documentation => doc}/reference/tasks/normalizer_task.md (100%) rename {Documentation => doc}/reference/tasks/property_getter_task.md (100%) rename {Documentation => doc}/reference/tasks/property_setter_task.md (100%) rename {Documentation => doc}/reference/tasks/transformer_task.md (100%) rename {Documentation => doc}/reference/tasks/xml_reader_task.md (100%) rename {Documentation => doc}/reference/tasks/xml_writer_task.md (100%) rename {Documentation => doc}/reference/traits/condition_trait.md (100%) rename {Documentation => doc}/reference/traits/transformer_trait.md (100%) rename {Documentation => doc}/reference/transformers/_template.md (100%) rename {Documentation => doc}/reference/transformers/array_filter_transformer.md (100%) rename {Documentation => doc}/reference/transformers/date_format.md (100%) rename {Documentation => doc}/reference/transformers/date_parser.md (100%) rename {Documentation => doc}/reference/transformers/mapping_transformer.md (100%) rename {Documentation => doc}/reference/transformers/rules_transformer.md (100%) rename {Documentation => doc}/reference/transformers/xpath_evaluator.md (100%) rename CleverAgeProcessBundle.php => src/CleverAgeProcessBundle.php (100%) rename {Command => src/Command}/ExecuteProcessCommand.php (100%) rename {Command => src/Command}/ListProcessCommand.php (100%) rename {Command => src/Command}/ProcessHelpCommand.php (100%) rename {Configuration => src/Configuration}/ProcessConfiguration.php (100%) rename {Configuration => src/Configuration}/TaskConfiguration.php (100%) rename {Context => src/Context}/ContextualOptionResolver.php (100%) rename {DependencyInjection => src/DependencyInjection}/CleverAgeProcessExtension.php (100%) rename {DependencyInjection => src/DependencyInjection}/Compiler/CheckSerializerCompilerPass.php (100%) rename {DependencyInjection => src/DependencyInjection}/Compiler/RegistryCompilerPass.php (100%) rename {DependencyInjection => src/DependencyInjection}/Configuration.php (100%) rename {Event => src/Event}/ConsoleProcessEvent.php (100%) rename {Event => src/Event}/EventDispatcherTaskEvent.php (100%) rename {Event => src/Event}/GenericEvent.php (100%) rename {Event => src/Event}/ProcessEvent.php (100%) rename {EventListener => src/EventListener}/DataQueueEventListener.php (100%) rename {Exception => src/Exception}/CircularProcessException.php (100%) rename {Exception => src/Exception}/InvalidProcessConfigurationException.php (100%) rename {Exception => src/Exception}/MissingProcessException.php (100%) rename {Exception => src/Exception}/MissingTaskConfigurationException.php (100%) rename {Exception => src/Exception}/MissingTransformerException.php (100%) rename {Exception => src/Exception}/MultiBranchProcessException.php (100%) rename {Exception => src/Exception}/ProcessExceptionInterface.php (100%) rename {Exception => src/Exception}/TransformerException.php (100%) rename {ExpressionLanguage => src/ExpressionLanguage}/PhpFunctionProvider.php (100%) rename {Filesystem => src/Filesystem}/CsvFile.php (100%) rename {Filesystem => src/Filesystem}/CsvResource.php (100%) rename {Filesystem => src/Filesystem}/FileStreamInterface.php (100%) rename {Filesystem => src/Filesystem}/JsonStreamFile.php (100%) rename {Filesystem => src/Filesystem}/SeekableFileInterface.php (100%) rename {Filesystem => src/Filesystem}/StructuredFileInterface.php (100%) rename {Filesystem => src/Filesystem}/WritableFileInterface.php (100%) rename {Filesystem => src/Filesystem}/WritableStructuredFileInterface.php (100%) rename {Filesystem => src/Filesystem}/XmlFile.php (100%) rename {Logger => src/Logger}/AbstractLogger.php (100%) rename {Logger => src/Logger}/AbstractProcessor.php (100%) rename {Logger => src/Logger}/ProcessLogger.php (100%) rename {Logger => src/Logger}/ProcessProcessor.php (100%) rename {Logger => src/Logger}/TaskLogger.php (100%) rename {Logger => src/Logger}/TaskProcessor.php (100%) rename {Logger => src/Logger}/TransformerProcessor.php (100%) rename {Manager => src/Manager}/ProcessManager.php (100%) rename {Model => src/Model}/AbstractConfigurableTask.php (100%) rename {Model => src/Model}/BlockingTaskInterface.php (100%) rename {Model => src/Model}/FinalizableTaskInterface.php (100%) rename {Model => src/Model}/FlushableTaskInterface.php (100%) rename {Model => src/Model}/InitializableTaskInterface.php (100%) rename {Model => src/Model}/IterableTaskInterface.php (100%) rename {Model => src/Model}/ProcessHistory.php (100%) rename {Model => src/Model}/ProcessState.php (100%) rename {Model => src/Model}/SubprocessInstance.php (100%) rename {Model => src/Model}/TaskInterface.php (100%) rename {Registry => src/Registry}/ProcessConfigurationRegistry.php (100%) rename {Registry => src/Registry}/TransformerRegistry.php (100%) rename {Resources => src/Resources}/config/services/command.yml (100%) rename {Resources => src/Resources}/config/services/event.yml (100%) rename {Resources => src/Resources}/config/services/expression_language.yml (100%) rename {Resources => src/Resources}/config/services/logger.yml (100%) rename {Resources => src/Resources}/config/services/manager.yml (100%) rename {Resources => src/Resources}/config/services/registry.yml (100%) rename {Resources => src/Resources}/config/services/task.yml (100%) rename {Resources => src/Resources}/config/services/transformer.yml (100%) rename {Resources => src/Resources}/migration/move_doctrine_to_addon.sh (100%) rename {Resources => src/Resources}/migration/move_flysystem_to_addon.sh (100%) rename {Resources => src/Resources}/migration/replace_deprecated.sh (100%) rename {Resources => src/Resources}/tests/config.yml (100%) rename {Resources => src/Resources}/tests/environment/README.md (100%) rename {Resources => src/Resources}/tests/environment/php/conf.ini (100%) rename {Resources => src/Resources}/tests/environment/sf5/composer.json (100%) rename {Resources => src/Resources}/tests/environment/sf5/config/bundles.php (100%) rename {Resources => src/Resources}/tests/environment/sf5/config/packages/framework.yaml (100%) rename {Resources => src/Resources}/tests/environment/sf5/config/packages/test/cleverage_process.yaml (100%) rename {Resources => src/Resources}/tests/environment/sf5/phpunit.xml.dist (100%) rename {Resources => src/Resources}/tests/process/blocking_tasks.yml (100%) rename {Resources => src/Resources}/tests/process/circular_process.yml (100%) rename {Resources => src/Resources}/tests/process/context.yml (100%) rename {Resources => src/Resources}/tests/process/empty_process.yml (100%) rename {Resources => src/Resources}/tests/process/error_process.yml (100%) rename {Resources => src/Resources}/tests/process/exception_management.yml (100%) rename {Resources => src/Resources}/tests/process/flushable_tasks.yml (100%) rename {Resources => src/Resources}/tests/process/help_command.yml (100%) rename {Resources => src/Resources}/tests/process/iterable_process.yml (100%) rename {Resources => src/Resources}/tests/process/long_process.yml (100%) rename {Resources => src/Resources}/tests/process/multi_branch_process.yml (100%) rename {Resources => src/Resources}/tests/process/multi_workflow_process.yml (100%) rename {Resources => src/Resources}/tests/process/simple_process.yml (100%) rename {Resources => src/Resources}/tests/task/column_aggregator_task.yml (100%) rename {Resources => src/Resources}/tests/task/filter_task.yml (100%) rename {Resources => src/Resources}/tests/task/process_execute_task.yml (100%) rename {Resources => src/Resources}/tests/task/stop_task.yml (100%) rename {Resources => src/Resources}/tests/task/transformer_task.yml (100%) rename {Resources => src/Resources}/tests/task/validator_task.yml (100%) rename {Resources => src/Resources}/tests/transfomer/array_filter_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/callback_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/date_transformers.yml (100%) rename {Resources => src/Resources}/tests/transfomer/generic_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/hash_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/mapping_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/rules_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/transformer_exception.yml (100%) rename {Resources => src/Resources}/tests/transfomer/type_setter_transformer.yml (100%) rename {Resources => src/Resources}/tests/transfomer/unset_transformer.yml (100%) rename {Task => src/Task}/AbstractIterableOutputTask.php (100%) rename {Task => src/Task}/AggregateIterableTask.php (100%) rename {Task => src/Task}/ArrayMergeTask.php (100%) rename {Task => src/Task}/ColumnAggregatorTask.php (100%) rename {Task => src/Task}/ConstantIterableOutputTask.php (100%) rename {Task => src/Task}/ConstantOutputTask.php (100%) rename {Task => src/Task}/CounterTask.php (100%) rename {Task => src/Task}/Debug/DebugTask.php (100%) rename {Task => src/Task}/Debug/DieTask.php (100%) rename {Task => src/Task}/Debug/ErrorForwarderTask.php (100%) rename {Task => src/Task}/Debug/MemInfoDumpTask.php (100%) rename {Task => src/Task}/DummyTask.php (100%) rename {Task => src/Task}/Event/EventDispatcherTask.php (100%) rename {Task => src/Task}/File/Csv/AbstractCsvResourceTask.php (100%) rename {Task => src/Task}/File/Csv/AbstractCsvTask.php (100%) rename {Task => src/Task}/File/Csv/CsvReaderTask.php (100%) rename {Task => src/Task}/File/Csv/CsvSplitterTask.php (100%) rename {Task => src/Task}/File/Csv/CsvWriterTask.php (100%) rename {Task => src/Task}/File/Csv/InputCsvReaderTask.php (100%) rename {Task => src/Task}/File/FileFetchTask.php (100%) rename {Task => src/Task}/File/FileMoverTask.php (100%) rename {Task => src/Task}/File/FileReaderTask.php (100%) rename {Task => src/Task}/File/FileRemoverTask.php (100%) rename {Task => src/Task}/File/FileWriterTask.php (100%) rename {Task => src/Task}/File/FolderBrowserTask.php (100%) rename {Task => src/Task}/File/InputFolderBrowserTask.php (100%) rename {Task => src/Task}/File/JsonStream/JsonStreamReaderTask.php (100%) rename {Task => src/Task}/File/Xml/XmlReaderTask.php (100%) rename {Task => src/Task}/File/Xml/XmlWriterTask.php (100%) rename {Task => src/Task}/File/YamlReaderTask.php (100%) rename {Task => src/Task}/File/YamlWriterTask.php (100%) rename {Task => src/Task}/FilterTask.php (100%) rename {Task => src/Task}/GroupByAggregateIterableTask.php (100%) rename {Task => src/Task}/InputAggregatorTask.php (100%) rename {Task => src/Task}/InputIteratorTask.php (100%) rename {Task => src/Task}/IterableBatchTask.php (100%) rename {Task => src/Task}/ObjectUpdaterTask.php (100%) rename {Task => src/Task}/Process/CommandRunnerTask.php (100%) rename {Task => src/Task}/Process/ProcessExecutorTask.php (100%) rename {Task => src/Task}/Process/ProcessLauncherTask.php (100%) rename {Task => src/Task}/PropertyGetterTask.php (100%) rename {Task => src/Task}/PropertySetterTask.php (100%) rename {Task => src/Task}/Reporting/AdvancedStatCounterTask.php (100%) rename {Task => src/Task}/Reporting/LoggerTask.php (100%) rename {Task => src/Task}/Reporting/StatCounterTask.php (100%) rename {Task => src/Task}/RowAggregatorTask.php (100%) rename {Task => src/Task}/Serialization/DenormalizerTask.php (100%) rename {Task => src/Task}/Serialization/DeserializerTask.php (100%) rename {Task => src/Task}/Serialization/NormalizerTask.php (100%) rename {Task => src/Task}/Serialization/SerializerTask.php (100%) rename {Task => src/Task}/SimpleBatchTask.php (100%) rename {Task => src/Task}/SkipEmptyTask.php (100%) rename {Task => src/Task}/SplitJoinLineTask.php (100%) rename {Task => src/Task}/StopTask.php (100%) rename {Task => src/Task}/TransformerTask.php (100%) rename {Task => src/Task}/Validation/ValidatorTask.php (100%) rename {Transformer => src/Transformer}/ArrayElementTransformer.php (100%) rename {Transformer => src/Transformer}/ArrayFilterTransformer.php (100%) rename {Transformer => src/Transformer}/ArrayFirstTransformer.php (100%) rename {Transformer => src/Transformer}/ArrayLastTransformer.php (100%) rename {Transformer => src/Transformer}/ArrayMapTransformer.php (100%) rename {Transformer => src/Transformer}/ArrayUnsetTransformer.php (100%) rename {Transformer => src/Transformer}/CachedTransformer.php (100%) rename {Transformer => src/Transformer}/CallbackTransformer.php (100%) rename {Transformer => src/Transformer}/CastTransformer.php (100%) rename {Transformer => src/Transformer}/ConditionTrait.php (100%) rename {Transformer => src/Transformer}/ConfigurableTransformerInterface.php (100%) rename {Transformer => src/Transformer}/ConstantTransformer.php (100%) rename {Transformer => src/Transformer}/ConvertValueTransformer.php (100%) rename {Transformer => src/Transformer}/DateFormatTransformer.php (100%) rename {Transformer => src/Transformer}/DateParserTransformer.php (100%) rename {Transformer => src/Transformer}/DebugTransformer.php (100%) rename {Transformer => src/Transformer}/DefaultTransformer.php (100%) rename {Transformer => src/Transformer}/DenormalizeTransformer.php (100%) rename {Transformer => src/Transformer}/EvaluatorTransformer.php (100%) rename {Transformer => src/Transformer}/ExplodeTransformer.php (100%) rename {Transformer => src/Transformer}/ExpressionLanguageMapTransformer.php (100%) rename {Transformer => src/Transformer}/GenericTransformer.php (100%) rename {Transformer => src/Transformer}/HashTransformer.php (100%) rename {Transformer => src/Transformer}/ImplodeTransformer.php (100%) rename {Transformer => src/Transformer}/MappingTransformer.php (100%) rename {Transformer => src/Transformer}/MultiReplaceTransformer.php (100%) rename {Transformer => src/Transformer}/NormalizeTransformer.php (100%) rename {Transformer => src/Transformer}/PregFilterTransformer.php (100%) rename {Transformer => src/Transformer}/PropertyAccessorTransformer.php (100%) rename {Transformer => src/Transformer}/RecursivePropertySetterTransformer.php (100%) rename {Transformer => src/Transformer}/RulesTransformer.php (100%) rename {Transformer => src/Transformer}/SlugifyTransformer.php (100%) rename {Transformer => src/Transformer}/SprintfTransformer.php (100%) rename {Transformer => src/Transformer}/TransformerInterface.php (100%) rename {Transformer => src/Transformer}/TransformerTrait.php (100%) rename {Transformer => src/Transformer}/TrimTransformer.php (100%) rename {Transformer => src/Transformer}/TypeSetterTransformer.php (100%) rename {Transformer => src/Transformer}/UnsetTransformer.php (100%) rename {Transformer => src/Transformer}/WrapperTransformer.php (100%) rename {Transformer => src/Transformer}/Xml/XpathEvaluatorTransformer.php (100%) rename {Validator => src/Validator}/ConstraintLoader.php (100%) rename {hooks => src/hooks}/build (100%) rename {Tests => tests}/AbstractProcessTest.php (100%) rename {Tests => tests}/BasicTest.php (100%) rename {Tests => tests}/BlockingTaskTest.php (100%) rename {Tests => tests}/CircularProcessTest.php (100%) rename {Tests => tests}/ContextTest.php (100%) rename {Tests => tests}/EmptyProcessTest.php (100%) rename {Tests => tests}/ExceptionManagementTest.php (100%) rename {Tests => tests}/FlushableTaskTest.php (100%) rename {Tests => tests}/IterableTaskTest.php (100%) rename {Tests => tests}/MultiBranchProcessTest.php (100%) rename {Tests => tests}/MultiWorkflowTest.php (100%) rename {Tests => tests}/ProcessManagerTest.php (100%) rename {Tests => tests}/Task/ColumnAggregatorTaskTest.php (100%) rename {Tests => tests}/Task/FilterTaskTest.php (100%) rename {Tests => tests}/Task/ProcessExecutorTaskTest.php (100%) rename {Tests => tests}/Task/StopTaskTest.php (100%) rename {Tests => tests}/Task/TransformerTaskTest.php (100%) rename {Tests => tests}/Task/ValidatorTaskTest.php (100%) rename {Tests => tests}/Transformer/ArrayFilterTransformerTest.php (100%) rename {Tests => tests}/Transformer/CallbackTransformerTest.php (100%) rename {Tests => tests}/Transformer/DateTransformersTest.php (100%) rename {Tests => tests}/Transformer/GenericTransformersTest.php (100%) rename {Tests => tests}/Transformer/HashTransformerTest.php (100%) rename {Tests => tests}/Transformer/MappingTransformerTest.php (100%) rename {Tests => tests}/Transformer/RulesTransformerTest.php (100%) rename {Tests => tests}/Transformer/TransformerExceptionTest.php (100%) rename {Tests => tests}/Transformer/TypeSetterTransformerTest.php (100%) rename {Tests => tests}/Transformer/UnsetTransformerTest.php (100%) rename {Tests => tests}/Transformer/XpathEvaluatorTransformerTest.php (100%) diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1aa13225..00000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: php - -services: - - docker - -before_script: - - docker pull cleverage/process-bundle:sf3 - - docker pull cleverage/process-bundle:sf4 - - docker pull cleverage/process-bundle:sf5 - -# Tests should be done in reversed order to check most important versions first -script: - - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf5 php vendor/bin/phpunit - - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf4 php vendor/bin/phpunit - - docker run -it --mount type=bind,src=$(pwd),dst=/src-cleverage_process cleverage/process-bundle:sf3 php vendor/bin/phpunit diff --git a/composer.json b/composer.json index e8ac257e..cd51bc7f 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ ], "autoload": { "psr-4": { - "CleverAge\\ProcessBundle\\": "" + "CleverAge\\ProcessBundle\\": "src" } }, "require": { diff --git a/Documentation/01-quick_start.md b/doc/01-quick_start.md similarity index 100% rename from Documentation/01-quick_start.md rename to doc/01-quick_start.md diff --git a/Documentation/02-task_types.md b/doc/02-task_types.md similarity index 100% rename from Documentation/02-task_types.md rename to doc/02-task_types.md diff --git a/Documentation/03-custom_tasks.md b/doc/03-custom_tasks.md similarity index 100% rename from Documentation/03-custom_tasks.md rename to doc/03-custom_tasks.md diff --git a/Documentation/04-advanced_workflow.md b/doc/04-advanced_workflow.md similarity index 100% rename from Documentation/04-advanced_workflow.md rename to doc/04-advanced_workflow.md diff --git a/Documentation/05-good_practices.md b/doc/05-good_practices.md similarity index 100% rename from Documentation/05-good_practices.md rename to doc/05-good_practices.md diff --git a/Documentation/06-testing.md b/doc/06-testing.md similarity index 100% rename from Documentation/06-testing.md rename to doc/06-testing.md diff --git a/Documentation/basic-etl.png b/doc/basic-etl.png similarity index 100% rename from Documentation/basic-etl.png rename to doc/basic-etl.png diff --git a/Documentation/changelog/CHANGELOG-2.0-1.1.md b/doc/changelog/CHANGELOG-2.0-1.1.md similarity index 100% rename from Documentation/changelog/CHANGELOG-2.0-1.1.md rename to doc/changelog/CHANGELOG-2.0-1.1.md diff --git a/Documentation/changelog/CHANGELOG-3.1.md b/doc/changelog/CHANGELOG-3.1.md similarity index 100% rename from Documentation/changelog/CHANGELOG-3.1.md rename to doc/changelog/CHANGELOG-3.1.md diff --git a/Documentation/changelog/CHANGELOG-3.2.md b/doc/changelog/CHANGELOG-3.2.md similarity index 100% rename from Documentation/changelog/CHANGELOG-3.2.md rename to doc/changelog/CHANGELOG-3.2.md diff --git a/Documentation/cookbooks/01-common_setup.md b/doc/cookbooks/01-common_setup.md similarity index 100% rename from Documentation/cookbooks/01-common_setup.md rename to doc/cookbooks/01-common_setup.md diff --git a/Documentation/cookbooks/memory_usage_graph.md b/doc/cookbooks/memory_usage_graph.md similarity index 100% rename from Documentation/cookbooks/memory_usage_graph.md rename to doc/cookbooks/memory_usage_graph.md diff --git a/Documentation/cookbooks/performances_monitoring.md b/doc/cookbooks/performances_monitoring.md similarity index 100% rename from Documentation/cookbooks/performances_monitoring.md rename to doc/cookbooks/performances_monitoring.md diff --git a/Documentation/reference/01-process_definition.md b/doc/reference/01-process_definition.md similarity index 100% rename from Documentation/reference/01-process_definition.md rename to doc/reference/01-process_definition.md diff --git a/Documentation/reference/02-task_definition.md b/doc/reference/02-task_definition.md similarity index 100% rename from Documentation/reference/02-task_definition.md rename to doc/reference/02-task_definition.md diff --git a/Documentation/reference/03-generic_transformers_definition.md b/doc/reference/03-generic_transformers_definition.md similarity index 100% rename from Documentation/reference/03-generic_transformers_definition.md rename to doc/reference/03-generic_transformers_definition.md diff --git a/Documentation/reference/tasks/_template.md b/doc/reference/tasks/_template.md similarity index 100% rename from Documentation/reference/tasks/_template.md rename to doc/reference/tasks/_template.md diff --git a/Documentation/reference/tasks/aggregate_iterable_task.md b/doc/reference/tasks/aggregate_iterable_task.md similarity index 100% rename from Documentation/reference/tasks/aggregate_iterable_task.md rename to doc/reference/tasks/aggregate_iterable_task.md diff --git a/Documentation/reference/tasks/constant_iterable_output_task.md b/doc/reference/tasks/constant_iterable_output_task.md similarity index 100% rename from Documentation/reference/tasks/constant_iterable_output_task.md rename to doc/reference/tasks/constant_iterable_output_task.md diff --git a/Documentation/reference/tasks/constant_output_task.md b/doc/reference/tasks/constant_output_task.md similarity index 100% rename from Documentation/reference/tasks/constant_output_task.md rename to doc/reference/tasks/constant_output_task.md diff --git a/Documentation/reference/tasks/csv_reader_task.md b/doc/reference/tasks/csv_reader_task.md similarity index 100% rename from Documentation/reference/tasks/csv_reader_task.md rename to doc/reference/tasks/csv_reader_task.md diff --git a/Documentation/reference/tasks/csv_writer_task.md b/doc/reference/tasks/csv_writer_task.md similarity index 100% rename from Documentation/reference/tasks/csv_writer_task.md rename to doc/reference/tasks/csv_writer_task.md diff --git a/Documentation/reference/tasks/debug_task.md b/doc/reference/tasks/debug_task.md similarity index 100% rename from Documentation/reference/tasks/debug_task.md rename to doc/reference/tasks/debug_task.md diff --git a/Documentation/reference/tasks/denormalizer_task.md b/doc/reference/tasks/denormalizer_task.md similarity index 100% rename from Documentation/reference/tasks/denormalizer_task.md rename to doc/reference/tasks/denormalizer_task.md diff --git a/Documentation/reference/tasks/dummy_task.md b/doc/reference/tasks/dummy_task.md similarity index 100% rename from Documentation/reference/tasks/dummy_task.md rename to doc/reference/tasks/dummy_task.md diff --git a/Documentation/reference/tasks/event_dispatcher_task.md b/doc/reference/tasks/event_dispatcher_task.md similarity index 100% rename from Documentation/reference/tasks/event_dispatcher_task.md rename to doc/reference/tasks/event_dispatcher_task.md diff --git a/Documentation/reference/tasks/input_aggregator_task.md b/doc/reference/tasks/input_aggregator_task.md similarity index 100% rename from Documentation/reference/tasks/input_aggregator_task.md rename to doc/reference/tasks/input_aggregator_task.md diff --git a/Documentation/reference/tasks/input_iterator_task.md b/doc/reference/tasks/input_iterator_task.md similarity index 100% rename from Documentation/reference/tasks/input_iterator_task.md rename to doc/reference/tasks/input_iterator_task.md diff --git a/Documentation/reference/tasks/iterable_batch_task.md b/doc/reference/tasks/iterable_batch_task.md similarity index 100% rename from Documentation/reference/tasks/iterable_batch_task.md rename to doc/reference/tasks/iterable_batch_task.md diff --git a/Documentation/reference/tasks/normalizer_task.md b/doc/reference/tasks/normalizer_task.md similarity index 100% rename from Documentation/reference/tasks/normalizer_task.md rename to doc/reference/tasks/normalizer_task.md diff --git a/Documentation/reference/tasks/property_getter_task.md b/doc/reference/tasks/property_getter_task.md similarity index 100% rename from Documentation/reference/tasks/property_getter_task.md rename to doc/reference/tasks/property_getter_task.md diff --git a/Documentation/reference/tasks/property_setter_task.md b/doc/reference/tasks/property_setter_task.md similarity index 100% rename from Documentation/reference/tasks/property_setter_task.md rename to doc/reference/tasks/property_setter_task.md diff --git a/Documentation/reference/tasks/transformer_task.md b/doc/reference/tasks/transformer_task.md similarity index 100% rename from Documentation/reference/tasks/transformer_task.md rename to doc/reference/tasks/transformer_task.md diff --git a/Documentation/reference/tasks/xml_reader_task.md b/doc/reference/tasks/xml_reader_task.md similarity index 100% rename from Documentation/reference/tasks/xml_reader_task.md rename to doc/reference/tasks/xml_reader_task.md diff --git a/Documentation/reference/tasks/xml_writer_task.md b/doc/reference/tasks/xml_writer_task.md similarity index 100% rename from Documentation/reference/tasks/xml_writer_task.md rename to doc/reference/tasks/xml_writer_task.md diff --git a/Documentation/reference/traits/condition_trait.md b/doc/reference/traits/condition_trait.md similarity index 100% rename from Documentation/reference/traits/condition_trait.md rename to doc/reference/traits/condition_trait.md diff --git a/Documentation/reference/traits/transformer_trait.md b/doc/reference/traits/transformer_trait.md similarity index 100% rename from Documentation/reference/traits/transformer_trait.md rename to doc/reference/traits/transformer_trait.md diff --git a/Documentation/reference/transformers/_template.md b/doc/reference/transformers/_template.md similarity index 100% rename from Documentation/reference/transformers/_template.md rename to doc/reference/transformers/_template.md diff --git a/Documentation/reference/transformers/array_filter_transformer.md b/doc/reference/transformers/array_filter_transformer.md similarity index 100% rename from Documentation/reference/transformers/array_filter_transformer.md rename to doc/reference/transformers/array_filter_transformer.md diff --git a/Documentation/reference/transformers/date_format.md b/doc/reference/transformers/date_format.md similarity index 100% rename from Documentation/reference/transformers/date_format.md rename to doc/reference/transformers/date_format.md diff --git a/Documentation/reference/transformers/date_parser.md b/doc/reference/transformers/date_parser.md similarity index 100% rename from Documentation/reference/transformers/date_parser.md rename to doc/reference/transformers/date_parser.md diff --git a/Documentation/reference/transformers/mapping_transformer.md b/doc/reference/transformers/mapping_transformer.md similarity index 100% rename from Documentation/reference/transformers/mapping_transformer.md rename to doc/reference/transformers/mapping_transformer.md diff --git a/Documentation/reference/transformers/rules_transformer.md b/doc/reference/transformers/rules_transformer.md similarity index 100% rename from Documentation/reference/transformers/rules_transformer.md rename to doc/reference/transformers/rules_transformer.md diff --git a/Documentation/reference/transformers/xpath_evaluator.md b/doc/reference/transformers/xpath_evaluator.md similarity index 100% rename from Documentation/reference/transformers/xpath_evaluator.md rename to doc/reference/transformers/xpath_evaluator.md diff --git a/ecs.php b/ecs.php index 5aa539a9..65fb2278 100644 --- a/ecs.php +++ b/ecs.php @@ -18,7 +18,7 @@ SetList::DOCTRINE_ANNOTATIONS, ]); - $ecsConfig->paths([__DIR__]); + $ecsConfig->paths([__DIR__ . 'src']); - $ecsConfig->skip([__DIR__ . 'vendor', AssignmentInConditionSniff::class]); + $ecsConfig->skip([AssignmentInConditionSniff::class]); }; diff --git a/phpstan.neon b/phpstan.neon index 289e6564..2fa41fc4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ parameters: level: 6 paths: - - . + - src excludePaths: - ecs.php - vendor/* diff --git a/rector.php b/rector.php index 4f9c066c..86236ee5 100644 --- a/rector.php +++ b/rector.php @@ -13,9 +13,7 @@ $rectorConfig->importNames(); $rectorConfig->importShortClasses(); - $rectorConfig->paths([__DIR__]); - - $rectorConfig->skip([__DIR__ . '/vendor']); + $rectorConfig->paths([__DIR__ . '/src']); $rectorConfig->sets([ SetList::TYPE_DECLARATION, diff --git a/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php similarity index 100% rename from CleverAgeProcessBundle.php rename to src/CleverAgeProcessBundle.php diff --git a/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php similarity index 100% rename from Command/ExecuteProcessCommand.php rename to src/Command/ExecuteProcessCommand.php diff --git a/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php similarity index 100% rename from Command/ListProcessCommand.php rename to src/Command/ListProcessCommand.php diff --git a/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php similarity index 100% rename from Command/ProcessHelpCommand.php rename to src/Command/ProcessHelpCommand.php diff --git a/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php similarity index 100% rename from Configuration/ProcessConfiguration.php rename to src/Configuration/ProcessConfiguration.php diff --git a/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php similarity index 100% rename from Configuration/TaskConfiguration.php rename to src/Configuration/TaskConfiguration.php diff --git a/Context/ContextualOptionResolver.php b/src/Context/ContextualOptionResolver.php similarity index 100% rename from Context/ContextualOptionResolver.php rename to src/Context/ContextualOptionResolver.php diff --git a/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php similarity index 100% rename from DependencyInjection/CleverAgeProcessExtension.php rename to src/DependencyInjection/CleverAgeProcessExtension.php diff --git a/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php similarity index 100% rename from DependencyInjection/Compiler/CheckSerializerCompilerPass.php rename to src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php diff --git a/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php similarity index 100% rename from DependencyInjection/Compiler/RegistryCompilerPass.php rename to src/DependencyInjection/Compiler/RegistryCompilerPass.php diff --git a/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php similarity index 100% rename from DependencyInjection/Configuration.php rename to src/DependencyInjection/Configuration.php diff --git a/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php similarity index 100% rename from Event/ConsoleProcessEvent.php rename to src/Event/ConsoleProcessEvent.php diff --git a/Event/EventDispatcherTaskEvent.php b/src/Event/EventDispatcherTaskEvent.php similarity index 100% rename from Event/EventDispatcherTaskEvent.php rename to src/Event/EventDispatcherTaskEvent.php diff --git a/Event/GenericEvent.php b/src/Event/GenericEvent.php similarity index 100% rename from Event/GenericEvent.php rename to src/Event/GenericEvent.php diff --git a/Event/ProcessEvent.php b/src/Event/ProcessEvent.php similarity index 100% rename from Event/ProcessEvent.php rename to src/Event/ProcessEvent.php diff --git a/EventListener/DataQueueEventListener.php b/src/EventListener/DataQueueEventListener.php similarity index 100% rename from EventListener/DataQueueEventListener.php rename to src/EventListener/DataQueueEventListener.php diff --git a/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php similarity index 100% rename from Exception/CircularProcessException.php rename to src/Exception/CircularProcessException.php diff --git a/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php similarity index 100% rename from Exception/InvalidProcessConfigurationException.php rename to src/Exception/InvalidProcessConfigurationException.php diff --git a/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php similarity index 100% rename from Exception/MissingProcessException.php rename to src/Exception/MissingProcessException.php diff --git a/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php similarity index 100% rename from Exception/MissingTaskConfigurationException.php rename to src/Exception/MissingTaskConfigurationException.php diff --git a/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php similarity index 100% rename from Exception/MissingTransformerException.php rename to src/Exception/MissingTransformerException.php diff --git a/Exception/MultiBranchProcessException.php b/src/Exception/MultiBranchProcessException.php similarity index 100% rename from Exception/MultiBranchProcessException.php rename to src/Exception/MultiBranchProcessException.php diff --git a/Exception/ProcessExceptionInterface.php b/src/Exception/ProcessExceptionInterface.php similarity index 100% rename from Exception/ProcessExceptionInterface.php rename to src/Exception/ProcessExceptionInterface.php diff --git a/Exception/TransformerException.php b/src/Exception/TransformerException.php similarity index 100% rename from Exception/TransformerException.php rename to src/Exception/TransformerException.php diff --git a/ExpressionLanguage/PhpFunctionProvider.php b/src/ExpressionLanguage/PhpFunctionProvider.php similarity index 100% rename from ExpressionLanguage/PhpFunctionProvider.php rename to src/ExpressionLanguage/PhpFunctionProvider.php diff --git a/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php similarity index 100% rename from Filesystem/CsvFile.php rename to src/Filesystem/CsvFile.php diff --git a/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php similarity index 100% rename from Filesystem/CsvResource.php rename to src/Filesystem/CsvResource.php diff --git a/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php similarity index 100% rename from Filesystem/FileStreamInterface.php rename to src/Filesystem/FileStreamInterface.php diff --git a/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php similarity index 100% rename from Filesystem/JsonStreamFile.php rename to src/Filesystem/JsonStreamFile.php diff --git a/Filesystem/SeekableFileInterface.php b/src/Filesystem/SeekableFileInterface.php similarity index 100% rename from Filesystem/SeekableFileInterface.php rename to src/Filesystem/SeekableFileInterface.php diff --git a/Filesystem/StructuredFileInterface.php b/src/Filesystem/StructuredFileInterface.php similarity index 100% rename from Filesystem/StructuredFileInterface.php rename to src/Filesystem/StructuredFileInterface.php diff --git a/Filesystem/WritableFileInterface.php b/src/Filesystem/WritableFileInterface.php similarity index 100% rename from Filesystem/WritableFileInterface.php rename to src/Filesystem/WritableFileInterface.php diff --git a/Filesystem/WritableStructuredFileInterface.php b/src/Filesystem/WritableStructuredFileInterface.php similarity index 100% rename from Filesystem/WritableStructuredFileInterface.php rename to src/Filesystem/WritableStructuredFileInterface.php diff --git a/Filesystem/XmlFile.php b/src/Filesystem/XmlFile.php similarity index 100% rename from Filesystem/XmlFile.php rename to src/Filesystem/XmlFile.php diff --git a/Logger/AbstractLogger.php b/src/Logger/AbstractLogger.php similarity index 100% rename from Logger/AbstractLogger.php rename to src/Logger/AbstractLogger.php diff --git a/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php similarity index 100% rename from Logger/AbstractProcessor.php rename to src/Logger/AbstractProcessor.php diff --git a/Logger/ProcessLogger.php b/src/Logger/ProcessLogger.php similarity index 100% rename from Logger/ProcessLogger.php rename to src/Logger/ProcessLogger.php diff --git a/Logger/ProcessProcessor.php b/src/Logger/ProcessProcessor.php similarity index 100% rename from Logger/ProcessProcessor.php rename to src/Logger/ProcessProcessor.php diff --git a/Logger/TaskLogger.php b/src/Logger/TaskLogger.php similarity index 100% rename from Logger/TaskLogger.php rename to src/Logger/TaskLogger.php diff --git a/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php similarity index 100% rename from Logger/TaskProcessor.php rename to src/Logger/TaskProcessor.php diff --git a/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php similarity index 100% rename from Logger/TransformerProcessor.php rename to src/Logger/TransformerProcessor.php diff --git a/Manager/ProcessManager.php b/src/Manager/ProcessManager.php similarity index 100% rename from Manager/ProcessManager.php rename to src/Manager/ProcessManager.php diff --git a/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php similarity index 100% rename from Model/AbstractConfigurableTask.php rename to src/Model/AbstractConfigurableTask.php diff --git a/Model/BlockingTaskInterface.php b/src/Model/BlockingTaskInterface.php similarity index 100% rename from Model/BlockingTaskInterface.php rename to src/Model/BlockingTaskInterface.php diff --git a/Model/FinalizableTaskInterface.php b/src/Model/FinalizableTaskInterface.php similarity index 100% rename from Model/FinalizableTaskInterface.php rename to src/Model/FinalizableTaskInterface.php diff --git a/Model/FlushableTaskInterface.php b/src/Model/FlushableTaskInterface.php similarity index 100% rename from Model/FlushableTaskInterface.php rename to src/Model/FlushableTaskInterface.php diff --git a/Model/InitializableTaskInterface.php b/src/Model/InitializableTaskInterface.php similarity index 100% rename from Model/InitializableTaskInterface.php rename to src/Model/InitializableTaskInterface.php diff --git a/Model/IterableTaskInterface.php b/src/Model/IterableTaskInterface.php similarity index 100% rename from Model/IterableTaskInterface.php rename to src/Model/IterableTaskInterface.php diff --git a/Model/ProcessHistory.php b/src/Model/ProcessHistory.php similarity index 100% rename from Model/ProcessHistory.php rename to src/Model/ProcessHistory.php diff --git a/Model/ProcessState.php b/src/Model/ProcessState.php similarity index 100% rename from Model/ProcessState.php rename to src/Model/ProcessState.php diff --git a/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php similarity index 100% rename from Model/SubprocessInstance.php rename to src/Model/SubprocessInstance.php diff --git a/Model/TaskInterface.php b/src/Model/TaskInterface.php similarity index 100% rename from Model/TaskInterface.php rename to src/Model/TaskInterface.php diff --git a/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php similarity index 100% rename from Registry/ProcessConfigurationRegistry.php rename to src/Registry/ProcessConfigurationRegistry.php diff --git a/Registry/TransformerRegistry.php b/src/Registry/TransformerRegistry.php similarity index 100% rename from Registry/TransformerRegistry.php rename to src/Registry/TransformerRegistry.php diff --git a/Resources/config/services/command.yml b/src/Resources/config/services/command.yml similarity index 100% rename from Resources/config/services/command.yml rename to src/Resources/config/services/command.yml diff --git a/Resources/config/services/event.yml b/src/Resources/config/services/event.yml similarity index 100% rename from Resources/config/services/event.yml rename to src/Resources/config/services/event.yml diff --git a/Resources/config/services/expression_language.yml b/src/Resources/config/services/expression_language.yml similarity index 100% rename from Resources/config/services/expression_language.yml rename to src/Resources/config/services/expression_language.yml diff --git a/Resources/config/services/logger.yml b/src/Resources/config/services/logger.yml similarity index 100% rename from Resources/config/services/logger.yml rename to src/Resources/config/services/logger.yml diff --git a/Resources/config/services/manager.yml b/src/Resources/config/services/manager.yml similarity index 100% rename from Resources/config/services/manager.yml rename to src/Resources/config/services/manager.yml diff --git a/Resources/config/services/registry.yml b/src/Resources/config/services/registry.yml similarity index 100% rename from Resources/config/services/registry.yml rename to src/Resources/config/services/registry.yml diff --git a/Resources/config/services/task.yml b/src/Resources/config/services/task.yml similarity index 100% rename from Resources/config/services/task.yml rename to src/Resources/config/services/task.yml diff --git a/Resources/config/services/transformer.yml b/src/Resources/config/services/transformer.yml similarity index 100% rename from Resources/config/services/transformer.yml rename to src/Resources/config/services/transformer.yml diff --git a/Resources/migration/move_doctrine_to_addon.sh b/src/Resources/migration/move_doctrine_to_addon.sh similarity index 100% rename from Resources/migration/move_doctrine_to_addon.sh rename to src/Resources/migration/move_doctrine_to_addon.sh diff --git a/Resources/migration/move_flysystem_to_addon.sh b/src/Resources/migration/move_flysystem_to_addon.sh similarity index 100% rename from Resources/migration/move_flysystem_to_addon.sh rename to src/Resources/migration/move_flysystem_to_addon.sh diff --git a/Resources/migration/replace_deprecated.sh b/src/Resources/migration/replace_deprecated.sh similarity index 100% rename from Resources/migration/replace_deprecated.sh rename to src/Resources/migration/replace_deprecated.sh diff --git a/Resources/tests/config.yml b/src/Resources/tests/config.yml similarity index 100% rename from Resources/tests/config.yml rename to src/Resources/tests/config.yml diff --git a/Resources/tests/environment/README.md b/src/Resources/tests/environment/README.md similarity index 100% rename from Resources/tests/environment/README.md rename to src/Resources/tests/environment/README.md diff --git a/Resources/tests/environment/php/conf.ini b/src/Resources/tests/environment/php/conf.ini similarity index 100% rename from Resources/tests/environment/php/conf.ini rename to src/Resources/tests/environment/php/conf.ini diff --git a/Resources/tests/environment/sf5/composer.json b/src/Resources/tests/environment/sf5/composer.json similarity index 100% rename from Resources/tests/environment/sf5/composer.json rename to src/Resources/tests/environment/sf5/composer.json diff --git a/Resources/tests/environment/sf5/config/bundles.php b/src/Resources/tests/environment/sf5/config/bundles.php similarity index 100% rename from Resources/tests/environment/sf5/config/bundles.php rename to src/Resources/tests/environment/sf5/config/bundles.php diff --git a/Resources/tests/environment/sf5/config/packages/framework.yaml b/src/Resources/tests/environment/sf5/config/packages/framework.yaml similarity index 100% rename from Resources/tests/environment/sf5/config/packages/framework.yaml rename to src/Resources/tests/environment/sf5/config/packages/framework.yaml diff --git a/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml b/src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml similarity index 100% rename from Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml rename to src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml diff --git a/Resources/tests/environment/sf5/phpunit.xml.dist b/src/Resources/tests/environment/sf5/phpunit.xml.dist similarity index 100% rename from Resources/tests/environment/sf5/phpunit.xml.dist rename to src/Resources/tests/environment/sf5/phpunit.xml.dist diff --git a/Resources/tests/process/blocking_tasks.yml b/src/Resources/tests/process/blocking_tasks.yml similarity index 100% rename from Resources/tests/process/blocking_tasks.yml rename to src/Resources/tests/process/blocking_tasks.yml diff --git a/Resources/tests/process/circular_process.yml b/src/Resources/tests/process/circular_process.yml similarity index 100% rename from Resources/tests/process/circular_process.yml rename to src/Resources/tests/process/circular_process.yml diff --git a/Resources/tests/process/context.yml b/src/Resources/tests/process/context.yml similarity index 100% rename from Resources/tests/process/context.yml rename to src/Resources/tests/process/context.yml diff --git a/Resources/tests/process/empty_process.yml b/src/Resources/tests/process/empty_process.yml similarity index 100% rename from Resources/tests/process/empty_process.yml rename to src/Resources/tests/process/empty_process.yml diff --git a/Resources/tests/process/error_process.yml b/src/Resources/tests/process/error_process.yml similarity index 100% rename from Resources/tests/process/error_process.yml rename to src/Resources/tests/process/error_process.yml diff --git a/Resources/tests/process/exception_management.yml b/src/Resources/tests/process/exception_management.yml similarity index 100% rename from Resources/tests/process/exception_management.yml rename to src/Resources/tests/process/exception_management.yml diff --git a/Resources/tests/process/flushable_tasks.yml b/src/Resources/tests/process/flushable_tasks.yml similarity index 100% rename from Resources/tests/process/flushable_tasks.yml rename to src/Resources/tests/process/flushable_tasks.yml diff --git a/Resources/tests/process/help_command.yml b/src/Resources/tests/process/help_command.yml similarity index 100% rename from Resources/tests/process/help_command.yml rename to src/Resources/tests/process/help_command.yml diff --git a/Resources/tests/process/iterable_process.yml b/src/Resources/tests/process/iterable_process.yml similarity index 100% rename from Resources/tests/process/iterable_process.yml rename to src/Resources/tests/process/iterable_process.yml diff --git a/Resources/tests/process/long_process.yml b/src/Resources/tests/process/long_process.yml similarity index 100% rename from Resources/tests/process/long_process.yml rename to src/Resources/tests/process/long_process.yml diff --git a/Resources/tests/process/multi_branch_process.yml b/src/Resources/tests/process/multi_branch_process.yml similarity index 100% rename from Resources/tests/process/multi_branch_process.yml rename to src/Resources/tests/process/multi_branch_process.yml diff --git a/Resources/tests/process/multi_workflow_process.yml b/src/Resources/tests/process/multi_workflow_process.yml similarity index 100% rename from Resources/tests/process/multi_workflow_process.yml rename to src/Resources/tests/process/multi_workflow_process.yml diff --git a/Resources/tests/process/simple_process.yml b/src/Resources/tests/process/simple_process.yml similarity index 100% rename from Resources/tests/process/simple_process.yml rename to src/Resources/tests/process/simple_process.yml diff --git a/Resources/tests/task/column_aggregator_task.yml b/src/Resources/tests/task/column_aggregator_task.yml similarity index 100% rename from Resources/tests/task/column_aggregator_task.yml rename to src/Resources/tests/task/column_aggregator_task.yml diff --git a/Resources/tests/task/filter_task.yml b/src/Resources/tests/task/filter_task.yml similarity index 100% rename from Resources/tests/task/filter_task.yml rename to src/Resources/tests/task/filter_task.yml diff --git a/Resources/tests/task/process_execute_task.yml b/src/Resources/tests/task/process_execute_task.yml similarity index 100% rename from Resources/tests/task/process_execute_task.yml rename to src/Resources/tests/task/process_execute_task.yml diff --git a/Resources/tests/task/stop_task.yml b/src/Resources/tests/task/stop_task.yml similarity index 100% rename from Resources/tests/task/stop_task.yml rename to src/Resources/tests/task/stop_task.yml diff --git a/Resources/tests/task/transformer_task.yml b/src/Resources/tests/task/transformer_task.yml similarity index 100% rename from Resources/tests/task/transformer_task.yml rename to src/Resources/tests/task/transformer_task.yml diff --git a/Resources/tests/task/validator_task.yml b/src/Resources/tests/task/validator_task.yml similarity index 100% rename from Resources/tests/task/validator_task.yml rename to src/Resources/tests/task/validator_task.yml diff --git a/Resources/tests/transfomer/array_filter_transformer.yml b/src/Resources/tests/transfomer/array_filter_transformer.yml similarity index 100% rename from Resources/tests/transfomer/array_filter_transformer.yml rename to src/Resources/tests/transfomer/array_filter_transformer.yml diff --git a/Resources/tests/transfomer/callback_transformer.yml b/src/Resources/tests/transfomer/callback_transformer.yml similarity index 100% rename from Resources/tests/transfomer/callback_transformer.yml rename to src/Resources/tests/transfomer/callback_transformer.yml diff --git a/Resources/tests/transfomer/date_transformers.yml b/src/Resources/tests/transfomer/date_transformers.yml similarity index 100% rename from Resources/tests/transfomer/date_transformers.yml rename to src/Resources/tests/transfomer/date_transformers.yml diff --git a/Resources/tests/transfomer/generic_transformer.yml b/src/Resources/tests/transfomer/generic_transformer.yml similarity index 100% rename from Resources/tests/transfomer/generic_transformer.yml rename to src/Resources/tests/transfomer/generic_transformer.yml diff --git a/Resources/tests/transfomer/hash_transformer.yml b/src/Resources/tests/transfomer/hash_transformer.yml similarity index 100% rename from Resources/tests/transfomer/hash_transformer.yml rename to src/Resources/tests/transfomer/hash_transformer.yml diff --git a/Resources/tests/transfomer/mapping_transformer.yml b/src/Resources/tests/transfomer/mapping_transformer.yml similarity index 100% rename from Resources/tests/transfomer/mapping_transformer.yml rename to src/Resources/tests/transfomer/mapping_transformer.yml diff --git a/Resources/tests/transfomer/rules_transformer.yml b/src/Resources/tests/transfomer/rules_transformer.yml similarity index 100% rename from Resources/tests/transfomer/rules_transformer.yml rename to src/Resources/tests/transfomer/rules_transformer.yml diff --git a/Resources/tests/transfomer/transformer_exception.yml b/src/Resources/tests/transfomer/transformer_exception.yml similarity index 100% rename from Resources/tests/transfomer/transformer_exception.yml rename to src/Resources/tests/transfomer/transformer_exception.yml diff --git a/Resources/tests/transfomer/type_setter_transformer.yml b/src/Resources/tests/transfomer/type_setter_transformer.yml similarity index 100% rename from Resources/tests/transfomer/type_setter_transformer.yml rename to src/Resources/tests/transfomer/type_setter_transformer.yml diff --git a/Resources/tests/transfomer/unset_transformer.yml b/src/Resources/tests/transfomer/unset_transformer.yml similarity index 100% rename from Resources/tests/transfomer/unset_transformer.yml rename to src/Resources/tests/transfomer/unset_transformer.yml diff --git a/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php similarity index 100% rename from Task/AbstractIterableOutputTask.php rename to src/Task/AbstractIterableOutputTask.php diff --git a/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php similarity index 100% rename from Task/AggregateIterableTask.php rename to src/Task/AggregateIterableTask.php diff --git a/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php similarity index 100% rename from Task/ArrayMergeTask.php rename to src/Task/ArrayMergeTask.php diff --git a/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php similarity index 100% rename from Task/ColumnAggregatorTask.php rename to src/Task/ColumnAggregatorTask.php diff --git a/Task/ConstantIterableOutputTask.php b/src/Task/ConstantIterableOutputTask.php similarity index 100% rename from Task/ConstantIterableOutputTask.php rename to src/Task/ConstantIterableOutputTask.php diff --git a/Task/ConstantOutputTask.php b/src/Task/ConstantOutputTask.php similarity index 100% rename from Task/ConstantOutputTask.php rename to src/Task/ConstantOutputTask.php diff --git a/Task/CounterTask.php b/src/Task/CounterTask.php similarity index 100% rename from Task/CounterTask.php rename to src/Task/CounterTask.php diff --git a/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php similarity index 100% rename from Task/Debug/DebugTask.php rename to src/Task/Debug/DebugTask.php diff --git a/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php similarity index 100% rename from Task/Debug/DieTask.php rename to src/Task/Debug/DieTask.php diff --git a/Task/Debug/ErrorForwarderTask.php b/src/Task/Debug/ErrorForwarderTask.php similarity index 100% rename from Task/Debug/ErrorForwarderTask.php rename to src/Task/Debug/ErrorForwarderTask.php diff --git a/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php similarity index 100% rename from Task/Debug/MemInfoDumpTask.php rename to src/Task/Debug/MemInfoDumpTask.php diff --git a/Task/DummyTask.php b/src/Task/DummyTask.php similarity index 100% rename from Task/DummyTask.php rename to src/Task/DummyTask.php diff --git a/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php similarity index 100% rename from Task/Event/EventDispatcherTask.php rename to src/Task/Event/EventDispatcherTask.php diff --git a/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php similarity index 100% rename from Task/File/Csv/AbstractCsvResourceTask.php rename to src/Task/File/Csv/AbstractCsvResourceTask.php diff --git a/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php similarity index 100% rename from Task/File/Csv/AbstractCsvTask.php rename to src/Task/File/Csv/AbstractCsvTask.php diff --git a/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php similarity index 100% rename from Task/File/Csv/CsvReaderTask.php rename to src/Task/File/Csv/CsvReaderTask.php diff --git a/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php similarity index 100% rename from Task/File/Csv/CsvSplitterTask.php rename to src/Task/File/Csv/CsvSplitterTask.php diff --git a/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php similarity index 100% rename from Task/File/Csv/CsvWriterTask.php rename to src/Task/File/Csv/CsvWriterTask.php diff --git a/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php similarity index 100% rename from Task/File/Csv/InputCsvReaderTask.php rename to src/Task/File/Csv/InputCsvReaderTask.php diff --git a/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php similarity index 100% rename from Task/File/FileFetchTask.php rename to src/Task/File/FileFetchTask.php diff --git a/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php similarity index 100% rename from Task/File/FileMoverTask.php rename to src/Task/File/FileMoverTask.php diff --git a/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php similarity index 100% rename from Task/File/FileReaderTask.php rename to src/Task/File/FileReaderTask.php diff --git a/Task/File/FileRemoverTask.php b/src/Task/File/FileRemoverTask.php similarity index 100% rename from Task/File/FileRemoverTask.php rename to src/Task/File/FileRemoverTask.php diff --git a/Task/File/FileWriterTask.php b/src/Task/File/FileWriterTask.php similarity index 100% rename from Task/File/FileWriterTask.php rename to src/Task/File/FileWriterTask.php diff --git a/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php similarity index 100% rename from Task/File/FolderBrowserTask.php rename to src/Task/File/FolderBrowserTask.php diff --git a/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php similarity index 100% rename from Task/File/InputFolderBrowserTask.php rename to src/Task/File/InputFolderBrowserTask.php diff --git a/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php similarity index 100% rename from Task/File/JsonStream/JsonStreamReaderTask.php rename to src/Task/File/JsonStream/JsonStreamReaderTask.php diff --git a/Task/File/Xml/XmlReaderTask.php b/src/Task/File/Xml/XmlReaderTask.php similarity index 100% rename from Task/File/Xml/XmlReaderTask.php rename to src/Task/File/Xml/XmlReaderTask.php diff --git a/Task/File/Xml/XmlWriterTask.php b/src/Task/File/Xml/XmlWriterTask.php similarity index 100% rename from Task/File/Xml/XmlWriterTask.php rename to src/Task/File/Xml/XmlWriterTask.php diff --git a/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php similarity index 100% rename from Task/File/YamlReaderTask.php rename to src/Task/File/YamlReaderTask.php diff --git a/Task/File/YamlWriterTask.php b/src/Task/File/YamlWriterTask.php similarity index 100% rename from Task/File/YamlWriterTask.php rename to src/Task/File/YamlWriterTask.php diff --git a/Task/FilterTask.php b/src/Task/FilterTask.php similarity index 100% rename from Task/FilterTask.php rename to src/Task/FilterTask.php diff --git a/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php similarity index 100% rename from Task/GroupByAggregateIterableTask.php rename to src/Task/GroupByAggregateIterableTask.php diff --git a/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php similarity index 100% rename from Task/InputAggregatorTask.php rename to src/Task/InputAggregatorTask.php diff --git a/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php similarity index 100% rename from Task/InputIteratorTask.php rename to src/Task/InputIteratorTask.php diff --git a/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php similarity index 100% rename from Task/IterableBatchTask.php rename to src/Task/IterableBatchTask.php diff --git a/Task/ObjectUpdaterTask.php b/src/Task/ObjectUpdaterTask.php similarity index 100% rename from Task/ObjectUpdaterTask.php rename to src/Task/ObjectUpdaterTask.php diff --git a/Task/Process/CommandRunnerTask.php b/src/Task/Process/CommandRunnerTask.php similarity index 100% rename from Task/Process/CommandRunnerTask.php rename to src/Task/Process/CommandRunnerTask.php diff --git a/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php similarity index 100% rename from Task/Process/ProcessExecutorTask.php rename to src/Task/Process/ProcessExecutorTask.php diff --git a/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php similarity index 100% rename from Task/Process/ProcessLauncherTask.php rename to src/Task/Process/ProcessLauncherTask.php diff --git a/Task/PropertyGetterTask.php b/src/Task/PropertyGetterTask.php similarity index 100% rename from Task/PropertyGetterTask.php rename to src/Task/PropertyGetterTask.php diff --git a/Task/PropertySetterTask.php b/src/Task/PropertySetterTask.php similarity index 100% rename from Task/PropertySetterTask.php rename to src/Task/PropertySetterTask.php diff --git a/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php similarity index 100% rename from Task/Reporting/AdvancedStatCounterTask.php rename to src/Task/Reporting/AdvancedStatCounterTask.php diff --git a/Task/Reporting/LoggerTask.php b/src/Task/Reporting/LoggerTask.php similarity index 100% rename from Task/Reporting/LoggerTask.php rename to src/Task/Reporting/LoggerTask.php diff --git a/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php similarity index 100% rename from Task/Reporting/StatCounterTask.php rename to src/Task/Reporting/StatCounterTask.php diff --git a/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php similarity index 100% rename from Task/RowAggregatorTask.php rename to src/Task/RowAggregatorTask.php diff --git a/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php similarity index 100% rename from Task/Serialization/DenormalizerTask.php rename to src/Task/Serialization/DenormalizerTask.php diff --git a/Task/Serialization/DeserializerTask.php b/src/Task/Serialization/DeserializerTask.php similarity index 100% rename from Task/Serialization/DeserializerTask.php rename to src/Task/Serialization/DeserializerTask.php diff --git a/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php similarity index 100% rename from Task/Serialization/NormalizerTask.php rename to src/Task/Serialization/NormalizerTask.php diff --git a/Task/Serialization/SerializerTask.php b/src/Task/Serialization/SerializerTask.php similarity index 100% rename from Task/Serialization/SerializerTask.php rename to src/Task/Serialization/SerializerTask.php diff --git a/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php similarity index 100% rename from Task/SimpleBatchTask.php rename to src/Task/SimpleBatchTask.php diff --git a/Task/SkipEmptyTask.php b/src/Task/SkipEmptyTask.php similarity index 100% rename from Task/SkipEmptyTask.php rename to src/Task/SkipEmptyTask.php diff --git a/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php similarity index 100% rename from Task/SplitJoinLineTask.php rename to src/Task/SplitJoinLineTask.php diff --git a/Task/StopTask.php b/src/Task/StopTask.php similarity index 100% rename from Task/StopTask.php rename to src/Task/StopTask.php diff --git a/Task/TransformerTask.php b/src/Task/TransformerTask.php similarity index 100% rename from Task/TransformerTask.php rename to src/Task/TransformerTask.php diff --git a/Task/Validation/ValidatorTask.php b/src/Task/Validation/ValidatorTask.php similarity index 100% rename from Task/Validation/ValidatorTask.php rename to src/Task/Validation/ValidatorTask.php diff --git a/Transformer/ArrayElementTransformer.php b/src/Transformer/ArrayElementTransformer.php similarity index 100% rename from Transformer/ArrayElementTransformer.php rename to src/Transformer/ArrayElementTransformer.php diff --git a/Transformer/ArrayFilterTransformer.php b/src/Transformer/ArrayFilterTransformer.php similarity index 100% rename from Transformer/ArrayFilterTransformer.php rename to src/Transformer/ArrayFilterTransformer.php diff --git a/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php similarity index 100% rename from Transformer/ArrayFirstTransformer.php rename to src/Transformer/ArrayFirstTransformer.php diff --git a/Transformer/ArrayLastTransformer.php b/src/Transformer/ArrayLastTransformer.php similarity index 100% rename from Transformer/ArrayLastTransformer.php rename to src/Transformer/ArrayLastTransformer.php diff --git a/Transformer/ArrayMapTransformer.php b/src/Transformer/ArrayMapTransformer.php similarity index 100% rename from Transformer/ArrayMapTransformer.php rename to src/Transformer/ArrayMapTransformer.php diff --git a/Transformer/ArrayUnsetTransformer.php b/src/Transformer/ArrayUnsetTransformer.php similarity index 100% rename from Transformer/ArrayUnsetTransformer.php rename to src/Transformer/ArrayUnsetTransformer.php diff --git a/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php similarity index 100% rename from Transformer/CachedTransformer.php rename to src/Transformer/CachedTransformer.php diff --git a/Transformer/CallbackTransformer.php b/src/Transformer/CallbackTransformer.php similarity index 100% rename from Transformer/CallbackTransformer.php rename to src/Transformer/CallbackTransformer.php diff --git a/Transformer/CastTransformer.php b/src/Transformer/CastTransformer.php similarity index 100% rename from Transformer/CastTransformer.php rename to src/Transformer/CastTransformer.php diff --git a/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php similarity index 100% rename from Transformer/ConditionTrait.php rename to src/Transformer/ConditionTrait.php diff --git a/Transformer/ConfigurableTransformerInterface.php b/src/Transformer/ConfigurableTransformerInterface.php similarity index 100% rename from Transformer/ConfigurableTransformerInterface.php rename to src/Transformer/ConfigurableTransformerInterface.php diff --git a/Transformer/ConstantTransformer.php b/src/Transformer/ConstantTransformer.php similarity index 100% rename from Transformer/ConstantTransformer.php rename to src/Transformer/ConstantTransformer.php diff --git a/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php similarity index 100% rename from Transformer/ConvertValueTransformer.php rename to src/Transformer/ConvertValueTransformer.php diff --git a/Transformer/DateFormatTransformer.php b/src/Transformer/DateFormatTransformer.php similarity index 100% rename from Transformer/DateFormatTransformer.php rename to src/Transformer/DateFormatTransformer.php diff --git a/Transformer/DateParserTransformer.php b/src/Transformer/DateParserTransformer.php similarity index 100% rename from Transformer/DateParserTransformer.php rename to src/Transformer/DateParserTransformer.php diff --git a/Transformer/DebugTransformer.php b/src/Transformer/DebugTransformer.php similarity index 100% rename from Transformer/DebugTransformer.php rename to src/Transformer/DebugTransformer.php diff --git a/Transformer/DefaultTransformer.php b/src/Transformer/DefaultTransformer.php similarity index 100% rename from Transformer/DefaultTransformer.php rename to src/Transformer/DefaultTransformer.php diff --git a/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php similarity index 100% rename from Transformer/DenormalizeTransformer.php rename to src/Transformer/DenormalizeTransformer.php diff --git a/Transformer/EvaluatorTransformer.php b/src/Transformer/EvaluatorTransformer.php similarity index 100% rename from Transformer/EvaluatorTransformer.php rename to src/Transformer/EvaluatorTransformer.php diff --git a/Transformer/ExplodeTransformer.php b/src/Transformer/ExplodeTransformer.php similarity index 100% rename from Transformer/ExplodeTransformer.php rename to src/Transformer/ExplodeTransformer.php diff --git a/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php similarity index 100% rename from Transformer/ExpressionLanguageMapTransformer.php rename to src/Transformer/ExpressionLanguageMapTransformer.php diff --git a/Transformer/GenericTransformer.php b/src/Transformer/GenericTransformer.php similarity index 100% rename from Transformer/GenericTransformer.php rename to src/Transformer/GenericTransformer.php diff --git a/Transformer/HashTransformer.php b/src/Transformer/HashTransformer.php similarity index 100% rename from Transformer/HashTransformer.php rename to src/Transformer/HashTransformer.php diff --git a/Transformer/ImplodeTransformer.php b/src/Transformer/ImplodeTransformer.php similarity index 100% rename from Transformer/ImplodeTransformer.php rename to src/Transformer/ImplodeTransformer.php diff --git a/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php similarity index 100% rename from Transformer/MappingTransformer.php rename to src/Transformer/MappingTransformer.php diff --git a/Transformer/MultiReplaceTransformer.php b/src/Transformer/MultiReplaceTransformer.php similarity index 100% rename from Transformer/MultiReplaceTransformer.php rename to src/Transformer/MultiReplaceTransformer.php diff --git a/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php similarity index 100% rename from Transformer/NormalizeTransformer.php rename to src/Transformer/NormalizeTransformer.php diff --git a/Transformer/PregFilterTransformer.php b/src/Transformer/PregFilterTransformer.php similarity index 100% rename from Transformer/PregFilterTransformer.php rename to src/Transformer/PregFilterTransformer.php diff --git a/Transformer/PropertyAccessorTransformer.php b/src/Transformer/PropertyAccessorTransformer.php similarity index 100% rename from Transformer/PropertyAccessorTransformer.php rename to src/Transformer/PropertyAccessorTransformer.php diff --git a/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/RecursivePropertySetterTransformer.php similarity index 100% rename from Transformer/RecursivePropertySetterTransformer.php rename to src/Transformer/RecursivePropertySetterTransformer.php diff --git a/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php similarity index 100% rename from Transformer/RulesTransformer.php rename to src/Transformer/RulesTransformer.php diff --git a/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php similarity index 100% rename from Transformer/SlugifyTransformer.php rename to src/Transformer/SlugifyTransformer.php diff --git a/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php similarity index 100% rename from Transformer/SprintfTransformer.php rename to src/Transformer/SprintfTransformer.php diff --git a/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php similarity index 100% rename from Transformer/TransformerInterface.php rename to src/Transformer/TransformerInterface.php diff --git a/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php similarity index 100% rename from Transformer/TransformerTrait.php rename to src/Transformer/TransformerTrait.php diff --git a/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php similarity index 100% rename from Transformer/TrimTransformer.php rename to src/Transformer/TrimTransformer.php diff --git a/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php similarity index 100% rename from Transformer/TypeSetterTransformer.php rename to src/Transformer/TypeSetterTransformer.php diff --git a/Transformer/UnsetTransformer.php b/src/Transformer/UnsetTransformer.php similarity index 100% rename from Transformer/UnsetTransformer.php rename to src/Transformer/UnsetTransformer.php diff --git a/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php similarity index 100% rename from Transformer/WrapperTransformer.php rename to src/Transformer/WrapperTransformer.php diff --git a/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php similarity index 100% rename from Transformer/Xml/XpathEvaluatorTransformer.php rename to src/Transformer/Xml/XpathEvaluatorTransformer.php diff --git a/Validator/ConstraintLoader.php b/src/Validator/ConstraintLoader.php similarity index 100% rename from Validator/ConstraintLoader.php rename to src/Validator/ConstraintLoader.php diff --git a/hooks/build b/src/hooks/build similarity index 100% rename from hooks/build rename to src/hooks/build diff --git a/Tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php similarity index 100% rename from Tests/AbstractProcessTest.php rename to tests/AbstractProcessTest.php diff --git a/Tests/BasicTest.php b/tests/BasicTest.php similarity index 100% rename from Tests/BasicTest.php rename to tests/BasicTest.php diff --git a/Tests/BlockingTaskTest.php b/tests/BlockingTaskTest.php similarity index 100% rename from Tests/BlockingTaskTest.php rename to tests/BlockingTaskTest.php diff --git a/Tests/CircularProcessTest.php b/tests/CircularProcessTest.php similarity index 100% rename from Tests/CircularProcessTest.php rename to tests/CircularProcessTest.php diff --git a/Tests/ContextTest.php b/tests/ContextTest.php similarity index 100% rename from Tests/ContextTest.php rename to tests/ContextTest.php diff --git a/Tests/EmptyProcessTest.php b/tests/EmptyProcessTest.php similarity index 100% rename from Tests/EmptyProcessTest.php rename to tests/EmptyProcessTest.php diff --git a/Tests/ExceptionManagementTest.php b/tests/ExceptionManagementTest.php similarity index 100% rename from Tests/ExceptionManagementTest.php rename to tests/ExceptionManagementTest.php diff --git a/Tests/FlushableTaskTest.php b/tests/FlushableTaskTest.php similarity index 100% rename from Tests/FlushableTaskTest.php rename to tests/FlushableTaskTest.php diff --git a/Tests/IterableTaskTest.php b/tests/IterableTaskTest.php similarity index 100% rename from Tests/IterableTaskTest.php rename to tests/IterableTaskTest.php diff --git a/Tests/MultiBranchProcessTest.php b/tests/MultiBranchProcessTest.php similarity index 100% rename from Tests/MultiBranchProcessTest.php rename to tests/MultiBranchProcessTest.php diff --git a/Tests/MultiWorkflowTest.php b/tests/MultiWorkflowTest.php similarity index 100% rename from Tests/MultiWorkflowTest.php rename to tests/MultiWorkflowTest.php diff --git a/Tests/ProcessManagerTest.php b/tests/ProcessManagerTest.php similarity index 100% rename from Tests/ProcessManagerTest.php rename to tests/ProcessManagerTest.php diff --git a/Tests/Task/ColumnAggregatorTaskTest.php b/tests/Task/ColumnAggregatorTaskTest.php similarity index 100% rename from Tests/Task/ColumnAggregatorTaskTest.php rename to tests/Task/ColumnAggregatorTaskTest.php diff --git a/Tests/Task/FilterTaskTest.php b/tests/Task/FilterTaskTest.php similarity index 100% rename from Tests/Task/FilterTaskTest.php rename to tests/Task/FilterTaskTest.php diff --git a/Tests/Task/ProcessExecutorTaskTest.php b/tests/Task/ProcessExecutorTaskTest.php similarity index 100% rename from Tests/Task/ProcessExecutorTaskTest.php rename to tests/Task/ProcessExecutorTaskTest.php diff --git a/Tests/Task/StopTaskTest.php b/tests/Task/StopTaskTest.php similarity index 100% rename from Tests/Task/StopTaskTest.php rename to tests/Task/StopTaskTest.php diff --git a/Tests/Task/TransformerTaskTest.php b/tests/Task/TransformerTaskTest.php similarity index 100% rename from Tests/Task/TransformerTaskTest.php rename to tests/Task/TransformerTaskTest.php diff --git a/Tests/Task/ValidatorTaskTest.php b/tests/Task/ValidatorTaskTest.php similarity index 100% rename from Tests/Task/ValidatorTaskTest.php rename to tests/Task/ValidatorTaskTest.php diff --git a/Tests/Transformer/ArrayFilterTransformerTest.php b/tests/Transformer/ArrayFilterTransformerTest.php similarity index 100% rename from Tests/Transformer/ArrayFilterTransformerTest.php rename to tests/Transformer/ArrayFilterTransformerTest.php diff --git a/Tests/Transformer/CallbackTransformerTest.php b/tests/Transformer/CallbackTransformerTest.php similarity index 100% rename from Tests/Transformer/CallbackTransformerTest.php rename to tests/Transformer/CallbackTransformerTest.php diff --git a/Tests/Transformer/DateTransformersTest.php b/tests/Transformer/DateTransformersTest.php similarity index 100% rename from Tests/Transformer/DateTransformersTest.php rename to tests/Transformer/DateTransformersTest.php diff --git a/Tests/Transformer/GenericTransformersTest.php b/tests/Transformer/GenericTransformersTest.php similarity index 100% rename from Tests/Transformer/GenericTransformersTest.php rename to tests/Transformer/GenericTransformersTest.php diff --git a/Tests/Transformer/HashTransformerTest.php b/tests/Transformer/HashTransformerTest.php similarity index 100% rename from Tests/Transformer/HashTransformerTest.php rename to tests/Transformer/HashTransformerTest.php diff --git a/Tests/Transformer/MappingTransformerTest.php b/tests/Transformer/MappingTransformerTest.php similarity index 100% rename from Tests/Transformer/MappingTransformerTest.php rename to tests/Transformer/MappingTransformerTest.php diff --git a/Tests/Transformer/RulesTransformerTest.php b/tests/Transformer/RulesTransformerTest.php similarity index 100% rename from Tests/Transformer/RulesTransformerTest.php rename to tests/Transformer/RulesTransformerTest.php diff --git a/Tests/Transformer/TransformerExceptionTest.php b/tests/Transformer/TransformerExceptionTest.php similarity index 100% rename from Tests/Transformer/TransformerExceptionTest.php rename to tests/Transformer/TransformerExceptionTest.php diff --git a/Tests/Transformer/TypeSetterTransformerTest.php b/tests/Transformer/TypeSetterTransformerTest.php similarity index 100% rename from Tests/Transformer/TypeSetterTransformerTest.php rename to tests/Transformer/TypeSetterTransformerTest.php diff --git a/Tests/Transformer/UnsetTransformerTest.php b/tests/Transformer/UnsetTransformerTest.php similarity index 100% rename from Tests/Transformer/UnsetTransformerTest.php rename to tests/Transformer/UnsetTransformerTest.php diff --git a/Tests/Transformer/XpathEvaluatorTransformerTest.php b/tests/Transformer/XpathEvaluatorTransformerTest.php similarity index 100% rename from Tests/Transformer/XpathEvaluatorTransformerTest.php rename to tests/Transformer/XpathEvaluatorTransformerTest.php From f8a1bd78aa8d8e0fad1fd4a162d39aa2ddc4b9b7 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 14 Mar 2023 20:06:46 +0100 Subject: [PATCH 165/304] only symfony 6 --- composer.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index cd51bc7f..e3ab1e1e 100644 --- a/composer.json +++ b/composer.json @@ -42,21 +42,21 @@ "ext-dom": "*", "ext-intl": "*", "ext-mbstring": "*", - "symfony/event-dispatcher": "^5.4|^6.0", "psr/cache": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", + "symfony/config": "^6.0", + "symfony/dependency-injection": "^6.0", + "symfony/event-dispatcher": "^6.0", + "symfony/form": "^6.0", + "symfony/framework-bundle": "^6.0", + "symfony/expression-language": "^6.0", "symfony/monolog-bundle": "~3.3", - "symfony/console": "^5.4|^6.0", - "symfony/options-resolver": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", + "symfony/console": "^6.0", + "symfony/options-resolver": "^6.0", + "symfony/process": "^6.0", + "symfony/property-access": "^6.0", + "symfony/serializer": "^6.0", + "symfony/validator": "^6.0", + "symfony/yaml": "^6.0", "league/flysystem-bundle": "^3.1" }, "require-dev": { From 6a7226ad82321688ba3cd1568a57ba61b7f19c44 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 23 Mar 2023 21:51:37 +0100 Subject: [PATCH 166/304] misc fixes --- .gitignore | 1 + composer.json | 12 ++- phpunit.xml.dist | 24 +++++ src/CleverAgeProcessBundle.php | 9 +- src/Command/ExecuteProcessCommand.php | 6 +- .../CleverAgeProcessExtension.php | 2 +- src/Registry/ProcessConfigurationRegistry.php | 15 ++- .../services/{command.yml => command.yaml} | 1 - .../config/services/{event.yml => event.yaml} | 0 ..._language.yml => expression_language.yaml} | 0 .../services/{logger.yml => logger.yaml} | 0 .../services/{manager.yml => manager.yaml} | 1 - .../services/{registry.yml => registry.yaml} | 1 - .../config/services/{task.yml => task.yaml} | 2 - .../{transformer.yml => transformer.yaml} | 3 +- .../migration/move_doctrine_to_addon.sh | 4 - .../migration/move_flysystem_to_addon.sh | 3 - src/Resources/migration/replace_deprecated.sh | 99 ------------------- tests/AbstractProcessTest.php | 4 +- 19 files changed, 52 insertions(+), 135 deletions(-) create mode 100644 phpunit.xml.dist rename src/Resources/config/services/{command.yml => command.yaml} (68%) rename src/Resources/config/services/{event.yml => event.yaml} (100%) rename src/Resources/config/services/{expression_language.yml => expression_language.yaml} (100%) rename src/Resources/config/services/{logger.yml => logger.yaml} (100%) rename src/Resources/config/services/{manager.yml => manager.yaml} (73%) rename src/Resources/config/services/{registry.yml => registry.yaml} (90%) rename src/Resources/config/services/{task.yml => task.yaml} (68%) rename src/Resources/config/services/{transformer.yml => transformer.yaml} (89%) delete mode 100644 src/Resources/migration/move_doctrine_to_addon.sh delete mode 100644 src/Resources/migration/move_flysystem_to_addon.sh delete mode 100644 src/Resources/migration/replace_deprecated.sh diff --git a/.gitignore b/.gitignore index 5a331df4..61f22ac1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /vendor-sf4 /vendor-sf5 .env +/phpunit.xml diff --git a/composer.json b/composer.json index e3ab1e1e..30c7187d 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,12 @@ ], "autoload": { "psr-4": { - "CleverAge\\ProcessBundle\\": "src" + "CleverAge\\ProcessBundle\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "CleverAge\\ProcessBundle\\Tests\\": "tests/" } }, "require": { @@ -45,7 +50,7 @@ "psr/cache": "^1|^2|^3", "symfony/config": "^6.0", "symfony/dependency-injection": "^6.0", - "symfony/event-dispatcher": "^6.0", + "symfony/event-dispatcher-contracts": "^3", "symfony/form": "^6.0", "symfony/framework-bundle": "^6.0", "symfony/expression-language": "^6.0", @@ -67,7 +72,8 @@ "phpstan/extension-installer": "*", "rector/rector": "*", "symplify/easy-coding-standard": "*", - "symplify/phpstan-rules": "*" + "symplify/phpstan-rules": "*", + "symfony/test-pack": "^1.1" }, "suggest": { "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..e0c32a1d --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + /tests + + + diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index f93be4bc..9e337912 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -27,12 +26,12 @@ class CleverAgeProcessBundle extends Bundle */ public function build(ContainerBuilder $container): void { + parent::build($container); + $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), - PassConfig::TYPE_BEFORE_OPTIMIZATION, - 0 + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') ); - $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); + $container->addCompilerPass(new CheckSerializerCompilerPass()); } } diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 25a29ed7..e4916886 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -87,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($input->getArgument('processCodes') as $code) { if (! $output->isQuiet()) { - $output->writeln("Starting process '{$code}'..."); + $output->writeln("Starting process '$code'..."); } // Execute each process @@ -95,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->handleOutputData($returnValue, $input, $output); if (! $output->isQuiet()) { - $output->writeln("Process '{$code}' executed successfully"); + $output->writeln("Process '$code' executed successfully"); } } @@ -109,7 +109,7 @@ protected function parseContextValues(InputInterface $input): array { $parser = new Parser(); - $pattern = '/([\w]+):(.*)/'; + $pattern = '/(\w+):(.*)/'; $contextValues = $input->getOption('context'); $context = []; foreach ($contextValues as $contextValue) { diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index 4dd6409a..fb0b3399 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -59,7 +59,7 @@ public function load(array $configs, ContainerBuilder $container): void /** * Recursively import config files into container */ - protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yml'): void + protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void { $finder = new Finder(); $finder->in($path) diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 6b02d8cf..4c8cba6d 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -21,6 +21,7 @@ use Psr\Log\LogLevel; use function array_key_exists; use function array_keys; +use function count; /** * Build and holds all the process configurations @@ -30,7 +31,7 @@ class ProcessConfigurationRegistry /** * @var ProcessConfiguration[] */ - protected $processConfigurations = []; + protected array $processConfigurations = []; public function __construct( protected array $rawConfiguration, @@ -73,13 +74,12 @@ protected function resolveConfiguration(string $processCode): void $rawProcessConfiguration = $this->rawConfiguration[$processCode]; /** @var TaskConfiguration[] $taskConfigurations */ $taskConfigurations = []; - /** @noinspection ForeachSourceInspection */ foreach ($rawProcessConfiguration['tasks'] as $taskCode => $rawTaskConfiguration) { - if ((is_countable($rawTaskConfiguration['errors']) ? \count($rawTaskConfiguration['errors']) : 0) > 0) { - if ((is_countable($rawTaskConfiguration['error_outputs']) ? \count( + if ((is_countable($rawTaskConfiguration['errors']) ? count($rawTaskConfiguration['errors']) : 0) > 0) { + if ((is_countable($rawTaskConfiguration['error_outputs']) ? count( $rawTaskConfiguration['error_outputs'] ) : 0) > 0) { - $m = "Don't define both 'errors' and 'error_outputs' for task {$taskCode}, these options "; + $m = "Don't define both 'errors' and 'error_outputs' for task $taskCode, these options "; $m .= "are the same, 'errors' is deprecated, just use the new one 'error_outputs'"; throw new LogicException($m); } @@ -150,10 +150,7 @@ protected function resolveConfiguration(string $processCode): void $this->processConfigurations[$processCode] = $processConfig; } - /** - * @param bool $isErrorBranch - */ - protected function markErrorBranch(TaskConfiguration $taskConfig, $isErrorBranch = true): void + protected function markErrorBranch(TaskConfiguration $taskConfig, bool $isErrorBranch = true): void { if ($taskConfig->isInErrorBranch() !== $isErrorBranch) { $taskConfig->setInErrorBranch($isErrorBranch); diff --git a/src/Resources/config/services/command.yml b/src/Resources/config/services/command.yaml similarity index 68% rename from src/Resources/config/services/command.yml rename to src/Resources/config/services/command.yaml index 65e75535..4c700e2f 100644 --- a/src/Resources/config/services/command.yml +++ b/src/Resources/config/services/command.yaml @@ -4,5 +4,4 @@ services: autowire: true autoconfigure: true bind: - $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' $container: '@service_container' diff --git a/src/Resources/config/services/event.yml b/src/Resources/config/services/event.yaml similarity index 100% rename from src/Resources/config/services/event.yml rename to src/Resources/config/services/event.yaml diff --git a/src/Resources/config/services/expression_language.yml b/src/Resources/config/services/expression_language.yaml similarity index 100% rename from src/Resources/config/services/expression_language.yml rename to src/Resources/config/services/expression_language.yaml diff --git a/src/Resources/config/services/logger.yml b/src/Resources/config/services/logger.yaml similarity index 100% rename from src/Resources/config/services/logger.yml rename to src/Resources/config/services/logger.yaml diff --git a/src/Resources/config/services/manager.yml b/src/Resources/config/services/manager.yaml similarity index 73% rename from src/Resources/config/services/manager.yml rename to src/Resources/config/services/manager.yaml index 8ba5e8e6..a4360642 100644 --- a/src/Resources/config/services/manager.yml +++ b/src/Resources/config/services/manager.yaml @@ -3,7 +3,6 @@ services: autowire: true public: false arguments: - $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' $container: '@service_container' CleverAge\ProcessBundle\Context\ContextualOptionResolver: diff --git a/src/Resources/config/services/registry.yml b/src/Resources/config/services/registry.yaml similarity index 90% rename from src/Resources/config/services/registry.yml rename to src/Resources/config/services/registry.yaml index 0afd64f5..7e0ec1aa 100644 --- a/src/Resources/config/services/registry.yml +++ b/src/Resources/config/services/registry.yaml @@ -1,6 +1,5 @@ services: CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry: - public: false arguments: - ~ - ~ diff --git a/src/Resources/config/services/task.yml b/src/Resources/config/services/task.yaml similarity index 68% rename from src/Resources/config/services/task.yml rename to src/Resources/config/services/task.yaml index 983e442a..61e64bf7 100644 --- a/src/Resources/config/services/task.yml +++ b/src/Resources/config/services/task.yaml @@ -6,5 +6,3 @@ services: shared: false tags: - { name: monolog.logger, channel: cleverage_process_task } - bind: - $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' diff --git a/src/Resources/config/services/transformer.yml b/src/Resources/config/services/transformer.yaml similarity index 89% rename from src/Resources/config/services/transformer.yml rename to src/Resources/config/services/transformer.yaml index cdb44895..63741e56 100644 --- a/src/Resources/config/services/transformer.yml +++ b/src/Resources/config/services/transformer.yaml @@ -1,7 +1,8 @@ services: _defaults: autowire: true - public: false + autoconfigure: true + public: true bind: $language: '@cleverage_process.expression_language' diff --git a/src/Resources/migration/move_doctrine_to_addon.sh b/src/Resources/migration/move_doctrine_to_addon.sh deleted file mode 100644 index 8440915e..00000000 --- a/src/Resources/migration/move_doctrine_to_addon.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Database/CleverAge\\DoctrineProcessBundle\\Task\\Database/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\Doctrine/CleverAge\\DoctrineProcessBundle\\Task\\EntityManager/g' {} \; diff --git a/src/Resources/migration/move_flysystem_to_addon.sh b/src/Resources/migration/move_flysystem_to_addon.sh deleted file mode 100644 index 5dc78064..00000000 --- a/src/Resources/migration/move_flysystem_to_addon.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\File\\FileFetchTask/CleverAge\\FlysystemProcessBundle\\Task\\FileFetchTask/g' {} \; diff --git a/src/Resources/migration/replace_deprecated.sh b/src/Resources/migration/replace_deprecated.sh deleted file mode 100644 index 41dfc948..00000000 --- a/src/Resources/migration/replace_deprecated.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash - -find . -type f -exec sed -i 's/cleverage_process.event_listener.data_queue/CleverAge\\ProcessBundle\\EventListener\\DataQueueEventListener/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.manager.process/CleverAge\\ProcessBundle\\Manager\\ProcessManager/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.registry.process_configuration/CleverAge\\ProcessBundle\\Registry\\ProcessConfigurationRegistry/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.registry.transformer/CleverAge\\ProcessBundle\\Registry\\TransformerRegistry/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.dummy/CleverAge\\ProcessBundle\\Task\\DummyTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.constant_output/CleverAge\\ProcessBundle\\Task\\ConstantOutputTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.constant_iterable_output/CleverAge\\ProcessBundle\\Task\\ConstantIterableOutputTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.yaml_reader/CleverAge\\ProcessBundle\\Task\\File\\YamlReaderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.debug/CleverAge\\ProcessBundle\\Task\\Debug\\DebugTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.die/CleverAge\\ProcessBundle\\Task\\Debug\\DieTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.logger/CleverAge\\ProcessBundle\\Task\\Reporting\\LoggerTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.validator/CleverAge\\ProcessBundle\\Task\\Validation\\ValidatorTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.serializer/CleverAge\\ProcessBundle\\Task\\Serialization\\SerializerTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.normalizer/CleverAge\\ProcessBundle\\Task\\Serialization\\NormalizerTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.denormalizer/CleverAge\\ProcessBundle\\Task\\Serialization\\DenormalizerTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.property_setter/CleverAge\\ProcessBundle\\Task\\PropertySetterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.property_getter/CleverAge\\ProcessBundle\\Task\\PropertyGetterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.csv_reader/CleverAge\\ProcessBundle\\Task\\File\\Csv\\CsvReaderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.csv_writer/CleverAge\\ProcessBundle\\Task\\File\\Csv\\CsvWriterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.csv_input_reader/CleverAge\\ProcessBundle\\Task\\File\\Csv\\InputCsvReaderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.csv_splitter/CleverAge\\ProcessBundle\\Task\\File\\Csv\\CsvSplitterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.database_reader/CleverAge\\ProcessBundle\\Task\\Database\\DatabaseReaderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.database_updater/CleverAge\\ProcessBundle\\Task\\Database\\DatabaseUpdaterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.doctrine_reader/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineReaderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.doctrine_writer/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineWriterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.doctrine_detacher/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineDetacherTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.doctrine_remover/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineRemoverTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.stat_counter/CleverAge\\ProcessBundle\\Task\\Reporting\\StatCounterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.advanced_stat_counter/CleverAge\\ProcessBundle\\Task\\Reporting\\AdvancedStatCounterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.transformer/CleverAge\\ProcessBundle\\Task\\TransformerTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.process_launcher/CleverAge\\ProcessBundle\\Task\\Process\\ProcessLauncherTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.folder_browser/CleverAge\\ProcessBundle\\Task\\File\\FolderBrowserTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.file_remover/CleverAge\\ProcessBundle\\Task\\File\\FileRemoverTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.file_mover/CleverAge\\ProcessBundle\\Task\\File\\FileMoverTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.file_writer/CleverAge\\ProcessBundle\\Task\\File\\FileWriterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.aggregate_iterable/CleverAge\\ProcessBundle\\Task\\AggregateIterableTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.filter/CleverAge\\ProcessBundle\\Task\\FilterTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.event_dispatcher/CleverAge\\ProcessBundle\\Task\\Event\\EventDispatcherTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.input_iterator/CleverAge\\ProcessBundle\\Task\\InputIteratorTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.input_aggregator/CleverAge\\ProcessBundle\\Task\\InputAggregatorTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.error_forwarder/CleverAge\\ProcessBundle\\Task\\Debug\\ErrorForwarderTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.skip_empty/CleverAge\\ProcessBundle\\Task\\SkipEmptyTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.stop/CleverAge\\ProcessBundle\\Task\\StopTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.array_merge/CleverAge\\ProcessBundle\\Task\\ArrayMergeTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.process_executor/CleverAge\\ProcessBundle\\Task\\Process\\ProcessExecutorTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.file_fetch/CleverAge\\ProcessBundle\\Task\\File\\FileFetchTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.task.row_aggregator/CleverAge\\ProcessBundle\\Task\\RowAggregatorTask/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.mapping/CleverAge\\ProcessBundle\\Transformer\\MappingTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.slugify/CleverAge\\ProcessBundle\\Transformer\\SlugifyTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.explode/CleverAge\\ProcessBundle\\Transformer\\ExplodeTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.implode/CleverAge\\ProcessBundle\\Transformer\\ImplodeTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.trim/CleverAge\\ProcessBundle\\Transformer\\TrimTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.sprintf/CleverAge\\ProcessBundle\\Transformer\\SprintfTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.array_map/CleverAge\\ProcessBundle\\Transformer\\ArrayMapTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.array_first/CleverAge\\ProcessBundle\\Transformer\\ArrayFirstTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.property_accessor/CleverAge\\ProcessBundle\\Transformer\\PropertyAccessorTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.recursive_property_setter/CleverAge\\ProcessBundle\\Transformer\\RecursivePropertySetterTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.denormalize/CleverAge\\ProcessBundle\\Transformer\\DenormalizeTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.normalize/CleverAge\\ProcessBundle\\Transformer\\NormalizeTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.convert_value/CleverAge\\ProcessBundle\\Transformer\\ConvertValueTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.callback/CleverAge\\ProcessBundle\\Transformer\\CallbackTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.wrapper/CleverAge\\ProcessBundle\\Transformer\\WrapperTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.evaluator/CleverAge\\ProcessBundle\\Transformer\\EvaluatorTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.preg_filter/CleverAge\\ProcessBundle\\Transformer\\PregFilterTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.date_format/CleverAge\\ProcessBundle\\Transformer\\DateFormatTransformer/g' {} \; -find . -type f -exec sed -i 's/cleverage_process.transformer.default/CleverAge\\ProcessBundle\\Transformer\\DefaultTransformer/g' {} \; - - -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DatabaseReaderTask/CleverAge\\ProcessBundle\\Task\\Database\\DatabaseReaderTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DatabaseUpdaterTask/CleverAge\\ProcessBundle\\Task\\Database\\DatabaseUpdaterTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DebugTask/CleverAge\\ProcessBundle\\Task\\Debug\\DebugTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DieTask/CleverAge\\ProcessBundle\\Task\\Debug\\DieTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\ErrorForwarderTask/CleverAge\\ProcessBundle\\Task\\Debug\\ErrorForwarderTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\AbstractDoctrineQueryTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\AbstractDoctrineQueryTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\AbstractDoctrineTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\AbstractDoctrineTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DoctrineDetacherTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineDetacherTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DoctrineReaderTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineReaderTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DoctrineRemoverTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineRemoverTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DoctrineWriterTask/CleverAge\\ProcessBundle\\Task\\Doctrine\\DoctrineWriterTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\EventDispatcherTask/CleverAge\\ProcessBundle\\Task\\Event\\EventDispatcherTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\AbstractCsvResourceTask/CleverAge\\ProcessBundle\\Task\\AbstractCsvResourceTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\AbstractCsvTask/CleverAge\\ProcessBundle\\Task\\File\\Csv\\AbstractCsvTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\CsvReaderTask/CleverAge\\ProcessBundle\\Task\\File\\Csv\\CsvReaderTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\CsvWriterTask/CleverAge\\ProcessBundle\\Task\\File\\Csv\\CsvWriterTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\FileMoverTask/CleverAge\\ProcessBundle\\Task\\File\\FileMoverTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\FileRemoverTask/CleverAge\\ProcessBundle\\Task\\File\\FileRemoverTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\FileWriterTask/CleverAge\\ProcessBundle\\Task\\File\\FileWriterTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\FolderBrowserTask/CleverAge\\ProcessBundle\\Task\\File\\FolderBrowserTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\YamlReaderTask/CleverAge\\ProcessBundle\\Task\\File\\YamlReaderTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\ProcessExecutorTask/CleverAge\\ProcessBundle\\Task\\Process\\ProcessExecutorTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\ProcessLauncherTask/CleverAge\\ProcessBundle\\Task\\Process\\ProcessLauncherTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\LoggerTask/CleverAge\\ProcessBundle\\Task\\Reporting\\LoggerTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\StatCounterTask/CleverAge\\ProcessBundle\\Task\\Reporting\\StatCounterTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\DenormalizerTask/CleverAge\\ProcessBundle\\Task\\Serialization\\DenormalizerTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\NormalizerTask/CleverAge\\ProcessBundle\\Task\\Serialization\\NormalizerTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\SerializerTask/CleverAge\\ProcessBundle\\Task\\Serialization\\SerializerTask/g' {} \; -find . -type f -exec sed -i 's/CleverAge\\ProcessBundle\\Task\\ValidatorTask/CleverAge\\ProcessBundle\\Task\\Validation\\ValidatorTask/g' {} \; diff --git a/tests/AbstractProcessTest.php b/tests/AbstractProcessTest.php index bb2997e8..75e07ce8 100644 --- a/tests/AbstractProcessTest.php +++ b/tests/AbstractProcessTest.php @@ -100,9 +100,9 @@ protected function assertDataQueue(array $expected, string $processName, bool $c * * Compatibility backport for symfony/phpunit-bridge that should work with v3 or v4 */ - protected function getContainer(): ContainerInterface + protected static function getContainer(): ContainerInterface { - if (isset(self::getContainer())) { + if (null !== self::getContainer()) { return self::getContainer(); } From 88c871c429374cba077c2e13bb62f2acd464e491 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 23 Mar 2023 22:07:45 +0100 Subject: [PATCH 167/304] misc fixes --- src/Command/ExecuteProcessCommand.php | 3 ++- src/Command/ListProcessCommand.php | 3 ++- src/Command/ProcessHelpCommand.php | 3 ++- src/Logger/AbstractProcessor.php | 25 +++++++++++------- src/Logger/TaskProcessor.php | 17 +++++++----- src/Logger/TransformerProcessor.php | 17 +++++++----- src/Manager/ProcessManager.php | 32 ++++++++++++++++------- src/Task/GroupByAggregateIterableTask.php | 3 +-- 8 files changed, 66 insertions(+), 37 deletions(-) diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index e4916886..ab1e3088 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -31,6 +31,8 @@ */ class ExecuteProcessCommand extends Command { + protected static $defaultName = 'cleverage:process:execute'; + final public const OUTPUT_STDOUT = '-'; final public const OUTPUT_FORMAT_DUMP = 'dump'; @@ -46,7 +48,6 @@ public function __construct( protected function configure() { - $this->setName('cleverage:process:execute'); $this->addArgument( 'processCodes', InputArgument::IS_ARRAY | InputArgument::REQUIRED, diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index 76af0cc9..9378bcd8 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -25,6 +25,8 @@ */ class ListProcessCommand extends Command { + protected static $defaultName = 'cleverage:process:list'; + protected static $defaultDescription = 'List defined process'; public function __construct( @@ -73,7 +75,6 @@ public function maxMessageLengthFilter($max, array $message): int protected function configure() { - $this->setName('cleverage:process:list'); $this->addOption('all', 'a', InputOption::VALUE_NONE, 'Shows all processes (including hidden ones)'); } diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 8fc33eac..2f191e76 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -37,6 +37,8 @@ */ class ProcessHelpCommand extends Command { + protected static $defaultName = 'cleverage:process:help'; + protected const CHAR_DOWN = '│'; protected const CHAR_MERGE = '┘'; @@ -70,7 +72,6 @@ public function __construct( protected function configure() { - $this->setName('cleverage:process:help'); $this->addArgument('process_code', InputArgument::REQUIRED, 'The code of the process'); } diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index d2ec2f9f..0415b12e 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -14,6 +14,7 @@ namespace CleverAge\ProcessBundle\Logger; use CleverAge\ProcessBundle\Manager\ProcessManager; +use Monolog\LogRecord; class AbstractProcessor { @@ -22,20 +23,24 @@ public function __construct( ) { } - /** - * @return array - */ - public function __invoke(array $record) + public function __invoke(LogRecord $record): LogRecord { - if (array_key_exists('context', $record) - && $record['context']) { - $record['context'] = $this->normalizeRecordData($record['context']); + if (!empty($record->context)) { + $context = $this->normalizeRecordData($record->context); + $record = new LogRecord( + $record->datetime, + $record->channel, + $record->level, + $record->message, + $context, + $record->extra, + $record->formatted + ); } - $this->processManager->getProcessHistory(); - $recordExtra = array_key_exists('extra', $record) ? $record['extra'] : []; + $recordExtra = $record->extra; $this->addProcessInfoToRecord($recordExtra); - $record['extra'] = $recordExtra; + $record->extra = $recordExtra; return $record; } diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index 3c695955..5ce18164 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -13,18 +13,23 @@ namespace CleverAge\ProcessBundle\Logger; +use Monolog\LogRecord; + +/** + * Class TaskProcessor + * + * @package CleverAge\ProcessBundle\Logger + * @author Madeline Veyrenc + */ class TaskProcessor extends AbstractProcessor { - /** - * @return array - */ - public function __invoke(array $record) + public function __invoke(LogRecord $record): LogRecord { $record = parent::__invoke($record); - $recordExtra = array_key_exists('extra', $record) ? $record['extra'] : []; + $recordExtra = $record->extra; $this->addTaskInfoToRecord($recordExtra); - $record['extra'] = $recordExtra; + $record->extra = $recordExtra; return $record; } diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index 4aff866d..dd9d58a7 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -13,18 +13,23 @@ namespace CleverAge\ProcessBundle\Logger; +use Monolog\LogRecord; + +/** + * Class TransformerProcessor + * + * @package CleverAge\ProcessBundle\Logger + * @author Madeline Veyrenc + */ class TransformerProcessor extends AbstractProcessor { - /** - * @return array - */ - public function __invoke(array $record) + public function __invoke(LogRecord $record): LogRecord { $record = parent::__invoke($record); - $recordExtra = array_key_exists('extra', $record) ? $record['extra'] : []; + $recordExtra = $record->extra; $this->addTaskInfoToRecord($recordExtra); - $record['extra'] = $recordExtra; + $record->extra = $recordExtra; return $record; } diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 4adb3b9d..a4480bb2 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -32,9 +32,13 @@ use Psr\EventDispatcher\EventDispatcherInterface; use RuntimeException; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\ErrorHandler\Error\FatalError; use Throwable; use UnexpectedValueException; +use function count; +use function in_array; + /** * Execute processes */ @@ -145,11 +149,10 @@ protected function doExecute(string $processCode, mixed $input = null, array $co } // Resolve task from main branch, starting by the end - /** @var TaskConfiguration[] $taskList */ $taskList = array_reverse($processConfiguration->getTaskConfigurations()); $allowedTasks = $processConfiguration->getMainTaskGroup(); foreach ($taskList as $taskConfiguration) { - if (\in_array($taskConfiguration->getCode(), $allowedTasks, true)) { + if (in_array($taskConfiguration->getCode(), $allowedTasks, true)) { $this->resolve($taskConfiguration); } } @@ -229,7 +232,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = $taskConfiguration; if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP - && (\count($taskConfiguration->getErrorOutputs())) > 0) { + && (count($taskConfiguration->getErrorOutputs())) > 0) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); @@ -237,8 +240,8 @@ protected function initialize(TaskConfiguration $taskConfiguration): void // @todo Refactor this using a Registry with this feature: // https://symfony.com/doc/current/service_container/service_subscribers_locators.html $serviceReference = $taskConfiguration->getServiceReference(); - if (str_starts_with((string) $serviceReference, '@')) { - $task = $this->container->get(ltrim((string) $serviceReference, '@')); + if (str_starts_with($serviceReference, '@')) { + $task = $this->container->get(ltrim($serviceReference, '@')); } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { @@ -303,7 +306,16 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF $m .= " during process {$state->getTaskConfiguration() ->getCode()}"; $m .= " with message: '{$exception->getMessage()}'.\n"; - throw new RuntimeException($m, -1, $exception); + throw new FatalError( + $m, + -1, + [ + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'type' => 500, + 'message' => $exception->getMessage() + ] + ); } return; @@ -392,7 +404,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e $this->processLogger->debug("Flushing task {$taskConfiguration->getCode()}"); $task->flush($state); } else { - throw new UnexpectedValueException("Unknown execution flag: {$executionFlag}"); + throw new UnexpectedValueException("Unknown execution flag: $executionFlag"); } $exception = $state->getException(); @@ -544,7 +556,7 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check multi-branch processes foreach ($taskConfigurations as $taskConfiguration) { - if (! \in_array($taskConfiguration->getCode(), $mainTaskList, true)) { + if (! in_array($taskConfiguration->getCode(), $mainTaskList, true)) { // We won't throw an error to ease development... but there must be some kind of warning $state = $taskConfiguration->getState(); $logContext = [ @@ -560,14 +572,14 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check coherence for entry/end points $processConfiguration->getEndPoint(); - if ($entryPoint && ! \in_array($entryPoint->getCode(), $mainTaskList, true)) { + if ($entryPoint && ! in_array($entryPoint->getCode(), $mainTaskList, true)) { throw InvalidProcessConfigurationException::createNotInMain( $processConfiguration, $entryPoint, $mainTaskList ); } - if ($endPoint && ! \in_array($endPoint->getCode(), $mainTaskList, true)) { + if ($endPoint && ! in_array($endPoint->getCode(), $mainTaskList, true)) { throw InvalidProcessConfigurationException::createNotInMain( $processConfiguration, $endPoint, diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 619e7ad4..b221b508 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -25,12 +25,11 @@ class GroupByAggregateIterableTask extends AbstractConfigurableTask implements B /** * @var array */ - protected $result; + protected array $result = []; public function __construct( protected PropertyAccessorInterface $accessor ) { - $this->result = []; } public function execute(ProcessState $state): void From f2b16161852dc549838bdf4b8d736c092a4e2255 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 23 Mar 2023 22:10:42 +0100 Subject: [PATCH 168/304] misc fixes --- src/Model/AbstractConfigurableTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 6a7a938f..b7639efd 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -21,7 +21,7 @@ */ abstract class AbstractConfigurableTask implements InitializableTaskInterface { - protected ?array $options; + protected ?array $options = null; /** * Only validate the options at initialization, ensuring that the task will not fail at runtime From 094177de2397e1724457fa2ae4a81c01a7620841 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 23 Mar 2023 22:15:24 +0100 Subject: [PATCH 169/304] misc fixes --- src/Command/ExecuteProcessCommand.php | 4 ++-- src/Command/ListProcessCommand.php | 6 ++---- src/Command/ProcessHelpCommand.php | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index ab1e3088..6a91e122 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -18,6 +18,7 @@ use CleverAge\ProcessBundle\Manager\ProcessManager; use InvalidArgumentException; use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -29,10 +30,9 @@ /** * Run a process from the command line interface */ +#[AsCommand(name: 'cleverage:process:execute', description: 'Execute a process',)] class ExecuteProcessCommand extends Command { - protected static $defaultName = 'cleverage:process:execute'; - final public const OUTPUT_STDOUT = '-'; final public const OUTPUT_FORMAT_DUMP = 'dump'; diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index 9378bcd8..97816042 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -15,6 +15,7 @@ use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -23,12 +24,9 @@ /** * List all configured processes */ +#[AsCommand(name: 'cleverage:process:list', description: 'List defined processes',)] class ListProcessCommand extends Command { - protected static $defaultName = 'cleverage:process:list'; - - protected static $defaultDescription = 'List defined process'; - public function __construct( protected ProcessConfigurationRegistry $processConfigRegistry ) { diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 2f191e76..1ee87fb7 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -24,6 +24,7 @@ use CleverAge\ProcessBundle\Task\Process\ProcessLauncherTask; use InvalidArgumentException; use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Input\InputArgument; @@ -35,10 +36,9 @@ * Describe a process configuration * This is a POC, waiting to evolve properly */ +#[AsCommand(name: 'cleverage:process:help', description: 'Describe a process',)] class ProcessHelpCommand extends Command { - protected static $defaultName = 'cleverage:process:help'; - protected const CHAR_DOWN = '│'; protected const CHAR_MERGE = '┘'; @@ -61,8 +61,6 @@ class ProcessHelpCommand extends Command protected const INDENT_SIZE = 4; - protected static $defaultDescription = 'Describe the process'; - public function __construct( protected ProcessConfigurationRegistry $processConfigRegistry, protected ContainerInterface $container From a6afc60f86f85f2d8d666f89c1114549e09dbcc7 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 23 Mar 2023 22:22:37 +0100 Subject: [PATCH 170/304] misc fixes --- src/Command/ExecuteProcessCommand.php | 6 ++- src/Command/ListProcessCommand.php | 56 +++++++-------------- src/Command/ProcessHelpCommand.php | 70 +++++++++++++-------------- 3 files changed, 56 insertions(+), 76 deletions(-) diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 6a91e122..605c0517 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -27,6 +27,8 @@ use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; +use function is_array; + /** * Run a process from the command line interface */ @@ -46,7 +48,7 @@ public function __construct( parent::__construct(); } - protected function configure() + protected function configure(): void { $this->addArgument( 'processCodes', @@ -148,7 +150,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { // JsonStreamFile::writeLine only takes an array... // TODO how to handle other cases ? - if (\is_array($data)) { + if (is_array($data)) { $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); $outputFile->writeLine($data); } diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index 97816042..56264089 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -20,6 +20,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use function array_reduce; +use function count; +use function max; +use function usort; /** * List all configured processes @@ -33,45 +37,27 @@ public function __construct( parent::__construct(); } - /** - * Counter callback for public processes - * - * @param int $sum - */ - public function publicProcessCounter($sum, ProcessConfiguration $processConfiguration): int + public function publicProcessCounter(int $sum, ProcessConfiguration $processConfiguration): int { return $sum + ($processConfiguration->isPublic() ? 1 : 0); } - /** - * Counter callback for private processes - * - * @param int $sum - */ - public function privateProcessCounter($sum, ProcessConfiguration $processConfiguration): int + public function privateProcessCounter(int $sum, ProcessConfiguration $processConfiguration): int { return $sum + ($processConfiguration->isPrivate() ? 1 : 0); } - /** - * Sorter callback for process codes - */ public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b): int { return $a->getCode() <=> $b->getCode(); } - /** - * Filter callback to find max message length - * - * @param int $max - */ - public function maxMessageLengthFilter($max, array $message): int + public function maxMessageLengthFilter(int $max, array $message): int { - return \max($max, strlen($this->filterOutTags($message['output']))); + return max($max, strlen($this->filterOutTags($message['output']))); } - protected function configure() + protected function configure(): void { $this->addOption('all', 'a', InputOption::VALUE_NONE, 'Shows all processes (including hidden ones)'); } @@ -79,19 +65,19 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output): int { $processConfigurations = $this->processConfigRegistry->getProcessConfigurations(); - \usort($processConfigurations, $this->processSorter(...)); + usort($processConfigurations, $this->processSorter(...)); - $publicCount = \array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); - $privateCount = \array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); + $publicCount = array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); + $privateCount = array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); $output->writeln( - "There are {$publicCount} process configurations defined (and {$privateCount} private) :" + "There are $publicCount process configurations defined (and $privateCount private) :" ); $messages = []; foreach ($processConfigurations as $processConfiguration) { if ($processConfiguration->isPublic() || $input->getOption('all')) { - $countTasks = \count($processConfiguration->getTaskConfigurations()); - $message = " - {$processConfiguration->getCode()} with {$countTasks} tasks"; + $countTasks = count($processConfiguration->getTaskConfigurations()); + $message = " - {$processConfiguration->getCode()} with $countTasks tasks"; if ($processConfiguration->isPrivate()) { $message .= ' (private)'; @@ -105,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // Add process descriptions at a fixed position - $maxMessageLength = \array_reduce($messages, $this->maxMessageLengthFilter(...), 0); + $maxMessageLength = array_reduce($messages, $this->maxMessageLengthFilter(...), 0); $outputMessages = []; foreach ($messages as $message) { /** @var ProcessConfiguration $processConfiguration */ @@ -128,12 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } - /** - * Returns a padded message (without counting metadata) - * - * @param int $length - */ - protected function padMessage(string $message, $length = 80): string + protected function padMessage(string $message, int $length = 80): string { $currentLen = strlen($this->filterOutTags($message)); if ($currentLen < $length) { @@ -143,9 +124,6 @@ protected function padMessage(string $message, $length = 80): string return $message; } - /** - * Filter out tags used in console outputs - */ protected function filterOutTags(string $string): string { return preg_replace('/<[^<>]*>/', '', $string); diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 1ee87fb7..a81793d1 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -32,6 +32,12 @@ use Symfony\Component\Console\Output\OutputInterface; use UnexpectedValueException; +use function array_slice; +use function count; +use function in_array; +use function is_callable; +use function is_string; + /** * Describe a process configuration * This is a POC, waiting to evolve properly @@ -68,7 +74,7 @@ public function __construct( parent::__construct(); } - protected function configure() + protected function configure(): void { $this->addArgument('process_code', InputArgument::REQUIRED, 'The code of the process'); } @@ -106,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $taskList = $process->getMainTaskGroup(); $remainingTasks = $taskList; - $totalBranches = \count($taskList); + $totalBranches = count($taskList); for ($i = 0; $i < $totalBranches; $i++) { // Find the best task to display $nextTaskCode = $this->findBestNextTask($branches, $remainingTasks, $process); @@ -120,7 +126,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $branches = array_filter($branches); if (! empty($branches)) { $branchStr = '[' . implode(', ', $branches) . ']'; - $output->writeln("All branches are not resolved : {$branchStr}"); + $output->writeln("All branches are not resolved : $branchStr"); } return Command::SUCCESS; @@ -128,11 +134,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * Try to find a best candidate for next display - * - * @param array $branches - * @param array $taskList */ - protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process): int|null|string + protected function findBestNextTask(array $branches, array $taskList, ProcessConfiguration $process): int|null|string { // Get resolvable tasks $taskCandidates = []; @@ -145,7 +148,7 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ // Check if task has all necessary ancestors in branches $hasAllAncestors = array_reduce( $task->getPreviousTasksConfigurations(), - static fn ($result, TaskConfiguration $prevTask): bool => $result && \in_array( + static fn ($result, TaskConfiguration $prevTask): bool => $result && in_array( $prevTask->getCode(), $branches, true @@ -178,7 +181,7 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ } if (! empty($task->getPreviousTasksConfigurations())) { - $weight /= \count($task->getPreviousTasksConfigurations()); + $weight /= count($task->getPreviousTasksConfigurations()); } $taskWeights[$taskCandidate] = $weight; @@ -207,10 +210,8 @@ protected function findBestNextTask($branches, $taskList, ProcessConfiguration $ /** * Get the number of children (error or not) of a task - * - * @return int */ - protected function getTaskChildrenCount(TaskConfiguration $task) + protected function getTaskChildrenCount(TaskConfiguration $task): int { $count = 0; @@ -249,7 +250,7 @@ protected function resolveBranchOutput( // Check previous branches if (empty($previousTasks)) { $branches[] = $task->getCode(); - } elseif (\count($previousTasks) === 1) { + } elseif (count($previousTasks) === 1) { $prevTask = current($previousTasks) ->getCode(); foreach (array_reverse($branches, true) as $i => $branchTask) { @@ -271,7 +272,7 @@ protected function resolveBranchOutput( if (! $foundBranch) { $output->writeln( - "Could not find previous branch : {$taskCode} depends on {$prevTask->getCode()}" + "Could not find previous branch : $taskCode depends on {$prevTask->getCode()}" ); } } @@ -280,7 +281,6 @@ protected function resolveBranchOutput( sort($branchesToMerge); $gapFrom = null; - $gapTo = null; foreach ($branchesToMerge as $i) { $gapTo = $i; if ($gapFrom !== null) { @@ -304,14 +304,14 @@ protected function resolveBranchOutput( $output, $branches, '', - static fn ($taskCode, $i): bool => \in_array($i, $branchesToMerge, true) - || \in_array($i, $gapBranches, true) + static fn ($taskCode, $i): bool => in_array($i, $branchesToMerge, true) + || in_array($i, $gapBranches, true) || $i === $origin, static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): string { if ($i === $origin) { return self::CHAR_RECEIVE; } - if (\in_array($i, $gapBranches, true)) { + if (in_array($i, $gapBranches, true)) { if ($branches[$i] !== null) { return self::CHAR_JUMP; } @@ -328,7 +328,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): ); foreach ($branches as $i => $branchTask) { - if (\in_array($i, $branchesToMerge, true)) { + if (in_array($i, $branchesToMerge, true)) { $branches[$i] = null; } } @@ -338,7 +338,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { if ($branchTask !== null) { - $branches = \array_slice($branches, 0, $i + 1); + $branches = array_slice($branches, 0, $i + 1); break; } } @@ -346,7 +346,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): // Write main line $nodeStr = self::CHAR_NODE; if ($task->isInErrorBranch()) { - $nodeStr = "{$nodeStr}"; + $nodeStr = "$nodeStr"; } $this->writeBranches( @@ -359,9 +359,9 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): // Write task help message if ($output->isVerbose() && $task->getHelp()) { - $helpLines = array_filter(explode("\n", (string) $task->getHelp())); + $helpLines = array_filter(explode("\n", $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "$helpLine"; $this->writeBranches($output, $branches, $helpMessage); } } @@ -373,7 +373,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) ) ); - if (\count($nextTasks) > 1) { + if (count($nextTasks) > 1) { $this->writeBranches($output, $branches); array_shift($nextTasks); $origin = array_search($taskCode, $branches, true); @@ -385,7 +385,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): $branches[$index] = $taskCode; $expandBranches[] = $index; } else { - $expandBranches[] = \count($branches); + $expandBranches[] = count($branches); $branches[] = $taskCode; } } @@ -412,7 +412,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) if ($i === $origin) { return self::CHAR_RECEIVE; } - if (\in_array($i, $gapBranches, true)) { + if (in_array($i, $gapBranches, true)) { if ($branches[$i] !== null) { return self::CHAR_JUMP; } @@ -439,7 +439,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { if ($branchTask !== null) { - $branches = \array_slice($branches, 0, $i + 1); + $branches = array_slice($branches, 0, $i + 1); break; } } @@ -460,9 +460,9 @@ protected function writeBranches( foreach ($branches as $i => $branchTask) { $str = ''; if ($match !== null && $match($branchTask, $i)) { - if (\is_string($char)) { + if (is_string($char)) { $str = $char; - } elseif (\is_callable($char)) { + } elseif (is_callable($char)) { $str = $char($branchTask, $i); } else { throw new InvalidArgumentException('Char must be string|callable'); @@ -472,7 +472,7 @@ protected function writeBranches( } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); + $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } @@ -504,11 +504,11 @@ protected function getTaskDescription(TaskConfiguration $task): string $subprocess[] = $task->getOption('process'); } - if (\count($interfaces)) { + if (count($interfaces)) { $description .= ' (' . implode(', ', $interfaces) . ')'; } - if (\count($subprocess)) { + if (count($subprocess)) { $description .= ' {' . implode(', ', $subprocess) . '}'; } @@ -519,14 +519,14 @@ protected function getTaskDescription(TaskConfiguration $task): string return $description; } - protected function getTaskService(TaskConfiguration $taskConfiguration): mixed + protected function getTaskService(TaskConfiguration $taskConfiguration): TaskInterface { // Duplicate code from \CleverAge\ProcessBundle\Manager\ProcessManager::initialize // @todo Refactor this using a Registry with this feature: // https://symfony.com/doc/current/service_container/service_subscribers_locators.html $serviceReference = $taskConfiguration->getServiceReference(); - if (str_starts_with((string) $serviceReference, '@')) { - $task = $this->container->get(ltrim((string) $serviceReference, '@')); + if (str_starts_with($serviceReference, '@')) { + $task = $this->container->get(ltrim($serviceReference, '@')); } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { From cef17c49e8906d3f041548c0a9786a199323f433 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 27 Mar 2023 21:55:54 +0200 Subject: [PATCH 171/304] fix deprecations --- src/Configuration/ProcessConfiguration.php | 44 ++++++++-------------- src/Configuration/TaskConfiguration.php | 40 ++++---------------- 2 files changed, 24 insertions(+), 60 deletions(-) diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index d0a48e29..cb539c72 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -16,39 +16,27 @@ use CleverAge\ProcessBundle\Exception\CircularProcessException; use CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException; +use function count; +use function in_array; + /** * Holds the processes configuration to launch a task */ class ProcessConfiguration { - /** - * @var array - */ - protected $dependencyGroups; + protected ?array $dependencyGroups = null; - /** - * @var array - */ - protected $mainTaskGroup; + protected ?array $mainTaskGroup = null; - /** - * @param string $code - * @param TaskConfiguration[] $taskConfigurations - * @param string $entryPoint - * @param string $endPoint - * @param string $description - * @param string $help - * @param bool $public - */ public function __construct( - protected $code, + protected string $code, protected array $taskConfigurations, protected array $options = [], - protected $entryPoint = null, - protected $endPoint = null, - protected $description = '', - protected $help = '', - protected $public = true + protected ?string $entryPoint = null, + protected ?string $endPoint = null, + protected string $description = '', + protected string $help = '', + protected bool $public = true ) { } @@ -129,7 +117,7 @@ public function getDependencyGroups(): array foreach ($this->getTaskConfigurations() as $taskConfiguration) { $isInBranch = false; foreach ($this->dependencyGroups as $branch) { - if (\in_array($taskConfiguration->getCode(), $branch, true)) { + if (in_array($taskConfiguration->getCode(), $branch, true)) { $isInBranch = true; break; } @@ -160,7 +148,7 @@ public function getMainTaskGroup(): array $mainTask = $this->getMainTask(); foreach ($this->getDependencyGroups() as $branch) { - if (\in_array($mainTask->getCode(), $branch, true)) { + if (in_array($mainTask->getCode(), $branch, true)) { $this->mainTaskGroup = $branch; break; } @@ -223,7 +211,7 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe $code = $taskConfig->getCode(); // May have been added by previous task - if (! \in_array($code, $dependencies, true)) { + if (! in_array($code, $dependencies, true)) { $dependencies[] = $code; foreach ($taskConfig->getPreviousTasksConfigurations() as $previousTasksConfig) { @@ -247,7 +235,7 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe */ protected function sortDependencies(array $dependencies): array { - if (\count($dependencies) <= 1) { + if (count($dependencies) <= 1) { return $dependencies; } @@ -259,7 +247,7 @@ protected function sortDependencies(array $dependencies): array } /** @var int $midOffset */ - $midOffset = \count($dependencies) / 2; + $midOffset = round(count($dependencies) / 2); $midTaskCode = $dependencies[$midOffset]; $midTask = $this->getTaskConfiguration($midTaskCode); diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index 97c6e553..d6e22f40 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -33,32 +33,25 @@ class TaskConfiguration /** * @var TaskConfiguration[] */ - protected $nextTasksConfigurations = []; + protected array $nextTasksConfigurations = []; /** * @var TaskConfiguration[] */ - protected $previousTasksConfigurations = []; + protected array $previousTasksConfigurations = []; /** * @var TaskConfiguration[] */ - protected $errorTasksConfigurations = []; + protected array $errorTasksConfigurations = []; - /** - * @var bool - */ - protected $inErrorBranch = false; + protected bool $inErrorBranch = false; protected bool $logErrors; - /** - * @param string $code - * @param string $serviceReference - */ public function __construct( - protected $code, - protected $serviceReference, + protected string $code, + protected string $serviceReference, protected array $options, protected string $description = '', protected string $help = '', @@ -105,12 +98,7 @@ public function getOptions(): array return $this->options; } - /** - * @param string $code - * - * @return mixed - */ - public function getOption($code, mixed $default = null) + public function getOption(string $code, mixed $default = null): mixed { if (array_key_exists($code, $this->options)) { return $this->options[$code]; @@ -228,10 +216,8 @@ public function hasAncestor(self $taskConfig): bool /** * Check task ancestors to find if it have a given task as child - * - * @param bool $checkErrors */ - public function hasDescendant(self $taskConfig, $checkErrors = true): bool + public function hasDescendant(self $taskConfig, bool $checkErrors = true): bool { foreach ($this->getNextTasksConfigurations() as $nextTaskConfig) { // Avoid errors for direct descendant @@ -277,14 +263,4 @@ public function getLogLevel(): string { return $this->logLevel; } - - /** - * @deprecated Use getLogLevel instead - */ - public function isLogErrors(): bool - { - @trigger_error('Deprecated method, use getLogLevel instead', E_USER_DEPRECATED); - - return $this->logErrors; - } } From 04945fafa4d4a030beb47baf7f251f8b25eef64e Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 29 Mar 2023 22:05:05 +0200 Subject: [PATCH 172/304] refacto deprecations tasks --- src/Model/AbstractConfigurableTask.php | 4 +-- src/Task/AbstractIterableOutputTask.php | 4 +-- src/Task/AggregateIterableTask.php | 8 +++--- src/Task/ArrayMergeTask.php | 10 ++++--- src/Task/ColumnAggregatorTask.php | 4 +-- src/Task/ConstantIterableOutputTask.php | 2 +- src/Task/ConstantOutputTask.php | 2 +- src/Task/CounterTask.php | 5 +--- src/Task/Debug/MemInfoDumpTask.php | 2 +- src/Task/Event/EventDispatcherTask.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 7 ++--- src/Task/File/Csv/AbstractCsvTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 4 +-- src/Task/File/Csv/CsvSplitterTask.php | 2 +- src/Task/File/Csv/CsvWriterTask.php | 8 +++--- src/Task/File/Csv/InputCsvReaderTask.php | 2 +- src/Task/File/FileFetchTask.php | 13 ++++++++-- src/Task/File/FileMoverTask.php | 4 +-- src/Task/File/FileReaderTask.php | 16 +++++++++--- src/Task/File/FileWriterTask.php | 2 +- src/Task/File/FolderBrowserTask.php | 11 ++++---- src/Task/File/InputFolderBrowserTask.php | 13 ++++------ .../File/JsonStream/JsonStreamReaderTask.php | 4 +++ src/Task/File/Xml/XmlReaderTask.php | 2 +- src/Task/File/Xml/XmlWriterTask.php | 2 +- src/Task/File/YamlReaderTask.php | 9 ++++--- src/Task/File/YamlWriterTask.php | 2 +- src/Task/FilterTask.php | 2 +- src/Task/GroupByAggregateIterableTask.php | 3 ++- src/Task/InputAggregatorTask.php | 13 +++++----- src/Task/InputIteratorTask.php | 7 ++++- src/Task/IterableBatchTask.php | 26 ++++++------------- src/Task/Process/ProcessExecutorTask.php | 13 +++++----- src/Task/Process/ProcessLauncherTask.php | 16 +++++------- src/Task/PropertyGetterTask.php | 2 +- src/Task/PropertySetterTask.php | 3 +-- .../Reporting/AdvancedStatCounterTask.php | 4 +-- src/Task/Reporting/LoggerTask.php | 5 +--- src/Task/Reporting/StatCounterTask.php | 7 ++--- src/Task/RowAggregatorTask.php | 11 +++----- src/Task/Serialization/DenormalizerTask.php | 6 ++++- src/Task/Serialization/NormalizerTask.php | 6 ++++- src/Task/Serialization/SerializerTask.php | 2 +- src/Task/SimpleBatchTask.php | 12 ++++----- src/Task/SplitJoinLineTask.php | 2 +- src/Task/TransformerTask.php | 10 +++---- src/Task/Validation/ValidatorTask.php | 2 +- 47 files changed, 149 insertions(+), 149 deletions(-) diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index b7639efd..3f2183a1 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -46,11 +46,11 @@ protected function getOption(ProcessState $state, string $code): mixed { $options = $this->getOptions($state); if (! array_key_exists($code, $options)) { - throw new InvalidArgumentException("Missing option {$code}"); + throw new InvalidArgumentException("Missing option $code"); } return $options[$code]; } - abstract protected function configureOptions(OptionsResolver $resolver); + abstract protected function configureOptions(OptionsResolver $resolver): void; } diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index 46916c1a..58855cfd 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -91,10 +91,8 @@ protected function handleIteratorFromInput(ProcessState $state): void /** * Allow to not implement this method, not required by most tasks, removing inheritance would break back-compat - * - * @inheritDoc */ - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { } diff --git a/src/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php index adb61a9d..7acdd2dc 100644 --- a/src/Task/AggregateIterableTask.php +++ b/src/Task/AggregateIterableTask.php @@ -15,6 +15,7 @@ use CleverAge\ProcessBundle\Model\BlockingTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; +use function count; /** * Class AggregateIterableTask @@ -23,10 +24,7 @@ */ class AggregateIterableTask implements BlockingTaskInterface { - /** - * @var array - */ - protected $result = []; + protected array $result = []; public function execute(ProcessState $state): void { @@ -35,7 +33,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (\count($this->result) === 0) { + if (count($this->result) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php index 565cb01d..422d609c 100644 --- a/src/Task/ArrayMergeTask.php +++ b/src/Task/ArrayMergeTask.php @@ -19,6 +19,8 @@ use InvalidArgumentException; use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function in_array; +use function is_array; /** * Merge every input array, and return the result @@ -32,13 +34,13 @@ class ArrayMergeTask extends AbstractConfigurableTask implements BlockingTaskInt public function execute(ProcessState $state): void { $input = $state->getInput(); - if (! \is_array($input)) { + if (! is_array($input)) { throw new UnexpectedValueException('Input must be an array'); } $mergeFunction = $this->getOption($state, 'merge_function'); - if (! \in_array($mergeFunction, self::MERGE_FUNC, true)) { - throw new InvalidArgumentException("Unknown merge function {$mergeFunction}"); + if (! in_array($mergeFunction, self::MERGE_FUNC, true)) { + throw new InvalidArgumentException("Unknown merge function $mergeFunction"); } $this->mergedOutput = $mergeFunction($this->mergedOutput, $input); } @@ -48,7 +50,7 @@ public function proceed(ProcessState $state): void $state->setOutput($this->mergedOutput); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('merge_function', 'array_merge'); $resolver->setAllowedTypes('merge_function', 'string'); diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index f098d8ac..333e7465 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -66,7 +66,7 @@ public function execute(ProcessState $state): void if (! empty($missingColumns)) { $colStr = implode(', ', $missingColumns); - $message = "Missing columns [{$colStr}] in input"; + $message = "Missing columns [$colStr] in input"; if ($this->getOption($state, 'ignore_missing')) { $this->logger->warning($message); @@ -97,7 +97,7 @@ protected function addValueToAggregationGroup( $this->result[$column][$aggregationKey][] = $input; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('columns'); $resolver->setAllowedTypes('columns', 'array'); diff --git a/src/Task/ConstantIterableOutputTask.php b/src/Task/ConstantIterableOutputTask.php index 93c66284..77310da9 100644 --- a/src/Task/ConstantIterableOutputTask.php +++ b/src/Task/ConstantIterableOutputTask.php @@ -23,7 +23,7 @@ */ class ConstantIterableOutputTask extends AbstractIterableOutputTask { - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['output']); $resolver->setAllowedTypes('output', ['array']); diff --git a/src/Task/ConstantOutputTask.php b/src/Task/ConstantOutputTask.php index fc19319c..6a0b6118 100644 --- a/src/Task/ConstantOutputTask.php +++ b/src/Task/ConstantOutputTask.php @@ -27,7 +27,7 @@ public function execute(ProcessState $state): void $state->setOutput($this->getOption($state, 'output')); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['output']); } diff --git a/src/Task/CounterTask.php b/src/Task/CounterTask.php index d54ace90..500222a7 100644 --- a/src/Task/CounterTask.php +++ b/src/Task/CounterTask.php @@ -24,10 +24,7 @@ */ class CounterTask extends AbstractConfigurableTask implements FlushableTaskInterface { - /** - * @var int - */ - protected $counter = 0; + protected int $counter = 0; public function execute(ProcessState $state): void { diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php index 22529f39..030f6cd7 100644 --- a/src/Task/Debug/MemInfoDumpTask.php +++ b/src/Task/Debug/MemInfoDumpTask.php @@ -40,7 +40,7 @@ public function execute(ProcessState $state): void } } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); diff --git a/src/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php index 7cc159e1..b17de298 100644 --- a/src/Task/Event/EventDispatcherTask.php +++ b/src/Task/Event/EventDispatcherTask.php @@ -42,7 +42,7 @@ public function execute(ProcessState $state): void $this->eventDispatcher->dispatch($event); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['event_name']); $resolver->setDefault('passive', true); diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index 868720b8..7fef7280 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -49,7 +49,7 @@ protected function initFile(ProcessState $state): void ); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'delimiter' => ';', @@ -63,8 +63,5 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('headers', ['null', 'array']); } - /** - * @return array - */ - abstract protected function getHeaders(ProcessState $state, array $options); + abstract protected function getHeaders(ProcessState $state, array $options): array; } diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index 1c5263d1..5b49a69c 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -40,7 +40,7 @@ protected function initFile(ProcessState $state): void ); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setRequired(['file_path']); diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index cb57628d..3c47ac8a 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -50,7 +50,7 @@ public function execute(ProcessState $state): void 'csv_file' => $this->csv->getFilePath(), 'csv_line' => $lineNumber, ]; - $this->logger->warning("Empty line detected at line: {$lineNumber}", $logContext); + $this->logger->warning("Empty line detected at line: $lineNumber", $logContext); } $state->setSkipped(true); @@ -83,7 +83,7 @@ protected function getHeaders(ProcessState $state, array $options): array return $options['headers']; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefaults([ diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 8f02b20c..0d700c3e 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -101,7 +101,7 @@ protected function splitCsv(CsvFile $csv, int $maxLines): string return $tmpFilePath; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefaults([ diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index bf61ec82..8629c9bb 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -20,6 +20,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function is_array; + /** * Reads the file path from configuration and iterates over it * Ignores any input @@ -44,7 +46,7 @@ public function proceed(ProcessState $state): void $state->setOutput($this->csv->getFilePath()); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefaults([ @@ -69,13 +71,13 @@ protected function configureOptions(OptionsResolver $resolver) protected function getInput(ProcessState $state): array { $input = $state->getInput(); - if (! \is_array($input)) { + if (! is_array($input)) { throw new UnexpectedValueException('Input value is not an array'); } $splitCharacter = $this->getOption($state, 'split_character'); foreach ($input as &$item) { - if (\is_array($item)) { + if (is_array($item)) { $item = implode($splitCharacter, $item); } } diff --git a/src/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php index 09b720c8..11aac285 100644 --- a/src/Task/File/Csv/InputCsvReaderTask.php +++ b/src/Task/File/Csv/InputCsvReaderTask.php @@ -31,7 +31,7 @@ protected function getOptions(ProcessState $state): array return $options; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->remove('file_path'); diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index 2fca55d7..3ecc8ed4 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -58,6 +58,9 @@ public function initialize(ProcessState $state): void $this->destinationFS = new Filesystem($this->getOption($state, 'destination_filesystem')); } + /** + * @throws FilesystemException + */ public function execute(ProcessState $state): void { $this->findMatchingFiles($state); @@ -74,7 +77,7 @@ public function execute(ProcessState $state): void } /** - * @return bool|mixed + * @throws FilesystemException */ public function next(ProcessState $state): mixed { @@ -83,6 +86,9 @@ public function next(ProcessState $state): mixed return next($this->matchingFiles); } + /** + * @throws FilesystemException + */ protected function findMatchingFiles(ProcessState $state): void { $filePattern = $this->getOption($state, 'file_pattern'); @@ -111,6 +117,9 @@ protected function findMatchingFiles(ProcessState $state): void } } + /** + * @throws FilesystemException + */ protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null { $prefixFrom = $this->getOption($state, 'source_filesystem'); @@ -135,7 +144,7 @@ protected function doFileCopy(ProcessState $state, string $filename, bool $remov return $result ? $filename : null; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['source_filesystem', 'destination_filesystem']); $resolver->setAllowedTypes('source_filesystem', 'string'); diff --git a/src/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php index 69d67109..2d8775a8 100644 --- a/src/Task/File/FileMoverTask.php +++ b/src/Task/File/FileMoverTask.php @@ -30,7 +30,7 @@ public function execute(ProcessState $state): void $fs = new Filesystem(); $file = $state->getInput(); if (! $fs->exists($file)) { - throw new UnexpectedValueException("File does not exists: '{$file}'"); + throw new UnexpectedValueException("File does not exists: '$file'"); } $dest = $options['destination']; if (is_dir($dest)) { @@ -43,7 +43,7 @@ public function execute(ProcessState $state): void $state->setOutput($dest); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['destination']); $resolver->setAllowedTypes('destination', ['string']); diff --git a/src/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php index 964c43c2..34c9144a 100644 --- a/src/Task/File/FileReaderTask.php +++ b/src/Task/File/FileReaderTask.php @@ -16,22 +16,30 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; +use UnexpectedValueException; /** * Read the whole file and output its content - * - * @todo Provide additional safeguards like if file exists and is readable */ class FileReaderTask extends AbstractConfigurableTask { public function execute(ProcessState $state): void { $options = $this->getOptions($state); + $filename = $options['filename']; + + if (! file_exists($filename)) { + throw new UnexpectedValueException("File does not exists: '$filename'"); + } + + if (! is_readable($filename)) { + throw new UnexpectedValueException("File is not readable: '$filename'"); + } - $state->setOutput(file_get_contents($options['filename'])); + $state->setOutput(file_get_contents($filename)); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['filename']); $resolver->setAllowedTypes('filename', ['string']); diff --git a/src/Task/File/FileWriterTask.php b/src/Task/File/FileWriterTask.php index 64516de2..e135da74 100644 --- a/src/Task/File/FileWriterTask.php +++ b/src/Task/File/FileWriterTask.php @@ -30,7 +30,7 @@ public function execute(ProcessState $state): void $state->setOutput($options['filename']); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['filename']); $resolver->setAllowedTypes('filename', ['string']); diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 63a4f31b..3124a479 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -73,9 +73,11 @@ public function execute(ProcessState $state): void * return true if the task has a next element * return false if the task has terminated it's iteration * + * @param ProcessState $state + * * @return bool */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { if (! $this->files) { return false; @@ -86,21 +88,20 @@ public function next(ProcessState $state) return $this->files->valid(); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['folder_path']); $resolver->setAllowedTypes('folder_path', ['string']); - /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'folder_path', static function (Options $options, $value) { if (! is_dir($value)) { throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '{$value}'" + "Folder path does not exists or is not a folder: '$value'" ); } if (! is_readable($value)) { - throw new InvalidConfigurationException("Folder path is not readable: '{$value}'"); + throw new InvalidConfigurationException("Folder path is not readable: '$value'"); } return $value; diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index ba75c17a..77bec3bd 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -24,10 +24,7 @@ */ class InputFolderBrowserTask extends FolderBrowserTask implements FlushableTaskInterface { - /** - * @var string|null - */ - protected $folderPath; + protected ?string $folderPath = null; public function flush(ProcessState $state): void { @@ -40,7 +37,7 @@ public function initialize(ProcessState $state): void parent::getOptions($state); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->remove(['folder_path']); @@ -58,7 +55,7 @@ protected function getOptions(ProcessState $state): array $folderPath = $options['base_folder_path'] . $state->getInput(); if ($this->folderPath && $folderPath !== $this->folderPath) { throw new LogicException( - "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" + "Folder path '$folderPath' already initialized with a different value $this->folderPath" ); } $this->folderPath = $folderPath; @@ -66,11 +63,11 @@ protected function getOptions(ProcessState $state): array if (! is_dir($this->folderPath)) { throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '{$this->folderPath}'" + "Folder path does not exists or is not a folder: '$this->folderPath'" ); } if (! is_readable($this->folderPath)) { - throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); + throw new InvalidConfigurationException("Folder path is not readable: '$this->folderPath'"); } $options['folder_path'] = $this->folderPath; diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index a799cf0f..628e5b3b 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -16,11 +16,15 @@ use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; +use JsonException; class JsonStreamReaderTask implements IterableTaskInterface { protected ?JsonStreamFile $file = null; + /** + * @throws JsonException + */ public function execute(ProcessState $state): void { if ($this->file === null) { diff --git a/src/Task/File/Xml/XmlReaderTask.php b/src/Task/File/Xml/XmlReaderTask.php index b292055a..81de9b3f 100644 --- a/src/Task/File/Xml/XmlReaderTask.php +++ b/src/Task/File/Xml/XmlReaderTask.php @@ -39,7 +39,7 @@ public function execute(ProcessState $state): void $state->setOutput($file->read()); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('file_path'); $resolver->setAllowedTypes('file_path', 'string'); diff --git a/src/Task/File/Xml/XmlWriterTask.php b/src/Task/File/Xml/XmlWriterTask.php index 6325227c..e03d4621 100644 --- a/src/Task/File/Xml/XmlWriterTask.php +++ b/src/Task/File/Xml/XmlWriterTask.php @@ -43,7 +43,7 @@ public function execute(ProcessState $state): void $state->setOutput($this->getOption($state, 'file_path')); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('file_path'); $resolver->setAllowedTypes('file_path', 'string'); diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php index 286f1a55..43c4abc9 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/YamlReaderTask.php @@ -22,13 +22,14 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Yaml\Yaml; use UnexpectedValueException; +use function is_array; /** * Reads a YAML file and iterate over its root elements */ class YamlReaderTask extends AbstractIterableOutputTask { - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); @@ -36,7 +37,7 @@ protected function configureOptions(OptionsResolver $resolver) 'file_path', static function (Options $options, $value) { if (! file_exists($value)) { - throw new UnexpectedValueException("File not found: {$value}"); + throw new UnexpectedValueException("File not found: $value"); } return $value; @@ -48,8 +49,8 @@ protected function initializeIterator(ProcessState $state): Iterator { $filePath = $this->getOption($state, 'file_path'); $content = Yaml::parseFile($filePath); - if (! \is_array($content)) { - throw new InvalidArgumentException("File content is not an array: {$filePath}"); + if (! is_array($content)) { + throw new InvalidArgumentException("File content is not an array: $filePath"); } return new ArrayIterator($content); diff --git a/src/Task/File/YamlWriterTask.php b/src/Task/File/YamlWriterTask.php index bc46b6d6..dd913335 100644 --- a/src/Task/File/YamlWriterTask.php +++ b/src/Task/File/YamlWriterTask.php @@ -30,7 +30,7 @@ public function execute(ProcessState $state): void $state->setOutput($options['file_path']); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['file_path']); $resolver->setAllowedTypes('file_path', ['string']); diff --git a/src/Task/FilterTask.php b/src/Task/FilterTask.php index 46df9723..f8cb8dbc 100644 --- a/src/Task/FilterTask.php +++ b/src/Task/FilterTask.php @@ -47,7 +47,7 @@ public function execute(ProcessState $state): void $state->setOutput($input); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $this->configureConditionOptions($resolver); } diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index b221b508..20395db9 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -10,6 +10,7 @@ use Exception; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use function count; /** * Attempt to aggregate inputs in an associative array with a key formed by configurable fields of the input. @@ -56,7 +57,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (\count($this->result) === 0) { + if (count($this->result) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index c6e2611b..8ec696f8 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -18,6 +18,7 @@ use RuntimeException; use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function in_array; /** * Wait for defined inputs before passing an aggregated output. @@ -47,7 +48,7 @@ public function execute(ProcessState $state): void $this->inputs = []; } else { throw new UnexpectedValueException( - "The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output" + "The output from input '$inputCode' has already been defined, please use an aggregator if you have an iterable output" ); } } @@ -59,7 +60,7 @@ public function execute(ProcessState $state): void $keepInputs = $this->getOption($state, 'keep_inputs'); // Only clear inputs that are not in the keep_inputs option foreach ($this->inputs as $inputCode => $value) { - if ($keepInputs !== null && \in_array($inputCode, $keepInputs, true)) { + if ($keepInputs !== null && in_array($inputCode, $keepInputs, true)) { continue; } unset($this->inputs[$inputCode]); @@ -69,7 +70,7 @@ public function execute(ProcessState $state): void } } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('input_codes'); $resolver->setDefaults([ @@ -83,10 +84,8 @@ protected function configureOptions(OptionsResolver $resolver) /** * Map the previous task code to an input code - * - * @return string */ - protected function getInputCode(ProcessState $state) + protected function getInputCode(ProcessState $state): string { $previousState = $state->getPreviousState(); if (! $previousState) { @@ -96,7 +95,7 @@ protected function getInputCode(ProcessState $state) ->getCode(); $inputCodes = $this->getOption($state, 'input_codes'); if (! array_key_exists($previousTaskCode, $inputCodes)) { - throw new UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); + throw new UnexpectedValueException("Task '$previousTaskCode' is not mapped in the input_codes option"); } return $inputCodes[$previousTaskCode]; diff --git a/src/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php index 9a8fbec8..30fcf6d8 100644 --- a/src/Task/InputIteratorTask.php +++ b/src/Task/InputIteratorTask.php @@ -15,15 +15,20 @@ use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; +use Exception; use Iterator; use IteratorAggregate; use UnexpectedValueException; +use function is_array; /** * Iterates from the input of the previous task */ class InputIteratorTask extends AbstractIterableOutputTask { + /** + * @throws Exception + */ protected function initializeIterator(ProcessState $state): Iterator { $input = $state->getInput(); @@ -33,7 +38,7 @@ protected function initializeIterator(ProcessState $state): Iterator if ($input instanceof IteratorAggregate) { return $input->getIterator(); } - if (\is_array($input)) { + if (is_array($input)) { return new ArrayIterator($input); } diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index f0403c23..635c2941 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -20,6 +20,7 @@ use Psr\Log\LoggerInterface; use SplQueue; use Symfony\Component\OptionsResolver\OptionsResolver; +use function count; /** * A Batch task that iterate on flush @@ -27,15 +28,9 @@ */ class IterableBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { - /** - * @var SplQueue - */ - protected $outputQueue; + protected ?SplQueue $outputQueue = null; - /** - * @var bool - */ - protected $flushMode = false; + protected bool $flushMode = false; public function __construct( protected LoggerInterface $logger @@ -68,7 +63,7 @@ public function execute(ProcessState $state): void } // Detect flushing - if ($batchCount !== null && \count($this->outputQueue) >= $batchCount) { + if ($batchCount !== null && count($this->outputQueue) >= $batchCount) { $this->flushMode = true; } @@ -80,20 +75,17 @@ public function execute(ProcessState $state): void } } - /** - * @return bool - */ - public function next(ProcessState $state) + public function next(ProcessState $state): bool { // Stop flushing once over - if (! \count($this->outputQueue)) { + if (! count($this->outputQueue)) { $this->flushMode = false; } return $this->flushMode; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'batch_count' => 10, @@ -104,10 +96,8 @@ protected function configureOptions(OptionsResolver $resolver) /** * Override this method to add a custom processing behavior - * - * @return mixed */ - protected function processInput(ProcessState $state) + protected function processInput(ProcessState $state): mixed { return $state->getInput(); } diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 5e294bb5..32df23a1 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -21,16 +21,14 @@ use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Throwable; /** * Execute one or many processes while chaining inputs in a iterable way */ class ProcessExecutorTask extends AbstractConfigurableTask { - /** - * @var array - */ - protected $process; + protected ?array $process = null; public function __construct( protected ProcessManager $processManager, @@ -39,6 +37,9 @@ public function __construct( ) { } + /** + * @throws Throwable + */ public function execute(ProcessState $state): void { $input = $state->getInput(); @@ -54,7 +55,7 @@ public function initialize(ProcessState $state): void $this->process = $this->getOption($state, 'process'); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('process'); $resolver->setDefaults([ @@ -66,7 +67,7 @@ protected function configureOptions(OptionsResolver $resolver) 'process', function (Options $options, $processCode) { if (! $this->processRegistry->hasProcessConfiguration($processCode)) { - throw new InvalidConfigurationException("Unknown process {$processCode}"); + throw new InvalidConfigurationException("Unknown process $processCode"); } return $processCode; diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index e7f4ea64..7ba1f194 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -28,6 +28,8 @@ use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use function count; + /** * Launch a new process for each input received, input must be a scalar, a resource or a \Traversable */ @@ -36,14 +38,11 @@ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableT /** * @var SubprocessInstance[] */ - protected $launchedProcesses = []; + protected array $launchedProcesses = []; protected SplQueue $finishedBuffers; - /** - * @var bool - */ - protected $flushMode = false; + protected bool $flushMode = false; public function __construct( protected LoggerInterface $logger, @@ -113,7 +112,7 @@ public function next(ProcessState $state): bool protected function handleInput(ProcessState $state): void { $options = $this->getOptions($state); - while (\count($this->launchedProcesses) >= $options['max_processes']) { + while (count($this->launchedProcesses) >= $options['max_processes']) { $this->handleProcesses($state); usleep($options['sleep_interval']); } @@ -186,15 +185,14 @@ protected function handleProcesses(ProcessState $state): void } } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['process']); - /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'process', function (Options $options, $value) { if (! $this->processRegistry->hasProcessConfiguration($value)) { - throw new InvalidConfigurationException("Unknown process {$value}"); + throw new InvalidConfigurationException("Unknown process $value"); } return $value; diff --git a/src/Task/PropertyGetterTask.php b/src/Task/PropertyGetterTask.php index 5a3c94b7..0f0654c0 100644 --- a/src/Task/PropertyGetterTask.php +++ b/src/Task/PropertyGetterTask.php @@ -49,7 +49,7 @@ public function execute(ProcessState $state): void $state->setOutput($output); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['property']); $resolver->setAllowedTypes('property', ['string']); diff --git a/src/Task/PropertySetterTask.php b/src/Task/PropertySetterTask.php index f5eb5026..7701d558 100644 --- a/src/Task/PropertySetterTask.php +++ b/src/Task/PropertySetterTask.php @@ -35,7 +35,6 @@ public function execute(ProcessState $state): void { $options = $this->getOptions($state); $input = $state->getInput(); - /** @noinspection ForeachSourceInspection */ foreach ($options['values'] as $key => $value) { try { $this->accessor->setValue($input, $key, $value); @@ -51,7 +50,7 @@ public function execute(ProcessState $state): void $state->setOutput($input); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['values']); $resolver->setAllowedTypes('values', ['array']); diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index 988cfd40..1f40b7f9 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -59,7 +59,7 @@ public function execute(ProcessState $state): void if ($seconds > 0) { $rate = number_format($items / $seconds, 2, ',', ' '); } - $fullText .= " - {$rate} items/s - {$items} items processed"; + $fullText .= " - $rate items/s - $items items processed"; $fullText .= " in {$now->diff($this->startedAt) ->format('%H:%I:%S')}"; @@ -71,7 +71,7 @@ public function execute(ProcessState $state): void $this->counter++; } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'num_items' => 1, diff --git a/src/Task/Reporting/LoggerTask.php b/src/Task/Reporting/LoggerTask.php index dbcf045d..80c64dd0 100644 --- a/src/Task/Reporting/LoggerTask.php +++ b/src/Task/Reporting/LoggerTask.php @@ -26,9 +26,6 @@ */ class LoggerTask extends AbstractConfigurableTask { - /** - * @internal param LoggerInterface $logger - */ public function __construct( protected LoggerInterface $logger, protected PropertyAccessorInterface $accessor @@ -50,7 +47,7 @@ public function execute(ProcessState $state): void $state->setOutput($state->getInput()); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults( [ diff --git a/src/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php index 64fad0e4..5a3d188b 100644 --- a/src/Task/Reporting/StatCounterTask.php +++ b/src/Task/Reporting/StatCounterTask.php @@ -22,10 +22,7 @@ */ class StatCounterTask implements FinalizableTaskInterface { - /** - * @var int - */ - protected $counter = 0; + protected int $counter = 0; public function __construct( protected LoggerInterface $logger @@ -34,7 +31,7 @@ public function __construct( public function finalize(ProcessState $state): void { - $this->logger->info("Processed item count: {$this->counter}"); + $this->logger->info("Processed item count: $this->counter"); } public function execute(ProcessState $state): void diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index c392a525..d343bcd1 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -28,10 +28,7 @@ */ class RowAggregatorTask extends AbstractConfigurableTask implements BlockingTaskInterface { - /** - * @var array - */ - protected $result = []; + protected array $result = []; public function __construct( protected LoggerInterface $logger @@ -52,7 +49,7 @@ public function execute(ProcessState $state): void if (! array_key_exists($aggregateBy, $input)) { throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column '{$aggregateBy}'" + "Array aggregator exception: missing column '$aggregateBy'" ); } @@ -71,7 +68,7 @@ public function execute(ProcessState $state): void foreach ($aggregateColumns as $aggregateColumn) { if (! array_key_exists($aggregateColumn, $input)) { throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column {$aggregateColumn}" + "Array aggregator exception: missing column $aggregateColumn" ); } $inputAggregateColumns[$aggregateColumn] = $input[$aggregateColumn]; @@ -84,7 +81,7 @@ public function proceed(ProcessState $state): void $state->setOutput(array_values($this->result)); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('aggregate_by'); $resolver->setRequired('aggregate_columns'); diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index 79bf33ac..0b33bd1c 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -16,6 +16,7 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** @@ -28,6 +29,9 @@ public function __construct( ) { } + /** + * @throws ExceptionInterface + */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -40,7 +44,7 @@ public function execute(ProcessState $state): void $state->setOutput($normalizedData); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['class']); $resolver->setAllowedTypes('class', ['string']); diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 86f9048c..613b5831 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -16,6 +16,7 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use UnexpectedValueException; @@ -29,6 +30,9 @@ public function __construct( ) { } + /** + * @throws ExceptionInterface + */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -45,7 +49,7 @@ public function execute(ProcessState $state): void $state->setOutput($normalizedData); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['format']); $resolver->setAllowedTypes('format', ['string']); diff --git a/src/Task/Serialization/SerializerTask.php b/src/Task/Serialization/SerializerTask.php index 43a685e2..f8158270 100644 --- a/src/Task/Serialization/SerializerTask.php +++ b/src/Task/Serialization/SerializerTask.php @@ -32,7 +32,7 @@ public function execute(ProcessState $state): void $state->setOutput($serializeData); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['format']); $resolver->setAllowedTypes('format', ['string']); diff --git a/src/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php index b573a0e1..3f17035e 100644 --- a/src/Task/SimpleBatchTask.php +++ b/src/Task/SimpleBatchTask.php @@ -17,20 +17,18 @@ use CleverAge\ProcessBundle\Model\FlushableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; +use function count; /** * Simple example of how to manage an internal buffer for batch processing */ class SimpleBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface { - /** - * @var array - */ - protected $elements = []; + protected array $elements = []; public function flush(ProcessState $state): void { - if (\count($this->elements) === 0) { + if (count($this->elements) === 0) { $state->setSkipped(true); } else { $state->setOutput($this->elements); @@ -43,7 +41,7 @@ public function execute(ProcessState $state): void $batchCount = $this->getOption($state, 'batch_count'); $this->elements[] = $state->getInput(); - if ($batchCount !== null && \count($this->elements) >= $batchCount) { + if ($batchCount !== null && count($this->elements) >= $batchCount) { $state->setOutput($this->elements); $this->elements = []; } else { @@ -51,7 +49,7 @@ public function execute(ProcessState $state): void } } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'batch_count' => 10, diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index ab3265e4..745b0ad4 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -57,7 +57,7 @@ protected function initializeIterator(ProcessState $state): Iterator $outputLines = []; foreach ($options['split_columns'] as $column) { if (! array_key_exists($column, $originalLine)) { - throw new UnexpectedValueException("Missing column {$column}"); + throw new UnexpectedValueException("Missing column $column"); } $columnValues = explode($options['split_character'], (string) $originalLine[$column]); foreach ($columnValues as $columnValue) { diff --git a/src/Task/TransformerTask.php b/src/Task/TransformerTask.php index b714a32e..e072ab29 100644 --- a/src/Task/TransformerTask.php +++ b/src/Task/TransformerTask.php @@ -29,10 +29,7 @@ class TransformerTask extends AbstractConfigurableTask { use TransformerTrait; - /** - * @var TransformerInterface - */ - protected $transformer; + protected ?TransformerInterface $transformer = null; public function __construct( protected LoggerInterface $logger, @@ -43,13 +40,12 @@ public function __construct( public function execute(ProcessState $state): void { - $output = null; $options = $this->getOptions($state); try { $output = $this->applyTransformers($options['transformers'], $state->getInput()); } catch (TransformerException $e) { - $state->addErrorContextValue('error', $e->getPrevious()->getMessage()); + $state->addErrorContextValue('error', $e->getPrevious()?->getMessage()); $state->setException($e); return; @@ -57,7 +53,7 @@ public function execute(ProcessState $state): void $state->setOutput($output); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $this->configureTransformersOptions($resolver); } diff --git a/src/Task/Validation/ValidatorTask.php b/src/Task/Validation/ValidatorTask.php index 0fa7a3e6..e9fe0b98 100644 --- a/src/Task/Validation/ValidatorTask.php +++ b/src/Task/Validation/ValidatorTask.php @@ -68,7 +68,7 @@ public function execute(ProcessState $state): void $state->setOutput($state->getInput()); } - protected function configureOptions(OptionsResolver $resolver) + protected function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('log_errors', LogLevel::CRITICAL); $resolver->setAllowedValues( From 08966d68febe01e3e4af6d05e88af67cca015409 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 29 Mar 2023 22:23:02 +0200 Subject: [PATCH 173/304] refacto deprecations transformers --- src/Transformer/ArrayElementTransformer.php | 2 +- src/Transformer/ArrayFilterTransformer.php | 2 +- src/Transformer/ArrayFirstTransformer.php | 6 +--- src/Transformer/ArrayLastTransformer.php | 2 +- src/Transformer/ArrayMapTransformer.php | 9 +++-- src/Transformer/ArrayUnsetTransformer.php | 5 +-- src/Transformer/CachedTransformer.php | 9 +++-- src/Transformer/CallbackTransformer.php | 16 ++++----- src/Transformer/CastTransformer.php | 2 +- src/Transformer/ConditionTrait.php | 25 +++---------- .../ConfigurableTransformerInterface.php | 2 +- src/Transformer/ConstantTransformer.php | 6 +--- src/Transformer/ConvertValueTransformer.php | 12 +++---- src/Transformer/DateFormatTransformer.php | 5 +-- src/Transformer/DateParserTransformer.php | 7 +--- src/Transformer/DebugTransformer.php | 2 +- src/Transformer/DefaultTransformer.php | 7 +--- src/Transformer/DenormalizeTransformer.php | 7 ++-- src/Transformer/EvaluatorTransformer.php | 7 +--- src/Transformer/ExplodeTransformer.php | 9 +---- .../ExpressionLanguageMapTransformer.php | 11 ++---- src/Transformer/GenericTransformer.php | 24 ++++--------- src/Transformer/HashTransformer.php | 2 +- src/Transformer/ImplodeTransformer.php | 5 +-- src/Transformer/MappingTransformer.php | 36 ++++++++----------- src/Transformer/MultiReplaceTransformer.php | 2 +- src/Transformer/NormalizeTransformer.php | 7 ++-- src/Transformer/PregFilterTransformer.php | 7 +--- .../PropertyAccessorTransformer.php | 9 +---- .../RecursivePropertySetterTransformer.php | 13 ++----- src/Transformer/RulesTransformer.php | 10 +++--- src/Transformer/SlugifyTransformer.php | 7 +--- src/Transformer/SprintfTransformer.php | 5 +-- src/Transformer/TransformerInterface.php | 10 ++---- src/Transformer/TrimTransformer.php | 7 +--- src/Transformer/TypeSetterTransformer.php | 2 +- src/Transformer/UnsetTransformer.php | 5 +-- src/Transformer/WrapperTransformer.php | 4 +-- .../Xml/XpathEvaluatorTransformer.php | 32 ++++++++--------- src/Validator/ConstraintLoader.php | 8 +++-- 40 files changed, 118 insertions(+), 230 deletions(-) diff --git a/src/Transformer/ArrayElementTransformer.php b/src/Transformer/ArrayElementTransformer.php index 89611646..0c9e6b4a 100644 --- a/src/Transformer/ArrayElementTransformer.php +++ b/src/Transformer/ArrayElementTransformer.php @@ -20,7 +20,7 @@ */ class ArrayElementTransformer implements ConfigurableTransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return array_values(array_slice($value, $options['index'], 1))[0]; } diff --git a/src/Transformer/ArrayFilterTransformer.php b/src/Transformer/ArrayFilterTransformer.php index d0f2a512..0a5e0d27 100644 --- a/src/Transformer/ArrayFilterTransformer.php +++ b/src/Transformer/ArrayFilterTransformer.php @@ -34,7 +34,7 @@ public function __construct(PropertyAccessorInterface $accessor) /** * @return array */ - public function transform($value, array $options = []): array + public function transform(mixed $value, array $options = []): array { if (! (is_iterable($value))) { throw new UnexpectedValueException('Given value is not iterable'); diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php index ec5c1f57..993d9323 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/ArrayFirstTransformer.php @@ -22,12 +22,8 @@ class ArrayFirstTransformer implements ConfigurableTransformerInterface { /** * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if ($options['allow_not_iterable'] && ! is_iterable($value)) { return $value; diff --git a/src/Transformer/ArrayLastTransformer.php b/src/Transformer/ArrayLastTransformer.php index f0d61f7a..8f689752 100644 --- a/src/Transformer/ArrayLastTransformer.php +++ b/src/Transformer/ArrayLastTransformer.php @@ -18,7 +18,7 @@ */ class ArrayLastTransformer implements TransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return array_values(array_slice($value, -1))[0]; } diff --git a/src/Transformer/ArrayMapTransformer.php b/src/Transformer/ArrayMapTransformer.php index b0a0ddc5..fe3bb18b 100644 --- a/src/Transformer/ArrayMapTransformer.php +++ b/src/Transformer/ArrayMapTransformer.php @@ -18,6 +18,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Traversable; use UnexpectedValueException; +use function is_array; /** * Applies transformers to each element of an array @@ -33,17 +34,15 @@ public function __construct(TransformerRegistry $transformerRegistry) /** * Must return the transformed $value - * - * @param mixed $values */ - public function transform($values, array $options = []): array + public function transform(mixed $value, array $options = []): array { - if (! \is_array($values) && ! $values instanceof Traversable) { + if (! is_array($value) && ! $value instanceof Traversable) { throw new UnexpectedValueException('Input value must be an array or traversable'); } $results = []; - foreach ($values as $key => $item) { + foreach ($value as $key => $item) { try { $item = $this->applyTransformers($options['transformers'], $item); if ($item === null && $options['skip_null']) { diff --git a/src/Transformer/ArrayUnsetTransformer.php b/src/Transformer/ArrayUnsetTransformer.php index a710b3bd..0062e1b0 100644 --- a/src/Transformer/ArrayUnsetTransformer.php +++ b/src/Transformer/ArrayUnsetTransformer.php @@ -15,15 +15,16 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function is_array; /** * Unset a key from an array */ class ArrayUnsetTransformer implements ConfigurableTransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { - if (! \is_array($value)) { + if (! is_array($value)) { throw new UnexpectedValueException('Given value is not an array'); } unset($value[$options['key']]); diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 27dae3a7..5a7dcc8c 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -21,6 +21,9 @@ use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use function implode; +use function is_string; +use function rawurlencode; class CachedTransformer implements ConfigurableTransformerInterface { @@ -62,7 +65,7 @@ function (Options $options, $value) { $this->configureTransformersOptions($resolver, 'key_transformers'); } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { $cacheKey = $this->generateCacheKey($options['cache_key'], $value, $options); if ($cacheKey && $this->cache instanceof CacheItemPoolInterface) { @@ -108,10 +111,10 @@ protected function generateCacheKey(string $cacheKeyRoot, string $value, array $ { $value = $this->applyTransformers($options['key_transformers'], $value); - if (! \is_string($value)) { + if (! is_string($value)) { return false; } - return \implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, \rawurlencode($value)]); + return implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, rawurlencode($value)]); } } diff --git a/src/Transformer/CallbackTransformer.php b/src/Transformer/CallbackTransformer.php index 9e0bb8e8..1056643f 100644 --- a/src/Transformer/CallbackTransformer.php +++ b/src/Transformer/CallbackTransformer.php @@ -16,6 +16,8 @@ use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use function call_user_func_array; +use function is_callable; /** * Convert input based on a callback @@ -24,12 +26,8 @@ class CallbackTransformer implements ConfigurableTransformerInterface { /** * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if ((is_countable($options['additional_parameters']) ? count($options['additional_parameters']) : 0) && ! (is_countable($options['right_parameters']) ? count($options['right_parameters']) : 0)) { @@ -39,7 +37,7 @@ public function transform($value, array $options = []) $parameters = $options['left_parameters']; array_push($parameters, $value, ...$options['right_parameters']); - return \call_user_func_array($options['callback'], $parameters); + return call_user_func_array($options['callback'], $parameters); } /** @@ -50,15 +48,14 @@ public function getCode(): string return 'callback'; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired(['callback']); $resolver->setAllowedTypes('callback', ['string', 'array']); - /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'callback', static function (Options $options, $value): callable { - if (! \is_callable($value)) { + if (! is_callable($value)) { throw new InvalidOptionsException('Callback option must be callable'); } @@ -76,7 +73,6 @@ static function (Options $options, $value): callable { $resolver->setAllowedTypes('right_parameters', ['array']); $resolver->setAllowedTypes('additional_parameters', ['array']); - /** @noinspection PhpUnusedParameterInspection */ $resolver->setNormalizer( 'additional_parameters', static function (Options $options, $value) { diff --git a/src/Transformer/CastTransformer.php b/src/Transformer/CastTransformer.php index 0e6e8151..6b36d844 100644 --- a/src/Transformer/CastTransformer.php +++ b/src/Transformer/CastTransformer.php @@ -20,7 +20,7 @@ */ class CastTransformer implements ConfigurableTransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { settype($value, $options['type']); diff --git a/src/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php index ff6ab11d..8a58ffb5 100644 --- a/src/Transformer/ConditionTrait.php +++ b/src/Transformer/ConditionTrait.php @@ -26,10 +26,8 @@ trait ConditionTrait /** * Test the input with the given set of conditions * True by default - * - * @param array $conditions */ - protected function checkCondition(mixed $input, $conditions): bool + protected function checkCondition(mixed $input, array $conditions): bool { foreach ($conditions['match'] as $key => $value) { if (! $this->checkValue($input, $key, $value)) { @@ -107,22 +105,15 @@ protected function configureConditionOptions(OptionsResolver $resolver): void /** * Softly check if an input key match a value, or not - * - * @param object|array $input - * @param string $key - * @param bool $shouldMatch - * @param bool $regexpMode */ - protected function checkValue($input, $key, mixed $value, $shouldMatch = true, $regexpMode = false): bool + protected function checkValue(object|array $input, string $key, mixed $value, bool $shouldMatch = true, bool $regexpMode = false): bool { $currentValue = $this->getValue($input, $key); - /** @noinspection TypeUnsafeComparisonInspection */ if ($shouldMatch && ! $regexpMode && $currentValue !== $value) { return false; } - /** @noinspection TypeUnsafeComparisonInspection */ if (! $shouldMatch && ! $regexpMode && $currentValue === $value) { return false; } @@ -144,11 +135,8 @@ protected function checkValue($input, $key, mixed $value, $shouldMatch = true, $ /** * Check if the input property is empty or not - * - * @param array|object $input - * @param string $key */ - protected function checkEmpty($input, $key): bool + protected function checkEmpty(object|array $input, string $key): bool { $currentValue = $this->getValue($input, $key); @@ -157,13 +145,8 @@ protected function checkEmpty($input, $key): bool /** * Soft value getter (return the value or null) - * - * @param array|object $input - * @param string $key - * - * @return mixed|null */ - protected function getValue($input, $key): mixed + protected function getValue(object|array $input, string $key): mixed { if ($key === '') { $currentValue = $input; diff --git a/src/Transformer/ConfigurableTransformerInterface.php b/src/Transformer/ConfigurableTransformerInterface.php index 4a60d128..e3403b5f 100644 --- a/src/Transformer/ConfigurableTransformerInterface.php +++ b/src/Transformer/ConfigurableTransformerInterface.php @@ -20,5 +20,5 @@ */ interface ConfigurableTransformerInterface extends TransformerInterface { - public function configureOptions(OptionsResolver $resolver); + public function configureOptions(OptionsResolver $resolver): void; } diff --git a/src/Transformer/ConstantTransformer.php b/src/Transformer/ConstantTransformer.php index 00b22e40..ba2c152b 100644 --- a/src/Transformer/ConstantTransformer.php +++ b/src/Transformer/ConstantTransformer.php @@ -28,12 +28,8 @@ public function configureOptions(OptionsResolver $resolver): void /** * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return $options['constant'] ?? null; } diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index a839e072..52c50001 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -23,22 +23,18 @@ class ConvertValueTransformer implements ConfigurableTransformerInterface { /** * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if ($value === null) { - return $value; + return null; } if (! is_string($value) && ! is_int($value)) { // If not a valid array index if (! $options['auto_cast']) { $type = gettype($value); throw new UnexpectedValueException( - "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" + "Value of type $type is not a valid array index, set auto_cast to true to cast it to a string" ); } if (is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here @@ -52,7 +48,7 @@ public function transform($value, array $options = []) return $value; } if (! $options['ignore_missing']) { - throw new UnexpectedValueException("Missing value in map '{$value}'"); + throw new UnexpectedValueException("Missing value in map '$value'"); } return null; diff --git a/src/Transformer/DateFormatTransformer.php b/src/Transformer/DateFormatTransformer.php index 7e44148f..9d5ca13d 100644 --- a/src/Transformer/DateFormatTransformer.php +++ b/src/Transformer/DateFormatTransformer.php @@ -28,10 +28,7 @@ */ class DateFormatTransformer implements ConfigurableTransformerInterface { - /** - * @param mixed $value - */ - public function transform($value, array $options = []): mixed + public function transform(mixed $value, array $options = []): mixed { if (! $value) { return $value; diff --git a/src/Transformer/DateParserTransformer.php b/src/Transformer/DateParserTransformer.php index bb6df2f4..664c2fb4 100644 --- a/src/Transformer/DateParserTransformer.php +++ b/src/Transformer/DateParserTransformer.php @@ -27,12 +27,7 @@ */ class DateParserTransformer implements ConfigurableTransformerInterface { - /** - * @param mixed $value - * - * @return mixed|string - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if (! $value || $value instanceof DateTime) { return $value; diff --git a/src/Transformer/DebugTransformer.php b/src/Transformer/DebugTransformer.php index b317cd12..fb5b8ac5 100644 --- a/src/Transformer/DebugTransformer.php +++ b/src/Transformer/DebugTransformer.php @@ -20,7 +20,7 @@ */ class DebugTransformer implements TransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if (class_exists(VarDumper::class)) { VarDumper::dump($value); diff --git a/src/Transformer/DefaultTransformer.php b/src/Transformer/DefaultTransformer.php index 11dddf88..3f10e43b 100644 --- a/src/Transformer/DefaultTransformer.php +++ b/src/Transformer/DefaultTransformer.php @@ -25,12 +25,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setRequired('value'); } - /** - * @param mixed $value - * - * @return mixed - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if (! $value) { return $options['value']; diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index f0fe6e6b..0710694b 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -14,6 +14,7 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** @@ -39,11 +40,9 @@ public function configureOptions(OptionsResolver $resolver): void } /** - * @param mixed $value - * - * @return mixed|object + * @throws ExceptionInterface */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return $this->denormalizer->denormalize($value, $options['class'], $options['format'], $options['context']); } diff --git a/src/Transformer/EvaluatorTransformer.php b/src/Transformer/EvaluatorTransformer.php index 2d3037ba..aaeaa6c0 100644 --- a/src/Transformer/EvaluatorTransformer.php +++ b/src/Transformer/EvaluatorTransformer.php @@ -47,12 +47,7 @@ function (Options $options, $expression) { ); } - /** - * @param mixed $value - * - * @return string - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return $this->language->evaluate($options['expression'], $value); } diff --git a/src/Transformer/ExplodeTransformer.php b/src/Transformer/ExplodeTransformer.php index 2f496c95..06798e19 100644 --- a/src/Transformer/ExplodeTransformer.php +++ b/src/Transformer/ExplodeTransformer.php @@ -20,14 +20,7 @@ */ class ExplodeTransformer implements ConfigurableTransformerInterface { - /** - * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): array { if ($value === null || $value === '') { return []; diff --git a/src/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php index 0d16cde7..b0499ae3 100644 --- a/src/Transformer/ExpressionLanguageMapTransformer.php +++ b/src/Transformer/ExpressionLanguageMapTransformer.php @@ -65,14 +65,7 @@ function (Options $options, $values): array { ); } - /** - * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { $input = [ 'data' => $value, @@ -87,7 +80,7 @@ public function transform($value, array $options = []) return $value; } if (! $options['ignore_missing']) { - throw new UnexpectedValueException("No expression accepting value '{$value}' in map"); + throw new UnexpectedValueException("No expression accepting value '$value' in map"); } return null; diff --git a/src/Transformer/GenericTransformer.php b/src/Transformer/GenericTransformer.php index b6c335b3..35dad513 100644 --- a/src/Transformer/GenericTransformer.php +++ b/src/Transformer/GenericTransformer.php @@ -26,20 +26,11 @@ class GenericTransformer implements ConfigurableTransformerInterface { use TransformerTrait; - /** - * @var string - */ - protected $transformerCode; + protected ?string $transformerCode = null; - /** - * @var array - */ - protected $preconfiguredTransformerOptions; + protected ?array $preconfiguredTransformerOptions = null; - /** - * @var array - */ - protected $contextualOptions; + protected ?array $contextualOptions = null; public function __construct( protected ContextualOptionResolver $contextualOptionResolver, @@ -86,7 +77,7 @@ public function configureInitialOptions(OptionsResolver $resolver): void /** * Called on process startup, prepare the real transformers */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { foreach ($this->contextualOptions as $option => $optionConfig) { if ($optionConfig['default'] !== null || $optionConfig['default_is_null']) { @@ -106,18 +97,17 @@ public function configureOptions(OptionsResolver $resolver) } $transformerOptions = $this->normalizeTransformerOptions($options, $this->preconfiguredTransformerOptions); - $transformers = $this->normalizeTransformers($options, $transformerOptions); - return $transformers; + return $this->normalizeTransformers($options, $transformerOptions); }); } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return $this->applyTransformers($options['transformers'], $value); } - public function getCode() + public function getCode(): string { return $this->transformerCode; } diff --git a/src/Transformer/HashTransformer.php b/src/Transformer/HashTransformer.php index b394c294..2f5db79a 100644 --- a/src/Transformer/HashTransformer.php +++ b/src/Transformer/HashTransformer.php @@ -30,7 +30,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefault('raw_output', false); } - public function transform($value, array $options = []): string + public function transform(mixed $value, array $options = []): string { return hash((string) $options['algo'], (string) $value, $options['raw_output']); } diff --git a/src/Transformer/ImplodeTransformer.php b/src/Transformer/ImplodeTransformer.php index 63e2550e..327ead0b 100644 --- a/src/Transformer/ImplodeTransformer.php +++ b/src/Transformer/ImplodeTransformer.php @@ -15,6 +15,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function is_array; /** * Implode multiple array values to a string, based on a split character @@ -28,9 +29,9 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('separator', 'string'); } - public function transform($value, array $options = []): string + public function transform(mixed $value, array $options = []): string { - if (! \is_array($value)) { + if (! is_array($value)) { throw new UnexpectedValueException('Given value is not an array'); } diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index 65e44d6c..ff9160da 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -15,7 +15,6 @@ use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use Exception; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\OptionsResolver\Options; @@ -23,6 +22,8 @@ use Symfony\Component\PropertyAccess\Exception\RuntimeException; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use UnexpectedValueException; +use function is_array; +use function is_callable; /** * Maps properties of an array/object to an other array/object @@ -39,12 +40,7 @@ public function __construct( $this->transformerRegistry = $transformerRegistry; } - /** - * Must return the transformed $value - * - * @param mixed $input - */ - public function transform($input, array $options = []): mixed + public function transform(mixed $value, array $options = []): mixed { if (! empty($options['initial_value']) && $options['keep_input']) { throw new InvalidOptionsException( @@ -54,10 +50,9 @@ public function transform($input, array $options = []): mixed $result = $options['initial_value']; if ($options['keep_input']) { - $result = $input; + $result = $value; } - /** @noinspection ForeachSourceInspection */ foreach ($options['mapping'] as $targetProperty => $mapping) { $targetProperty = (string) $targetProperty; $sourceProperty = $mapping['code'] ?? $targetProperty; @@ -68,12 +63,11 @@ public function transform($input, array $options = []): mixed $inputValue = $mapping['constant']; } elseif ($mapping['set_null']) { $inputValue = null; - } elseif (\is_array($sourceProperty)) { + } elseif (is_array($sourceProperty)) { $inputValue = []; - /** @var array $sourceProperty */ foreach ($sourceProperty as $destKey => $srcKey) { try { - $inputValue[$destKey] = $this->extractInputValue($input, $srcKey); + $inputValue[$destKey] = $this->extractInputValue($value, $srcKey); } catch (RuntimeException $missingPropertyError) { $this->handleInputMissingExceptions($missingPropertyError, $srcKey); if ($ignoreMissingFlag) { @@ -84,7 +78,7 @@ public function transform($input, array $options = []): mixed } } else { try { - $inputValue = $this->extractInputValue($input, $sourceProperty); + $inputValue = $this->extractInputValue($value, $sourceProperty); } catch (RuntimeException $missingPropertyError) { $this->handleInputMissingExceptions($missingPropertyError, $sourceProperty); if ($ignoreMissingFlag) { @@ -103,13 +97,13 @@ public function transform($input, array $options = []): mixed 'Transformation exception', [ 'message' => $exception->getPrevious() - ->getMessage(), + ?->getMessage(), 'file' => $exception->getPrevious() - ->getFile(), + ?->getFile(), 'line' => $exception->getPrevious() - ->getLine(), + ?->getLine(), 'trace' => $exception->getPrevious() - ->getTraceAsString(), + ?->getTraceAsString(), ] ); @@ -117,14 +111,14 @@ public function transform($input, array $options = []): mixed } // Set transformed value into result - if (\is_callable($options['merge_callback'])) { + if (is_callable($options['merge_callback'])) { $options['merge_callback']($result, $targetProperty, $transformedValue); } elseif ($this->accessor->isWritable($result, $targetProperty)) { $this->accessor->setValue($result, $targetProperty, $transformedValue); - } elseif (\is_array($result)) { + } elseif (is_array($result)) { $result[$targetProperty] = $transformedValue; } else { - throw new UnexpectedValueException("Property '{$targetProperty}' is not writable"); + throw new UnexpectedValueException("Property '$targetProperty' is not writable"); } } @@ -149,7 +143,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'mapping', - function (/** @noinspection PhpUnusedParameterInspection */ Options $options, $value): array { + function (Options $options, $value): array { $resolvedMapping = []; $mappingResolver = new OptionsResolver(); $this->configureMappingOptions($mappingResolver); diff --git a/src/Transformer/MultiReplaceTransformer.php b/src/Transformer/MultiReplaceTransformer.php index dea49686..2fa42461 100644 --- a/src/Transformer/MultiReplaceTransformer.php +++ b/src/Transformer/MultiReplaceTransformer.php @@ -24,7 +24,7 @@ */ class MultiReplaceTransformer implements ConfigurableTransformerInterface { - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { foreach ($options['replace_mapping'] as $pattern => $replacement) { $value = str_replace($pattern, $replacement, (string) $value); diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index 08ea96c2..962c89d9 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -14,6 +14,7 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -37,11 +38,9 @@ public function configureOptions(OptionsResolver $resolver): void } /** - * @param mixed $value - * - * @return array|bool|float|int|mixed|string + * @throws ExceptionInterface */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { return $this->normalizer->normalize($value, $options['format'], $options['context']); } diff --git a/src/Transformer/PregFilterTransformer.php b/src/Transformer/PregFilterTransformer.php index 6d8aac0e..47f8806c 100644 --- a/src/Transformer/PregFilterTransformer.php +++ b/src/Transformer/PregFilterTransformer.php @@ -17,12 +17,7 @@ class PregFilterTransformer implements ConfigurableTransformerInterface { - /** - * Must return the transformed $value - * - * @param mixed $value - */ - public function transform($value, array $options = []): array|string|null + public function transform(mixed $value, array $options = []): array|string|null { $pattern = $options['pattern']; $replacement = $options['replacement']; diff --git a/src/Transformer/PropertyAccessorTransformer.php b/src/Transformer/PropertyAccessorTransformer.php index 077825cd..0014d6ce 100644 --- a/src/Transformer/PropertyAccessorTransformer.php +++ b/src/Transformer/PropertyAccessorTransformer.php @@ -26,14 +26,7 @@ public function __construct( ) { } - /** - * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if ($value === null && $options['ignore_null']) { return null; diff --git a/src/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/RecursivePropertySetterTransformer.php index f20b6767..f9f487ed 100644 --- a/src/Transformer/RecursivePropertySetterTransformer.php +++ b/src/Transformer/RecursivePropertySetterTransformer.php @@ -29,14 +29,7 @@ public function __construct( ) { } - /** - * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if ($value === null && $options['ignore_null']) { return null; @@ -54,9 +47,7 @@ public function transform($value, array $options = []) $protertiesToSet = []; foreach ($options['set_properties'] as $propertyName => $propertyValuePath) { $protertiesValue = null; - if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $propertyValuePath)) { - $protertiesValue = null; - } else { + if (! $options['ignore_missing'] || $this->accessor->isReadable($value, $propertyValuePath)) { $protertiesValue = $this->accessor->getValue($value, $propertyValuePath); if ($protertiesValue === null && ! $options['ignore_null']) { throw new TransformerException($propertyValuePath); diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index 374c1bc8..2ce44a25 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -34,16 +34,15 @@ public function __construct( $this->transformerRegistry = $transformerRegistry; } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { foreach ($options['rules_set'] as $rule) { if ($this->matchRule($value, $rule, $options['use_value_as_variables'])) { if ($rule['set_null']) { return null; - } elseif ($rule['constant'] !== null) { - return $rule['constant']; } - return $this->applyTransformers($rule['transformers'], $value); + + return $rule['constant'] ?? $this->applyTransformers($rule['transformers'], $value); } } @@ -55,7 +54,7 @@ public function getCode(): string return 'rules'; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('use_value_as_variables', false); $resolver->setAllowedTypes('use_value_as_variables', 'bool'); @@ -141,6 +140,7 @@ protected function matchRule(mixed $value, string|ParsedExpression $rule, bool $ return $this->language->evaluate($rule['condition'], $expressionValues); } + /** @noinspection PhpStrictTypeCheckingInspection */ return $rule['default']; } } diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php index 60bef40f..34241a3e 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/SlugifyTransformer.php @@ -22,12 +22,7 @@ */ class SlugifyTransformer implements ConfigurableTransformerInterface { - /** - * Must return the transformed $value - * - * @param mixed $value - */ - public function transform($value, array $options = []): string + public function transform(mixed $value, array $options = []): string { /** @var Transliterator $transliterator */ $transliterator = $options['transliterator']; diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php index 020c9dd6..00f033d2 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/SprintfTransformer.php @@ -14,6 +14,7 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; +use function is_array; /** * Use sprintf() function to format string @@ -27,9 +28,9 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('format', 'string'); } - public function transform($value, array $options = []): string + public function transform(mixed $value, array $options = []): string { - if (! \is_array($value)) { + if (! is_array($value)) { $value = [$value]; } diff --git a/src/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php index e18a871d..d9401d2d 100644 --- a/src/Transformer/TransformerInterface.php +++ b/src/Transformer/TransformerInterface.php @@ -20,17 +20,11 @@ interface TransformerInterface { /** * Must return the transformed $value - * - * @param mixed $value - * - * @return mixed */ - public function transform($value, array $options = []); + public function transform(mixed $value, array $options = []): mixed; /** * Returns the unique code to identify the transformer - * - * @return string */ - public function getCode(); + public function getCode(): string; } diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index 2430f525..c20b71ae 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -20,12 +20,7 @@ */ class TrimTransformer implements ConfigurableTransformerInterface { - /** - * Must return the transformed $value - * - * @param mixed $value - */ - public function transform($value, array $options = []): ?string + public function transform(mixed $value, array $options = []): ?string { if ($value === null) { return null; diff --git a/src/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php index 0e33845b..c74b3fc8 100644 --- a/src/Transformer/TypeSetterTransformer.php +++ b/src/Transformer/TypeSetterTransformer.php @@ -28,7 +28,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('type', 'string'); } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { $return = settype($value, $options['type']); diff --git a/src/Transformer/UnsetTransformer.php b/src/Transformer/UnsetTransformer.php index 5d6ab8cf..39c27718 100644 --- a/src/Transformer/UnsetTransformer.php +++ b/src/Transformer/UnsetTransformer.php @@ -16,6 +16,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use UnexpectedValueException; +use function is_array; /** * Unset a given property @@ -29,9 +30,9 @@ public function __construct(PropertyAccessorInterface $accessor) $this->accessor = $accessor; } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): array { - if (! \is_array($value)) { + if (! is_array($value)) { throw new UnexpectedValueException('Given value must be an array'); } diff --git a/src/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php index 2335bbd5..711dbea1 100644 --- a/src/Transformer/WrapperTransformer.php +++ b/src/Transformer/WrapperTransformer.php @@ -20,10 +20,10 @@ class WrapperTransformer implements ConfigurableTransformerInterface /** * Must return the transformed $value */ - public function transform(mixed $input, array $options = []): array + public function transform(mixed $value, array $options = []): array { return [ - $options['wrapper_key'] => $input, + $options['wrapper_key'] => $value, ]; } diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index 561383e9..d1d84e55 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -23,24 +23,27 @@ use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use UnexpectedValueException; +use function array_map; +use function is_array; +use function is_string; /** * Manipulate XML elements using xpath */ class XpathEvaluatorTransformer implements ConfigurableTransformerInterface { - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired('query'); $resolver->setAllowedTypes('query', ['string', 'array']); $resolver->setNormalizer('query', function (Options $options, $value): string|array { // Basic case : a single query - if (\is_string($value)) { + if (is_string($value)) { return $value; } // Complex case : a list of subqueries, each can override root level options - if (\is_array($value)) { + if (is_array($value)) { $queryOptions = []; $queryResolver = new OptionsResolver(); $this->configureQueryOptions($queryResolver, $options); @@ -48,7 +51,7 @@ public function configureOptions(OptionsResolver $resolver) $queryResolver->setAllowedTypes('subquery', 'string'); foreach ($value as $code => $subquery) { - if (\is_string($subquery)) { + if (is_string($subquery)) { $subquery = [ 'subquery' => $subquery, ]; @@ -84,7 +87,7 @@ public function configureQueryOptions(OptionsResolver $resolver, Options $parent $resolver->setAllowedTypes('unwrap_value', 'bool'); } - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { if (! $value instanceof DOMNode) { throw new UnexpectedValueException('Input should be a ' . DOMNode::class); @@ -93,8 +96,8 @@ public function transform($value, array $options = []) $xpath = $this->buildXpath($value); $query = $options['query']; - if (\is_array($query)) { - $result = \array_map( + if (is_array($query)) { + $result = array_map( fn ($subquery) => $this->query($xpath, $subquery['subquery'], $value, $subquery), $query ); @@ -117,10 +120,7 @@ public function buildXpath(DOMNode $node): DOMXPath return new DOMXPath($doc); } - /** - * @return mixed - */ - public function query(DOMXPath $xpath, string $query, DOMNode $node, array $options) + public function query(DOMXPath $xpath, string $query, DOMNode $node, array $options): mixed { // TODO check if query is relative ? $nodeList = $xpath->query($query, $node); @@ -128,7 +128,7 @@ public function query(DOMXPath $xpath, string $query, DOMNode $node, array $opti // Convert results to text if ($options['unwrap_value']) { - $results = \array_map(function (DOMNode $item) use ($query): string { + $results = array_map(static function (DOMNode $item) use ($query): string { if ($item instanceof DOMAttr) { return $item->value; } @@ -138,18 +138,18 @@ public function query(DOMXPath $xpath, string $query, DOMNode $node, array $opti return $item->textContent; } - throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); + throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '$query'"); }, $results); } // Unwrap the node list if ($options['single_result']) { if (count($results) > 1) { - throw new UnexpectedValueException("There is too much results for query '{$query}'"); + throw new UnexpectedValueException("There is too much results for query '$query'"); } - if (count($results) === 0 && ! $options['ignore_missing']) { - throw new UnexpectedValueException("There is not enough results for query '{$query}'"); + if ( ! $options['ignore_missing'] && count($results) === 0) { + throw new UnexpectedValueException("There is not enough results for query '$query'"); } if (count($results) === 1) { diff --git a/src/Validator/ConstraintLoader.php b/src/Validator/ConstraintLoader.php index eae41577..d698c7c6 100644 --- a/src/Validator/ConstraintLoader.php +++ b/src/Validator/ConstraintLoader.php @@ -15,6 +15,8 @@ use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Loader\AbstractLoader; +use function count; +use function is_array; class ConstraintLoader extends AbstractLoader { @@ -32,16 +34,16 @@ public function buildConstraints(array $nodes): array $values = []; foreach ($nodes as $name => $childNodes) { - if (is_numeric($name) && \is_array($childNodes) && \count($childNodes) === 1) { + if (is_numeric($name) && is_array($childNodes) && count($childNodes) === 1) { $options = current($childNodes); - if (\is_array($options)) { + if (is_array($options)) { $options = $this->buildConstraints($options); } $values[] = $this->newConstraint(key($childNodes), $options); } else { - if (\is_array($childNodes)) { + if (is_array($childNodes)) { $childNodes = $this->buildConstraints($childNodes); } From 4de4c0a368cb1c2a21b4a4e458c5bf668a1daa97 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 29 Mar 2023 22:25:16 +0200 Subject: [PATCH 174/304] refacto deprecations Model --- src/Model/SubprocessInstance.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index 1c606882..8a51d282 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -49,7 +49,7 @@ public function __construct( $this->consolePath = $kernel->getProjectDir() . '/bin/console'; $this->environment = $kernel->getEnvironment(); - $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid() . '.json-stream'; // Todo use param ? + $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid('', true) . '.json-stream'; $this->logDir = $kernel->getLogDir() . '/process'; } @@ -58,7 +58,7 @@ public function __construct( * * @return $this */ - public function buildProcess() + public function buildProcess(): static { $pathFinder = new PhpExecutableFinder(); @@ -74,7 +74,7 @@ public function buildProcess() $fs = new Filesystem(); $fs->mkdir($this->logDir); if (! $fs->exists($this->consolePath)) { - throw new RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); + throw new RuntimeException("Unable to resolve path to symfony console '$this->consolePath'"); } if ($this->options[self::OPTION_JSON_BUFFERING]) { From 8ba646aa9a19bc45b0b501d075be67f2497df538 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 17:43:58 +0200 Subject: [PATCH 175/304] remove obsolete code --- Makefile | 5 +---- src/hooks/build | 6 ------ 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100755 src/hooks/build diff --git a/Makefile b/Makefile index f25e19ac..a4c6ac06 100644 --- a/Makefile +++ b/Makefile @@ -17,12 +17,9 @@ pull: pull/$(SF_ENV) pull/sf5: docker pull cleverage/process-bundle:sf5 -build/local: +build: docker build -t cleverage_process:test . -build/%: - DOCKER_TAG=$(@F) DOCKERFILE_PATH=Dockerfile IMAGE_NAME=cleverage/process-bundle:$(@F) ./hooks/build - shell: shell/$(SF_ENV) shell/local: diff --git a/src/hooks/build b/src/hooks/build deleted file mode 100755 index d12dd88b..00000000 --- a/src/hooks/build +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -# This script file is used by https://hub.docker.com/ for automated build -# See https://docs.docker.com/docker-hub/builds/advanced/ for available variables - -docker build --build-arg SF_ENV=${DOCKER_TAG} -f ${DOCKERFILE_PATH} -t ${IMAGE_NAME} . From 68776d1b714b4aac08a478ee31b5118bbae1ca28 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 17:53:31 +0200 Subject: [PATCH 176/304] refacto Exceptions --- src/Exception/CircularProcessException.php | 8 +--- .../InvalidProcessConfigurationException.php | 2 +- src/Exception/MissingProcessException.php | 7 +--- .../MissingTaskConfigurationException.php | 7 +--- src/Exception/MissingTransformerException.php | 7 +--- src/Exception/MultiBranchProcessException.php | 41 ------------------- .../PhpFunctionProvider.php | 2 +- 7 files changed, 10 insertions(+), 64 deletions(-) delete mode 100644 src/Exception/MultiBranchProcessException.php diff --git a/src/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php index 58d6d1c8..22e4978b 100644 --- a/src/Exception/CircularProcessException.php +++ b/src/Exception/CircularProcessException.php @@ -20,13 +20,9 @@ */ class CircularProcessException extends UnexpectedValueException implements ProcessExceptionInterface { - /** - * @param string $processCode - * @param string $taskCode - */ - public static function create($processCode, $taskCode): self + public static function create(?string $processCode = '', ?string $taskCode = ''): self { - $errorStr = "Process '{$processCode}' contains circular dependency (task '{$taskCode}' has itself as ancestor, at some point)"; + $errorStr = "Process '$processCode' contains circular dependency (task '$taskCode' has itself as ancestor, at some point)"; return new self($errorStr); } diff --git a/src/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php index bab90070..ea5507ea 100644 --- a/src/Exception/InvalidProcessConfigurationException.php +++ b/src/Exception/InvalidProcessConfigurationException.php @@ -30,7 +30,7 @@ public static function createNotInMain( $taskListStr = '[' . implode(', ', $mainTaskList) . ']'; return new self( - "Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr} (from process: {$processConfiguration->getCode()})" + "Task '{$taskConfig->getCode()}' is not in main task list : $taskListStr (from process: {$processConfiguration->getCode()})" ); } diff --git a/src/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php index 0e9ad2ac..43fb197c 100644 --- a/src/Exception/MissingProcessException.php +++ b/src/Exception/MissingProcessException.php @@ -20,12 +20,9 @@ */ class MissingProcessException extends UnexpectedValueException implements ProcessExceptionInterface { - /** - * @param string $code - */ - public static function create($code): self + public static function create(?string $code = ''): self { - $errorStr = "No process with code : {$code}"; + $errorStr = "No process with code : $code"; return new self($errorStr); } diff --git a/src/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php index f6b93a00..413fa5a3 100644 --- a/src/Exception/MissingTaskConfigurationException.php +++ b/src/Exception/MissingTaskConfigurationException.php @@ -20,12 +20,9 @@ */ class MissingTaskConfigurationException extends UnexpectedValueException implements ProcessExceptionInterface { - /** - * @param string $code - */ - public static function create($code): self + public static function create(?string $code = ''): self { - $errorStr = "No task configuration with code : {$code}"; + $errorStr = "No task configuration with code : $code"; return new self($errorStr); } diff --git a/src/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php index 6abaef7f..8c33fd7b 100644 --- a/src/Exception/MissingTransformerException.php +++ b/src/Exception/MissingTransformerException.php @@ -20,12 +20,9 @@ */ class MissingTransformerException extends UnexpectedValueException implements ProcessExceptionInterface { - /** - * @param string $code - */ - public static function create($code): self + public static function create(?string $code = ''): self { - $errorStr = "No transformer with code : {$code}"; + $errorStr = "No transformer with code : $code"; return new self($errorStr); } diff --git a/src/Exception/MultiBranchProcessException.php b/src/Exception/MultiBranchProcessException.php deleted file mode 100644 index 6d10cbcd..00000000 --- a/src/Exception/MultiBranchProcessException.php +++ /dev/null @@ -1,41 +0,0 @@ - ExpressionFunction::fromPhp($func), $this->functions); } From 3df905fda282faf425b75a4122498f8a8ee8c174 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 17:54:55 +0200 Subject: [PATCH 177/304] refacto EventListener --- src/EventListener/DataQueueEventListener.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/EventListener/DataQueueEventListener.php b/src/EventListener/DataQueueEventListener.php index 036f73f8..59297b8b 100644 --- a/src/EventListener/DataQueueEventListener.php +++ b/src/EventListener/DataQueueEventListener.php @@ -26,7 +26,7 @@ class DataQueueEventListener /** * @var SplQueue[] */ - protected $queues = []; + protected array $queues = []; public function pushData(EventDispatcherTaskEvent $event): void { @@ -34,10 +34,7 @@ public function pushData(EventDispatcherTaskEvent $event): void $queue->push(clone $event->getState()); } - /** - * @param string $processName - */ - public function getQueue($processName): SplQueue + public function getQueue(string $processName): SplQueue { if (! array_key_exists($processName, $this->queues)) { $this->queues[$processName] = new SplQueue(); From 3e524792a69289d03ae4992f2610a0b9f41b3f77 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 17:58:04 +0200 Subject: [PATCH 178/304] refacto Events --- src/Event/ConsoleProcessEvent.php | 8 +++---- src/Event/EventDispatcherTaskEvent.php | 3 ++- src/Event/GenericEvent.php | 31 -------------------------- src/Event/ProcessEvent.php | 13 ++++------- 4 files changed, 9 insertions(+), 46 deletions(-) delete mode 100644 src/Event/GenericEvent.php diff --git a/src/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php index 3b577896..79b7ef7c 100644 --- a/src/Event/ConsoleProcessEvent.php +++ b/src/Event/ConsoleProcessEvent.php @@ -15,11 +15,12 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Event object used during CLI process manipulation */ -class ConsoleProcessEvent extends GenericEvent +class ConsoleProcessEvent extends Event { final public const EVENT_CLI_INIT = 'cleverage_process.cli.init'; @@ -41,10 +42,7 @@ public function getConsoleOutput(): OutputInterface return $this->consoleOutput; } - /** - * @return mixed - */ - public function getProcessInput() + public function getProcessInput(): mixed { return $this->processInput; } diff --git a/src/Event/EventDispatcherTaskEvent.php b/src/Event/EventDispatcherTaskEvent.php index 5b48d56d..1646ab0c 100644 --- a/src/Event/EventDispatcherTaskEvent.php +++ b/src/Event/EventDispatcherTaskEvent.php @@ -14,8 +14,9 @@ namespace CleverAge\ProcessBundle\Event; use CleverAge\ProcessBundle\Model\ProcessState; +use Symfony\Contracts\EventDispatcher\Event; -class EventDispatcherTaskEvent extends GenericEvent +class EventDispatcherTaskEvent extends Event { public function __construct( protected ProcessState $state diff --git a/src/Event/GenericEvent.php b/src/Event/GenericEvent.php deleted file mode 100644 index 788ce05b..00000000 --- a/src/Event/GenericEvent.php +++ /dev/null @@ -1,31 +0,0 @@ -processCode; } - /** - * @return mixed - */ - public function getProcessInput() + public function getProcessInput(): mixed { return $this->processInput; } - /** - * @return mixed - */ - public function getProcessOutput() + public function getProcessOutput(): mixed { return $this->processOutput; } From f291aed2c9587ca576867fa772ceb2fd5d7adf24 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 18:01:05 +0200 Subject: [PATCH 179/304] refacto DependencyInjection --- src/DependencyInjection/CleverAgeProcessExtension.php | 9 ++++++++- .../Compiler/RegistryCompilerPass.php | 11 +++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index fb0b3399..959f54ec 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -15,6 +15,7 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use CleverAge\ProcessBundle\Transformer\GenericTransformer; +use Exception; use ReflectionClass; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -22,6 +23,7 @@ use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\Finder\Finder; +use function dirname; /** * This is the class that loads and manages your bundle configuration. @@ -30,11 +32,14 @@ */ class CleverAgeProcessExtension extends Extension { + /** + * @throws Exception + */ public function load(array $configs, ContainerBuilder $container): void { // Get the path of the service folder wherever the bundle is installed $reflection = new ReflectionClass($this); - $serviceFolderPath = \dirname($reflection->getFileName(), 2) . '/Resources/config/services'; + $serviceFolderPath = dirname($reflection->getFileName(), 2) . '/Resources/config/services'; $this->findServices($container, $serviceFolderPath); $configuration = new Configuration(); @@ -58,6 +63,8 @@ public function load(array $configs, ContainerBuilder $container): void /** * Recursively import config files into container + * + * @throws Exception */ protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void { diff --git a/src/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php index 0ca13ee0..2677e941 100644 --- a/src/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/src/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -22,15 +22,10 @@ */ class RegistryCompilerPass implements CompilerPassInterface { - /** - * @param string $registry - * @param string $tag - * @param string $method - */ public function __construct( - protected $registry, - protected $tag, - protected $method + protected ?string $registry = null, + protected ?string $tag = null, + protected ?string $method = null ) { } From 8e18c05320733b2b076bf29f800216ab058c239d Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 18:03:09 +0200 Subject: [PATCH 180/304] remove deprecated method --- src/DependencyInjection/Configuration.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 47c0f109..4cdfeabb 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -172,15 +172,6 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition): void ->values($logLevels) ->defaultValue(LogLevel::CRITICAL); - $logErrorNode = $definition->booleanNode('log_errors') - ->defaultTrue(); - $this->deprecateNode( - $logErrorNode, - 'cleverage/process-bundle', - '2.0', - 'The child node "%node%" at path "%path%" is deprecated in favor of "log_level".' - ); - foreach (['outputs', 'errors', 'error_outputs'] as $nodeName) { $definition->arrayNode($nodeName) ->beforeNormalization() @@ -190,17 +181,6 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition): void } } - /** - * An helper method to deprecate a node. - * Provides compatibility with Sf3, 4 and 5 - * - * @TODO remove this once support for Symfony 3 and 4 is dropped - */ - protected function deprecateNode(NodeDefinition $node, string $package, string $version, string $message): void - { - $node->setDeprecated($package, $version, $message); - } - /** * An helper method to create a TreeBuilder and get the root node. * Provides compatibility with Sf3, 4 and 5 From 8ff1b6ca7160950c55c9621bf7c95902d5158354 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 18:11:09 +0200 Subject: [PATCH 181/304] remove deprecated method --- src/DependencyInjection/Configuration.php | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 4cdfeabb..4beceb24 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -17,7 +17,6 @@ use Psr\Log\LogLevel; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\NodeBuilder; -use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -33,9 +32,10 @@ public function __construct( ) { } - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { - [$treeBuilder, $rootNode] = $this->createTreeBuilder(); + $treeBuilder = new TreeBuilder($this->root); + $rootNode = $treeBuilder->getRootNode(); $definition = $rootNode->children(); // Default error strategy $definition->enumNode('default_error_strategy') @@ -86,7 +86,6 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition): v /** * "configurations" root configuration - * @TODO rename this root as "processes" */ protected function appendRootProcessConfigDefinition(NodeBuilder $definition): void { @@ -180,20 +179,4 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition): void ->prototype('scalar'); } } - - /** - * An helper method to create a TreeBuilder and get the root node. - * Provides compatibility with Sf3, 4 and 5 - * - * @TODO remove this once support for Symfony 3 and 4 is dropped - * - * @return array A tuple containing [TreeBuilder, NodeDefinition] - */ - protected function createTreeBuilder(): array - { - $treeBuilder = new TreeBuilder($this->root); - $rootNode = $treeBuilder->getRootNode(); - - return [$treeBuilder, $rootNode]; - } } From d289879d0fea6aef0e4b9edf1b0a2ac62430fc63 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 20:48:39 +0200 Subject: [PATCH 182/304] upgrade symfony + remove polyfill + deprecations --- composer.json | 39 +++++++++++++------ src/Command/ExecuteProcessCommand.php | 19 ++++++--- src/Configuration/ProcessConfiguration.php | 2 +- src/Context/ContextualOptionResolver.php | 11 +++--- src/DependencyInjection/Configuration.php | 16 ++++---- .../PhpFunctionProvider.php | 2 +- 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index 30c7187d..8add6982 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,12 @@ "email": "mveyrenc@clever-age.com", "homepage": "https://github.com/mveyrenc", "role": "Developer" + }, + { + "name": "Xavier Marchegay", + "email": "xmarchegay@clever-age.com", + "homepage": "https://github.com/xaviermarchegay", + "role": "Lead Developer" } ], "autoload": { @@ -41,6 +47,15 @@ "CleverAge\\ProcessBundle\\Tests\\": "tests/" } }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*" + }, "require": { "php": ">=8.1", "ext-json": "*", @@ -48,20 +63,20 @@ "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", - "symfony/config": "^6.0", - "symfony/dependency-injection": "^6.0", + "symfony/config": "^6.2", + "symfony/dependency-injection": "^6.2", "symfony/event-dispatcher-contracts": "^3", - "symfony/form": "^6.0", - "symfony/framework-bundle": "^6.0", - "symfony/expression-language": "^6.0", + "symfony/form": "^6.2", + "symfony/framework-bundle": "^6.2", + "symfony/expression-language": "^6.2", "symfony/monolog-bundle": "~3.3", - "symfony/console": "^6.0", - "symfony/options-resolver": "^6.0", - "symfony/process": "^6.0", - "symfony/property-access": "^6.0", - "symfony/serializer": "^6.0", - "symfony/validator": "^6.0", - "symfony/yaml": "^6.0", + "symfony/console": "^6.2", + "symfony/options-resolver": "^6.2", + "symfony/process": "^6.2", + "symfony/property-access": "^6.2", + "symfony/serializer": "^6.2", + "symfony/validator": "^6.2", + "symfony/yaml": "^6.2", "league/flysystem-bundle": "^3.1" }, "require-dev": { diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 605c0517..74afd662 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -17,6 +17,7 @@ use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use InvalidArgumentException; +use JsonException; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -26,7 +27,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; - +use Throwable; +use function count; use function is_array; /** @@ -74,6 +76,10 @@ protected function configure(): void $this->addOption('output-format', 't', InputOption::VALUE_OPTIONAL, 'Output format'); } + /** + * @throws Throwable + * @throws JsonException + */ protected function execute(InputInterface $input, OutputInterface $output): int { $inputData = $input->getOption('input'); @@ -117,7 +123,7 @@ protected function parseContextValues(InputInterface $input): array $context = []; foreach ($contextValues as $contextValue) { preg_match($pattern, (string) $contextValue, $parts); - if (\count($parts) !== 3 + if (count($parts) !== 3 || $parts[0] !== $contextValue) { throw new InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); } @@ -127,6 +133,9 @@ protected function parseContextValues(InputInterface $input): array return $context; } + /** + * @throws JsonException + */ protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output): void { // Skip all if undefined @@ -137,8 +146,8 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn // Handle printing the output if ($input->getOption('output') === self::OUTPUT_STDOUT) { if ($output->isVeryVerbose()) { - if ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP && class_exists(VarDumper::class)) { - VarDumper::dump($data); // @todo remove this please + if (class_exists(VarDumper::class) && ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP)) { + VarDumper::dump($data); } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { $output->writeln(json_encode($data, JSON_THROW_ON_ERROR)); } else { @@ -155,7 +164,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn $outputFile->writeLine($data); } - if ($output->isVerbose() && isset($outputFile)) { + if (isset($outputFile) && $output->isVerbose()) { $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index cb539c72..69555f02 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -148,7 +148,7 @@ public function getMainTaskGroup(): array $mainTask = $this->getMainTask(); foreach ($this->getDependencyGroups() as $branch) { - if (in_array($mainTask->getCode(), $branch, true)) { + if (in_array($mainTask?->getCode(), $branch, true)) { $this->mainTaskGroup = $branch; break; } diff --git a/src/Context/ContextualOptionResolver.php b/src/Context/ContextualOptionResolver.php index 0e96a040..2728ae3a 100644 --- a/src/Context/ContextualOptionResolver.php +++ b/src/Context/ContextualOptionResolver.php @@ -13,22 +13,23 @@ namespace CleverAge\ProcessBundle\Context; +use function is_array; +use function is_string; + class ContextualOptionResolver { /** * Basic value inference * Replaces "{{ key }}" by context[key] - * - * @return mixed */ - public function contextualizeOption(mixed $value, array $context) + public function contextualizeOption(mixed $value, array $context): mixed { // Recursively parse options - if (\is_array($value)) { + if (is_array($value)) { return $this->contextualizeOptions($value, $context); } - if (\is_string($value)) { + if (is_string($value)) { $pattern = sprintf('/{{[ ]*(%s){1}[ ]*}}/', implode('|', array_keys($context))); $matches = []; diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 4beceb24..f18ea989 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -77,11 +77,11 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition): v ->arrayNode('contextual_options') ->prototype('variable') ->end() - ->end() + ?->end() ->arrayNode('transformers') ->prototype('variable') ->end() - ->end(); + ?->end(); } /** @@ -110,22 +110,22 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition): void ->scalarNode('entry_point') ->defaultNull() ->end() - ->scalarNode('end_point') + ?->scalarNode('end_point') ->defaultNull() ->end() - ->scalarNode('description') + ?->scalarNode('description') ->defaultValue('') ->end() - ->scalarNode('help') + ?->scalarNode('help') ->defaultValue('') ->end() - ->scalarNode('public') + ?->scalarNode('public') ->defaultTrue() ->end() - ->arrayNode('options') + ?->arrayNode('options') ->prototype('variable') ->end() - ->end(); + ?->end(); /** @var ArrayNodeDefinition $tasksArrayDefinition */ $tasksArrayDefinition = $definition diff --git a/src/ExpressionLanguage/PhpFunctionProvider.php b/src/ExpressionLanguage/PhpFunctionProvider.php index 2a68f545..13d01be3 100644 --- a/src/ExpressionLanguage/PhpFunctionProvider.php +++ b/src/ExpressionLanguage/PhpFunctionProvider.php @@ -31,6 +31,6 @@ public function __construct( */ public function getFunctions(): array { - return array_map(fn ($func): ExpressionFunction => ExpressionFunction::fromPhp($func), $this->functions); + return array_map(static fn ($func): ExpressionFunction => ExpressionFunction::fromPhp($func), $this->functions); } } From 36f07b23326ab78b3368eb0e954df97af1887916 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 21:02:39 +0200 Subject: [PATCH 183/304] ecs + typage fort --- ecs.php | 2 +- src/CleverAgeProcessBundle.php | 10 ++- src/Command/ExecuteProcessCommand.php | 19 ++--- src/Command/ListProcessCommand.php | 4 +- src/Command/ProcessHelpCommand.php | 17 ++-- .../CleverAgeProcessExtension.php | 6 -- src/Exception/CircularProcessException.php | 2 +- .../InvalidProcessConfigurationException.php | 2 +- src/Exception/MissingProcessException.php | 2 +- .../MissingTaskConfigurationException.php | 2 +- src/Exception/MissingTransformerException.php | 2 +- src/Filesystem/CsvFile.php | 23 +++--- src/Filesystem/CsvResource.php | 79 +++++++------------ src/Filesystem/FileStreamInterface.php | 5 +- src/Filesystem/JsonStreamFile.php | 29 +++---- src/Filesystem/SeekableFileInterface.php | 4 +- src/Logger/AbstractProcessor.php | 2 +- src/Logger/TaskProcessor.php | 3 - src/Logger/TransformerProcessor.php | 3 - src/Manager/ProcessManager.php | 4 +- src/Model/AbstractConfigurableTask.php | 2 +- src/Model/SubprocessInstance.php | 2 +- src/Registry/ProcessConfigurationRegistry.php | 2 +- src/Task/ArrayMergeTask.php | 2 +- src/Task/ColumnAggregatorTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 2 +- src/Task/File/FileFetchTask.php | 16 +--- src/Task/File/FileMoverTask.php | 2 +- src/Task/File/FileReaderTask.php | 4 +- src/Task/File/FolderBrowserTask.php | 8 +- src/Task/File/InputFolderBrowserTask.php | 6 +- .../File/JsonStream/JsonStreamReaderTask.php | 5 +- src/Task/File/YamlReaderTask.php | 4 +- src/Task/GroupByAggregateIterableTask.php | 4 +- src/Task/InputAggregatorTask.php | 4 +- src/Task/InputIteratorTask.php | 4 - src/Task/IterableBatchTask.php | 4 +- src/Task/Process/ProcessExecutorTask.php | 7 +- src/Task/Process/ProcessLauncherTask.php | 2 +- .../Reporting/AdvancedStatCounterTask.php | 2 +- src/Task/Reporting/StatCounterTask.php | 2 +- src/Task/RowAggregatorTask.php | 4 +- src/Task/Serialization/DenormalizerTask.php | 5 +- src/Task/Serialization/NormalizerTask.php | 5 +- src/Task/SplitJoinLineTask.php | 2 +- src/Transformer/ConditionTrait.php | 9 ++- src/Transformer/ConvertValueTransformer.php | 4 +- src/Transformer/DenormalizeTransformer.php | 5 +- .../ExpressionLanguageMapTransformer.php | 2 +- src/Transformer/MappingTransformer.php | 2 +- src/Transformer/NormalizeTransformer.php | 5 +- .../Xml/XpathEvaluatorTransformer.php | 8 +- 52 files changed, 144 insertions(+), 213 deletions(-) diff --git a/ecs.php b/ecs.php index 65fb2278..adf7d649 100644 --- a/ecs.php +++ b/ecs.php @@ -18,7 +18,7 @@ SetList::DOCTRINE_ANNOTATIONS, ]); - $ecsConfig->paths([__DIR__ . 'src']); + $ecsConfig->paths([__DIR__ . '/src']); $ecsConfig->skip([AssignmentInConditionSniff::class]); }; diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 9e337912..acd3d0a0 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -29,9 +29,15 @@ public function build(ContainerBuilder $container): void parent::build($container); $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), + \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, + 0 ); - $container->addCompilerPass(new CheckSerializerCompilerPass()); + $container->addCompilerPass( + new CheckSerializerCompilerPass(), + \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, + 0 + ); } } diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 74afd662..fd01e3da 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -17,7 +17,6 @@ use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use InvalidArgumentException; -use JsonException; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -27,7 +26,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; -use Throwable; use function count; use function is_array; @@ -76,10 +74,7 @@ protected function configure(): void $this->addOption('output-format', 't', InputOption::VALUE_OPTIONAL, 'Output format'); } - /** - * @throws Throwable - * @throws JsonException - */ + protected function execute(InputInterface $input, OutputInterface $output): int { $inputData = $input->getOption('input'); @@ -96,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($input->getArgument('processCodes') as $code) { if (! $output->isQuiet()) { - $output->writeln("Starting process '$code'..."); + $output->writeln("Starting process '{$code}'..."); } // Execute each process @@ -104,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->handleOutputData($returnValue, $input, $output); if (! $output->isQuiet()) { - $output->writeln("Process '$code' executed successfully"); + $output->writeln("Process '{$code}' executed successfully"); } } @@ -133,9 +128,7 @@ protected function parseContextValues(InputInterface $input): array return $context; } - /** - * @throws JsonException - */ + protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output): void { // Skip all if undefined @@ -146,7 +139,9 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn // Handle printing the output if ($input->getOption('output') === self::OUTPUT_STDOUT) { if ($output->isVeryVerbose()) { - if (class_exists(VarDumper::class) && ($input->getOption('output-format') === self::OUTPUT_FORMAT_DUMP)) { + if (class_exists(VarDumper::class) && ($input->getOption( + 'output-format' + ) === self::OUTPUT_FORMAT_DUMP)) { VarDumper::dump($data); } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { $output->writeln(json_encode($data, JSON_THROW_ON_ERROR)); diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index 56264089..cf022da4 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -70,14 +70,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $publicCount = array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); $privateCount = array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); $output->writeln( - "There are $publicCount process configurations defined (and $privateCount private) :" + "There are {$publicCount} process configurations defined (and {$privateCount} private) :" ); $messages = []; foreach ($processConfigurations as $processConfiguration) { if ($processConfiguration->isPublic() || $input->getOption('all')) { $countTasks = count($processConfiguration->getTaskConfigurations()); - $message = " - {$processConfiguration->getCode()} with $countTasks tasks"; + $message = " - {$processConfiguration->getCode()} with {$countTasks} tasks"; if ($processConfiguration->isPrivate()) { $message .= ' (private)'; diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index a81793d1..22176bad 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -126,7 +126,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $branches = array_filter($branches); if (! empty($branches)) { $branchStr = '[' . implode(', ', $branches) . ']'; - $output->writeln("All branches are not resolved : $branchStr"); + $output->writeln("All branches are not resolved : {$branchStr}"); } return Command::SUCCESS; @@ -135,8 +135,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * Try to find a best candidate for next display */ - protected function findBestNextTask(array $branches, array $taskList, ProcessConfiguration $process): int|null|string - { + protected function findBestNextTask( + array $branches, + array $taskList, + ProcessConfiguration $process + ): int|null|string { // Get resolvable tasks $taskCandidates = []; foreach ($taskList as $taskCode) { @@ -272,7 +275,7 @@ protected function resolveBranchOutput( if (! $foundBranch) { $output->writeln( - "Could not find previous branch : $taskCode depends on {$prevTask->getCode()}" + "Could not find previous branch : {$taskCode} depends on {$prevTask->getCode()}" ); } } @@ -346,7 +349,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): // Write main line $nodeStr = self::CHAR_NODE; if ($task->isInErrorBranch()) { - $nodeStr = "$nodeStr"; + $nodeStr = "{$nodeStr}"; } $this->writeBranches( @@ -361,7 +364,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): if ($output->isVerbose() && $task->getHelp()) { $helpLines = array_filter(explode("\n", $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "$helpLine"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; $this->writeBranches($output, $branches, $helpMessage); } } @@ -472,7 +475,7 @@ protected function writeBranches( } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', $str)); + $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index 959f54ec..480002b4 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -15,7 +15,6 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use CleverAge\ProcessBundle\Transformer\GenericTransformer; -use Exception; use ReflectionClass; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -32,9 +31,6 @@ */ class CleverAgeProcessExtension extends Extension { - /** - * @throws Exception - */ public function load(array $configs, ContainerBuilder $container): void { // Get the path of the service folder wherever the bundle is installed @@ -63,8 +59,6 @@ public function load(array $configs, ContainerBuilder $container): void /** * Recursively import config files into container - * - * @throws Exception */ protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void { diff --git a/src/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php index 22e4978b..eb851599 100644 --- a/src/Exception/CircularProcessException.php +++ b/src/Exception/CircularProcessException.php @@ -22,7 +22,7 @@ class CircularProcessException extends UnexpectedValueException implements Proce { public static function create(?string $processCode = '', ?string $taskCode = ''): self { - $errorStr = "Process '$processCode' contains circular dependency (task '$taskCode' has itself as ancestor, at some point)"; + $errorStr = "Process '{$processCode}' contains circular dependency (task '{$taskCode}' has itself as ancestor, at some point)"; return new self($errorStr); } diff --git a/src/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php index ea5507ea..bab90070 100644 --- a/src/Exception/InvalidProcessConfigurationException.php +++ b/src/Exception/InvalidProcessConfigurationException.php @@ -30,7 +30,7 @@ public static function createNotInMain( $taskListStr = '[' . implode(', ', $mainTaskList) . ']'; return new self( - "Task '{$taskConfig->getCode()}' is not in main task list : $taskListStr (from process: {$processConfiguration->getCode()})" + "Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr} (from process: {$processConfiguration->getCode()})" ); } diff --git a/src/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php index 43fb197c..3d376124 100644 --- a/src/Exception/MissingProcessException.php +++ b/src/Exception/MissingProcessException.php @@ -22,7 +22,7 @@ class MissingProcessException extends UnexpectedValueException implements Proces { public static function create(?string $code = ''): self { - $errorStr = "No process with code : $code"; + $errorStr = "No process with code : {$code}"; return new self($errorStr); } diff --git a/src/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php index 413fa5a3..e3b959f7 100644 --- a/src/Exception/MissingTaskConfigurationException.php +++ b/src/Exception/MissingTaskConfigurationException.php @@ -22,7 +22,7 @@ class MissingTaskConfigurationException extends UnexpectedValueException impleme { public static function create(?string $code = ''): self { - $errorStr = "No task configuration with code : $code"; + $errorStr = "No task configuration with code : {$code}"; return new self($errorStr); } diff --git a/src/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php index 8c33fd7b..78c8f9f5 100644 --- a/src/Exception/MissingTransformerException.php +++ b/src/Exception/MissingTransformerException.php @@ -22,7 +22,7 @@ class MissingTransformerException extends UnexpectedValueException implements Pr { public static function create(?string $code = ''): self { - $errorStr = "No transformer with code : $code"; + $errorStr = "No transformer with code : {$code}"; return new self($errorStr); } diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 9dca8beb..12ec3d0c 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -16,29 +16,32 @@ use RuntimeException; use UnexpectedValueException; +use function dirname; +use function in_array; + /** * Read and write CSV files through a simple API. */ class CsvFile extends CsvResource { /** - * @param string $filePath Also accept a resource - * @param string $delimiter CSV delimiter - * @param string $enclosure - * @param string $escape - * @param mixed[]|null $headers Leave null to read the headers from the file - * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) + * @param string $filePath Also accept a resource + * @param string $delimiter CSV delimiter + * @param string $enclosure + * @param string $escape + * @param ?array $headers Leave null to read the headers from the file + * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) */ public function __construct( protected $filePath, $delimiter = ',', $enclosure = '"', $escape = '\\', - array $headers = null, + ?array $headers = null, string $mode = 'rb' ) { - if (! \in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { - $dirname = \dirname($this->filePath); + if (! in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { + $dirname = dirname($this->filePath); if (! @mkdir($dirname, 0755, true) && ! is_dir($dirname)) { throw new RuntimeException(sprintf('Directory "%s" was not created', $dirname)); } @@ -50,7 +53,7 @@ public function __construct( } // All modes allowing file reading, binary safe modes are handled by stripping out the b during test $readAllowedModes = ['r', 'r+', 'w+', 'a+', 'x+', 'c+']; - if ($headers === null && ! \in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { + if ($headers === null && ! in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { // Cannot read headers if the file was just created throw new UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index eace7964..18aa0371 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -16,6 +16,11 @@ use LogicException; use RuntimeException; use UnexpectedValueException; +use ValueError; +use function count; +use function gettype; +use function is_array; +use function is_resource; /** * Read and write CSV resources through a simple API. @@ -27,54 +32,35 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf */ protected $handler; - /** - * @var int|null - */ - protected $lineCount; + protected ?int $lineCount = null; protected array $headers; - /** - * @var bool - */ - protected $manualHeaders = false; + protected bool $manualHeaders = false; protected int $headerCount; - /** - * @var int - */ - protected $lineNumber = 1; + protected ?int $lineNumber = 1; protected bool $closed; - /** - * @var bool - */ - protected $seekCalled = false; + protected bool $seekCalled = false; - /** - * @param resource $resource - * @param string $delimiter CSV delimiter - * @param string $enclosure - * @param string $escape - * @param mixed[]|null $headers Leave null to read the headers from the file - */ public function __construct( $resource, - protected $delimiter = ',', - protected $enclosure = '"', - protected $escape = '\\', + protected string $delimiter = ',', + protected string $enclosure = '"', + protected string $escape = '\\', array $headers = null ) { - if (! \is_resource($resource)) { - $type = \gettype($resource); + if (! is_resource($resource)) { + $type = gettype($resource); throw new UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); } $this->handler = $resource; $this->headers = $this->parseHeaders($headers); - $this->headerCount = \count($this->headers); + $this->headerCount = count($this->headers); } /** @@ -169,10 +155,8 @@ public function isEndOfFile(): bool /** * Warning, this function will return exactly the same value as the fgetcsv() function. - * - * @param null|int $length */ - public function readRaw($length = null): array|false + public function readRaw(?int $length = null): array|false { $this->assertOpened(); ++$this->lineNumber; @@ -180,12 +164,7 @@ public function readRaw($length = null): array|false return fgetcsv($this->handler, $length, $this->delimiter, $this->enclosure, $this->escape); } - /** - * @param int|null $length - * - * @return array - */ - public function readLine($length = null): ?array + public function readLine(int $length = null): ?array { if ($this->seekCalled) { $filePosition = "at position {$this->tell()}"; @@ -202,15 +181,16 @@ public function readLine($length = null): ?array throw new UnexpectedValueException($message); } - $count = \count($values); + $count = count($values); if ($count !== $this->headerCount) { $message = "Number of columns not matching {$filePosition} for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; throw new UnexpectedValueException($message); } - $combined = array_combine($this->headers, $values); - if ($combined === false) { + try { + $combined = array_combine($this->headers, $values); + } catch (ValueError) { throw new RuntimeException('Cannot combine headers with values'); } @@ -220,7 +200,7 @@ public function readLine($length = null): ?array /** * Warning, this function will return exactly the same value as the fgetcsv() function. */ - public function writeRaw(array $fields): int + public function writeRaw(array $fields): int|false { $this->assertOpened(); ++$this->lineNumber; @@ -230,7 +210,7 @@ public function writeRaw(array $fields): int public function writeLine(array $fields): int { - $count = \count($fields); + $count = count($fields); if ($count !== $this->headerCount) { $message = "Trying to write an invalid number of columns for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; @@ -276,10 +256,7 @@ public function tell(): int return ftell($this->handler); } - /** - * @param int $offset - */ - public function seek($offset): int + public function seek(int $offset): int { $this->assertOpened(); $this->seekCalled = true; @@ -325,7 +302,7 @@ protected function parseHeaders(array $headers = null): array // If headers are not passed in the constructor but file is readable, try to read headers from file if ($headers === null) { $autoHeaders = $this->readRaw(); - if ($autoHeaders === false || \count($autoHeaders) === 0) { + if ($autoHeaders === false || count($autoHeaders) === 0) { throw new UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any @@ -336,12 +313,14 @@ protected function parseHeaders(array $headers = null): array } $this->manualHeaders = true; - if ($headers === null || ! \is_array($headers)) { + + if (! is_array($headers)) { throw new UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } - if (\count($headers) === 0) { + + if (count($headers) === 0) { throw new UnexpectedValueException( "Empty headers for {$this->getResourceName()}, you need to pass the headers manually" ); diff --git a/src/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php index 117ae72a..ec7ae244 100644 --- a/src/Filesystem/FileStreamInterface.php +++ b/src/Filesystem/FileStreamInterface.php @@ -27,10 +27,7 @@ public function getLineNumber(): int; public function isEndOfFile(): bool; - /** - * @param int|null $length - */ - public function readLine($length = null): ?array; + public function readLine(?int $length = null): ?array; /** * This methods rewinds the file to the first line of data, skipping the headers. diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index cce95a1a..cfc1f2ac 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -13,6 +13,7 @@ namespace CleverAge\ProcessBundle\Filesystem; +use JsonException; use SplFileObject; /** @@ -22,22 +23,11 @@ class JsonStreamFile implements FileStreamInterface, WritableFileInterface { protected SplFileObject $file; - /** - * @var int - */ - protected $lineCount; + protected ?int $lineCount = null; - /** - * @var int - */ - protected $lineNumber = 1; + protected int $lineNumber = 1; - /** - * JsonStreamFile constructor. - * - * @param string $mode - */ - public function __construct(string $filename, $mode = 'rb') + public function __construct(string $filename, string $mode = 'rb') { $this->file = new SplFileObject($filename, $mode); @@ -78,9 +68,9 @@ public function isEndOfFile(): bool /** * Return an array containing current data and moving the file pointer * - * @param null $length + * @throws JsonException */ - public function readLine($length = null): ?array + public function readLine(int $length = null): ?array { if ($this->isEndOfFile()) { return null; @@ -92,9 +82,12 @@ public function readLine($length = null): ?array return json_decode($rawLine, true, 512, JSON_THROW_ON_ERROR); } - public function writeLine(array $item): int + /** + * @throws JsonException + */ + public function writeLine(array $fields): int { - $this->file->fwrite(json_encode($item, JSON_THROW_ON_ERROR) . PHP_EOL); + $this->file->fwrite(json_encode($fields, JSON_THROW_ON_ERROR) . PHP_EOL); $this->lineNumber++; return $this->lineNumber; diff --git a/src/Filesystem/SeekableFileInterface.php b/src/Filesystem/SeekableFileInterface.php index 8b570e4f..798f6353 100644 --- a/src/Filesystem/SeekableFileInterface.php +++ b/src/Filesystem/SeekableFileInterface.php @@ -25,8 +25,6 @@ public function tell(): int; /** * Go to a specific position inside the file - * - * @param int $offset */ - public function seek($offset): int; + public function seek(int $offset): int; } diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index 0415b12e..05b98eb8 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -25,7 +25,7 @@ public function __construct( public function __invoke(LogRecord $record): LogRecord { - if (!empty($record->context)) { + if (! empty($record->context)) { $context = $this->normalizeRecordData($record->context); $record = new LogRecord( $record->datetime, diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index 5ce18164..fdc7094e 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -17,9 +17,6 @@ /** * Class TaskProcessor - * - * @package CleverAge\ProcessBundle\Logger - * @author Madeline Veyrenc */ class TaskProcessor extends AbstractProcessor { diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index dd9d58a7..d0729ecc 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -17,9 +17,6 @@ /** * Class TransformerProcessor - * - * @package CleverAge\ProcessBundle\Logger - * @author Madeline Veyrenc */ class TransformerProcessor extends AbstractProcessor { diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index a4480bb2..696cf0fd 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -313,7 +313,7 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'type' => 500, - 'message' => $exception->getMessage() + 'message' => $exception->getMessage(), ] ); } @@ -404,7 +404,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e $this->processLogger->debug("Flushing task {$taskConfiguration->getCode()}"); $task->flush($state); } else { - throw new UnexpectedValueException("Unknown execution flag: $executionFlag"); + throw new UnexpectedValueException("Unknown execution flag: {$executionFlag}"); } $exception = $state->getException(); diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 3f2183a1..9eebbc38 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -46,7 +46,7 @@ protected function getOption(ProcessState $state, string $code): mixed { $options = $this->getOptions($state); if (! array_key_exists($code, $options)) { - throw new InvalidArgumentException("Missing option $code"); + throw new InvalidArgumentException("Missing option {$code}"); } return $options[$code]; diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index 8a51d282..d41c944a 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -74,7 +74,7 @@ public function buildProcess(): static $fs = new Filesystem(); $fs->mkdir($this->logDir); if (! $fs->exists($this->consolePath)) { - throw new RuntimeException("Unable to resolve path to symfony console '$this->consolePath'"); + throw new RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); } if ($this->options[self::OPTION_JSON_BUFFERING]) { diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 4c8cba6d..8659e9b8 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -79,7 +79,7 @@ protected function resolveConfiguration(string $processCode): void if ((is_countable($rawTaskConfiguration['error_outputs']) ? count( $rawTaskConfiguration['error_outputs'] ) : 0) > 0) { - $m = "Don't define both 'errors' and 'error_outputs' for task $taskCode, these options "; + $m = "Don't define both 'errors' and 'error_outputs' for task {$taskCode}, these options "; $m .= "are the same, 'errors' is deprecated, just use the new one 'error_outputs'"; throw new LogicException($m); } diff --git a/src/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php index 422d609c..0842cc36 100644 --- a/src/Task/ArrayMergeTask.php +++ b/src/Task/ArrayMergeTask.php @@ -40,7 +40,7 @@ public function execute(ProcessState $state): void $mergeFunction = $this->getOption($state, 'merge_function'); if (! in_array($mergeFunction, self::MERGE_FUNC, true)) { - throw new InvalidArgumentException("Unknown merge function $mergeFunction"); + throw new InvalidArgumentException("Unknown merge function {$mergeFunction}"); } $this->mergedOutput = $mergeFunction($this->mergedOutput, $input); } diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index 333e7465..e72562ba 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -66,7 +66,7 @@ public function execute(ProcessState $state): void if (! empty($missingColumns)) { $colStr = implode(', ', $missingColumns); - $message = "Missing columns [$colStr] in input"; + $message = "Missing columns [{$colStr}] in input"; if ($this->getOption($state, 'ignore_missing')) { $this->logger->warning($message); diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index 3c47ac8a..3dde2a19 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -50,7 +50,7 @@ public function execute(ProcessState $state): void 'csv_file' => $this->csv->getFilePath(), 'csv_line' => $lineNumber, ]; - $this->logger->warning("Empty line detected at line: $lineNumber", $logContext); + $this->logger->warning("Empty line detected at line: {$lineNumber}", $logContext); } $state->setSkipped(true); diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index 3ecc8ed4..e49b7804 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -58,9 +58,7 @@ public function initialize(ProcessState $state): void $this->destinationFS = new Filesystem($this->getOption($state, 'destination_filesystem')); } - /** - * @throws FilesystemException - */ + public function execute(ProcessState $state): void { $this->findMatchingFiles($state); @@ -76,9 +74,7 @@ public function execute(ProcessState $state): void $state->setOutput($file); } - /** - * @throws FilesystemException - */ + public function next(ProcessState $state): mixed { $this->findMatchingFiles($state); @@ -86,9 +82,7 @@ public function next(ProcessState $state): mixed return next($this->matchingFiles); } - /** - * @throws FilesystemException - */ + protected function findMatchingFiles(ProcessState $state): void { $filePattern = $this->getOption($state, 'file_pattern'); @@ -117,9 +111,7 @@ protected function findMatchingFiles(ProcessState $state): void } } - /** - * @throws FilesystemException - */ + protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null { $prefixFrom = $this->getOption($state, 'source_filesystem'); diff --git a/src/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php index 2d8775a8..bbdf9eca 100644 --- a/src/Task/File/FileMoverTask.php +++ b/src/Task/File/FileMoverTask.php @@ -30,7 +30,7 @@ public function execute(ProcessState $state): void $fs = new Filesystem(); $file = $state->getInput(); if (! $fs->exists($file)) { - throw new UnexpectedValueException("File does not exists: '$file'"); + throw new UnexpectedValueException("File does not exists: '{$file}'"); } $dest = $options['destination']; if (is_dir($dest)) { diff --git a/src/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php index 34c9144a..e7382815 100644 --- a/src/Task/File/FileReaderTask.php +++ b/src/Task/File/FileReaderTask.php @@ -29,11 +29,11 @@ public function execute(ProcessState $state): void $filename = $options['filename']; if (! file_exists($filename)) { - throw new UnexpectedValueException("File does not exists: '$filename'"); + throw new UnexpectedValueException("File does not exists: '{$filename}'"); } if (! is_readable($filename)) { - throw new UnexpectedValueException("File is not readable: '$filename'"); + throw new UnexpectedValueException("File is not readable: '{$filename}'"); } $state->setOutput(file_get_contents($filename)); diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 3124a479..55d64d9c 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -72,10 +72,6 @@ public function execute(ProcessState $state): void * Moves the internal pointer to the next element, * return true if the task has a next element * return false if the task has terminated it's iteration - * - * @param ProcessState $state - * - * @return bool */ public function next(ProcessState $state): bool { @@ -97,11 +93,11 @@ protected function configureOptions(OptionsResolver $resolver): void static function (Options $options, $value) { if (! is_dir($value)) { throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '$value'" + "Folder path does not exists or is not a folder: '{$value}'" ); } if (! is_readable($value)) { - throw new InvalidConfigurationException("Folder path is not readable: '$value'"); + throw new InvalidConfigurationException("Folder path is not readable: '{$value}'"); } return $value; diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index 77bec3bd..d3c88220 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -55,7 +55,7 @@ protected function getOptions(ProcessState $state): array $folderPath = $options['base_folder_path'] . $state->getInput(); if ($this->folderPath && $folderPath !== $this->folderPath) { throw new LogicException( - "Folder path '$folderPath' already initialized with a different value $this->folderPath" + "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" ); } $this->folderPath = $folderPath; @@ -63,11 +63,11 @@ protected function getOptions(ProcessState $state): array if (! is_dir($this->folderPath)) { throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '$this->folderPath'" + "Folder path does not exists or is not a folder: '{$this->folderPath}'" ); } if (! is_readable($this->folderPath)) { - throw new InvalidConfigurationException("Folder path is not readable: '$this->folderPath'"); + throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); } $options['folder_path'] = $this->folderPath; diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index 628e5b3b..972f04f3 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -16,15 +16,12 @@ use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use JsonException; class JsonStreamReaderTask implements IterableTaskInterface { protected ?JsonStreamFile $file = null; - /** - * @throws JsonException - */ + public function execute(ProcessState $state): void { if ($this->file === null) { diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php index 43c4abc9..0a3788b1 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/YamlReaderTask.php @@ -37,7 +37,7 @@ protected function configureOptions(OptionsResolver $resolver): void 'file_path', static function (Options $options, $value) { if (! file_exists($value)) { - throw new UnexpectedValueException("File not found: $value"); + throw new UnexpectedValueException("File not found: {$value}"); } return $value; @@ -50,7 +50,7 @@ protected function initializeIterator(ProcessState $state): Iterator $filePath = $this->getOption($state, 'file_path'); $content = Yaml::parseFile($filePath); if (! is_array($content)) { - throw new InvalidArgumentException("File content is not an array: $filePath"); + throw new InvalidArgumentException("File content is not an array: {$filePath}"); } return new ArrayIterator($content); diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 20395db9..b12b73e3 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -23,9 +23,7 @@ class GroupByAggregateIterableTask extends AbstractConfigurableTask implements B */ final public const GROUP_BY_OPTION = 'group_by_accessors'; - /** - * @var array - */ + protected array $result = []; public function __construct( diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 8ec696f8..689d1858 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -48,7 +48,7 @@ public function execute(ProcessState $state): void $this->inputs = []; } else { throw new UnexpectedValueException( - "The output from input '$inputCode' has already been defined, please use an aggregator if you have an iterable output" + "The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output" ); } } @@ -95,7 +95,7 @@ protected function getInputCode(ProcessState $state): string ->getCode(); $inputCodes = $this->getOption($state, 'input_codes'); if (! array_key_exists($previousTaskCode, $inputCodes)) { - throw new UnexpectedValueException("Task '$previousTaskCode' is not mapped in the input_codes option"); + throw new UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); } return $inputCodes[$previousTaskCode]; diff --git a/src/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php index 30fcf6d8..6029dfa9 100644 --- a/src/Task/InputIteratorTask.php +++ b/src/Task/InputIteratorTask.php @@ -15,7 +15,6 @@ use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; -use Exception; use Iterator; use IteratorAggregate; use UnexpectedValueException; @@ -26,9 +25,6 @@ */ class InputIteratorTask extends AbstractIterableOutputTask { - /** - * @throws Exception - */ protected function initializeIterator(ProcessState $state): Iterator { $input = $state->getInput(); diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index 635c2941..9a540138 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -63,7 +63,7 @@ public function execute(ProcessState $state): void } // Detect flushing - if ($batchCount !== null && count($this->outputQueue) >= $batchCount) { + if ($batchCount !== null && ($this->outputQueue === null ? 0 : count($this->outputQueue)) >= $batchCount) { $this->flushMode = true; } @@ -78,7 +78,7 @@ public function execute(ProcessState $state): void public function next(ProcessState $state): bool { // Stop flushing once over - if (! count($this->outputQueue)) { + if (! ($this->outputQueue === null ? 0 : count($this->outputQueue))) { $this->flushMode = false; } diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 32df23a1..6386d3cc 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -21,7 +21,6 @@ use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Throwable; /** * Execute one or many processes while chaining inputs in a iterable way @@ -37,9 +36,7 @@ public function __construct( ) { } - /** - * @throws Throwable - */ + public function execute(ProcessState $state): void { $input = $state->getInput(); @@ -67,7 +64,7 @@ protected function configureOptions(OptionsResolver $resolver): void 'process', function (Options $options, $processCode) { if (! $this->processRegistry->hasProcessConfiguration($processCode)) { - throw new InvalidConfigurationException("Unknown process $processCode"); + throw new InvalidConfigurationException("Unknown process {$processCode}"); } return $processCode; diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index 7ba1f194..bab2ab6f 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -192,7 +192,7 @@ protected function configureOptions(OptionsResolver $resolver): void 'process', function (Options $options, $value) { if (! $this->processRegistry->hasProcessConfiguration($value)) { - throw new InvalidConfigurationException("Unknown process $value"); + throw new InvalidConfigurationException("Unknown process {$value}"); } return $value; diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index 1f40b7f9..d4cd840d 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -59,7 +59,7 @@ public function execute(ProcessState $state): void if ($seconds > 0) { $rate = number_format($items / $seconds, 2, ',', ' '); } - $fullText .= " - $rate items/s - $items items processed"; + $fullText .= " - {$rate} items/s - {$items} items processed"; $fullText .= " in {$now->diff($this->startedAt) ->format('%H:%I:%S')}"; diff --git a/src/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php index 5a3d188b..da2be200 100644 --- a/src/Task/Reporting/StatCounterTask.php +++ b/src/Task/Reporting/StatCounterTask.php @@ -31,7 +31,7 @@ public function __construct( public function finalize(ProcessState $state): void { - $this->logger->info("Processed item count: $this->counter"); + $this->logger->info("Processed item count: {$this->counter}"); } public function execute(ProcessState $state): void diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index d343bcd1..e4d1fc60 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -49,7 +49,7 @@ public function execute(ProcessState $state): void if (! array_key_exists($aggregateBy, $input)) { throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column '$aggregateBy'" + "Array aggregator exception: missing column '{$aggregateBy}'" ); } @@ -68,7 +68,7 @@ public function execute(ProcessState $state): void foreach ($aggregateColumns as $aggregateColumn) { if (! array_key_exists($aggregateColumn, $input)) { throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column $aggregateColumn" + "Array aggregator exception: missing column {$aggregateColumn}" ); } $inputAggregateColumns[$aggregateColumn] = $input[$aggregateColumn]; diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index 0b33bd1c..ec48fd47 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** @@ -29,9 +28,7 @@ public function __construct( ) { } - /** - * @throws ExceptionInterface - */ + public function execute(ProcessState $state): void { $options = $this->getOptions($state); diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 613b5831..3119b48e 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use UnexpectedValueException; @@ -30,9 +29,7 @@ public function __construct( ) { } - /** - * @throws ExceptionInterface - */ + public function execute(ProcessState $state): void { $options = $this->getOptions($state); diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index 745b0ad4..ab3265e4 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -57,7 +57,7 @@ protected function initializeIterator(ProcessState $state): Iterator $outputLines = []; foreach ($options['split_columns'] as $column) { if (! array_key_exists($column, $originalLine)) { - throw new UnexpectedValueException("Missing column $column"); + throw new UnexpectedValueException("Missing column {$column}"); } $columnValues = explode($options['split_character'], (string) $originalLine[$column]); foreach ($columnValues as $columnValue) { diff --git a/src/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php index 8a58ffb5..a51f8e97 100644 --- a/src/Transformer/ConditionTrait.php +++ b/src/Transformer/ConditionTrait.php @@ -106,8 +106,13 @@ protected function configureConditionOptions(OptionsResolver $resolver): void /** * Softly check if an input key match a value, or not */ - protected function checkValue(object|array $input, string $key, mixed $value, bool $shouldMatch = true, bool $regexpMode = false): bool - { + protected function checkValue( + object|array $input, + string $key, + mixed $value, + bool $shouldMatch = true, + bool $regexpMode = false + ): bool { $currentValue = $this->getValue($input, $key); if ($shouldMatch && ! $regexpMode && $currentValue !== $value) { diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index 52c50001..bd42f79f 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -34,7 +34,7 @@ public function transform(mixed $value, array $options = []): mixed if (! $options['auto_cast']) { $type = gettype($value); throw new UnexpectedValueException( - "Value of type $type is not a valid array index, set auto_cast to true to cast it to a string" + "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" ); } if (is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here @@ -48,7 +48,7 @@ public function transform(mixed $value, array $options = []): mixed return $value; } if (! $options['ignore_missing']) { - throw new UnexpectedValueException("Missing value in map '$value'"); + throw new UnexpectedValueException("Missing value in map '{$value}'"); } return null; diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index 0710694b..1ed84007 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -14,7 +14,6 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** @@ -39,9 +38,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('context', ['array']); } - /** - * @throws ExceptionInterface - */ + public function transform(mixed $value, array $options = []): mixed { return $this->denormalizer->denormalize($value, $options['class'], $options['format'], $options['context']); diff --git a/src/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php index b0499ae3..6e463953 100644 --- a/src/Transformer/ExpressionLanguageMapTransformer.php +++ b/src/Transformer/ExpressionLanguageMapTransformer.php @@ -80,7 +80,7 @@ public function transform(mixed $value, array $options = []): mixed return $value; } if (! $options['ignore_missing']) { - throw new UnexpectedValueException("No expression accepting value '$value' in map"); + throw new UnexpectedValueException("No expression accepting value '{$value}' in map"); } return null; diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index ff9160da..8d1893be 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -118,7 +118,7 @@ public function transform(mixed $value, array $options = []): mixed } elseif (is_array($result)) { $result[$targetProperty] = $transformedValue; } else { - throw new UnexpectedValueException("Property '$targetProperty' is not writable"); + throw new UnexpectedValueException("Property '{$targetProperty}' is not writable"); } } diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index 962c89d9..14174d0e 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -14,7 +14,6 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -37,9 +36,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('context', ['array']); } - /** - * @throws ExceptionInterface - */ + public function transform(mixed $value, array $options = []): mixed { return $this->normalizer->normalize($value, $options['format'], $options['context']); diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index d1d84e55..3fe2f072 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -138,18 +138,18 @@ public function query(DOMXPath $xpath, string $query, DOMNode $node, array $opti return $item->textContent; } - throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '$query'"); + throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); }, $results); } // Unwrap the node list if ($options['single_result']) { if (count($results) > 1) { - throw new UnexpectedValueException("There is too much results for query '$query'"); + throw new UnexpectedValueException("There is too much results for query '{$query}'"); } - if ( ! $options['ignore_missing'] && count($results) === 0) { - throw new UnexpectedValueException("There is not enough results for query '$query'"); + if (! $options['ignore_missing'] && count($results) === 0) { + throw new UnexpectedValueException("There is not enough results for query '{$query}'"); } if (count($results) === 1) { From 131fd757957ce59211ce7036b14cbc6da5af7622 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 21:37:04 +0200 Subject: [PATCH 184/304] ecs + typage fort --- src/CleverAgeProcessBundle.php | 9 +- src/Command/ExecuteProcessCommand.php | 2 - src/Filesystem/CsvFile.php | 8 +- src/Filesystem/JsonStreamFile.php | 6 - src/Logger/TaskProcessor.php | 3 - src/Logger/TransformerProcessor.php | 3 - src/Manager/ProcessManager.php | 19 +-- src/Model/IterableTaskInterface.php | 4 +- src/Model/ProcessState.php | 149 +++--------------- src/Model/SubprocessInstance.php | 2 +- src/Task/File/FileFetchTask.php | 4 - .../File/JsonStream/JsonStreamReaderTask.php | 1 - src/Task/GroupByAggregateIterableTask.php | 1 - src/Task/Process/ProcessExecutorTask.php | 1 - src/Task/Serialization/DenormalizerTask.php | 1 - src/Task/Serialization/NormalizerTask.php | 1 - src/Transformer/DenormalizeTransformer.php | 1 - src/Transformer/NormalizeTransformer.php | 1 - 18 files changed, 32 insertions(+), 184 deletions(-) diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index acd3d0a0..66215744 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -16,6 +16,7 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -30,14 +31,10 @@ public function build(ContainerBuilder $container): void $container->addCompilerPass( new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), - \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, + PassConfig::TYPE_BEFORE_OPTIMIZATION, 0 ); - $container->addCompilerPass( - new CheckSerializerCompilerPass(), - \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, - 0 - ); + $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); } } diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index fd01e3da..08e96aa6 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -74,7 +74,6 @@ protected function configure(): void $this->addOption('output-format', 't', InputOption::VALUE_OPTIONAL, 'Output format'); } - protected function execute(InputInterface $input, OutputInterface $output): int { $inputData = $input->getOption('input'); @@ -128,7 +127,6 @@ protected function parseContextValues(InputInterface $input): array return $context; } - protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output): void { // Skip all if undefined diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 12ec3d0c..2c5b3260 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -27,16 +27,14 @@ class CsvFile extends CsvResource /** * @param string $filePath Also accept a resource * @param string $delimiter CSV delimiter - * @param string $enclosure - * @param string $escape * @param ?array $headers Leave null to read the headers from the file * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) */ public function __construct( protected $filePath, - $delimiter = ',', - $enclosure = '"', - $escape = '\\', + string $delimiter = ',', + string $enclosure = '"', + string $escape = '\\', ?array $headers = null, string $mode = 'rb' ) { diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index cfc1f2ac..1e90eb41 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -13,7 +13,6 @@ namespace CleverAge\ProcessBundle\Filesystem; -use JsonException; use SplFileObject; /** @@ -67,8 +66,6 @@ public function isEndOfFile(): bool /** * Return an array containing current data and moving the file pointer - * - * @throws JsonException */ public function readLine(int $length = null): ?array { @@ -82,9 +79,6 @@ public function readLine(int $length = null): ?array return json_decode($rawLine, true, 512, JSON_THROW_ON_ERROR); } - /** - * @throws JsonException - */ public function writeLine(array $fields): int { $this->file->fwrite(json_encode($fields, JSON_THROW_ON_ERROR) . PHP_EOL); diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index fdc7094e..cd0b0950 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -15,9 +15,6 @@ use Monolog\LogRecord; -/** - * Class TaskProcessor - */ class TaskProcessor extends AbstractProcessor { public function __invoke(LogRecord $record): LogRecord diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index d0729ecc..d10b25a2 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -15,9 +15,6 @@ use Monolog\LogRecord; -/** - * Class TransformerProcessor - */ class TransformerProcessor extends AbstractProcessor { public function __invoke(LogRecord $record): LogRecord diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 696cf0fd..4231f27c 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -50,20 +50,15 @@ class ProcessManager protected const EXECUTE_FLUSH = 4; - /** - * @var TaskConfiguration - */ - protected $blockingTaskConfiguration; - /** * @var TaskConfiguration[] */ - protected $processedIterables = []; + protected array $processedIterables = []; /** * @var TaskConfiguration[] */ - protected $processedBlockings = []; + protected array $processedBlockings = []; protected ?ProcessHistory $processHistory = null; @@ -94,12 +89,8 @@ public function getTaskConfiguration(): ?TaskConfiguration * * This method decorates the real execution to add event & error handling * @see ProcessManager::doExecute - * - * @param null $input - * - * @return mixed */ - public function execute(string $processCode, mixed $input = null, array $context = []) + public function execute(string $processCode, mixed $input = null, array $context = []): mixed { try { $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context)); @@ -123,10 +114,8 @@ public function execute(string $processCode, mixed $input = null, array $context /** * Real process execution, with a given input and context - * - * @return mixed */ - protected function doExecute(string $processCode, mixed $input = null, array $context = []) + protected function doExecute(string $processCode, mixed $input = null, array $context = []): mixed { $parentProcessHistory = $this->processHistory; $processConfiguration = $this->processConfigurationRegistry->getProcessConfiguration($processCode); diff --git a/src/Model/IterableTaskInterface.php b/src/Model/IterableTaskInterface.php index 2881b9a3..cfbd63bb 100644 --- a/src/Model/IterableTaskInterface.php +++ b/src/Model/IterableTaskInterface.php @@ -22,8 +22,6 @@ interface IterableTaskInterface extends TaskInterface * Moves the internal pointer to the next element, * return true if the task has a next element * return false if the task has terminated it's iteration - * - * @return bool */ - public function next(ProcessState $state); + public function next(ProcessState $state): bool; } diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index 2f1d18b8..0d3cba50 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -19,6 +19,7 @@ use RuntimeException; use Throwable; use UnexpectedValueException; +use function in_array; /** * Used to pass information between tasks @@ -42,66 +43,33 @@ class ProcessState protected TaskConfiguration $taskConfiguration; - /** - * @var mixed - */ - protected $input; + protected mixed $input = null; - /** - * @var mixed - */ - protected $output; + protected mixed $output = null; - /** - * @var mixed - */ - protected $errorOutput; + protected mixed $errorOutput = null; - /** - * @var boolean - */ - protected $hasErrorOutput = false; + protected bool $hasErrorOutput = false; - /** - * @var bool - */ - protected $stopped = false; + protected bool $stopped = false; protected ?Throwable $exception = null; - /** - * @var array - */ - protected $errorContext = []; + protected array $errorContext = []; - /** - * @var int - */ - protected $returnCode; + protected ?int $returnCode = null; protected bool $skipped; - /** - * @var array - */ - protected $context; + protected ?array $context = null; - /** - * @var ContextualOptionResolver - */ - protected $contextualOptionResolver; + protected ?ContextualOptionResolver $contextualOptionResolver = null; - /** - * @var array - */ - protected $contextualizedOptions; + protected ?array $contextualizedOptions = null; - protected ?\CleverAge\ProcessBundle\Model\ProcessState $previousState = null; + protected ?ProcessState $previousState = null; - /** - * @var string - */ - protected $status = self::STATUS_NEW; + protected string $status = self::STATUS_NEW; public function __construct( protected ProcessConfiguration $processConfiguration, @@ -128,10 +96,8 @@ public function duplicate(): self /** * Reset the state object * To be used before execution - * - * @param bool $cleanInput */ - public function reset($cleanInput): void + public function reset(bool $cleanInput): void { $this->setOutput(null); $this->setSkipped(false); @@ -165,10 +131,7 @@ public function setTaskConfiguration(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = $taskConfiguration; } - /** - * @return mixed - */ - public function getInput() + public function getInput(): mixed { return $this->input; } @@ -178,10 +141,7 @@ public function setInput(mixed $input): void $this->input = $input; } - /** - * @return mixed - */ - public function getOutput() + public function getOutput(): mixed { return $this->output; } @@ -191,42 +151,7 @@ public function setOutput(mixed $output): void $this->output = $output; } - /** - * @return mixed - * - * @deprecated Use getErrorOutput instead - */ - public function getError() - { - @trigger_error('Deprecated method, use getErrorOutput instead', E_USER_DEPRECATED); - - return $this->getErrorOutput(); - } - - /** - * @deprecated Use setErrorOutput instead - */ - public function setError(mixed $error): void - { - @trigger_error('Deprecated method, use setErrorOutput instead', E_USER_DEPRECATED); - - $this->setErrorOutput($error); - } - - /** - * @deprecated Use hasErrorOutput instead - */ - public function hasError(): bool - { - @trigger_error('Deprecated method, use hasErrorOutput instead', E_USER_DEPRECATED); - - return $this->hasErrorOutput(); - } - - /** - * @return mixed - */ - public function getErrorOutput() + public function getErrorOutput(): mixed { return $this->errorOutput; } @@ -292,11 +217,7 @@ public function removeErrorContext(string|int $key): void public function getReturnCode(): int { - if ($this->returnCode !== null) { - return $this->returnCode; - } - - return 0; + return $this->returnCode ?? 0; } public function setReturnCode(int $returnCode): void @@ -331,7 +252,7 @@ public function getStatus(): string public function setStatus(string $status): void { - if (! \in_array($status, self::STATUS, true)) { + if (! in_array($status, self::STATUS, true)) { throw new UnexpectedValueException("Unknown status {$status}"); } @@ -371,12 +292,7 @@ public function getContextualizedOptions(): ?array return $this->contextualizedOptions; } - /** - * @param string $code - * - * @return mixed - */ - public function getContextualizedOption($code, mixed $default = null) + public function getContextualizedOption(string $code, mixed $default = null): mixed { $contextualizedOptions = $this->getContextualizedOptions(); if (array_key_exists($code, $contextualizedOptions)) { @@ -385,29 +301,4 @@ public function getContextualizedOption($code, mixed $default = null) return $default; } - - /** - * @deprecated Use monolog processors instead - */ - public function getLogContext(): array - { - @trigger_error('Deprecated method, use monolog processors instead', E_USER_DEPRECATED); - $context = [ - 'process_id' => $this->processHistory->getId(), - 'process_code' => $this->processConfiguration->getCode(), - 'process_context' => $this->context, - 'task_code' => $this->taskConfiguration->getCode(), - 'task_service' => $this->taskConfiguration->getServiceReference(), - ]; - - if ($this->hasErrorOutput()) { - $context['error'] = $this->getErrorOutput(); - } - - if ($this->exception) { - $context['exception'] = $this->exception; - } - - return $context; - } } diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index d41c944a..4145e5d2 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -89,7 +89,7 @@ public function buildProcess(): static $arguments[] = $this->processCode; - $this->process = Process::fromShellCommandline($this->process->getCommandLine(), null, null, $this->input); + $this->process = new Process($arguments, null, null, $this->input); $this->process->enableOutput(); return $this; diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index e49b7804..e6b35d53 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -58,7 +58,6 @@ public function initialize(ProcessState $state): void $this->destinationFS = new Filesystem($this->getOption($state, 'destination_filesystem')); } - public function execute(ProcessState $state): void { $this->findMatchingFiles($state); @@ -74,7 +73,6 @@ public function execute(ProcessState $state): void $state->setOutput($file); } - public function next(ProcessState $state): mixed { $this->findMatchingFiles($state); @@ -82,7 +80,6 @@ public function next(ProcessState $state): mixed return next($this->matchingFiles); } - protected function findMatchingFiles(ProcessState $state): void { $filePattern = $this->getOption($state, 'file_pattern'); @@ -111,7 +108,6 @@ protected function findMatchingFiles(ProcessState $state): void } } - protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null { $prefixFrom = $this->getOption($state, 'source_filesystem'); diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index 972f04f3..a799cf0f 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -21,7 +21,6 @@ class JsonStreamReaderTask implements IterableTaskInterface { protected ?JsonStreamFile $file = null; - public function execute(ProcessState $state): void { if ($this->file === null) { diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index b12b73e3..97cab49c 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -23,7 +23,6 @@ class GroupByAggregateIterableTask extends AbstractConfigurableTask implements B */ final public const GROUP_BY_OPTION = 'group_by_accessors'; - protected array $result = []; public function __construct( diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 6386d3cc..543d7b0d 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -36,7 +36,6 @@ public function __construct( ) { } - public function execute(ProcessState $state): void { $input = $state->getInput(); diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index ec48fd47..9a4beb56 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -28,7 +28,6 @@ public function __construct( ) { } - public function execute(ProcessState $state): void { $options = $this->getOptions($state); diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 3119b48e..6c663c9d 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -29,7 +29,6 @@ public function __construct( ) { } - public function execute(ProcessState $state): void { $options = $this->getOptions($state); diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index 1ed84007..f053b3ad 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -38,7 +38,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('context', ['array']); } - public function transform(mixed $value, array $options = []): mixed { return $this->denormalizer->denormalize($value, $options['class'], $options['format'], $options['context']); diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index 14174d0e..d582fdf9 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -36,7 +36,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('context', ['array']); } - public function transform(mixed $value, array $options = []): mixed { return $this->normalizer->normalize($value, $options['format'], $options['context']); From d8f7813422b915b156a92473469dcd5240745ae7 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 22:05:46 +0200 Subject: [PATCH 185/304] ecs + typage fort --- src/Command/ProcessHelpCommand.php | 2 +- src/Logger/AbstractProcessor.php | 9 +- src/Model/ProcessHistory.php | 11 +- .../tests/environment/sf5/composer.json | 113 +++++++++--------- .../tests/environment/sf5/config/bundles.php | 18 +-- .../tests/environment/sf5/phpunit.xml.dist | 5 + src/Task/File/FileFetchTask.php | 2 +- src/Transformer/TransformerTrait.php | 9 +- 8 files changed, 78 insertions(+), 91 deletions(-) diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 22176bad..dee85d35 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -475,7 +475,7 @@ protected function writeBranches( } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); + $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index 05b98eb8..eb3d206b 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -77,9 +77,7 @@ protected function addTaskInfoToRecord(array &$record): void $this->addToRecord($record, 'task_service', $taskConfiguration->getServiceReference()); $state = $taskConfiguration->getState(); - if (! $state) { - return; - } + if ($state->hasErrorOutput()) { $this->addToRecord($record, 'error', $state->getErrorOutput()); } @@ -89,10 +87,7 @@ protected function addTaskInfoToRecord(array &$record): void } } - /** - * @param string $name - */ - protected function addToRecord(array &$record, $name, mixed $data): void + protected function addToRecord(array &$record, string $name, mixed $data): void { $record[$name] = $data; } diff --git a/src/Model/ProcessHistory.php b/src/Model/ProcessHistory.php index d4f52bf1..e9c30b5b 100644 --- a/src/Model/ProcessHistory.php +++ b/src/Model/ProcessHistory.php @@ -15,6 +15,7 @@ use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use DateTime; +use DateTimeInterface; use Stringable; /** @@ -32,9 +33,9 @@ class ProcessHistory implements Stringable protected string $processCode; - protected ?DateTime $startDate; + protected ?DateTimeInterface $startDate; - protected ?DateTime $endDate = null; + protected ?DateTimeInterface $endDate = null; protected string $state = self::STATE_STARTED; @@ -51,7 +52,7 @@ public function __toString(): string { $reference = $this->getProcessCode() . '[' . $this->getState() . ']'; $time = $this->getStartDate() - ->format(DateTime::ATOM); + ->format(DateTimeInterface::ATOM); return $reference . ': ' . $time; } @@ -71,12 +72,12 @@ public function getContext(): array return $this->context; } - public function getStartDate(): DateTime + public function getStartDate(): DateTimeInterface { return $this->startDate; } - public function getEndDate(): ?DateTime + public function getEndDate(): ?DateTimeInterface { return $this->endDate; } diff --git a/src/Resources/tests/environment/sf5/composer.json b/src/Resources/tests/environment/sf5/composer.json index 16c2a7d5..b30fff42 100644 --- a/src/Resources/tests/environment/sf5/composer.json +++ b/src/Resources/tests/environment/sf5/composer.json @@ -1,60 +1,61 @@ { - "type": "project", - "license": "proprietary", - "require": { - "symfony/framework-bundle": "^5.4", - "symfony/dotenv": "^5.4", - "symfony/flex": "^1.11", - "symfony/event-dispatcher": "^5.4", - "symfony/config": "^5.4", - "symfony/dependency-injection": "^5.4", - "symfony/expression-language": "^5.4", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "^5.4", - "symfony/form": "^5.4", - "symfony/options-resolver": "^5.4", - "symfony/process": "^5.4", - "symfony/property-access": "^5.4", - "symfony/runtime": "^5.4", - "symfony/serializer": "^5.4", - "symfony/validator": "^5.4", - "symfony/yaml": "^5.4" - }, - "require-dev": { - "symfony/phpunit-bridge": "^5.4", - "phpunit/phpunit": "*", - "phpstan/phpstan": "*", - "phpstan/phpstan-symfony": "*", - "phpstan/extension-installer": "*" - }, - "autoload": { - "psr-4": { - "App\\": "src/", - "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" - } - }, - "autoload-dev": { - "psr-4": { - "App\\Tests\\": "tests/" - } - }, - "scripts": { - "auto-scripts": { - "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" - }, - "post-install-cmd": [ - "@auto-scripts" - ], - "post-update-cmd": [ - "@auto-scripts" - ] + "type": "project", + "license": "proprietary", + "require": { + "symfony/framework-bundle": "^5.4", + "symfony/dotenv": "^5.4", + "symfony/flex": "^1.11", + "symfony/event-dispatcher": "^5.4", + "symfony/config": "^5.4", + "symfony/dependency-injection": "^5.4", + "symfony/expression-language": "^5.4", + "symfony/monolog-bundle": "~3.3", + "symfony/console": "^5.4", + "symfony/form": "^5.4", + "symfony/options-resolver": "^5.4", + "symfony/process": "^5.4", + "symfony/property-access": "^5.4", + "symfony/runtime": "^5.4", + "symfony/serializer": "^5.4", + "symfony/validator": "^5.4", + "symfony/yaml": "^5.4" + }, + "require-dev": { + "roave/security-advisories": "dev-latest", + "symfony/phpunit-bridge": "^5.4", + "phpunit/phpunit": "*", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpstan/extension-installer": "*" + }, + "autoload": { + "psr-4": { + "App\\": "src/", + "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" }, - "config": { - "allow-plugins": { - "symfony/runtime": true, - "phpstan/extension-installer": true, - "symfony/flex": true - } + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + }, + "config": { + "allow-plugins": { + "symfony/runtime": true, + "phpstan/extension-installer": true, + "symfony/flex": true } + } } diff --git a/src/Resources/tests/environment/sf5/config/bundles.php b/src/Resources/tests/environment/sf5/config/bundles.php index ef87cf11..d1a265ef 100644 --- a/src/Resources/tests/environment/sf5/config/bundles.php +++ b/src/Resources/tests/environment/sf5/config/bundles.php @@ -1,19 +1,7 @@ [ - 'all' => true, - ], - CleverAgeProcessBundle::class => [ - 'all' => true, - ], - MonologBundle::class => [ - 'all' => true, - ], + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], + CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], ]; diff --git a/src/Resources/tests/environment/sf5/phpunit.xml.dist b/src/Resources/tests/environment/sf5/phpunit.xml.dist index b2a3a915..c2a76a4d 100644 --- a/src/Resources/tests/environment/sf5/phpunit.xml.dist +++ b/src/Resources/tests/environment/sf5/phpunit.xml.dist @@ -14,6 +14,11 @@ + + + + + diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index e6b35d53..ad3601bd 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -73,7 +73,7 @@ public function execute(ProcessState $state): void $state->setOutput($file); } - public function next(ProcessState $state): mixed + public function next(ProcessState $state): bool { $this->findMatchingFiles($state); diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 826261c4..f832c8c5 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -54,14 +54,13 @@ public function normalizeTransformers(Options $options, array $transformers): ar /** * @return mixed */ - protected function applyTransformers(array $transformers, mixed $value) + protected function applyTransformers(array $transformers, mixed $value): mixed { // Quick return for better perfs if (empty($transformers)) { return $value; } - /** @noinspection ForeachSourceInspection */ foreach ($transformers as $transformerCode => $transformerClosure) { try { $value = $transformerClosure($value); @@ -78,8 +77,6 @@ protected function applyTransformers(array $transformers, mixed $value) * keys This way you can chain multiple times the same transformer. Without this, it would silently call only the * 1st one. * - * @return string - * * @example * transformers: * callback#1: @@ -87,7 +84,7 @@ protected function applyTransformers(array $transformers, mixed $value) * callback#2: * callback: array_reverse */ - protected function getCleanedTransfomerCode(string $transformerCode) + protected function getCleanedTransfomerCode(string $transformerCode): string { $match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts); @@ -104,7 +101,7 @@ protected function configureTransformersOptions( ): void { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); - $resolver->setNormalizer($optionName, Closure::fromCallable([$this, 'normalizeTransformers'])); + $resolver->setNormalizer($optionName, $this->normalizeTransformers(...)); } /** From 6eb127f37f531a95a827a77352c05aac4c5fe7be Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 22:15:16 +0200 Subject: [PATCH 186/304] phpstan --- phpstan.neon | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 2fa41fc4..a9f5c7bc 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,10 +5,10 @@ parameters: excludePaths: - ecs.php - vendor/* - - Resources/tests/* - - Tests/* + - tests/* - rector.php - var/* + - src/Resources/tests/* ignoreErrors: - '#type has no value type specified in iterable type#' - '#has parameter .* with no value type specified in iterable type#' @@ -20,4 +20,5 @@ parameters: - '#Negated boolean expression is always false#' checkGenericClassInNonGenericObjectType: false reportUnmatchedIgnoredErrors: false - inferPrivatePropertyTypeFromConstructor: true \ No newline at end of file + inferPrivatePropertyTypeFromConstructor: true + treatPhpDocTypesAsCertain: false \ No newline at end of file From 6a8c1489b201dcf928303d36d681697174431759 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 31 Mar 2023 22:44:25 +0200 Subject: [PATCH 187/304] rector --- rector.php | 3 ++- src/Command/ProcessHelpCommand.php | 2 +- src/Resources/tests/environment/sf5/config/bundles.php | 9 ++++++--- src/Transformer/TransformerTrait.php | 3 --- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/rector.php b/rector.php index 86236ee5..e9d9ab95 100644 --- a/rector.php +++ b/rector.php @@ -14,11 +14,12 @@ $rectorConfig->importShortClasses(); $rectorConfig->paths([__DIR__ . '/src']); + $rectorConfig->skip([__DIR__ . '/src/Resources/tests']); $rectorConfig->sets([ SetList::TYPE_DECLARATION, LevelSetList::UP_TO_PHP_81, - SymfonyLevelSetList::UP_TO_SYMFONY_54, + SymfonyLevelSetList::UP_TO_SYMFONY_62, ]); $rectorConfig->phpVersion(PhpVersion::PHP_81); diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index dee85d35..22176bad 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -475,7 +475,7 @@ protected function writeBranches( } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', $str)); + $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } diff --git a/src/Resources/tests/environment/sf5/config/bundles.php b/src/Resources/tests/environment/sf5/config/bundles.php index d1a265ef..1cc2b6ae 100644 --- a/src/Resources/tests/environment/sf5/config/bundles.php +++ b/src/Resources/tests/environment/sf5/config/bundles.php @@ -1,7 +1,10 @@ ['all' => true], - CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], - Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + FrameworkBundle::class => ['all' => true], + CleverAgeProcessBundle::class => ['all' => true], + MonologBundle::class => ['all' => true], ]; diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index f832c8c5..12d10117 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -51,9 +51,6 @@ public function normalizeTransformers(Options $options, array $transformers): ar return $transformerClosures; } - /** - * @return mixed - */ protected function applyTransformers(array $transformers, mixed $value): mixed { // Quick return for better perfs From a026feb997b1c611bc01da3193a757f73e48c758 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 3 Apr 2023 18:32:27 +0200 Subject: [PATCH 188/304] fix error configuration --- src/Registry/ProcessConfigurationRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 8659e9b8..84febcaf 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -94,7 +94,7 @@ protected function resolveConfiguration(string $processCode): void $rawTaskConfiguration['outputs'], $rawTaskConfiguration['error_outputs'], $rawTaskConfiguration['error_strategy'] ?? $this->defaultErrorStrategy, - $rawTaskConfiguration['log_errors'] ? $rawTaskConfiguration['log_level'] : LogLevel::DEBUG + $rawTaskConfiguration['log_level'] ?: LogLevel::DEBUG ); } From af36a3bb34a315994ed183ade2a0128394772c41 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 3 Apr 2023 18:56:56 +0200 Subject: [PATCH 189/304] add stopwatch --- composer.json | 3 +- .../Compiler/CheckSerializerCompilerPass.php | 2 +- src/Event/ConsoleProcessEvent.php | 2 - src/Task/Debug/StopwatchTask.php | 39 +++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/Task/Debug/StopwatchTask.php diff --git a/composer.json b/composer.json index 8add6982..49609146 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ { "name": "Vincent Chalnot", "email": "vchalnot@clever-age.com", - "homepage": "http://chalnot.fr", + "homepage": "https://github.com/VincentChalnot", "role": "Lead Developer" }, { @@ -75,6 +75,7 @@ "symfony/process": "^6.2", "symfony/property-access": "^6.2", "symfony/serializer": "^6.2", + "symfony/stopwatch": "^6.2", "symfony/validator": "^6.2", "symfony/yaml": "^6.2", "league/flysystem-bundle": "^3.1" diff --git a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 4dd382cf..71d08c28 100644 --- a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -25,7 +25,7 @@ class CheckSerializerCompilerPass implements CompilerPassInterface { final public const MSG = 'The Symfony serializer component do not seem enabled, consider toggling framework.serializer.enable (see https://symfony.com/doc/current/reference/configuration/framework.html#reference-serializer-enabled)'; - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { if (! $container->has('serializer') && ! $container->has(DenormalizerInterface::class)) { throw new AutowiringFailedException('serializer', self::MSG); diff --git a/src/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php index 79b7ef7c..c9c740d1 100644 --- a/src/Event/ConsoleProcessEvent.php +++ b/src/Event/ConsoleProcessEvent.php @@ -22,8 +22,6 @@ */ class ConsoleProcessEvent extends Event { - final public const EVENT_CLI_INIT = 'cleverage_process.cli.init'; - public function __construct( private readonly InputInterface $consoleInput, private readonly OutputInterface $consoleOutput, diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php new file mode 100644 index 00000000..4aa75224 --- /dev/null +++ b/src/Task/Debug/StopwatchTask.php @@ -0,0 +1,39 @@ +stopwatch->getSectionEvents('__root__') as $event) { + $this->logger->info($event); + } + } +} From bfd5dce3ff013c7de86686b966bc4407755d4961 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 4 Apr 2023 21:48:22 +0200 Subject: [PATCH 190/304] refacto phpunit --- Makefile | 3 ++- composer.json | 3 ++- phpunit.xml.dist | 39 +++++++++++++++++++++------------------ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index a4c6ac06..e14dbd1b 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ test: test/$(SF_ENV) test/local: $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) ./bin/console c:c - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) php vendor/bin/phpunit + $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report test/%: $(DOCKER_RUN) cleverage/process-bundle:$(@F) ./bin/console c:c @@ -62,3 +62,4 @@ linter/local: vendor/bin/rector process vendor/bin/ecs check --fix vendor/bin/phpstan + php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report diff --git a/composer.json b/composer.json index 49609146..0ff9a443 100644 --- a/composer.json +++ b/composer.json @@ -101,7 +101,8 @@ "config": { "allow-plugins": { "phpstan/extension-installer": true, - "symfony/flex": true + "symfony/flex": true, + "symfony/runtime": true } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e0c32a1d..766495c5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,24 +1,27 @@ - - - - - - - - - - - - + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd" + bootstrap="vendor/autoload.php" + cacheResultFile=".phpunit.cache/test-results" + executionOrder="depends,defects" + forceCoversAnnotation="true" + beStrictAboutCoversAnnotation="true" + beStrictAboutOutputDuringTests="true" + beStrictAboutTodoAnnotatedTests="true" + convertDeprecationsToExceptions="true" + failOnRisky="true" + failOnWarning="true" + verbose="true"> - - /tests + + tests + + + + src + + From 775142a815878596cdbdd487ec297da147a6a886 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 4 Apr 2023 21:52:11 +0200 Subject: [PATCH 191/304] refacto phpunit --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 61f22ac1..cc2bca51 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ /vendor-sf4 /vendor-sf5 .env +.idea /phpunit.xml +.phpunit.result.cache +.phpunit.cache \ No newline at end of file From a267e0c5fc118b84533691f174baa0bf3ef9392b Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 4 Apr 2023 22:19:03 +0200 Subject: [PATCH 192/304] phpunit tests --- src/Resources/tests/environment/README.md | 4 -- src/Resources/tests/environment/php/conf.ini | 1 - .../tests/environment/sf5/composer.json | 61 ------------------- .../tests/environment/sf5/config/bundles.php | 10 --- .../sf5/config/packages/framework.yaml | 10 --- .../packages/test/cleverage_process.yaml | 2 - .../tests/environment/sf5/phpunit.xml.dist | 29 --------- src/Task/Debug/StopwatchTask.php | 5 +- src/Transformer/TrimTransformer.php | 11 +++- {tests => tests.old}/AbstractProcessTest.php | 0 {tests => tests.old}/BasicTest.php | 0 {tests => tests.old}/BlockingTaskTest.php | 0 {tests => tests.old}/CircularProcessTest.php | 0 {tests => tests.old}/ContextTest.php | 0 {tests => tests.old}/EmptyProcessTest.php | 0 .../ExceptionManagementTest.php | 0 {tests => tests.old}/FlushableTaskTest.php | 0 {tests => tests.old}/IterableTaskTest.php | 0 .../MultiBranchProcessTest.php | 0 {tests => tests.old}/MultiWorkflowTest.php | 0 {tests => tests.old}/ProcessManagerTest.php | 0 .../Task/ColumnAggregatorTaskTest.php | 0 {tests => tests.old}/Task/FilterTaskTest.php | 0 .../Task/ProcessExecutorTaskTest.php | 0 {tests => tests.old}/Task/StopTaskTest.php | 0 .../Task/TransformerTaskTest.php | 0 .../Task/ValidatorTaskTest.php | 0 .../ArrayFilterTransformerTest.php | 0 .../Transformer/CallbackTransformerTest.php | 0 .../Transformer/DateTransformersTest.php | 0 .../Transformer/GenericTransformersTest.php | 0 .../Transformer/HashTransformerTest.php | 0 .../Transformer/MappingTransformerTest.php | 0 .../Transformer/RulesTransformerTest.php | 0 .../Transformer/TransformerExceptionTest.php | 0 .../Transformer/TypeSetterTransformerTest.php | 0 .../Transformer/UnsetTransformerTest.php | 0 .../XpathEvaluatorTransformerTest.php | 0 tests/Transformer/TrimTransformerTest.php | 35 +++++++++++ 39 files changed, 47 insertions(+), 121 deletions(-) delete mode 100644 src/Resources/tests/environment/README.md delete mode 100644 src/Resources/tests/environment/php/conf.ini delete mode 100644 src/Resources/tests/environment/sf5/composer.json delete mode 100644 src/Resources/tests/environment/sf5/config/bundles.php delete mode 100644 src/Resources/tests/environment/sf5/config/packages/framework.yaml delete mode 100644 src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml delete mode 100644 src/Resources/tests/environment/sf5/phpunit.xml.dist rename {tests => tests.old}/AbstractProcessTest.php (100%) rename {tests => tests.old}/BasicTest.php (100%) rename {tests => tests.old}/BlockingTaskTest.php (100%) rename {tests => tests.old}/CircularProcessTest.php (100%) rename {tests => tests.old}/ContextTest.php (100%) rename {tests => tests.old}/EmptyProcessTest.php (100%) rename {tests => tests.old}/ExceptionManagementTest.php (100%) rename {tests => tests.old}/FlushableTaskTest.php (100%) rename {tests => tests.old}/IterableTaskTest.php (100%) rename {tests => tests.old}/MultiBranchProcessTest.php (100%) rename {tests => tests.old}/MultiWorkflowTest.php (100%) rename {tests => tests.old}/ProcessManagerTest.php (100%) rename {tests => tests.old}/Task/ColumnAggregatorTaskTest.php (100%) rename {tests => tests.old}/Task/FilterTaskTest.php (100%) rename {tests => tests.old}/Task/ProcessExecutorTaskTest.php (100%) rename {tests => tests.old}/Task/StopTaskTest.php (100%) rename {tests => tests.old}/Task/TransformerTaskTest.php (100%) rename {tests => tests.old}/Task/ValidatorTaskTest.php (100%) rename {tests => tests.old}/Transformer/ArrayFilterTransformerTest.php (100%) rename {tests => tests.old}/Transformer/CallbackTransformerTest.php (100%) rename {tests => tests.old}/Transformer/DateTransformersTest.php (100%) rename {tests => tests.old}/Transformer/GenericTransformersTest.php (100%) rename {tests => tests.old}/Transformer/HashTransformerTest.php (100%) rename {tests => tests.old}/Transformer/MappingTransformerTest.php (100%) rename {tests => tests.old}/Transformer/RulesTransformerTest.php (100%) rename {tests => tests.old}/Transformer/TransformerExceptionTest.php (100%) rename {tests => tests.old}/Transformer/TypeSetterTransformerTest.php (100%) rename {tests => tests.old}/Transformer/UnsetTransformerTest.php (100%) rename {tests => tests.old}/Transformer/XpathEvaluatorTransformerTest.php (100%) create mode 100644 tests/Transformer/TrimTransformerTest.php diff --git a/src/Resources/tests/environment/README.md b/src/Resources/tests/environment/README.md deleted file mode 100644 index e5f0bbbc..00000000 --- a/src/Resources/tests/environment/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Test environment -================ - -Those files are used to build a test environment for this bundle. For now, only Symfony4.3 is available. diff --git a/src/Resources/tests/environment/php/conf.ini b/src/Resources/tests/environment/php/conf.ini deleted file mode 100644 index 5391bc87..00000000 --- a/src/Resources/tests/environment/php/conf.ini +++ /dev/null @@ -1 +0,0 @@ -memory_limit = 256M diff --git a/src/Resources/tests/environment/sf5/composer.json b/src/Resources/tests/environment/sf5/composer.json deleted file mode 100644 index b30fff42..00000000 --- a/src/Resources/tests/environment/sf5/composer.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "type": "project", - "license": "proprietary", - "require": { - "symfony/framework-bundle": "^5.4", - "symfony/dotenv": "^5.4", - "symfony/flex": "^1.11", - "symfony/event-dispatcher": "^5.4", - "symfony/config": "^5.4", - "symfony/dependency-injection": "^5.4", - "symfony/expression-language": "^5.4", - "symfony/monolog-bundle": "~3.3", - "symfony/console": "^5.4", - "symfony/form": "^5.4", - "symfony/options-resolver": "^5.4", - "symfony/process": "^5.4", - "symfony/property-access": "^5.4", - "symfony/runtime": "^5.4", - "symfony/serializer": "^5.4", - "symfony/validator": "^5.4", - "symfony/yaml": "^5.4" - }, - "require-dev": { - "roave/security-advisories": "dev-latest", - "symfony/phpunit-bridge": "^5.4", - "phpunit/phpunit": "*", - "phpstan/phpstan": "*", - "phpstan/phpstan-symfony": "*", - "phpstan/extension-installer": "*" - }, - "autoload": { - "psr-4": { - "App\\": "src/", - "CleverAge\\ProcessBundle\\": "/src-cleverage_process/" - } - }, - "autoload-dev": { - "psr-4": { - "App\\Tests\\": "tests/" - } - }, - "scripts": { - "auto-scripts": { - "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" - }, - "post-install-cmd": [ - "@auto-scripts" - ], - "post-update-cmd": [ - "@auto-scripts" - ] - }, - "config": { - "allow-plugins": { - "symfony/runtime": true, - "phpstan/extension-installer": true, - "symfony/flex": true - } - } -} diff --git a/src/Resources/tests/environment/sf5/config/bundles.php b/src/Resources/tests/environment/sf5/config/bundles.php deleted file mode 100644 index 1cc2b6ae..00000000 --- a/src/Resources/tests/environment/sf5/config/bundles.php +++ /dev/null @@ -1,10 +0,0 @@ - ['all' => true], - CleverAgeProcessBundle::class => ['all' => true], - MonologBundle::class => ['all' => true], -]; diff --git a/src/Resources/tests/environment/sf5/config/packages/framework.yaml b/src/Resources/tests/environment/sf5/config/packages/framework.yaml deleted file mode 100644 index 5a1678d2..00000000 --- a/src/Resources/tests/environment/sf5/config/packages/framework.yaml +++ /dev/null @@ -1,10 +0,0 @@ -framework: - secret: '%env(APP_SECRET)%' - - serializer: - enabled: true - - #esi: true - #fragments: true - php_errors: - log: true diff --git a/src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml b/src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml deleted file mode 100644 index a03e25d8..00000000 --- a/src/Resources/tests/environment/sf5/config/packages/test/cleverage_process.yaml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: '@CleverAgeProcessBundle/Resources/tests/config.yml' } diff --git a/src/Resources/tests/environment/sf5/phpunit.xml.dist b/src/Resources/tests/environment/sf5/phpunit.xml.dist deleted file mode 100644 index c2a76a4d..00000000 --- a/src/Resources/tests/environment/sf5/phpunit.xml.dist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - /src-cleverage_process/Tests - - - diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php index 4aa75224..8ca66b96 100644 --- a/src/Task/Debug/StopwatchTask.php +++ b/src/Task/Debug/StopwatchTask.php @@ -26,13 +26,12 @@ class StopwatchTask implements TaskInterface public function __construct( protected LoggerInterface $logger, private readonly Stopwatch $stopwatch - ) - { + ) { } public function execute(ProcessState $state): void { - foreach($this->stopwatch->getSectionEvents('__root__') as $event) { + foreach ($this->stopwatch->getSectionEvents('__root__') as $event) { $this->logger->info($event); } } diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index c20b71ae..c51b5bd4 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -20,8 +20,14 @@ */ class TrimTransformer implements ConfigurableTransformerInterface { - public function transform(mixed $value, array $options = []): ?string + public function transform(mixed $value, ?array $options = []): ?string { + if ($options === null || $options === []) { + $options = [ + 'charlist' => " \t\n\r\0\x0B", + ]; + } + if ($value === null) { return null; } @@ -37,6 +43,9 @@ public function getCode(): string return 'trim'; } + /** + * @codeCoverageIgnore + */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ diff --git a/tests/AbstractProcessTest.php b/tests.old/AbstractProcessTest.php similarity index 100% rename from tests/AbstractProcessTest.php rename to tests.old/AbstractProcessTest.php diff --git a/tests/BasicTest.php b/tests.old/BasicTest.php similarity index 100% rename from tests/BasicTest.php rename to tests.old/BasicTest.php diff --git a/tests/BlockingTaskTest.php b/tests.old/BlockingTaskTest.php similarity index 100% rename from tests/BlockingTaskTest.php rename to tests.old/BlockingTaskTest.php diff --git a/tests/CircularProcessTest.php b/tests.old/CircularProcessTest.php similarity index 100% rename from tests/CircularProcessTest.php rename to tests.old/CircularProcessTest.php diff --git a/tests/ContextTest.php b/tests.old/ContextTest.php similarity index 100% rename from tests/ContextTest.php rename to tests.old/ContextTest.php diff --git a/tests/EmptyProcessTest.php b/tests.old/EmptyProcessTest.php similarity index 100% rename from tests/EmptyProcessTest.php rename to tests.old/EmptyProcessTest.php diff --git a/tests/ExceptionManagementTest.php b/tests.old/ExceptionManagementTest.php similarity index 100% rename from tests/ExceptionManagementTest.php rename to tests.old/ExceptionManagementTest.php diff --git a/tests/FlushableTaskTest.php b/tests.old/FlushableTaskTest.php similarity index 100% rename from tests/FlushableTaskTest.php rename to tests.old/FlushableTaskTest.php diff --git a/tests/IterableTaskTest.php b/tests.old/IterableTaskTest.php similarity index 100% rename from tests/IterableTaskTest.php rename to tests.old/IterableTaskTest.php diff --git a/tests/MultiBranchProcessTest.php b/tests.old/MultiBranchProcessTest.php similarity index 100% rename from tests/MultiBranchProcessTest.php rename to tests.old/MultiBranchProcessTest.php diff --git a/tests/MultiWorkflowTest.php b/tests.old/MultiWorkflowTest.php similarity index 100% rename from tests/MultiWorkflowTest.php rename to tests.old/MultiWorkflowTest.php diff --git a/tests/ProcessManagerTest.php b/tests.old/ProcessManagerTest.php similarity index 100% rename from tests/ProcessManagerTest.php rename to tests.old/ProcessManagerTest.php diff --git a/tests/Task/ColumnAggregatorTaskTest.php b/tests.old/Task/ColumnAggregatorTaskTest.php similarity index 100% rename from tests/Task/ColumnAggregatorTaskTest.php rename to tests.old/Task/ColumnAggregatorTaskTest.php diff --git a/tests/Task/FilterTaskTest.php b/tests.old/Task/FilterTaskTest.php similarity index 100% rename from tests/Task/FilterTaskTest.php rename to tests.old/Task/FilterTaskTest.php diff --git a/tests/Task/ProcessExecutorTaskTest.php b/tests.old/Task/ProcessExecutorTaskTest.php similarity index 100% rename from tests/Task/ProcessExecutorTaskTest.php rename to tests.old/Task/ProcessExecutorTaskTest.php diff --git a/tests/Task/StopTaskTest.php b/tests.old/Task/StopTaskTest.php similarity index 100% rename from tests/Task/StopTaskTest.php rename to tests.old/Task/StopTaskTest.php diff --git a/tests/Task/TransformerTaskTest.php b/tests.old/Task/TransformerTaskTest.php similarity index 100% rename from tests/Task/TransformerTaskTest.php rename to tests.old/Task/TransformerTaskTest.php diff --git a/tests/Task/ValidatorTaskTest.php b/tests.old/Task/ValidatorTaskTest.php similarity index 100% rename from tests/Task/ValidatorTaskTest.php rename to tests.old/Task/ValidatorTaskTest.php diff --git a/tests/Transformer/ArrayFilterTransformerTest.php b/tests.old/Transformer/ArrayFilterTransformerTest.php similarity index 100% rename from tests/Transformer/ArrayFilterTransformerTest.php rename to tests.old/Transformer/ArrayFilterTransformerTest.php diff --git a/tests/Transformer/CallbackTransformerTest.php b/tests.old/Transformer/CallbackTransformerTest.php similarity index 100% rename from tests/Transformer/CallbackTransformerTest.php rename to tests.old/Transformer/CallbackTransformerTest.php diff --git a/tests/Transformer/DateTransformersTest.php b/tests.old/Transformer/DateTransformersTest.php similarity index 100% rename from tests/Transformer/DateTransformersTest.php rename to tests.old/Transformer/DateTransformersTest.php diff --git a/tests/Transformer/GenericTransformersTest.php b/tests.old/Transformer/GenericTransformersTest.php similarity index 100% rename from tests/Transformer/GenericTransformersTest.php rename to tests.old/Transformer/GenericTransformersTest.php diff --git a/tests/Transformer/HashTransformerTest.php b/tests.old/Transformer/HashTransformerTest.php similarity index 100% rename from tests/Transformer/HashTransformerTest.php rename to tests.old/Transformer/HashTransformerTest.php diff --git a/tests/Transformer/MappingTransformerTest.php b/tests.old/Transformer/MappingTransformerTest.php similarity index 100% rename from tests/Transformer/MappingTransformerTest.php rename to tests.old/Transformer/MappingTransformerTest.php diff --git a/tests/Transformer/RulesTransformerTest.php b/tests.old/Transformer/RulesTransformerTest.php similarity index 100% rename from tests/Transformer/RulesTransformerTest.php rename to tests.old/Transformer/RulesTransformerTest.php diff --git a/tests/Transformer/TransformerExceptionTest.php b/tests.old/Transformer/TransformerExceptionTest.php similarity index 100% rename from tests/Transformer/TransformerExceptionTest.php rename to tests.old/Transformer/TransformerExceptionTest.php diff --git a/tests/Transformer/TypeSetterTransformerTest.php b/tests.old/Transformer/TypeSetterTransformerTest.php similarity index 100% rename from tests/Transformer/TypeSetterTransformerTest.php rename to tests.old/Transformer/TypeSetterTransformerTest.php diff --git a/tests/Transformer/UnsetTransformerTest.php b/tests.old/Transformer/UnsetTransformerTest.php similarity index 100% rename from tests/Transformer/UnsetTransformerTest.php rename to tests.old/Transformer/UnsetTransformerTest.php diff --git a/tests/Transformer/XpathEvaluatorTransformerTest.php b/tests.old/Transformer/XpathEvaluatorTransformerTest.php similarity index 100% rename from tests/Transformer/XpathEvaluatorTransformerTest.php rename to tests.old/Transformer/XpathEvaluatorTransformerTest.php diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/TrimTransformerTest.php new file mode 100644 index 00000000..b1972b98 --- /dev/null +++ b/tests/Transformer/TrimTransformerTest.php @@ -0,0 +1,35 @@ +transform(' test 1 '); + $this->assertEquals('test 1', $result); + + $result = $trimTransformer->transform(null); + $this->assertNull($result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::getCode + */ + public function testCode(): void + { + $trimTransformer = new TrimTransformer(); + $result = $trimTransformer->getCode(); + $this->assertEquals('trim', $result); + } +} \ No newline at end of file From 78276bb5fedb01b222c4261ba6bfd01a5b892aca Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 5 Apr 2023 18:31:14 +0200 Subject: [PATCH 193/304] phpunit tests --- src/Transformer/SprintfTransformer.php | 17 ++++++---- tests/Transformer/SprintfTransformerTest.php | 35 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 tests/Transformer/SprintfTransformerTest.php diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php index 00f033d2..8fb584e8 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/SprintfTransformer.php @@ -21,13 +21,6 @@ */ class SprintfTransformer implements ConfigurableTransformerInterface { - public function configureOptions(OptionsResolver $resolver): void - { - $resolver->setRequired('format'); - $resolver->setDefault('format', '%s'); - $resolver->setAllowedTypes('format', 'string'); - } - public function transform(mixed $value, array $options = []): string { if (! is_array($value)) { @@ -41,4 +34,14 @@ public function getCode(): string { return 'sprintf'; } + + /** + * @codeCoverageIgnore + */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('format'); + $resolver->setDefault('format', '%s'); + $resolver->setAllowedTypes('format', 'string'); + } } diff --git a/tests/Transformer/SprintfTransformerTest.php b/tests/Transformer/SprintfTransformerTest.php new file mode 100644 index 00000000..81b80b35 --- /dev/null +++ b/tests/Transformer/SprintfTransformerTest.php @@ -0,0 +1,35 @@ +transform(['bar'], ['format' => 'foo %s']); + $this->assertEquals('foo bar', $result); + + $result = $sprintfTransformer->transform('bar', ['format' => 'foo %s']); + $this->assertEquals('foo bar', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\SprintfTransformer::getCode + */ + public function testCode(): void + { + $trimTransformer = new SprintfTransformer(); + $result = $trimTransformer->getCode(); + $this->assertEquals('sprintf', $result); + } +} From d9fffdfb454ad7e51965181b7f569dd3a50460ab Mon Sep 17 00:00:00 2001 From: VincentChalnot Date: Thu, 20 Apr 2023 16:41:29 +0200 Subject: [PATCH 194/304] Allowing WrapperTransformer to work without a wrapper_key, using 0 as a key by default --- Transformer/WrapperTransformer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Transformer/WrapperTransformer.php b/Transformer/WrapperTransformer.php index 4b10389a..53514813 100644 --- a/Transformer/WrapperTransformer.php +++ b/Transformer/WrapperTransformer.php @@ -41,9 +41,9 @@ public function transform($input, array $options = []) */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired( + $resolver->setDefaults( [ - 'wrapper_key', + 'wrapper_key' => 0, ] ); $resolver->setAllowedTypes('wrapper_key', ['string', 'int']); From ae37db435ec1d1ca46d52a32e6c4c1b6a187eaab Mon Sep 17 00:00:00 2001 From: VincentChalnot Date: Thu, 20 Apr 2023 16:42:38 +0200 Subject: [PATCH 195/304] New InstantiateTransformer that can be used to create a new object with arguments from input. --- Transformer/InstantiateTransformer.php | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Transformer/InstantiateTransformer.php diff --git a/Transformer/InstantiateTransformer.php b/Transformer/InstantiateTransformer.php new file mode 100644 index 00000000..5c2312ef --- /dev/null +++ b/Transformer/InstantiateTransformer.php @@ -0,0 +1,45 @@ + + */ +class InstantiateTransformer implements ConfigurableTransformerInterface +{ + public function transform(mixed $value, array $options = []) + { + if (!is_array($value)) { + throw new \UnexpectedValueException('Input value must be an array for transformer instantiate'); + } + + return (new \ReflectionClass($options['class']))->newInstanceArgs($value); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired( + [ + 'class', + ] + ); + $resolver->setAllowedTypes('class', ['string']); + } + + public function getCode() + { + return 'instantiate'; + } +} From a8e280e027dbc043cfc7877a72444df5404a88ad Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 25 Apr 2023 11:09:16 +0200 Subject: [PATCH 196/304] merge from 3.2.X --- src/Transformer/InstantiateTransformer.php | 44 ++++++++++++++++++++++ src/Transformer/WrapperTransformer.php | 4 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/Transformer/InstantiateTransformer.php diff --git a/src/Transformer/InstantiateTransformer.php b/src/Transformer/InstantiateTransformer.php new file mode 100644 index 00000000..ceb8ed8f --- /dev/null +++ b/src/Transformer/InstantiateTransformer.php @@ -0,0 +1,44 @@ +newInstanceArgs($value); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired(['class']); + $resolver->setAllowedTypes('class', ['string']); + } + + public function getCode(): string + { + return 'instantiate'; + } +} diff --git a/src/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php index 711dbea1..46c5b9fc 100644 --- a/src/Transformer/WrapperTransformer.php +++ b/src/Transformer/WrapperTransformer.php @@ -29,7 +29,9 @@ public function transform(mixed $value, array $options = []): array public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired(['wrapper_key']); + $resolver->setDefaults([ + 'wrapper_key' => 0, + ]); $resolver->setAllowedTypes('wrapper_key', ['string', 'int']); } From 8c7dcc9a695ca257cc5a9a6e507fb92b4968e0f8 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 25 Apr 2023 11:11:11 +0200 Subject: [PATCH 197/304] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1fa67ca9..9efe2fdc 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ { "name": "Vincent Chalnot", "email": "vchalnot@clever-age.com", - "homepage": "http://chalnot.fr", + "homepage": "https://github.com/VincentChalnot", "role": "Lead Developer" }, { From 4e0014f5a4c1cd8098a92be34042c5e2b4ca1bc2 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 21 May 2023 21:30:06 +0200 Subject: [PATCH 198/304] linter + phpunit tests --- Makefile | 56 +---------- src/Model/SubprocessInstance.php | 2 +- src/Transformer/ArrayFirstTransformer.php | 2 +- src/Transformer/TrimTransformer.php | 5 +- .../Transformer/ArrayFirstTransformerTest.php | 92 +++++++++++++++++++ tests/Transformer/TrimTransformerTest.php | 72 +++++++++++++-- 6 files changed, 161 insertions(+), 68 deletions(-) create mode 100644 tests/Transformer/ArrayFirstTransformerTest.php diff --git a/Makefile b/Makefile index e14dbd1b..c35ae84f 100644 --- a/Makefile +++ b/Makefile @@ -6,60 +6,10 @@ ifneq ("",$(wildcard $(.env))) include .env endif -# Default image to use for tests -SF_ENV=sf5 -LOCAL_DOCKER_TAG=cleverage_process:test -DOCKER_RUN=docker run -it --rm \ - --mount type=bind,src=$$(pwd),dst=/src-cleverage_process - -pull: pull/$(SF_ENV) - -pull/sf5: - docker pull cleverage/process-bundle:sf5 - -build: - docker build -t cleverage_process:test . - -shell: shell/$(SF_ENV) - -shell/local: - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) bash - -shell/%: - $(DOCKER_RUN) cleverage/process-bundle:$(@F) bash - -test: test/$(SF_ENV) - -test/local: - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) ./bin/console c:c - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report - -test/%: - $(DOCKER_RUN) cleverage/process-bundle:$(@F) ./bin/console c:c - $(DOCKER_RUN) cleverage/process-bundle:$(@F) php vendor/bin/phpunit - -bench: bench/$(SF_ENV) - -bench/local: - $(DOCKER_RUN) $(LOCAL_DOCKER_TAG) /bin/bash -c \ - "./bin/console --env=test c:c; \ - blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" - -bench/%: - $(DOCKER_RUN) cleverage/process-bundle:$(@F) /bin/bash -c \ - "./bin/console --env=test c:c; \ - blackfire run ./bin/console --env=test c:p:e test.long_process -vvv" - -vendor: vendor/$(SF_ENV) - -vendor/%: - rm -rf vendor-$(@F) || true - docker container create --name cleverage_process_bundle_tmp cleverage/process-bundle:$(@F) - docker cp cleverage_process_bundle_tmp:/app/vendor vendor-$(@F) - docker container rm cleverage_process_bundle_tmp +test: + php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report -linter/local: +linter: vendor/bin/rector process vendor/bin/ecs check --fix vendor/bin/phpstan - php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index 4145e5d2..7c9b7b78 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -78,7 +78,7 @@ public function buildProcess(): static } if ($this->options[self::OPTION_JSON_BUFFERING]) { - $arguments = array_merge($arguments, ['--output=' . $this->bufferPath, '--output-format=json-stream']); + $arguments = [...$arguments, '--output=' . $this->bufferPath, '--output-format=json-stream']; } if (! empty($this->context)) { diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php index 993d9323..b32a81f1 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/ArrayFirstTransformer.php @@ -25,7 +25,7 @@ class ArrayFirstTransformer implements ConfigurableTransformerInterface */ public function transform(mixed $value, array $options = []): mixed { - if ($options['allow_not_iterable'] && ! is_iterable($value)) { + if ($options['allow_not_iterable'] === false && ! is_iterable($value)) { return $value; } diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index c51b5bd4..c6d1c586 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -11,6 +11,8 @@ * file that was distributed with this source code. */ +namespace Transformer; + namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -43,9 +45,6 @@ public function getCode(): string return 'trim'; } - /** - * @codeCoverageIgnore - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/ArrayFirstTransformerTest.php new file mode 100644 index 00000000..90dad74b --- /dev/null +++ b/tests/Transformer/ArrayFirstTransformerTest.php @@ -0,0 +1,92 @@ + false]; + + $result = $transformer->transform($value, $options); + + $this->assertEquals(1, $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::transform + */ + public function testTransformReturnsValueIfNotIterableAndAllowed(): void + { + $this->expectException(TypeError::class); + + $transformer = new ArrayFirstTransformer(); + $value = 'not_iterable_value'; + $options = ['allow_not_iterable' => true]; + + $result = $transformer->transform($value, $options); + + $this->assertEquals('not_iterable_value', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::transform + */ + public function testTransformThrowsExceptionIfNotIterableAndNotAllowed(): void + { + $transformer = new ArrayFirstTransformer(); + $value = 'not_iterable_value'; + $options = ['allow_not_iterable' => false]; + + $result = $transformer->transform($value, $options); + + $this->assertEquals($value, $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new ArrayFirstTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('array_first', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::configureOptions + */ + public function testConfigureOptionsSetsDefaultOptions(): void + { + $resolver = new OptionsResolver(); + $transformer = new ArrayFirstTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['allow_not_iterable' => false], $resolvedOptions); + } +} diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/TrimTransformerTest.php index b1972b98..1c6a1dc4 100644 --- a/tests/Transformer/TrimTransformerTest.php +++ b/tests/Transformer/TrimTransformerTest.php @@ -2,34 +2,86 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) 2017-2023 Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Transformer; use CleverAge\ProcessBundle\Transformer\TrimTransformer; use PHPUnit\Framework\TestCase; +use Symfony\Component\OptionsResolver\OptionsResolver; class TrimTransformerTest extends TestCase { + /** + * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform + */ + public function testTransformTrimsStringWithDefaultCharlist(): void + { + $transformer = new TrimTransformer(); + $value = ' trim me '; + + $result = $transformer->transform($value); + + $this->assertEquals('trim me', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform + */ + public function testTransformTrimsStringWithCustomCharlist(): void + { + $transformer = new TrimTransformer(); + $value = '-trim me-'; + $options = ['charlist' => '-']; + + $result = $transformer->transform($value, $options); + + $this->assertEquals('trim me', $result); + } /** * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform */ - public function testTrim(): void + public function testTransformReturnsNullForNullValue(): void { - $trimTransformer = new TrimTransformer(); - $result = $trimTransformer->transform(' test 1 '); - $this->assertEquals('test 1', $result); + $transformer = new TrimTransformer(); + $value = null; + + $result = $transformer->transform($value); - $result = $trimTransformer->transform(null); $this->assertNull($result); } /** * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::getCode */ - public function testCode(): void + public function testGetCodeReturnsCorrectCode(): void { - $trimTransformer = new TrimTransformer(); - $result = $trimTransformer->getCode(); - $this->assertEquals('trim', $result); + $transformer = new TrimTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('trim', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::configureOptions + */ + public function testConfigureOptionsSetsDefaultOptions(): void + { + $resolver = new OptionsResolver(); + $transformer = new TrimTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['charlist' => " \t\n\r\0\x0B"], $resolvedOptions); } -} \ No newline at end of file +} From 7b27fed6382f10bc4384f607df183c299154a8fe Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 21 May 2023 21:59:04 +0200 Subject: [PATCH 199/304] linter + phpunit tests --- .../ArrayElementTransformerTest.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/Transformer/ArrayElementTransformerTest.php diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/ArrayElementTransformerTest.php new file mode 100644 index 00000000..c038dbb8 --- /dev/null +++ b/tests/Transformer/ArrayElementTransformerTest.php @@ -0,0 +1,63 @@ + 1]; + + $result = $transformer->transform($value, $options); + + $this->assertEquals('bar', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer::configureOptions + */ + public function testConfigureOptionsSetsRequiredOptions(): void + { + $resolver = new OptionsResolver(); + $resolver->setDefault('index', 1); + + $transformer = new ArrayElementTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['index'], array_keys($resolvedOptions)); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new ArrayElementTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('array_element', $code); + } +} From 135b1f4752c6bf0459067ddb34f8a3c5e90a7448 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 22 May 2023 19:14:25 +0200 Subject: [PATCH 200/304] phpunit tests --- tests/Transformer/ExplodeTransformerTest.php | 86 ++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tests/Transformer/ExplodeTransformerTest.php diff --git a/tests/Transformer/ExplodeTransformerTest.php b/tests/Transformer/ExplodeTransformerTest.php new file mode 100644 index 00000000..63188e90 --- /dev/null +++ b/tests/Transformer/ExplodeTransformerTest.php @@ -0,0 +1,86 @@ +transform('1,2,3', ['delimiter' => ',']); + + $this->assertEquals(['1', '2', '3'], $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::transform + */ + public function testTransformWithEmptyString(): void + { + $transformer = new ExplodeTransformer(); + + $result = $transformer->transform('', ['delimiter' => ',']); + + $this->assertEquals([], $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::transform + */ + public function testTransformWithNullValue(): void + { + $transformer = new ExplodeTransformer(); + + $result = $transformer->transform(null, ['delimiter' => ',']); + + $this->assertEquals([], $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::getCode + */ + public function testGetCode(): void + { + $transformer = new ExplodeTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('explode', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new ExplodeTransformer(); + $resolver = new OptionsResolver(); + $resolver->setDefault('delimiter', ','); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('delimiter')); + + $resolvedOptions = $resolver->resolve(); + $this->assertEquals(['delimiter'], array_keys($resolvedOptions)); + } +} From b06796d861455e1bbc2bb147b53fe193a04243bd Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 16 Jun 2023 12:07:32 +0200 Subject: [PATCH 201/304] upgrade symfony -> 6.3 --- composer.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 0ff9a443..c64dbccd 100644 --- a/composer.json +++ b/composer.json @@ -63,21 +63,21 @@ "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", - "symfony/config": "^6.2", - "symfony/dependency-injection": "^6.2", + "symfony/config": "^6.3", + "symfony/dependency-injection": "^6.3", "symfony/event-dispatcher-contracts": "^3", - "symfony/form": "^6.2", - "symfony/framework-bundle": "^6.2", - "symfony/expression-language": "^6.2", + "symfony/form": "^6.3", + "symfony/framework-bundle": "^6.3", + "symfony/expression-language": "^6.3", "symfony/monolog-bundle": "~3.3", - "symfony/console": "^6.2", - "symfony/options-resolver": "^6.2", - "symfony/process": "^6.2", - "symfony/property-access": "^6.2", - "symfony/serializer": "^6.2", - "symfony/stopwatch": "^6.2", - "symfony/validator": "^6.2", - "symfony/yaml": "^6.2", + "symfony/console": "^6.3", + "symfony/options-resolver": "^6.3", + "symfony/process": "^6.3", + "symfony/property-access": "^6.3", + "symfony/serializer": "^6.3", + "symfony/stopwatch": "^6.3", + "symfony/validator": "^6.3", + "symfony/yaml": "^6.3", "league/flysystem-bundle": "^3.1" }, "require-dev": { From 72abf47d62f0bfedbfcec51bc731dca3bf5b9c49 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sun, 24 Sep 2023 19:39:35 +0200 Subject: [PATCH 202/304] tweak README.md --- .gitignore | 3 ++- README.md | 76 ++++++++++++++++++++++++++---------------------------- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index cc2bca51..02653685 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ .idea /phpunit.xml .phpunit.result.cache -.phpunit.cache \ No newline at end of file +.phpunit.cache +coverage-report \ No newline at end of file diff --git a/README.md b/README.md index d829dd34..3bb86089 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,13 @@ Compatible with every [currently supported Symfony versions](https://symfony.com ## Index -- [Quick start](Documentation/01-quick_start.md) -- [Task types](Documentation/02-task_types.md) -- [Custom tasks and development](Documentation/03-custom_tasks.md) -- [Advanced workflow](Documentation/04-advanced_workflow.md) -- [Good practices] -- [Testing] +- [Quick start](doc/01-quick_start.md) +- [Task types](doc/02-task_types.md) +- [Custom tasks and development](doc/03-custom_tasks.md) +- [Advanced workflow](doc/04-advanced_workflow.md) - [Contribute](CONTRIBUTING.md) - Cookbooks - - [Common Setup](Documentation/cookbooks/01-common_setup.md) + - [Common Setup](doc/cookbooks/01-common_setup.md) - [Transformations] - [Flow manipulation] - [Dummy tasks] @@ -27,44 +25,42 @@ Compatible with every [currently supported Symfony versions](https://symfony.com - [Subprocess] - [File manipulation] - [Direct call (in controller)] - - [Performances monitoring](Documentation/cookbooks/performances_monitoring.md) - - [Memory usage analysis](Documentation/cookbooks/memory_usage_graph.md) + - [Performances monitoring](doc/cookbooks/performances_monitoring.md) + - [Memory usage analysis](doc/cookbooks/memory_usage_graph.md) - Reference - - [Process definition](Documentation/reference/01-process_definition.md) - - [Task definition](Documentation/reference/02-task_definition.md) + - [Process definition](doc/reference/01-process_definition.md) + - [Task definition](doc/reference/02-task_definition.md) - Basic and debug - - [ConstantOutputTask](Documentation/reference/tasks/constant_output_task.md) - - [ConstantIterableOutputTask](Documentation/reference/tasks/constant_iterable_output_task.md) - - [DebugTask](Documentation/reference/tasks/debug_task.md) - - [DummyTask](Documentation/reference/tasks/dummy_task.md) - - [EventDispatcherTask](Documentation/reference/tasks/event_dispatcher_task.md) + - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) + - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) + - [DebugTask](doc/reference/tasks/debug_task.md) + - [DummyTask](doc/reference/tasks/dummy_task.md) + - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) - Data manipulation and transformations - - [DenormalizerTask](Documentation/reference/tasks/denormalizer_task.md) - - [NormalizerTask](Documentation/reference/tasks/normalizer_task.md) - - [PropertyGetterTask](Documentation/reference/tasks/property_getter_task.md) - - [PropertySetterTask](Documentation/reference/tasks/property_setter_task.md) - - [TransformerTask](Documentation/reference/tasks/transformer_task.md) + - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) + - [NormalizerTask](doc/reference/tasks/normalizer_task.md) + - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) + - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) + - [TransformerTask](doc/reference/tasks/transformer_task.md) - File/CSV - - [CsvReaderTask](Documentation/reference/tasks/csv_reader_task.md) - - [CsvWriterTask](Documentation/reference/tasks/csv_writer_task.md) + - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) + - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) - File/XML - - [XmlReaderTask](Documentation/reference/tasks/xml_reader_task.md) - - [XmlWriterTask](Documentation/reference/tasks/xml_writer_task.md) + - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) + - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) - Flow manipulation - - [AggregateIterableTask](Documentation/reference/tasks/aggregate_iterable_task.md) - - [InputAggregatorTask](Documentation/reference/tasks/input_aggregator_task.md) - - [InputIteratorTask](Documentation/reference/tasks/input_iterator_task.md) + - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) + - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) + - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) - Transformers - - [ArrayFilterTransformer](Documentation/reference/transformers/array_filter_transformer.md) - - [MappingTransformer](Documentation/reference/transformers/mapping_transformer.md) - - [RulesTransformer](Documentation/reference/transformers/rules_transformer.md) - - [DateFormatTransformer](Documentation/reference/transformers/date_format.md) - - [DateParserTransformer](Documentation/reference/transformers/date_parser.md) - - [XpathEvaluatorTransformer](Documentation/reference/transformers/xpath_evaluator.md) - - [Generic transformers definition](Documentation/reference/03-generic_transformers_definition.md) -- Examples - - [Simple ETL] + - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) + - [MappingTransformer](doc/reference/transformers/mapping_transformer.md) + - [RulesTransformer](doc/reference/transformers/rules_transformer.md) + - [DateFormatTransformer](doc/reference/transformers/date_format.md) + - [DateParserTransformer](doc/reference/transformers/date_parser.md) + - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) + - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) - Changelog - - [v3.2](Documentation/changelog/CHANGELOG-3.2.md) - - [v3.1](Documentation/changelog/CHANGELOG-3.1.md) - - [Older versions](Documentation/changelog/CHANGELOG-2.0-1.1.md) + - [v3.2](doc/changelog/CHANGELOG-3.2.md) + - [v3.1](doc/changelog/CHANGELOG-3.1.md) + - [Older versions](doc/changelog/CHANGELOG-2.0-1.1.md) From e3c96389f91d81882ca4ebd6edbe7f6dd9ba46c6 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 25 Sep 2023 18:29:12 +0200 Subject: [PATCH 203/304] move CHANGELOG + update rector --- CHANGELOG.md | 225 ++++++++++++++++++ README.md | 4 - doc/changelog/CHANGELOG-2.0-1.1.md | 50 ---- doc/changelog/CHANGELOG-3.1.md | 88 ------- doc/changelog/CHANGELOG-3.2.md | 72 ------ rector.php | 2 +- .../Xml/XpathEvaluatorTransformer.php | 2 +- 7 files changed, 227 insertions(+), 216 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 doc/changelog/CHANGELOG-2.0-1.1.md delete mode 100644 doc/changelog/CHANGELOG-3.1.md delete mode 100644 doc/changelog/CHANGELOG-3.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..4129a633 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,225 @@ +v3.2.8 +------ + +### Fixes + +https://github.com/cleverage/process-bundle/compare/v3.2.7...v3.2.8 + +v3.2.7 +------ + +### Fixes + +Suppress deprecation message + +v3.2.6 +------ + +### Fixes + +Fix SubprocessInstance Task for Symfony >=5 + +v3.2.5 +------ + +### Fixes + +Upgrade psr/cache + +v3.2.4 +------ + +### Features + +* Added a `ttl` option in the `cached` transformer + +v3.2.3 +------ + +### Features + +* Added `multi_replace` transformer +* Added `cached` transformer + +### Fixes + +* Fixed return value of list and help commands (mandatory for Symfony 5) + +### BC breaks + +* Added `psr/cache` as a dependency, but it shouldn't break anything +* Added `ext-intl` as a dependency, since required by the `slugify` transformer + +v3.2.2 +------ + +### Fixes + +* Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. +* Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop +* `\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException` now displays the failing process code +* `\CleverAge\ProcessBundle\Transformer\TransformerTrait` now displays a more explicit message on wrong options type + + +v3.2.1 +------ + +### Fixes + +* Fatal error while loading configuration in Symfony 3.4 + +v3.2.0 +------ + +### Features + +* [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 +* [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners + +### BC breaks + +There is no BC break for this version, but note that `sidus/base-bundle` has been removed from dependencies. +If you use it, it should already be inside your own composer.json. + + + +Release v3.1 +============ + +v3.1-dev +------ + +### Features + +_Nothing yet_ + +### Fixes + +_Nothing yet_ + +### BC breaks + +_Nothing yet_ + +v3.1.5 +------ + +### Fixes + +* [GITHUB-120](https://github.com/cleverage/process-bundle/pull/120): FolderBrowserTask: Accept array type for `name_pattern` option + + +v3.1.4 +------ + +### Features + +* (_backport from v3.0.9_) Adding simple task to launch system commands + + +v3.1.3 +------ + +### Features + +* (_backport from v3.0.7_) Allowing ValidatorTask to output constraint violations with an option +* (_backport from v3.0.6_) Adding ArrayUnsetTransformer +* (_backport from v3.0.5_) Adding basic debug transformer + +### Fixes + +* (_backport from v3.0.8_) Fixing AbstractIterableOutputTask that was inconsistent when chained, refactoring InputIteratorTask that had the proper implementation with the AbstractIterableOutputTask as parent + +v3.1.2 +------ + +### Fixes + +* Fixed bad static access in tests + +v3.1.1 +------ + +### Features + +* (_backport from v3.0.4_) Adding simple file reader task and cast transformer +* (_backport from v3.0.3_) FilterTask now outputs skipped content to error output + +### Fixes + +* Removed useless, CPU intensive, log on CsvSplitterTask + +v3.1.0 +------ + +### Features + +* [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) + around process execution +* [GITHUB-86](https://github.com/cleverage/process-bundle/issues/86): added XML manipulation tools +* [GITHUB-109](https://github.com/cleverage/process-bundle/issues/109): added an event during CLI process execution +* [GITHUB-107](https://github.com/cleverage/process-bundle/issues/107): allow to use directly a string in task `outputs` + and `errors` configurations + +### Fixes + +* [GITHUB-99](https://github.com/cleverage/process-bundle/issues/99): transformer exception message improvements + +### BC breaks + +* [GIHTUB-82](https://github.com/cleverage/process-bundle/issues/82): the `default_error_strategy` is now mandatory. + If you have any doubt, you can use `default_error_strategy: skip` to keep previous behavior. +* [GITHUB-106](https://github.com/cleverage/process-bundle/issues/106): an entry-point cannot have an ancestor anymore. + The behaviour was undefined, and now it will throw an exception. + + +UPGRADE TO 2.0 +============== + +Task Logging +------------ + +Instead of using `CleverAge\ProcessBundle\Model\ProcessState::log` you must now use the standard +`Psr\Log\LoggerInterface` with the `cleverage_process_task` chanel. You should also pass +`CleverAge\ProcessBundle\Model\ProcessState::getLogContext` to the log context. + +TransformerTask +--------------- + +The main option is now "transformers", which accept transformer codes and then transformer options. +Default options should now look like: +```yaml +options: + transformers: + mapping: + mapping: + : +``` + + +UPGRADE TO 1.1 +============== + +MappingTransformer +------------------ + +* The option "ignore_extra" is renamed to "keep_input". + +Other +----- + +* Fixed issues with blocking tasks +* Removed deprecated methods +* added input/output in process manager (may allow a start_process_task) + +New issues : +* Error workflow + +Planned (v2+) +============ + +* automated transformer creation & refactoring + * easy test cases via yml ? +* changes in interfaces + * allow blocking + iterable +* FIFO queues for in/out diff --git a/README.md b/README.md index 3bb86089..fadcea4f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,3 @@ Compatible with every [currently supported Symfony versions](https://symfony.com - [DateParserTransformer](doc/reference/transformers/date_parser.md) - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) -- Changelog - - [v3.2](doc/changelog/CHANGELOG-3.2.md) - - [v3.1](doc/changelog/CHANGELOG-3.1.md) - - [Older versions](doc/changelog/CHANGELOG-2.0-1.1.md) diff --git a/doc/changelog/CHANGELOG-2.0-1.1.md b/doc/changelog/CHANGELOG-2.0-1.1.md deleted file mode 100644 index 655c3480..00000000 --- a/doc/changelog/CHANGELOG-2.0-1.1.md +++ /dev/null @@ -1,50 +0,0 @@ -UPGRADE TO 2.0 -============== - -Task Logging ------------- - -Instead of using `CleverAge\ProcessBundle\Model\ProcessState::log` you must now use the standard -`Psr\Log\LoggerInterface` with the `cleverage_process_task` chanel. You should also pass -`CleverAge\ProcessBundle\Model\ProcessState::getLogContext` to the log context. - -TransformerTask ---------------- - -The main option is now "transformers", which accept transformer codes and then transformer options. -Default options should now look like: -```yaml -options: - transformers: - mapping: - mapping: - : -``` - - -UPGRADE TO 1.1 -============== - -MappingTransformer ------------------- - -* The option "ignore_extra" is renamed to "keep_input". - -Other ------ - -* Fixed issues with blocking tasks -* Removed deprecated methods -* added input/output in process manager (may allow a start_process_task) - -New issues : -* Error workflow - -Planned (v2+) -============ - -* automated transformer creation & refactoring - * easy test cases via yml ? -* changes in interfaces - * allow blocking + iterable -* FIFO queues for in/out diff --git a/doc/changelog/CHANGELOG-3.1.md b/doc/changelog/CHANGELOG-3.1.md deleted file mode 100644 index 0128828d..00000000 --- a/doc/changelog/CHANGELOG-3.1.md +++ /dev/null @@ -1,88 +0,0 @@ -Release v3.1 -============ - -v3.1-dev ------- - -### Features - -_Nothing yet_ - -### Fixes - -_Nothing yet_ - -### BC breaks - -_Nothing yet_ - -v3.1.5 ------- - -### Fixes - -* [GITHUB-120](https://github.com/cleverage/process-bundle/pull/120): FolderBrowserTask: Accept array type for `name_pattern` option - - -v3.1.4 ------- - -### Features - -* (_backport from v3.0.9_) Adding simple task to launch system commands - - -v3.1.3 ------- - -### Features - -* (_backport from v3.0.7_) Allowing ValidatorTask to output constraint violations with an option -* (_backport from v3.0.6_) Adding ArrayUnsetTransformer -* (_backport from v3.0.5_) Adding basic debug transformer - -### Fixes - -* (_backport from v3.0.8_) Fixing AbstractIterableOutputTask that was inconsistent when chained, refactoring InputIteratorTask that had the proper implementation with the AbstractIterableOutputTask as parent - -v3.1.2 ------- - -### Fixes - -* Fixed bad static access in tests - -v3.1.1 ------- - -### Features - -* (_backport from v3.0.4_) Adding simple file reader task and cast transformer -* (_backport from v3.0.3_) FilterTask now outputs skipped content to error output - -### Fixes - -* Removed useless, CPU intensive, log on CsvSplitterTask - -v3.1.0 ------- - -### Features - -* [GITHUB-83](https://github.com/cleverage/process-bundle/issues/83): added [events](../04-advanced_workflow.md#events) -around process execution -* [GITHUB-86](https://github.com/cleverage/process-bundle/issues/86): added XML manipulation tools -* [GITHUB-109](https://github.com/cleverage/process-bundle/issues/109): added an event during CLI process execution -* [GITHUB-107](https://github.com/cleverage/process-bundle/issues/107): allow to use directly a string in task `outputs` -and `errors` configurations - -### Fixes - -* [GITHUB-99](https://github.com/cleverage/process-bundle/issues/99): transformer exception message improvements - -### BC breaks - -* [GIHTUB-82](https://github.com/cleverage/process-bundle/issues/82): the `default_error_strategy` is now mandatory. -If you have any doubt, you can use `default_error_strategy: skip` to keep previous behavior. -* [GITHUB-106](https://github.com/cleverage/process-bundle/issues/106): an entry-point cannot have an ancestor anymore. -The behaviour was undefined, and now it will throw an exception. diff --git a/doc/changelog/CHANGELOG-3.2.md b/doc/changelog/CHANGELOG-3.2.md deleted file mode 100644 index 70e07389..00000000 --- a/doc/changelog/CHANGELOG-3.2.md +++ /dev/null @@ -1,72 +0,0 @@ -Release v3.2 -============ - -v3.2-dev ------- - -### Features - -_Nothing yet_ - -### Fixes - -_Nothing yet_ - -### BC breaks - -_Nothing yet_ - -v3.2.4 ------- - -### Features - -* Added a `ttl` option in the `cached` transformer - -v3.2.3 ------- - -### Features - -* Added `multi_replace` transformer -* Added `cached` transformer - -### Fixes - -* Fixed return value of list and help commands (mandatory for Symfony 5) - -### BC breaks - -* Added `psr/cache` as a dependency, but it shouldn't break anything -* Added `ext-intl` as a dependency, since required by the `slugify` transformer - -v3.2.2 ------- - -### Fixes - -* Ignore empty lines in `\CleverAge\ProcessBundle\Filesystem\CsvResource::getLineCount`. -* Fixed `\CleverAge\ProcessBundle\Task\AbstractIterableOutputTask` skipping iterations when inside another iteration loop -* `\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException` now displays the failing process code -* `\CleverAge\ProcessBundle\Transformer\TransformerTrait` now displays a more explicit message on wrong options type - - -v3.2.1 ------- - -### Fixes - -* Fatal error while loading configuration in Symfony 3.4 - -v3.2.0 ------- - -### Features - -* [GITHUB-121](https://github.com/cleverage/process-bundle/issues/121): Enable compatibility with Symfony 5 -* [GITHUB-118](https://github.com/cleverage/process-bundle/pull/118): Added boilerplate code to avoid deprecations notices for event listeners - -### BC breaks - -There is no BC break for this version, but note that `sidus/base-bundle` has been removed from dependencies. -If you use it, it should already be inside your own composer.json. diff --git a/rector.php b/rector.php index e9d9ab95..e19ab41a 100644 --- a/rector.php +++ b/rector.php @@ -19,7 +19,7 @@ $rectorConfig->sets([ SetList::TYPE_DECLARATION, LevelSetList::UP_TO_PHP_81, - SymfonyLevelSetList::UP_TO_SYMFONY_62, + SymfonyLevelSetList::UP_TO_SYMFONY_63, ]); $rectorConfig->phpVersion(PhpVersion::PHP_81); diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index 3fe2f072..20e32080 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -98,7 +98,7 @@ public function transform(mixed $value, array $options = []): mixed $query = $options['query']; if (is_array($query)) { $result = array_map( - fn ($subquery) => $this->query($xpath, $subquery['subquery'], $value, $subquery), + fn ($subquery): mixed => $this->query($xpath, $subquery['subquery'], $value, $subquery), $query ); } else { From 51d52f378235995cbb84d8cac0e76a2491a8b7b0 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 25 Sep 2023 18:44:18 +0200 Subject: [PATCH 204/304] update README --- doc/01-quick_start.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/01-quick_start.md b/doc/01-quick_start.md index a4c9b14f..0bab2f4f 100644 --- a/doc/01-quick_start.md +++ b/doc/01-quick_start.md @@ -20,16 +20,16 @@ The most common example is the ETL. It's a kind of application whose main purpos ## Installation -This bundle requires Symfony 3. You can install it using composer: +This bundle requires Symfony 6.3 minimum. You can install it using composer: ```bash composer require cleverage/process-bundle ``` -Remember to update your AppKernel +Remember to add the following line to bundles.php (not required if Symfony Flex is used) ```php -$bundles[] = new CleverAge\ProcessBundle\CleverAgeProcessBundle(); +CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], ``` Some tasks and transformers use the main Symfony serializer service. You might need to explicitly enable it, or dependency From 1db60fa6207006f98567f8e4a277735c8cdb8096 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 20:04:58 +0200 Subject: [PATCH 205/304] add unit tests --- .../Transformer/DateParserTransformerTest.php | 110 ++++++++++++++++++ tests/Transformer/ImplodeTransformerTest.php | 86 ++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 tests/Transformer/DateParserTransformerTest.php create mode 100644 tests/Transformer/ImplodeTransformerTest.php diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/DateParserTransformerTest.php new file mode 100644 index 00000000..5ac7c4ef --- /dev/null +++ b/tests/Transformer/DateParserTransformerTest.php @@ -0,0 +1,110 @@ + 'Y-m-d']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertInstanceOf(DateTime::class, $transformedValue); + $this->assertEquals('2023-09-28', $transformedValue->format('Y-m-d')); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + */ + public function testTransformInvalidDate(): void + { + $transformer = new DateParserTransformer(); + $value = 'invalid_date'; + $options = ['format' => 'Y-m-d']; + + $this->expectException(UnexpectedValueException::class); + + $transformer->transform($value, $options); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + */ + public function testTransformNullValue(): void + { + $transformer = new DateParserTransformer(); + $value = null; + $options = ['format' => 'Y-m-d']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertNull($transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + */ + public function testTransformDateTimeObject(): void + { + // Arrange + $transformer = new DateParserTransformer(); + $value = new DateTime('2023-09-28'); + $options = ['format' => 'Y-m-d']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertSame($value, $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::getCode + */ + public function testGetCode(): void + { + $transformer = new DateParserTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('date_parser', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new DateParserTransformer(); + $resolver = new OptionsResolver(); + $resolver->setDefault('format', 'd/m/Y'); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('format')); + + $resolvedOptions = $resolver->resolve(); + $this->assertEquals(['format'], array_keys($resolvedOptions)); + } +} diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/ImplodeTransformerTest.php new file mode 100644 index 00000000..934aa499 --- /dev/null +++ b/tests/Transformer/ImplodeTransformerTest.php @@ -0,0 +1,86 @@ +transform(['1', '2', '3'], ['separator' => ',']); + + $this->assertEquals('1,2,3', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::transform + */ + public function testTransformWithInvalidValue(): void + { + $this->expectException(UnexpectedValueException::class); + + $transformer = new ImplodeTransformer(); + + $transformer->transform('invalid_value', ['separator' => ',']); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::transform + */ + public function testTransformWithDefaultSeparator(): void + { + $transformer = new ImplodeTransformer(); + + $result = $transformer->transform(['1', '2', '3'], ['separator' => '|']); + + $this->assertEquals('1|2|3', $result); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::getCode + */ + public function testGetCode(): void + { + $transformer = new ImplodeTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('implode', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new ImplodeTransformer(); + $resolver = new OptionsResolver(); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('separator')); + + $resolvedOptions = $resolver->resolve(); + $this->assertEquals(['separator'], array_keys($resolvedOptions)); + } +} From 7e575227061bcae4cc48649f496f598380b1044c Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 20:20:43 +0200 Subject: [PATCH 206/304] add unit tests --- tests/Transformer/CastTransformerTest.php | 124 +++++++++++++++++++++ tests/Transformer/DebugTransformerTest.php | 50 +++++++++ 2 files changed, 174 insertions(+) create mode 100644 tests/Transformer/CastTransformerTest.php create mode 100644 tests/Transformer/DebugTransformerTest.php diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php new file mode 100644 index 00000000..f9a1989b --- /dev/null +++ b/tests/Transformer/CastTransformerTest.php @@ -0,0 +1,124 @@ + 'int']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertIsInt($transformedValue); + $this->assertEquals(123, $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + */ + public function testCastToFloat(): void + { + $transformer = new CastTransformer(); + $value = '123.45'; + $options = ['type' => 'float']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertIsFloat($transformedValue); + $this->assertEquals(123.45, $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + */ + public function testCastToString(): void + { + $transformer = new CastTransformer(); + $value = 123; + $options = ['type' => 'string']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertIsString($transformedValue); + $this->assertEquals('123', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + */ + public function testCastToBool(): void + { + $transformer = new CastTransformer(); + $value = 'true'; + $options = ['type' => 'bool']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertIsBool($transformedValue); + $this->assertTrue($transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + */ + public function testCastToInvalidType(): void + { + $transformer = new CastTransformer(); + $value = '123'; + $options = ['type' => 'invalid_type']; + + $this->expectException(ValueError::class); + + $transformer->transform($value, $options); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::configureOptions + */ + public function testConfigureOptionsSetsRequiredOptions(): void + { + $resolver = new OptionsResolver(); + $resolver->setDefault('type', 'int'); + + $transformer = new CastTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['type'], array_keys($resolvedOptions)); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new CastTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('cast', $code); + } +} diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php new file mode 100644 index 00000000..2076d77e --- /dev/null +++ b/tests/Transformer/DebugTransformerTest.php @@ -0,0 +1,50 @@ +transform($value); + + $this->assertSame($value, $transformedValue); + + if (class_exists(VarDumper::class)) { + VarDumper::dump($value); + } + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DebugTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new DebugTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('dump', $code); + } +} From 34972e22c882b5c92b4cd9a36fa666884c09584a Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 20:33:20 +0200 Subject: [PATCH 207/304] add unit tests --- .../Transformer/DateFormatTransformerTest.php | 96 +++++++++++++++++++ tests/Transformer/DefaultTransformerTest.php | 77 +++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 tests/Transformer/DateFormatTransformerTest.php create mode 100644 tests/Transformer/DefaultTransformerTest.php diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/DateFormatTransformerTest.php new file mode 100644 index 00000000..4277bf9b --- /dev/null +++ b/tests/Transformer/DateFormatTransformerTest.php @@ -0,0 +1,96 @@ + 'Y-m-d']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertIsString($transformedValue); + $this->assertEquals('2023-09-28', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::transform + */ + public function testTransformInvalidDate(): void + { + $transformer = new DateFormatTransformer(); + $value = 'invalid_date'; + $options = ['format' => 'Y-m-d']; + + $this->expectException(UnexpectedValueException::class); + + $transformer->transform($value, $options); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::transform + */ + public function testTransformNullValue(): void + { + // Arrange + $transformer = new DateFormatTransformer(); + $value = null; + $options = ['format' => 'Y-m-d']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertNull($transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::getCode + */ + public function testGetCode(): void + { + $transformer = new DateFormatTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('date_format', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new DateFormatTransformer(); + $resolver = new OptionsResolver(); + $resolver->setDefault('format', 'd/m/Y'); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('format')); + + $resolvedOptions = $resolver->resolve(); + $this->assertEquals(['format'], array_keys($resolvedOptions)); + } +} diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php new file mode 100644 index 00000000..2d749d33 --- /dev/null +++ b/tests/Transformer/DefaultTransformerTest.php @@ -0,0 +1,77 @@ + 'default_value']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertSame($value, $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::transform + */ + public function testTransformWithNullValue(): void + { + $transformer = new DefaultTransformer(); + $value = null; + $options = ['value' => 'default_value']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('default_value', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $resolver = new OptionsResolver(); + $resolver->setDefault('value', 'default_value'); + + $transformer = new DefaultTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['value'], array_keys($resolvedOptions)); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new DefaultTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('default', $code); + } +} From 6027f2e542a2e8dbb8273ebcf5a4c10aa752a4a4 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 20:43:56 +0200 Subject: [PATCH 208/304] add unit tests --- tests/Transformer/ConstantTransformerTest.php | 75 +++++++++++++ .../MultiReplaceTransformerTest.php | 104 ++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 tests/Transformer/ConstantTransformerTest.php create mode 100644 tests/Transformer/MultiReplaceTransformerTest.php diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php new file mode 100644 index 00000000..35cdd88c --- /dev/null +++ b/tests/Transformer/ConstantTransformerTest.php @@ -0,0 +1,75 @@ + 'default_value']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('default_value', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::transform + */ + public function testTransformWithNullValue(): void + { + $transformer = new ConstantTransformer(); + $value = null; + $options = ['constant' => 'default_value']; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('default_value', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new ConstantTransformer(); + $resolver = new OptionsResolver(); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('constant')); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new ConstantTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('constant', $code); + } +} diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php new file mode 100644 index 00000000..9a2ee68b --- /dev/null +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -0,0 +1,104 @@ + [ + 'This' => 'That', + 'string' => 'sentence', + ], + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('That is a test sentence.', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::transform + */ + public function testTransformWithEmptyReplaceMapping(): void + { + $transformer = new MultiReplaceTransformer(); + $value = 'This is a test string.'; + $options = [ + 'replace_mapping' => [], + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('This is a test string.', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::transform + */ + public function testTransformWithNullValue(): void + { + $transformer = new MultiReplaceTransformer(); + $value = null; + $options = [ + 'replace_mapping' => [ + 'This' => 'That', + 'string' => 'sentence', + ], + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals('', $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::configureOptions + */ + public function testConfigureOptions(): void + { + $transformer = new MultiReplaceTransformer(); + $resolver = new OptionsResolver(); + $resolver->setDefault('replace_mapping', []); + + $transformer->configureOptions($resolver); + + $this->assertTrue($resolver->isRequired('replace_mapping')); + + $resolvedOptions = $resolver->resolve(); + $this->assertEquals(['replace_mapping'], array_keys($resolvedOptions)); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new MultiReplaceTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('multi_replace', $code); + } +} From 4c6270b9cc5bd1eaf6f373462e445506310c10b0 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 20:59:36 +0200 Subject: [PATCH 209/304] add unit tests --- tests/Transformer/WrapperTransformerTest.php | 95 ++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/Transformer/WrapperTransformerTest.php diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php new file mode 100644 index 00000000..d1785e4b --- /dev/null +++ b/tests/Transformer/WrapperTransformerTest.php @@ -0,0 +1,95 @@ + 'key', + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals(['key' => 'my_value'], $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::transform + */ + public function testTransformWithIntegerWrapperKey(): void + { + $transformer = new WrapperTransformer(); + $value = 'my_value'; + $options = [ + 'wrapper_key' => 1, + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals([1 => 'my_value'], $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::transform + */ + public function testTransformWithNullValue(): void + { + $transformer = new WrapperTransformer(); + $value = null; + $options = [ + 'wrapper_key' => 'key', + ]; + + $transformedValue = $transformer->transform($value, $options); + + $this->assertEquals(['key' => null], $transformedValue); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new WrapperTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('wrapper', $code); + } + + /** + * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::configureOptions + */ + public function testConfigureOptionsSetsDefaultOptions(): void + { + $resolver = new OptionsResolver(); + $transformer = new WrapperTransformer(); + + $transformer->configureOptions($resolver); + $resolvedOptions = $resolver->resolve(); + + $this->assertEquals(['wrapper_key'], array_keys($resolvedOptions)); + } +} From 5de91dcd3117c460d904d317a5840559cef9bec5 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 28 Sep 2023 21:23:29 +0200 Subject: [PATCH 210/304] add unit tests --- .../MissingTransformerExceptionTest.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/Exception/MissingTransformerExceptionTest.php diff --git a/tests/Exception/MissingTransformerExceptionTest.php b/tests/Exception/MissingTransformerExceptionTest.php new file mode 100644 index 00000000..4e3631f1 --- /dev/null +++ b/tests/Exception/MissingTransformerExceptionTest.php @@ -0,0 +1,23 @@ +assertInstanceOf(UnexpectedValueException::class, $exception); + $this->assertEquals('No transformer with code : my_transformer', $exception->getMessage()); + } +} From 2aaaa3f7128265f71947a807ecf8fcf6f9c37965 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Fri, 29 Sep 2023 15:50:35 +0200 Subject: [PATCH 211/304] ajout symfony messenger/scheduler --- composer.json | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index c64dbccd..03fd86a1 100644 --- a/composer.json +++ b/composer.json @@ -63,22 +63,24 @@ "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", + "league/flysystem-bundle": "^3.1", "symfony/config": "^6.3", + "symfony/console": "^6.3", "symfony/dependency-injection": "^6.3", "symfony/event-dispatcher-contracts": "^3", + "symfony/expression-language": "^6.3", "symfony/form": "^6.3", "symfony/framework-bundle": "^6.3", - "symfony/expression-language": "^6.3", + "symfony/messenger": "^6.3", "symfony/monolog-bundle": "~3.3", - "symfony/console": "^6.3", "symfony/options-resolver": "^6.3", "symfony/process": "^6.3", "symfony/property-access": "^6.3", + "symfony/scheduler": "^6.3", "symfony/serializer": "^6.3", "symfony/stopwatch": "^6.3", "symfony/validator": "^6.3", - "symfony/yaml": "^6.3", - "league/flysystem-bundle": "^3.1" + "symfony/yaml": "^6.3" }, "require-dev": { "roave/security-advisories": "dev-latest", @@ -103,6 +105,7 @@ "phpstan/extension-installer": true, "symfony/flex": true, "symfony/runtime": true - } + }, + "sort-packages": true } } From 02161e7edad5c149370834147e0e877649e096b4 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Sat, 30 Sep 2023 15:14:25 +0200 Subject: [PATCH 212/304] fix events --- src/Manager/ProcessManager.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 4231f27c..3f5e2594 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -93,18 +93,27 @@ public function getTaskConfiguration(): ?TaskConfiguration public function execute(string $processCode, mixed $input = null, array $context = []): mixed { try { - $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context)); + $this->eventDispatcher->dispatch( + new ProcessEvent($processCode, $input, $context), + ProcessEvent::EVENT_PROCESS_STARTED + ); $this->processLogger->debug('Process start'); $result = $this->doExecute($processCode, $input, $context); $this->processLogger->debug('Process end'); - $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context, $result)); + $this->eventDispatcher->dispatch( + new ProcessEvent($processCode, $input, $context, $result), + ProcessEvent::EVENT_PROCESS_ENDED + ); } catch (Throwable $error) { $this->processLogger->critical('Critical process failure', [ 'error' => $error->getMessage(), ]); - $this->eventDispatcher->dispatch(new ProcessEvent($processCode, $input, $context, null, $error)); + $this->eventDispatcher->dispatch( + new ProcessEvent($processCode, $input, $context, null, $error), + ProcessEvent::EVENT_PROCESS_FAILED + ); throw $error; } From 5fdf334db7e608f913e36944f178eac795f30d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Tonon?= Date: Thu, 5 Oct 2023 09:47:02 +0200 Subject: [PATCH 213/304] Fix error when headers option to Csv resource task is null --- src/Filesystem/CsvResource.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 2 +- src/Task/File/Csv/CsvWriterTask.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 18aa0371..4a021cad 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -42,7 +42,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf protected ?int $lineNumber = 1; - protected bool $closed; + protected bool $closed = false; protected bool $seekCalled = false; diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index 7fef7280..d82f273c 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -63,5 +63,5 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('headers', ['null', 'array']); } - abstract protected function getHeaders(ProcessState $state, array $options): array; + abstract protected function getHeaders(ProcessState $state, array $options): ?array; } diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index 3dde2a19..5fae26af 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -78,7 +78,7 @@ public function next(ProcessState $state): bool return ! $this->csv->isEndOfFile(); } - protected function getHeaders(ProcessState $state, array $options): array + protected function getHeaders(ProcessState $state, array $options): ?array { return $options['headers']; } diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index 8629c9bb..82a860c8 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -85,7 +85,7 @@ protected function getInput(ProcessState $state): array return $input; } - protected function getHeaders(ProcessState $state, array $options): array + protected function getHeaders(ProcessState $state, array $options): ?array { $headers = $options['headers']; if ($headers === null) { From 1addbb68ae83c9c24ad2dbc35e9b05f0524e386e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Tonon?= Date: Thu, 5 Oct 2023 08:10:57 +0000 Subject: [PATCH 214/304] Fix error on csv resource task when headers options is set to null --- src/Filesystem/CsvResource.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 2 +- src/Task/File/Csv/CsvWriterTask.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 18aa0371..4a021cad 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -42,7 +42,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf protected ?int $lineNumber = 1; - protected bool $closed; + protected bool $closed = false; protected bool $seekCalled = false; diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index 7fef7280..d82f273c 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -63,5 +63,5 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('headers', ['null', 'array']); } - abstract protected function getHeaders(ProcessState $state, array $options): array; + abstract protected function getHeaders(ProcessState $state, array $options): ?array; } diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index 3dde2a19..5fae26af 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -78,7 +78,7 @@ public function next(ProcessState $state): bool return ! $this->csv->isEndOfFile(); } - protected function getHeaders(ProcessState $state, array $options): array + protected function getHeaders(ProcessState $state, array $options): ?array { return $options['headers']; } diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index 8629c9bb..82a860c8 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -85,7 +85,7 @@ protected function getInput(ProcessState $state): array return $input; } - protected function getHeaders(ProcessState $state, array $options): array + protected function getHeaders(ProcessState $state, array $options): ?array { $headers = $options['headers']; if ($headers === null) { From 32775f11d807aaeb7f02773ca6aa73946948d6ff Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 9 Oct 2023 20:17:54 +0200 Subject: [PATCH 215/304] fix deprecation --- src/Transformer/TransformerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 12d10117..098453f5 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -41,7 +41,7 @@ public function normalizeTransformers(Options $options, array $transformers): ar $transformer->configureOptions($transformerOptionsResolver); $transformerOptions = $transformerOptionsResolver->resolve($transformerOptions); } elseif (! empty($transformerOptions)) { - throw new InvalidArgumentException("Transformer ${$origTransformerCode} should not have options"); + throw new InvalidArgumentException("Transformer {${$origTransformerCode}} should not have options"); } $closure = static fn ($value) => $transformer->transform($value, $transformerOptions); From fb53766c0ea07821de4cf676c7dc11a472c02911 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 10 Oct 2023 13:38:54 +0200 Subject: [PATCH 216/304] ajout documentation --- README.md | 1 + doc/reference/tasks/debug_task.md | 5 +++++ doc/reference/tasks/die_task.md | 25 +++++++++++++++++++++++++ src/Task/Debug/DebugTask.php | 2 ++ src/Task/Debug/DieTask.php | 2 ++ 5 files changed, 35 insertions(+) create mode 100644 doc/reference/tasks/die_task.md diff --git a/README.md b/README.md index fadcea4f..da35666a 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Compatible with every [currently supported Symfony versions](https://symfony.com - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) - [DebugTask](doc/reference/tasks/debug_task.md) + - [DieTask](doc/reference/tasks/die_task.md) - [DummyTask](doc/reference/tasks/dummy_task.md) - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) - Data manipulation and transformations diff --git a/doc/reference/tasks/debug_task.md b/doc/reference/tasks/debug_task.md index 1c8b1131..1a98b263 100644 --- a/doc/reference/tasks/debug_task.md +++ b/doc/reference/tasks/debug_task.md @@ -19,3 +19,8 @@ Possible outputs ---------------- `any`: re-output given input + +Example +---------------- + +https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.debug.yaml \ No newline at end of file diff --git a/doc/reference/tasks/die_task.md b/doc/reference/tasks/die_task.md new file mode 100644 index 00000000..cdde437e --- /dev/null +++ b/doc/reference/tasks/die_task.md @@ -0,0 +1,25 @@ +DieTask +========= + +Stops the process brutally + + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Debug\DieTask` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +None + +Example +---------------- + +https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.die.yaml \ No newline at end of file diff --git a/src/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php index 761da86b..8c482a0e 100644 --- a/src/Task/Debug/DebugTask.php +++ b/src/Task/Debug/DebugTask.php @@ -19,6 +19,8 @@ /** * Dump the content of the input + * + * @example https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.debug.yaml */ class DebugTask implements TaskInterface { diff --git a/src/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php index 42a05739..ab3ab625 100644 --- a/src/Task/Debug/DieTask.php +++ b/src/Task/Debug/DieTask.php @@ -20,6 +20,8 @@ * Class DieTask * * Stops the process brutally + * + * @example https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.die.yaml */ class DieTask implements TaskInterface { From 4e0069cdcef1cf7c455ff3ffcc57e7a4a533a47d Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 10 Oct 2023 14:34:50 +0200 Subject: [PATCH 217/304] ajout phpcsfixer --- .gitignore | 1 + .php-cs-fixer.dist.php | 38 ++++++ Makefile | 16 +-- composer.json | 9 +- ecs.php | 2 +- rector.php | 4 +- src/CleverAgeProcessBundle.php | 2 +- src/Command/ExecuteProcessCommand.php | 39 +++--- src/Command/ListProcessCommand.php | 22 ++-- src/Command/ProcessHelpCommand.php | 110 ++++++++--------- src/Configuration/ProcessConfiguration.php | 47 ++++---- src/Configuration/TaskConfiguration.php | 14 +-- src/Context/ContextualOptionResolver.php | 11 +- .../CleverAgeProcessExtension.php | 12 +- .../Compiler/CheckSerializerCompilerPass.php | 4 +- .../Compiler/RegistryCompilerPass.php | 6 +- src/DependencyInjection/Configuration.php | 6 +- src/Event/ConsoleProcessEvent.php | 2 +- src/Event/ProcessEvent.php | 7 +- src/EventListener/DataQueueEventListener.php | 11 +- src/Exception/CircularProcessException.php | 6 +- .../InvalidProcessConfigurationException.php | 7 +- src/Exception/MissingProcessException.php | 6 +- .../MissingTaskConfigurationException.php | 6 +- src/Exception/MissingTransformerException.php | 6 +- src/Exception/ProcessExceptionInterface.php | 6 +- src/Exception/TransformerException.php | 9 +- .../PhpFunctionProvider.php | 2 +- src/Filesystem/CsvFile.php | 32 ++--- src/Filesystem/CsvResource.php | 75 ++++++------ src/Filesystem/FileStreamInterface.php | 4 +- src/Filesystem/JsonStreamFile.php | 28 ++--- src/Filesystem/SeekableFileInterface.php | 6 +- src/Filesystem/StructuredFileInterface.php | 2 +- src/Filesystem/WritableFileInterface.php | 2 +- .../WritableStructuredFileInterface.php | 4 +- src/Filesystem/XmlFile.php | 20 ++-- src/Logger/AbstractLogger.php | 2 +- src/Logger/AbstractProcessor.php | 6 +- src/Manager/ProcessManager.php | 111 +++++++++--------- src/Model/AbstractConfigurableTask.php | 11 +- src/Model/FinalizableTaskInterface.php | 2 +- src/Model/FlushableTaskInterface.php | 2 +- src/Model/InitializableTaskInterface.php | 2 +- src/Model/IterableTaskInterface.php | 4 +- src/Model/ProcessHistory.php | 39 +++--- src/Model/ProcessState.php | 30 ++--- src/Model/SubprocessInstance.php | 25 ++-- src/Model/TaskInterface.php | 2 +- src/Registry/ProcessConfigurationRegistry.php | 20 ++-- src/Registry/TransformerRegistry.php | 11 +- src/Task/AbstractIterableOutputTask.php | 23 ++-- src/Task/AggregateIterableTask.php | 5 +- src/Task/ArrayMergeTask.php | 14 +-- src/Task/ColumnAggregatorTask.php | 9 +- src/Task/ConstantIterableOutputTask.php | 8 +- src/Task/ConstantOutputTask.php | 2 +- src/Task/CounterTask.php | 10 +- src/Task/Debug/DebugTask.php | 2 +- src/Task/Debug/DieTask.php | 4 +- src/Task/Debug/ErrorForwarderTask.php | 2 +- src/Task/Debug/MemInfoDumpTask.php | 6 +- src/Task/Debug/StopwatchTask.php | 2 +- src/Task/DummyTask.php | 2 +- src/Task/Event/EventDispatcherTask.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/AbstractCsvTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 15 ++- src/Task/File/Csv/CsvSplitterTask.php | 21 ++-- src/Task/File/Csv/CsvWriterTask.php | 17 ++- src/Task/File/Csv/InputCsvReaderTask.php | 12 +- src/Task/File/FileFetchTask.php | 27 ++--- src/Task/File/FileMoverTask.php | 13 +- src/Task/File/FileReaderTask.php | 11 +- src/Task/File/FileRemoverTask.php | 2 +- src/Task/File/FolderBrowserTask.php | 19 ++- src/Task/File/InputFolderBrowserTask.php | 11 +- .../File/JsonStream/JsonStreamReaderTask.php | 4 +- src/Task/File/Xml/XmlReaderTask.php | 4 +- src/Task/File/Xml/XmlWriterTask.php | 8 +- src/Task/File/YamlReaderTask.php | 19 ++- src/Task/File/YamlWriterTask.php | 2 +- src/Task/FilterTask.php | 4 +- src/Task/GroupByAggregateIterableTask.php | 6 +- src/Task/InputAggregatorTask.php | 29 ++--- src/Task/InputIteratorTask.php | 19 ++- src/Task/IterableBatchTask.php | 16 ++- src/Task/ObjectUpdaterTask.php | 11 +- src/Task/Process/CommandRunnerTask.php | 2 +- src/Task/Process/ProcessExecutorTask.php | 4 +- src/Task/Process/ProcessLauncherTask.php | 39 +++--- src/Task/PropertyGetterTask.php | 5 +- src/Task/PropertySetterTask.php | 5 +- .../Reporting/AdvancedStatCounterTask.php | 17 ++- src/Task/Reporting/LoggerTask.php | 2 +- src/Task/Reporting/StatCounterTask.php | 4 +- src/Task/RowAggregatorTask.php | 10 +- src/Task/Serialization/DenormalizerTask.php | 2 +- src/Task/Serialization/NormalizerTask.php | 7 +- src/Task/SimpleBatchTask.php | 7 +- src/Task/SkipEmptyTask.php | 2 +- src/Task/SplitJoinLineTask.php | 15 +-- src/Task/StopTask.php | 2 +- src/Task/TransformerTask.php | 2 +- src/Task/Validation/ValidatorTask.php | 9 +- src/Transformer/ArrayElementTransformer.php | 4 +- src/Transformer/ArrayFilterTransformer.php | 7 +- src/Transformer/ArrayFirstTransformer.php | 8 +- src/Transformer/ArrayLastTransformer.php | 4 +- src/Transformer/ArrayMapTransformer.php | 15 +-- src/Transformer/ArrayUnsetTransformer.php | 8 +- src/Transformer/CachedTransformer.php | 19 ++- src/Transformer/CallbackTransformer.php | 18 ++- src/Transformer/CastTransformer.php | 2 +- src/Transformer/ConditionTrait.php | 34 +++--- .../ConfigurableTransformerInterface.php | 2 +- src/Transformer/ConstantTransformer.php | 6 +- src/Transformer/ConvertValueTransformer.php | 27 ++--- src/Transformer/DateFormatTransformer.php | 8 +- src/Transformer/DateParserTransformer.php | 12 +- src/Transformer/DebugTransformer.php | 2 +- src/Transformer/DefaultTransformer.php | 2 +- src/Transformer/DenormalizeTransformer.php | 4 +- src/Transformer/EvaluatorTransformer.php | 2 +- src/Transformer/ExplodeTransformer.php | 6 +- .../ExpressionLanguageMapTransformer.php | 13 +- src/Transformer/GenericTransformer.php | 19 ++- src/Transformer/HashTransformer.php | 2 +- src/Transformer/ImplodeTransformer.php | 8 +- src/Transformer/InstantiateTransformer.php | 10 +- src/Transformer/MappingTransformer.php | 25 ++-- src/Transformer/MultiReplaceTransformer.php | 2 +- src/Transformer/NormalizeTransformer.php | 4 +- src/Transformer/PregFilterTransformer.php | 2 +- .../PropertyAccessorTransformer.php | 8 +- .../RecursivePropertySetterTransformer.php | 17 ++- src/Transformer/RulesTransformer.php | 20 ++-- src/Transformer/SlugifyTransformer.php | 9 +- src/Transformer/SprintfTransformer.php | 5 +- src/Transformer/TransformerInterface.php | 6 +- src/Transformer/TransformerTrait.php | 20 ++-- src/Transformer/TrimTransformer.php | 8 +- src/Transformer/TypeSetterTransformer.php | 2 +- src/Transformer/UnsetTransformer.php | 12 +- src/Transformer/WrapperTransformer.php | 4 +- .../Xml/XpathEvaluatorTransformer.php | 56 ++++----- src/Validator/ConstraintLoader.php | 11 +- tests.old/AbstractProcessTest.php | 18 ++- tests.old/BasicTest.php | 21 ++-- tests.old/BlockingTaskTest.php | 8 +- tests.old/CircularProcessTest.php | 23 ++-- tests.old/ContextTest.php | 16 +-- tests.old/EmptyProcessTest.php | 4 +- tests.old/ExceptionManagementTest.php | 4 +- tests.old/FlushableTaskTest.php | 2 +- tests.old/IterableTaskTest.php | 6 +- tests.old/MultiBranchProcessTest.php | 10 +- tests.old/MultiWorkflowTest.php | 2 +- tests.old/Task/FilterTaskTest.php | 4 +- tests.old/Task/ProcessExecutorTaskTest.php | 10 +- tests.old/Task/StopTaskTest.php | 2 +- tests.old/Task/TransformerTaskTest.php | 12 +- tests.old/Task/ValidatorTaskTest.php | 4 +- .../ArrayFilterTransformerTest.php | 6 +- .../Transformer/CallbackTransformerTest.php | 14 +-- .../Transformer/DateTransformersTest.php | 25 ++-- tests.old/Transformer/HashTransformerTest.php | 6 +- .../Transformer/MappingTransformerTest.php | 20 ++-- .../Transformer/RulesTransformerTest.php | 2 +- .../Transformer/TransformerExceptionTest.php | 12 +- .../Transformer/TypeSetterTransformerTest.php | 8 +- .../Transformer/UnsetTransformerTest.php | 18 +-- .../XpathEvaluatorTransformerTest.php | 22 ++-- .../MissingTransformerExceptionTest.php | 3 +- .../ArrayElementTransformerTest.php | 2 +- .../Transformer/ArrayFirstTransformerTest.php | 3 +- tests/Transformer/CastTransformerTest.php | 3 +- tests/Transformer/ConstantTransformerTest.php | 1 - .../Transformer/DateFormatTransformerTest.php | 6 +- .../Transformer/DateParserTransformerTest.php | 8 +- tests/Transformer/ImplodeTransformerTest.php | 3 +- tests/Transformer/SprintfTransformerTest.php | 1 - 182 files changed, 974 insertions(+), 1138 deletions(-) create mode 100644 .php-cs-fixer.dist.php diff --git a/.gitignore b/.gitignore index 02653685..4eb7427a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ /phpunit.xml .phpunit.result.cache .phpunit.cache +.php-cs-fixer.cache coverage-report \ No newline at end of file diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..f1d55879 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,38 @@ +in(__DIR__) + ->ignoreDotFiles(true) + ->ignoreVCS(true) + ->exclude(['build', 'vendor']) + ->files() + ->name('*.php') +; + +$config = new PhpCsFixer\Config(); + +return $config + ->setUsingCache(true) + ->setRiskyAllowed(true) + ->setFinder($finder) + ->setRules([ + '@Symfony' => true, + '@Symfony:risky' => true, + '@PHPUnit48Migration:risky' => true, + 'array_syntax' => ['syntax' => 'short'], + 'fopen_flags' => false, + 'ordered_imports' => true, + 'protected_to_private' => false, + // Part of @Symfony:risky in PHP-CS-Fixer 2.13.0. To be removed from the config file once upgrading + 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced', 'strict' => true], + // Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'single_line_throw' => false, + // this must be disabled because the output of some tests include NBSP characters + 'non_printable_character' => false, + 'blank_line_between_import_groups' => false, + 'no_trailing_comma_in_singleline' => false, + 'nullable_type_declaration_for_default_null_value' => true, + 'phpdoc_to_comment' => false, + ]) +; diff --git a/Makefile b/Makefile index c35ae84f..e9e753c2 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,11 @@ -# Include .env.dist for the default values -include .env.dist - -# Include .env only if it exists -ifneq ("",$(wildcard $(.env))) -include .env -endif +.ONESHELL: +SHELL := /bin/bash test: php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report -linter: - vendor/bin/rector process - vendor/bin/ecs check --fix +linter: #[Linter] + vendor/bin/php-cs-fixer fix + +phpstan: #[Phpstan] vendor/bin/phpstan diff --git a/composer.json b/composer.json index 03fd86a1..7195245c 100644 --- a/composer.json +++ b/composer.json @@ -83,14 +83,13 @@ "symfony/yaml": "^6.3" }, "require-dev": { - "roave/security-advisories": "dev-latest", - "phpunit/phpunit": "*", + "friendsofphp/php-cs-fixer": "*", + "phpstan/extension-installer": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", - "phpstan/extension-installer": "*", + "phpunit/phpunit": "*", "rector/rector": "*", - "symplify/easy-coding-standard": "*", - "symplify/phpstan-rules": "*", + "roave/security-advisories": "dev-latest", "symfony/test-pack": "^1.1" }, "suggest": { diff --git a/ecs.php b/ecs.php index adf7d649..69fb8167 100644 --- a/ecs.php +++ b/ecs.php @@ -18,7 +18,7 @@ SetList::DOCTRINE_ANNOTATIONS, ]); - $ecsConfig->paths([__DIR__ . '/src']); + $ecsConfig->paths([__DIR__.'/src']); $ecsConfig->skip([AssignmentInConditionSniff::class]); }; diff --git a/rector.php b/rector.php index e19ab41a..bc0c62e5 100644 --- a/rector.php +++ b/rector.php @@ -13,8 +13,8 @@ $rectorConfig->importNames(); $rectorConfig->importShortClasses(); - $rectorConfig->paths([__DIR__ . '/src']); - $rectorConfig->skip([__DIR__ . '/src/Resources/tests']); + $rectorConfig->paths([__DIR__.'/src']); + $rectorConfig->skip([__DIR__.'/src/Resources/tests']); $rectorConfig->sets([ SetList::TYPE_DECLARATION, diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 66215744..4b1d95aa 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -23,7 +23,7 @@ class CleverAgeProcessBundle extends Bundle { /** - * Adding compiler passes to inject services into registry + * Adding compiler passes to inject services into registry. */ public function build(ContainerBuilder $container): void { diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 08e96aa6..895fa2b1 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Event\ConsoleProcessEvent; use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; -use InvalidArgumentException; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -26,13 +25,11 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; -use function count; -use function is_array; /** - * Run a process from the command line interface + * Run a process from the command line interface. */ -#[AsCommand(name: 'cleverage:process:execute', description: 'Execute a process',)] +#[AsCommand(name: 'cleverage:process:execute', description: 'Execute a process', )] class ExecuteProcessCommand extends Command { final public const OUTPUT_STDOUT = '-'; @@ -79,8 +76,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $inputData = $input->getOption('input'); if ($input->getOption('input-from-stdin')) { $inputData = ''; - while (! feof(STDIN)) { - $inputData .= fread(STDIN, 8192); + while (!feof(\STDIN)) { + $inputData .= fread(\STDIN, 8192); } } @@ -89,7 +86,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->eventDispatcher->dispatch(new ConsoleProcessEvent($input, $output, $inputData, $context)); foreach ($input->getArgument('processCodes') as $code) { - if (! $output->isQuiet()) { + if (!$output->isQuiet()) { $output->writeln("Starting process '{$code}'..."); } @@ -97,7 +94,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $returnValue = $this->processManager->execute($code, $inputData, $context); $this->handleOutputData($returnValue, $input, $output); - if (! $output->isQuiet()) { + if (!$output->isQuiet()) { $output->writeln("Process '{$code}' executed successfully"); } } @@ -117,9 +114,9 @@ protected function parseContextValues(InputInterface $input): array $context = []; foreach ($contextValues as $contextValue) { preg_match($pattern, (string) $contextValue, $parts); - if (count($parts) !== 3 + if (3 !== \count($parts) || $parts[0] !== $contextValue) { - throw new InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); + throw new \InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); } $context[$parts[1]] = $parser->parse($parts[2]); } @@ -130,29 +127,29 @@ protected function parseContextValues(InputInterface $input): array protected function handleOutputData(mixed $data, InputInterface $input, OutputInterface $output): void { // Skip all if undefined - if (! $input->getOption('output-format')) { + if (!$input->getOption('output-format')) { return; } // Handle printing the output - if ($input->getOption('output') === self::OUTPUT_STDOUT) { + if (self::OUTPUT_STDOUT === $input->getOption('output')) { if ($output->isVeryVerbose()) { - if (class_exists(VarDumper::class) && ($input->getOption( + if (class_exists(VarDumper::class) && (self::OUTPUT_FORMAT_DUMP === $input->getOption( 'output-format' - ) === self::OUTPUT_FORMAT_DUMP)) { + ))) { VarDumper::dump($data); - } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { - $output->writeln(json_encode($data, JSON_THROW_ON_ERROR)); + } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { + $output->writeln(json_encode($data, \JSON_THROW_ON_ERROR)); } else { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) ); } } - } elseif ($input->getOption('output-format') === self::OUTPUT_FORMAT_JSON) { + } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { // JsonStreamFile::writeLine only takes an array... // TODO how to handle other cases ? - if (is_array($data)) { + if (\is_array($data)) { $outputFile = new JsonStreamFile($input->getOption('output'), 'wb'); $outputFile->writeLine($data); } @@ -161,7 +158,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) ); } diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index cf022da4..f8be31c4 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -20,15 +20,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use function array_reduce; -use function count; -use function max; -use function usort; /** - * List all configured processes + * List all configured processes. */ -#[AsCommand(name: 'cleverage:process:list', description: 'List defined processes',)] +#[AsCommand(name: 'cleverage:process:list', description: 'List defined processes', )] class ListProcessCommand extends Command { public function __construct( @@ -54,7 +50,7 @@ public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b): public function maxMessageLengthFilter(int $max, array $message): int { - return max($max, strlen($this->filterOutTags($message['output']))); + return \max($max, \strlen($this->filterOutTags($message['output']))); } protected function configure(): void @@ -65,10 +61,10 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { $processConfigurations = $this->processConfigRegistry->getProcessConfigurations(); - usort($processConfigurations, $this->processSorter(...)); + \usort($processConfigurations, $this->processSorter(...)); - $publicCount = array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); - $privateCount = array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); + $publicCount = \array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); + $privateCount = \array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); $output->writeln( "There are {$publicCount} process configurations defined (and {$privateCount} private) :" ); @@ -76,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $messages = []; foreach ($processConfigurations as $processConfiguration) { if ($processConfiguration->isPublic() || $input->getOption('all')) { - $countTasks = count($processConfiguration->getTaskConfigurations()); + $countTasks = \count($processConfiguration->getTaskConfigurations()); $message = " - {$processConfiguration->getCode()} with {$countTasks} tasks"; if ($processConfiguration->isPrivate()) { @@ -91,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // Add process descriptions at a fixed position - $maxMessageLength = array_reduce($messages, $this->maxMessageLengthFilter(...), 0); + $maxMessageLength = \array_reduce($messages, $this->maxMessageLengthFilter(...), 0); $outputMessages = []; foreach ($messages as $message) { /** @var ProcessConfiguration $processConfiguration */ @@ -116,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int protected function padMessage(string $message, int $length = 80): string { - $currentLen = strlen($this->filterOutTags($message)); + $currentLen = \strlen($this->filterOutTags($message)); if ($currentLen < $length) { $message .= str_repeat(' ', $length - $currentLen); } diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 22176bad..25e3eb70 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -22,7 +22,6 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use CleverAge\ProcessBundle\Task\Process\ProcessExecutorTask; use CleverAge\ProcessBundle\Task\Process\ProcessLauncherTask; -use InvalidArgumentException; use Psr\Container\ContainerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -30,19 +29,12 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use UnexpectedValueException; - -use function array_slice; -use function count; -use function in_array; -use function is_callable; -use function is_string; /** * Describe a process configuration - * This is a POC, waiting to evolve properly + * This is a POC, waiting to evolve properly. */ -#[AsCommand(name: 'cleverage:process:help', description: 'Describe a process',)] +#[AsCommand(name: 'cleverage:process:help', description: 'Describe a process', )] class ProcessHelpCommand extends Command { protected const CHAR_DOWN = '│'; @@ -88,12 +80,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $process = $this->processConfigRegistry->getProcessConfiguration($processCode); $output->writeln('Process: '); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $processCode); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); $output->writeln(''); if ($process->getDescription()) { $output->writeln('Description:'); - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $process->getDescription()); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); $output->writeln(''); } @@ -101,7 +93,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Help:'); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { - $output->writeln(str_repeat(' ', self::INDENT_SIZE) . $helpLine); + $output->writeln(str_repeat(' ', self::INDENT_SIZE).$helpLine); } $output->writeln(''); } @@ -112,8 +104,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $taskList = $process->getMainTaskGroup(); $remainingTasks = $taskList; - $totalBranches = count($taskList); - for ($i = 0; $i < $totalBranches; $i++) { + $totalBranches = \count($taskList); + for ($i = 0; $i < $totalBranches; ++$i) { // Find the best task to display $nextTaskCode = $this->findBestNextTask($branches, $remainingTasks, $process); @@ -124,8 +116,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $branches = array_filter($branches); - if (! empty($branches)) { - $branchStr = '[' . implode(', ', $branches) . ']'; + if (!empty($branches)) { + $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } @@ -133,7 +125,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } /** - * Try to find a best candidate for next display + * Try to find a best candidate for next display. */ protected function findBestNextTask( array $branches, @@ -151,7 +143,7 @@ protected function findBestNextTask( // Check if task has all necessary ancestors in branches $hasAllAncestors = array_reduce( $task->getPreviousTasksConfigurations(), - static fn ($result, TaskConfiguration $prevTask): bool => $result && in_array( + static fn ($result, TaskConfiguration $prevTask): bool => $result && \in_array( $prevTask->getCode(), $branches, true @@ -165,7 +157,7 @@ protected function findBestNextTask( } if (empty($taskCandidates)) { - throw new UnexpectedValueException('Cannot find a task to output'); + throw new \UnexpectedValueException('Cannot find a task to output'); } // Try to find the task the most on the right @@ -177,14 +169,14 @@ protected function findBestNextTask( $key = array_search($prevTask->getCode(), $branches, true); // Should never be non-numeric... - if (! is_numeric($key)) { - throw new UnexpectedValueException('Invalid key type'); + if (!is_numeric($key)) { + throw new \UnexpectedValueException('Invalid key type'); } $weight += $key; } - if (! empty($task->getPreviousTasksConfigurations())) { - $weight /= count($task->getPreviousTasksConfigurations()); + if (!empty($task->getPreviousTasksConfigurations())) { + $weight /= \count($task->getPreviousTasksConfigurations()); } $taskWeights[$taskCandidate] = $weight; @@ -196,7 +188,7 @@ protected function findBestNextTask( $equalWeights = array_filter($taskWeights, static fn ($item): bool => $item === $bestWeight); - if (count($equalWeights) === 1) { + if (1 === \count($equalWeights)) { return $bestCandidate; } @@ -212,7 +204,7 @@ protected function findBestNextTask( } /** - * Get the number of children (error or not) of a task + * Get the number of children (error or not) of a task. */ protected function getTaskChildrenCount(TaskConfiguration $task): int { @@ -230,7 +222,7 @@ protected function getTaskChildrenCount(TaskConfiguration $task): int } /** - * Merge needed branches, display a task node, split following needed branches + * Merge needed branches, display a task node, split following needed branches. */ protected function resolveBranchOutput( array &$branches, @@ -253,7 +245,7 @@ protected function resolveBranchOutput( // Check previous branches if (empty($previousTasks)) { $branches[] = $task->getCode(); - } elseif (count($previousTasks) === 1) { + } elseif (1 === \count($previousTasks)) { $prevTask = current($previousTasks) ->getCode(); foreach (array_reverse($branches, true) as $i => $branchTask) { @@ -273,7 +265,7 @@ protected function resolveBranchOutput( } } - if (! $foundBranch) { + if (!$foundBranch) { $output->writeln( "Could not find previous branch : {$taskCode} depends on {$prevTask->getCode()}" ); @@ -286,7 +278,7 @@ protected function resolveBranchOutput( $gapFrom = null; foreach ($branchesToMerge as $i) { $gapTo = $i; - if ($gapFrom !== null) { + if (null !== $gapFrom) { for ($j = $gapFrom + 1; $j < $gapTo; ++$j) { $gapBranches[] = $j; } @@ -300,22 +292,22 @@ protected function resolveBranchOutput( } // Merge branches - if (! empty($branchesToMerge)) { + if (!empty($branchesToMerge)) { $this->writeBranches($output, $branches); $this->writeBranches( $output, $branches, '', - static fn ($taskCode, $i): bool => in_array($i, $branchesToMerge, true) - || in_array($i, $gapBranches, true) + static fn ($taskCode, $i): bool => \in_array($i, $branchesToMerge, true) + || \in_array($i, $gapBranches, true) || $i === $origin, static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): string { if ($i === $origin) { return self::CHAR_RECEIVE; } - if (in_array($i, $gapBranches, true)) { - if ($branches[$i] !== null) { + if (\in_array($i, $gapBranches, true)) { + if (null !== $branches[$i]) { return self::CHAR_JUMP; } @@ -331,7 +323,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): ); foreach ($branches as $i => $branchTask) { - if (in_array($i, $branchesToMerge, true)) { + if (\in_array($i, $branchesToMerge, true)) { $branches[$i] = null; } } @@ -340,8 +332,8 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { - if ($branchTask !== null) { - $branches = array_slice($branches, 0, $i + 1); + if (null !== $branchTask) { + $branches = \array_slice($branches, 0, $i + 1); break; } } @@ -364,7 +356,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): if ($output->isVerbose() && $task->getHelp()) { $helpLines = array_filter(explode("\n", $task->getHelp())); foreach ($helpLines as $helpLine) { - $helpMessage = str_repeat(' ', self::INDENT_SIZE) . "{$helpLine}"; + $helpMessage = str_repeat(' ', self::INDENT_SIZE)."{$helpLine}"; $this->writeBranches($output, $branches, $helpMessage); } } @@ -376,19 +368,19 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): array_merge($task->getNextTasksConfigurations(), $task->getErrorTasksConfigurations()) ) ); - if (count($nextTasks) > 1) { + if (\count($nextTasks) > 1) { $this->writeBranches($output, $branches); array_shift($nextTasks); $origin = array_search($taskCode, $branches, true); $expandBranches = []; foreach ($nextTasks as $nextTask) { $index = array_search(null, $branches, true); - if ($index !== false && $index >= $origin) { + if (false !== $index && $index >= $origin) { /** @var int $index */ $branches[$index] = $taskCode; $expandBranches[] = $index; } else { - $expandBranches[] = count($branches); + $expandBranches[] = \count($branches); $branches[] = $taskCode; } } @@ -415,8 +407,8 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) if ($i === $origin) { return self::CHAR_RECEIVE; } - if (in_array($i, $gapBranches, true)) { - if ($branches[$i] !== null) { + if (\in_array($i, $gapBranches, true)) { + if (null !== $branches[$i]) { return self::CHAR_JUMP; } @@ -441,8 +433,8 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) // Cleanup empty trailing branches foreach (array_reverse($branches, true) as $i => $branchTask) { - if ($branchTask !== null) { - $branches = array_slice($branches, 0, $i + 1); + if (null !== $branchTask) { + $branches = \array_slice($branches, 0, $i + 1); break; } } @@ -455,22 +447,22 @@ protected function writeBranches( array $branches, string|iterable $comment = '', ?callable $match = null, - string|callable $char = null + string|callable|null $char = null ): void { $output->write(str_repeat(' ', self::INDENT_SIZE)); // Merge lines foreach ($branches as $i => $branchTask) { $str = ''; - if ($match !== null && $match($branchTask, $i)) { - if (is_string($char)) { + if (null !== $match && $match($branchTask, $i)) { + if (\is_string($char)) { $str = $char; - } elseif (is_callable($char)) { + } elseif (\is_callable($char)) { $str = $char($branchTask, $i); } else { - throw new InvalidArgumentException('Char must be string|callable'); + throw new \InvalidArgumentException('Char must be string|callable'); } - } elseif ($branchTask !== null) { + } elseif (null !== $branchTask) { $str = self::CHAR_DOWN; } @@ -507,12 +499,12 @@ protected function getTaskDescription(TaskConfiguration $task): string $subprocess[] = $task->getOption('process'); } - if (count($interfaces)) { - $description .= ' (' . implode(', ', $interfaces) . ')'; + if (\count($interfaces)) { + $description .= ' ('.implode(', ', $interfaces).')'; } - if (count($subprocess)) { - $description .= ' {' . implode(', ', $subprocess) . '}'; + if (\count($subprocess)) { + $description .= ' {'.implode(', ', $subprocess).'}'; } if ($task->getDescription()) { @@ -533,12 +525,12 @@ protected function getTaskService(TaskConfiguration $taskConfiguration): TaskInt } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" ); } - if (! $task instanceof TaskInterface) { - throw new UnexpectedValueException( + if (!$task instanceof TaskInterface) { + throw new \UnexpectedValueException( "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" ); } diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 69555f02..8d0de248 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -16,11 +16,8 @@ use CleverAge\ProcessBundle\Exception\CircularProcessException; use CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException; -use function count; -use function in_array; - /** - * Holds the processes configuration to launch a task + * Holds the processes configuration to launch a task. */ class ProcessConfiguration { @@ -52,7 +49,7 @@ public function getOptions(): array public function getEntryPoint(): ?TaskConfiguration { - if ($this->entryPoint === null) { + if (null === $this->entryPoint) { return null; } @@ -61,7 +58,7 @@ public function getEntryPoint(): ?TaskConfiguration public function getEndPoint(): ?TaskConfiguration { - if ($this->endPoint === null) { + if (null === $this->endPoint) { return null; } @@ -85,7 +82,7 @@ public function isPublic(): bool public function isPrivate(): bool { - return ! $this->public; + return !$this->public; } /** @@ -98,7 +95,7 @@ public function getTaskConfigurations(): array public function getTaskConfiguration(string $taskCode): TaskConfiguration { - if (! array_key_exists($taskCode, $this->taskConfigurations)) { + if (!\array_key_exists($taskCode, $this->taskConfigurations)) { throw MissingTaskConfigurationException::create($taskCode); } @@ -106,24 +103,24 @@ public function getTaskConfiguration(string $taskCode): TaskConfiguration } /** - * Group all task by dependencies + * Group all task by dependencies. * * If one task depend from another, it should come after */ public function getDependencyGroups(): array { - if ($this->dependencyGroups === null) { + if (null === $this->dependencyGroups) { $this->dependencyGroups = []; foreach ($this->getTaskConfigurations() as $taskConfiguration) { $isInBranch = false; foreach ($this->dependencyGroups as $branch) { - if (in_array($taskConfiguration->getCode(), $branch, true)) { + if (\in_array($taskConfiguration->getCode(), $branch, true)) { $isInBranch = true; break; } } - if (! $isInBranch) { + if (!$isInBranch) { $dependencies = $this->buildDependencies($taskConfiguration); $dependencies = $this->sortDependencies($dependencies); @@ -137,18 +134,18 @@ public function getDependencyGroups(): array /** * Get the main task group that will be executed - * It may be defined by the entry_point, or the end_point or simply the first task + * It may be defined by the entry_point, or the end_point or simply the first task. * * If one task depend from another, it should come after */ public function getMainTaskGroup(): array { - if ($this->mainTaskGroup === null) { + if (null === $this->mainTaskGroup) { $this->mainTaskGroup = []; $mainTask = $this->getMainTask(); foreach ($this->getDependencyGroups() as $branch) { - if (in_array($mainTask?->getCode(), $branch, true)) { + if (\in_array($mainTask?->getCode(), $branch, true)) { $this->mainTaskGroup = $branch; break; } @@ -160,24 +157,24 @@ public function getMainTaskGroup(): array /** * Get the most important task (may be the entry or end task, or simply the first) - * Used to check which tree should be used + * Used to check which tree should be used. */ public function getMainTask(): ?TaskConfiguration { $entryTask = $this->getEntryPoint(); // If there's no entry point, we might use the end point - if (! $entryTask) { + if (!$entryTask) { $entryTask = $this->getEndPoint(); } // By default use the first defined task - if (! $entryTask) { + if (!$entryTask) { $entryTask = reset($this->taskConfigurations); } // May happen with an empty array - if ($entryTask === false) { + if (false === $entryTask) { return null; } @@ -185,7 +182,7 @@ public function getMainTask(): ?TaskConfiguration } /** - * Assert the process does not contain circular dependencies + * Assert the process does not contain circular dependencies. */ public function checkCircularDependencies(): void { @@ -204,14 +201,14 @@ public function checkCircularDependencies(): void } /** - * Cross all relations of a task to find all dependencies, and append them to the given array + * Cross all relations of a task to find all dependencies, and append them to the given array. */ protected function buildDependencies(TaskConfiguration $taskConfig, array &$dependencies = []): array { $code = $taskConfig->getCode(); // May have been added by previous task - if (! in_array($code, $dependencies, true)) { + if (!\in_array($code, $dependencies, true)) { $dependencies[] = $code; foreach ($taskConfig->getPreviousTasksConfigurations() as $previousTasksConfig) { @@ -231,11 +228,11 @@ protected function buildDependencies(TaskConfiguration $taskConfig, array &$depe } /** - * Sort the tasks by dependencies + * Sort the tasks by dependencies. */ protected function sortDependencies(array $dependencies): array { - if (count($dependencies) <= 1) { + if (\count($dependencies) <= 1) { return $dependencies; } @@ -247,7 +244,7 @@ protected function sortDependencies(array $dependencies): array } /** @var int $midOffset */ - $midOffset = round(count($dependencies) / 2); + $midOffset = round(\count($dependencies) / 2); $midTaskCode = $dependencies[$midOffset]; $midTask = $this->getTaskConfiguration($midTaskCode); diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index d6e22f40..ae3535b6 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -18,7 +18,7 @@ use Psr\Log\LogLevel; /** - * Represents a task configuration inside a process + * Represents a task configuration inside a process. */ class TaskConfiguration { @@ -60,7 +60,7 @@ public function __construct( protected string $errorStrategy = self::STRATEGY_SKIP, protected string $logLevel = LogLevel::CRITICAL ) { - $this->logErrors = $logLevel !== LogLevel::DEBUG; // @deprecated, remove me in next version + $this->logErrors = LogLevel::DEBUG !== $logLevel; // @deprecated, remove me in next version } public function getCode(): string @@ -100,7 +100,7 @@ public function getOptions(): array public function getOption(string $code, mixed $default = null): mixed { - if (array_key_exists($code, $this->options)) { + if (\array_key_exists($code, $this->options)) { return $this->options[$code]; } @@ -117,7 +117,7 @@ public function getOutputs(): array */ public function getErrors(): array { - @trigger_error('Deprecated method, use getErrorOutputs instead', E_USER_DEPRECATED); + @trigger_error('Deprecated method, use getErrorOutputs instead', \E_USER_DEPRECATED); return $this->getErrorOutputs(); } @@ -188,11 +188,11 @@ public function setInErrorBranch(bool $inErrorBranch): void public function isRoot(): bool { - return empty($this->getPreviousTasksConfigurations()) && ! $this->isInErrorBranch(); + return empty($this->getPreviousTasksConfigurations()) && !$this->isInErrorBranch(); } /** - * Check task ancestors to find if it have a given task as parent + * Check task ancestors to find if it have a given task as parent. */ public function hasAncestor(self $taskConfig): bool { @@ -215,7 +215,7 @@ public function hasAncestor(self $taskConfig): bool } /** - * Check task ancestors to find if it have a given task as child + * Check task ancestors to find if it have a given task as child. */ public function hasDescendant(self $taskConfig, bool $checkErrors = true): bool { diff --git a/src/Context/ContextualOptionResolver.php b/src/Context/ContextualOptionResolver.php index 2728ae3a..caf52aa5 100644 --- a/src/Context/ContextualOptionResolver.php +++ b/src/Context/ContextualOptionResolver.php @@ -13,23 +13,20 @@ namespace CleverAge\ProcessBundle\Context; -use function is_array; -use function is_string; - class ContextualOptionResolver { /** * Basic value inference - * Replaces "{{ key }}" by context[key] + * Replaces "{{ key }}" by context[key]. */ public function contextualizeOption(mixed $value, array $context): mixed { // Recursively parse options - if (is_array($value)) { + if (\is_array($value)) { return $this->contextualizeOptions($value, $context); } - if (is_string($value)) { + if (\is_string($value)) { $pattern = sprintf('/{{[ ]*(%s){1}[ ]*}}/', implode('|', array_keys($context))); $matches = []; @@ -48,7 +45,7 @@ public function contextualizeOption(mixed $value, array $context): mixed } /** - * Replace all contextualized values from options + * Replace all contextualized values from options. */ public function contextualizeOptions(array $options, array $context): array { diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index 480002b4..b3844903 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -15,14 +15,12 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use CleverAge\ProcessBundle\Transformer\GenericTransformer; -use ReflectionClass; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\Finder\Finder; -use function dirname; /** * This is the class that loads and manages your bundle configuration. @@ -34,8 +32,8 @@ class CleverAgeProcessExtension extends Extension public function load(array $configs, ContainerBuilder $container): void { // Get the path of the service folder wherever the bundle is installed - $reflection = new ReflectionClass($this); - $serviceFolderPath = dirname($reflection->getFileName(), 2) . '/Resources/config/services'; + $reflection = new \ReflectionClass($this); + $serviceFolderPath = \dirname($reflection->getFileName(), 2).'/Resources/config/services'; $this->findServices($container, $serviceFolderPath); $configuration = new Configuration(); @@ -53,18 +51,18 @@ public function load(array $configs, ContainerBuilder $container): void $transformerDefinition->addMethodCall('initialize', [$transformerCode, $transformerConfig]); $transformerDefinition->addTag('cleverage.transformer'); - $container->setDefinition(GenericTransformer::class . '\\' . $transformerCode, $transformerDefinition); + $container->setDefinition(GenericTransformer::class.'\\'.$transformerCode, $transformerDefinition); } } /** - * Recursively import config files into container + * Recursively import config files into container. */ protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void { $finder = new Finder(); $finder->in($path) - ->name('*.' . $extension)->files(); + ->name('*.'.$extension)->files(); $loader = new YamlFileLoader($container, new FileLocator($path)); foreach ($finder as $file) { $loader->load($file->getFilename()); diff --git a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 71d08c28..2c7d010f 100644 --- a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -19,7 +19,7 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** - * Check the presence of the serializer (required for this bundle), and help the user to set it + * Check the presence of the serializer (required for this bundle), and help the user to set it. */ class CheckSerializerCompilerPass implements CompilerPassInterface { @@ -27,7 +27,7 @@ class CheckSerializerCompilerPass implements CompilerPassInterface public function process(ContainerBuilder $container): void { - if (! $container->has('serializer') && ! $container->has(DenormalizerInterface::class)) { + if (!$container->has('serializer') && !$container->has(DenormalizerInterface::class)) { throw new AutowiringFailedException('serializer', self::MSG); } } diff --git a/src/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php index 2677e941..e414ee08 100644 --- a/src/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/src/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -18,7 +18,7 @@ use Symfony\Component\DependencyInjection\Reference; /** - * Generic compiler pass to add tagged services to a registry + * Generic compiler pass to add tagged services to a registry. */ class RegistryCompilerPass implements CompilerPassInterface { @@ -30,11 +30,11 @@ public function __construct( } /** - * Inject tagged services into defined registry + * Inject tagged services into defined registry. */ public function process(ContainerBuilder $container): void { - if (! $container->has($this->registry)) { + if (!$container->has($this->registry)) { return; } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index f18ea989..4d3b03a1 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -49,7 +49,7 @@ public function getConfigTreeBuilder(): TreeBuilder } /** - * "generic_transformers" root configuration + * "generic_transformers" root configuration. */ protected function appendRootTransformersConfigDefinition(NodeBuilder $definition): void { @@ -69,7 +69,7 @@ protected function appendRootTransformersConfigDefinition(NodeBuilder $definitio } /** - * Single transformer configuration + * Single transformer configuration. */ protected function appendTransformerConfigDefinition(NodeBuilder $definition): void { @@ -85,7 +85,7 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition): v } /** - * "configurations" root configuration + * "configurations" root configuration. */ protected function appendRootProcessConfigDefinition(NodeBuilder $definition): void { diff --git a/src/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php index c9c740d1..5acb2320 100644 --- a/src/Event/ConsoleProcessEvent.php +++ b/src/Event/ConsoleProcessEvent.php @@ -18,7 +18,7 @@ use Symfony\Contracts\EventDispatcher\Event; /** - * Event object used during CLI process manipulation + * Event object used during CLI process manipulation. */ class ConsoleProcessEvent extends Event { diff --git a/src/Event/ProcessEvent.php b/src/Event/ProcessEvent.php index c955a7c5..a3eb6b96 100644 --- a/src/Event/ProcessEvent.php +++ b/src/Event/ProcessEvent.php @@ -14,10 +14,9 @@ namespace CleverAge\ProcessBundle\Event; use Symfony\Contracts\EventDispatcher\Event; -use Throwable; /** - * Event object for process start/stop/fail + * Event object for process start/stop/fail. */ class ProcessEvent extends Event { @@ -32,7 +31,7 @@ public function __construct( protected mixed $processInput = null, protected array $processContext = [], protected mixed $processOutput = null, - protected ?Throwable $processError = null + protected ?\Throwable $processError = null ) { } @@ -56,7 +55,7 @@ public function getProcessContext(): array return $this->processContext; } - public function getProcessError(): ?Throwable + public function getProcessError(): ?\Throwable { return $this->processError; } diff --git a/src/EventListener/DataQueueEventListener.php b/src/EventListener/DataQueueEventListener.php index 59297b8b..84d8283e 100644 --- a/src/EventListener/DataQueueEventListener.php +++ b/src/EventListener/DataQueueEventListener.php @@ -14,17 +14,16 @@ namespace CleverAge\ProcessBundle\EventListener; use CleverAge\ProcessBundle\Event\EventDispatcherTaskEvent; -use SplQueue; /** * Class DataQueueEventListener * This is a basic queue, mainly aiming to catch data coming out of a process - * Used mostly for testing purpose + * Used mostly for testing purpose. */ class DataQueueEventListener { /** - * @var SplQueue[] + * @var \SplQueue[] */ protected array $queues = []; @@ -34,10 +33,10 @@ public function pushData(EventDispatcherTaskEvent $event): void $queue->push(clone $event->getState()); } - public function getQueue(string $processName): SplQueue + public function getQueue(string $processName): \SplQueue { - if (! array_key_exists($processName, $this->queues)) { - $this->queues[$processName] = new SplQueue(); + if (!\array_key_exists($processName, $this->queues)) { + $this->queues[$processName] = new \SplQueue(); } return $this->queues[$processName]; diff --git a/src/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php index eb851599..9f2e5453 100644 --- a/src/Exception/CircularProcessException.php +++ b/src/Exception/CircularProcessException.php @@ -13,12 +13,10 @@ namespace CleverAge\ProcessBundle\Exception; -use UnexpectedValueException; - /** - * Thrown when a circular dependency is found in a process + * Thrown when a circular dependency is found in a process. */ -class CircularProcessException extends UnexpectedValueException implements ProcessExceptionInterface +class CircularProcessException extends \UnexpectedValueException implements ProcessExceptionInterface { public static function create(?string $processCode = '', ?string $taskCode = ''): self { diff --git a/src/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php index bab90070..4dedd34a 100644 --- a/src/Exception/InvalidProcessConfigurationException.php +++ b/src/Exception/InvalidProcessConfigurationException.php @@ -15,19 +15,18 @@ use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; -use UnexpectedValueException; /** - * Thrown when the process configuration cannot be resolved + * Thrown when the process configuration cannot be resolved. */ -class InvalidProcessConfigurationException extends UnexpectedValueException implements ProcessExceptionInterface +class InvalidProcessConfigurationException extends \UnexpectedValueException implements ProcessExceptionInterface { public static function createNotInMain( ProcessConfiguration $processConfiguration, TaskConfiguration $taskConfig, array $mainTaskList ): self { - $taskListStr = '[' . implode(', ', $mainTaskList) . ']'; + $taskListStr = '['.implode(', ', $mainTaskList).']'; return new self( "Task '{$taskConfig->getCode()}' is not in main task list : {$taskListStr} (from process: {$processConfiguration->getCode()})" diff --git a/src/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php index 3d376124..ee11dbb4 100644 --- a/src/Exception/MissingProcessException.php +++ b/src/Exception/MissingProcessException.php @@ -13,12 +13,10 @@ namespace CleverAge\ProcessBundle\Exception; -use UnexpectedValueException; - /** - * Exception thrown when trying to fetch a missing process + * Exception thrown when trying to fetch a missing process. */ -class MissingProcessException extends UnexpectedValueException implements ProcessExceptionInterface +class MissingProcessException extends \UnexpectedValueException implements ProcessExceptionInterface { public static function create(?string $code = ''): self { diff --git a/src/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php index e3b959f7..679666b9 100644 --- a/src/Exception/MissingTaskConfigurationException.php +++ b/src/Exception/MissingTaskConfigurationException.php @@ -13,12 +13,10 @@ namespace CleverAge\ProcessBundle\Exception; -use UnexpectedValueException; - /** - * Exception thrown when trying to fetch a missing task configuration + * Exception thrown when trying to fetch a missing task configuration. */ -class MissingTaskConfigurationException extends UnexpectedValueException implements ProcessExceptionInterface +class MissingTaskConfigurationException extends \UnexpectedValueException implements ProcessExceptionInterface { public static function create(?string $code = ''): self { diff --git a/src/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php index 78c8f9f5..381e36f1 100644 --- a/src/Exception/MissingTransformerException.php +++ b/src/Exception/MissingTransformerException.php @@ -13,12 +13,10 @@ namespace CleverAge\ProcessBundle\Exception; -use UnexpectedValueException; - /** - * Exception thrown when trying to fetch a missing transformer + * Exception thrown when trying to fetch a missing transformer. */ -class MissingTransformerException extends UnexpectedValueException implements ProcessExceptionInterface +class MissingTransformerException extends \UnexpectedValueException implements ProcessExceptionInterface { public static function create(?string $code = ''): self { diff --git a/src/Exception/ProcessExceptionInterface.php b/src/Exception/ProcessExceptionInterface.php index ee370b43..8d73f959 100644 --- a/src/Exception/ProcessExceptionInterface.php +++ b/src/Exception/ProcessExceptionInterface.php @@ -13,11 +13,9 @@ namespace CleverAge\ProcessBundle\Exception; -use Throwable; - /** - * Common interface for process exception + * Common interface for process exception. */ -interface ProcessExceptionInterface extends Throwable +interface ProcessExceptionInterface extends \Throwable { } diff --git a/src/Exception/TransformerException.php b/src/Exception/TransformerException.php index 6334ca0f..0a768b7f 100644 --- a/src/Exception/TransformerException.php +++ b/src/Exception/TransformerException.php @@ -13,20 +13,17 @@ namespace CleverAge\ProcessBundle\Exception; -use RuntimeException; -use Throwable; - /** - * Runtime error that should wrap any Transformation error + * Runtime error that should wrap any Transformation error. */ -class TransformerException extends RuntimeException implements ProcessExceptionInterface +class TransformerException extends \RuntimeException implements ProcessExceptionInterface { protected string $targetProperty; public function __construct( protected string $transformerCode, int $code = 0, - Throwable $previous = null + ?\Throwable $previous = null ) { parent::__construct('', $code, $previous); $this->updateMessage(); diff --git a/src/ExpressionLanguage/PhpFunctionProvider.php b/src/ExpressionLanguage/PhpFunctionProvider.php index 13d01be3..0fb1e48f 100644 --- a/src/ExpressionLanguage/PhpFunctionProvider.php +++ b/src/ExpressionLanguage/PhpFunctionProvider.php @@ -17,7 +17,7 @@ use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; /** - * Allow to inject a set of PHP function into an ExpressionLanguage instance + * Allow to inject a set of PHP function into an ExpressionLanguage instance. */ class PhpFunctionProvider implements ExpressionFunctionProviderInterface { diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 2c5b3260..d35c03d4 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -13,22 +13,16 @@ namespace CleverAge\ProcessBundle\Filesystem; -use RuntimeException; -use UnexpectedValueException; - -use function dirname; -use function in_array; - /** * Read and write CSV files through a simple API. */ class CsvFile extends CsvResource { /** - * @param string $filePath Also accept a resource - * @param string $delimiter CSV delimiter - * @param ?array $headers Leave null to read the headers from the file - * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) + * @param string $filePath Also accept a resource + * @param string $delimiter CSV delimiter + * @param ?array $headers Leave null to read the headers from the file + * @param string $mode Same parameter as the mode in the fopen function (r, w, a, etc.) */ public function __construct( protected $filePath, @@ -38,22 +32,22 @@ public function __construct( ?array $headers = null, string $mode = 'rb' ) { - if (! in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { - $dirname = dirname($this->filePath); - if (! @mkdir($dirname, 0755, true) && ! is_dir($dirname)) { - throw new RuntimeException(sprintf('Directory "%s" was not created', $dirname)); + if (!\in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { + $dirname = \dirname($this->filePath); + if (!@mkdir($dirname, 0755, true) && !is_dir($dirname)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $dirname)); } } $resource = fopen($filePath, $mode); - if ($resource === false) { - throw new UnexpectedValueException("Unable to open file: '{$filePath}' in {$mode} mode"); + if (false === $resource) { + throw new \UnexpectedValueException("Unable to open file: '{$filePath}' in {$mode} mode"); } // All modes allowing file reading, binary safe modes are handled by stripping out the b during test $readAllowedModes = ['r', 'r+', 'w+', 'a+', 'x+', 'c+']; - if ($headers === null && ! in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { + if (null === $headers && !\in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { // Cannot read headers if the file was just created - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } @@ -62,7 +56,7 @@ public function __construct( } /** - * Will return a resource if the file was created using a resource + * Will return a resource if the file was created using a resource. */ public function getFilePath(): string { diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 4a021cad..894826e5 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -13,14 +13,7 @@ namespace CleverAge\ProcessBundle\Filesystem; -use LogicException; -use RuntimeException; -use UnexpectedValueException; -use ValueError; use function count; -use function gettype; -use function is_array; -use function is_resource; /** * Read and write CSV resources through a simple API. @@ -51,16 +44,16 @@ public function __construct( protected string $delimiter = ',', protected string $enclosure = '"', protected string $escape = '\\', - array $headers = null + ?array $headers = null ) { - if (! is_resource($resource)) { - $type = gettype($resource); - throw new UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); + if (!\is_resource($resource)) { + $type = \gettype($resource); + throw new \UnexpectedValueException("Resource argument must be a resource, '{$type}' given"); } $this->handler = $resource; $this->headers = $this->parseHeaders($headers); - $this->headerCount = count($this->headers); + $this->headerCount = \count($this->headers); } /** @@ -103,10 +96,10 @@ public function getHandler() */ public function getLineCount(): int { - if ($this->lineCount === null) { + if (null === $this->lineCount) { $this->rewind(); $line = 0; - while (! $this->isEndOfFile()) { + while (!$this->isEndOfFile()) { if ($this->readRaw()) { ++$line; } @@ -130,7 +123,7 @@ public function getHeaderCount(): int } /** - * Write headers to the file + * Write headers to the file. */ public function writeHeaders(): void { @@ -140,7 +133,7 @@ public function writeHeaders(): void public function getLineNumber(): int { if ($this->seekCalled) { - throw new LogicException('Cannot get current line number after calling "seek": the line number is lost'); + throw new \LogicException('Cannot get current line number after calling "seek": the line number is lost'); } return $this->lineNumber; @@ -164,7 +157,7 @@ public function readRaw(?int $length = null): array|false return fgetcsv($this->handler, $length, $this->delimiter, $this->enclosure, $this->escape); } - public function readLine(int $length = null): ?array + public function readLine(?int $length = null): ?array { if ($this->seekCalled) { $filePosition = "at position {$this->tell()}"; @@ -173,25 +166,25 @@ public function readLine(int $length = null): ?array } $values = $this->readRaw($length); - if ($values === false) { + if (false === $values) { if ($this->isEndOfFile()) { return null; } $message = "Unable to parse data {$filePosition} for {$this->getResourceName()}"; - throw new UnexpectedValueException($message); + throw new \UnexpectedValueException($message); } - $count = count($values); + $count = \count($values); if ($count !== $this->headerCount) { $message = "Number of columns not matching {$filePosition} for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; - throw new UnexpectedValueException($message); + throw new \UnexpectedValueException($message); } try { $combined = array_combine($this->headers, $values); - } catch (ValueError) { - throw new RuntimeException('Cannot combine headers with values'); + } catch (\ValueError) { + throw new \RuntimeException('Cannot combine headers with values'); } return $combined; @@ -210,25 +203,25 @@ public function writeRaw(array $fields): int|false public function writeLine(array $fields): int { - $count = count($fields); + $count = \count($fields); if ($count !== $this->headerCount) { $message = "Trying to write an invalid number of columns for {$this->getResourceName()}: "; $message .= "{$count} columns for {$this->headerCount} headers"; - throw new UnexpectedValueException($message); + throw new \UnexpectedValueException($message); } $parsedFields = []; foreach ($this->headers as $column) { - if (! array_key_exists($column, $fields)) { + if (!\array_key_exists($column, $fields)) { $message = "Missing column {$column} in given fields for {$this->getResourceName()}"; - throw new UnexpectedValueException($message); + throw new \UnexpectedValueException($message); } $parsedFields[$column] = $fields[$column]; } $length = $this->writeRaw($parsedFields); - if ($length === false) { - throw new RuntimeException("Unable to write data to {$this->getResourceName()}"); + if (false === $length) { + throw new \RuntimeException("Unable to write data to {$this->getResourceName()}"); } return $length; @@ -240,11 +233,11 @@ public function writeLine(array $fields): int public function rewind(): void { $this->assertOpened(); - if (! rewind($this->handler)) { - throw new RuntimeException("Unable to rewind '{$this->getResourceName()}'"); + if (!rewind($this->handler)) { + throw new \RuntimeException("Unable to rewind '{$this->getResourceName()}'"); } $this->lineNumber = 1; - if (! $this->manualHeaders) { + if (!$this->manualHeaders) { $this->readRaw(); // skip headers if not manual headers } } @@ -293,17 +286,17 @@ public function getFilePath(): string protected function assertOpened(): void { if ($this->closed) { - throw new RuntimeException("{$this->getResourceName()} was closed earlier"); + throw new \RuntimeException("{$this->getResourceName()} was closed earlier"); } } - protected function parseHeaders(array $headers = null): array + protected function parseHeaders(?array $headers = null): array { // If headers are not passed in the constructor but file is readable, try to read headers from file - if ($headers === null) { + if (null === $headers) { $autoHeaders = $this->readRaw(); - if ($autoHeaders === false || count($autoHeaders) === 0) { - throw new UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); + if (false === $autoHeaders || 0 === \count($autoHeaders)) { + throw new \UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any $bom = pack('H*', 'EFBBBF'); @@ -314,14 +307,14 @@ protected function parseHeaders(array $headers = null): array $this->manualHeaders = true; - if (! is_array($headers)) { - throw new UnexpectedValueException( + if (!\is_array($headers)) { + throw new \UnexpectedValueException( "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" ); } - if (count($headers) === 0) { - throw new UnexpectedValueException( + if (0 === \count($headers)) { + throw new \UnexpectedValueException( "Empty headers for {$this->getResourceName()}, you need to pass the headers manually" ); } diff --git a/src/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php index ec7ae244..bc6f9997 100644 --- a/src/Filesystem/FileStreamInterface.php +++ b/src/Filesystem/FileStreamInterface.php @@ -14,14 +14,14 @@ namespace CleverAge\ProcessBundle\Filesystem; /** - * Define a common interface for all file reading systems + * Define a common interface for all file reading systems. */ interface FileStreamInterface { public function getLineCount(): int; /** - * Warning! This returns the line number of the pointer inside the file so you need to call it BEFORE reading a line + * Warning! This returns the line number of the pointer inside the file so you need to call it BEFORE reading a line. */ public function getLineNumber(): int; diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index 1e90eb41..2051d63c 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -13,14 +13,12 @@ namespace CleverAge\ProcessBundle\Filesystem; -use SplFileObject; - /** - * Wrapper around JSON files to read them in a stream + * Wrapper around JSON files to read them in a stream. */ class JsonStreamFile implements FileStreamInterface, WritableFileInterface { - protected SplFileObject $file; + protected \SplFileObject $file; protected ?int $lineCount = null; @@ -28,10 +26,10 @@ class JsonStreamFile implements FileStreamInterface, WritableFileInterface public function __construct(string $filename, string $mode = 'rb') { - $this->file = new SplFileObject($filename, $mode); + $this->file = new \SplFileObject($filename, $mode); // Useful to skip empty trailing lines - $this->file->setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); + $this->file->setFlags(\SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); } /** @@ -39,10 +37,10 @@ public function __construct(string $filename, string $mode = 'rb') */ public function getLineCount(): int { - if ($this->lineCount === null) { + if (null === $this->lineCount) { $this->rewind(); $line = 0; - while (! $this->isEndOfFile()) { + while (!$this->isEndOfFile()) { ++$line; $this->file->next(); } @@ -65,30 +63,30 @@ public function isEndOfFile(): bool } /** - * Return an array containing current data and moving the file pointer + * Return an array containing current data and moving the file pointer. */ - public function readLine(int $length = null): ?array + public function readLine(?int $length = null): ?array { if ($this->isEndOfFile()) { return null; } $rawLine = $this->file->fgets(); - $this->lineNumber++; + ++$this->lineNumber; - return json_decode($rawLine, true, 512, JSON_THROW_ON_ERROR); + return json_decode($rawLine, true, 512, \JSON_THROW_ON_ERROR); } public function writeLine(array $fields): int { - $this->file->fwrite(json_encode($fields, JSON_THROW_ON_ERROR) . PHP_EOL); - $this->lineNumber++; + $this->file->fwrite(json_encode($fields, \JSON_THROW_ON_ERROR).\PHP_EOL); + ++$this->lineNumber; return $this->lineNumber; } /** - * Rewind data to array + * Rewind data to array. */ public function rewind(): void { diff --git a/src/Filesystem/SeekableFileInterface.php b/src/Filesystem/SeekableFileInterface.php index 798f6353..bb9d0ae3 100644 --- a/src/Filesystem/SeekableFileInterface.php +++ b/src/Filesystem/SeekableFileInterface.php @@ -14,17 +14,17 @@ namespace CleverAge\ProcessBundle\Filesystem; /** - * Define a common interface for seekable files + * Define a common interface for seekable files. */ interface SeekableFileInterface extends FileStreamInterface { /** - * Returns the current position of the cursor inside the file + * Returns the current position of the cursor inside the file. */ public function tell(): int; /** - * Go to a specific position inside the file + * Go to a specific position inside the file. */ public function seek(int $offset): int; } diff --git a/src/Filesystem/StructuredFileInterface.php b/src/Filesystem/StructuredFileInterface.php index 027c4a1e..827b8607 100644 --- a/src/Filesystem/StructuredFileInterface.php +++ b/src/Filesystem/StructuredFileInterface.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Filesystem; /** - * Define a common interface for all file with headers + * Define a common interface for all file with headers. */ interface StructuredFileInterface extends FileStreamInterface { diff --git a/src/Filesystem/WritableFileInterface.php b/src/Filesystem/WritableFileInterface.php index 6c4f9cdd..91f6e794 100644 --- a/src/Filesystem/WritableFileInterface.php +++ b/src/Filesystem/WritableFileInterface.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Filesystem; /** - * Define a common interface for all file reading systems + * Define a common interface for all file reading systems. */ interface WritableFileInterface extends FileStreamInterface { diff --git a/src/Filesystem/WritableStructuredFileInterface.php b/src/Filesystem/WritableStructuredFileInterface.php index c5098fc7..5ba4f51a 100644 --- a/src/Filesystem/WritableStructuredFileInterface.php +++ b/src/Filesystem/WritableStructuredFileInterface.php @@ -14,12 +14,12 @@ namespace CleverAge\ProcessBundle\Filesystem; /** - * Define a common interface for all file with headers + * Define a common interface for all file with headers. */ interface WritableStructuredFileInterface extends StructuredFileInterface, WritableFileInterface { /** - * Write headers to the file + * Write headers to the file. */ public function writeHeaders(): void; } diff --git a/src/Filesystem/XmlFile.php b/src/Filesystem/XmlFile.php index 05a8ffb0..8218f181 100644 --- a/src/Filesystem/XmlFile.php +++ b/src/Filesystem/XmlFile.php @@ -13,25 +13,21 @@ namespace CleverAge\ProcessBundle\Filesystem; -use DOMDocument; -use RuntimeException; -use SplFileObject; - /** - * Read and write XML files + * Read and write XML files. */ class XmlFile { - protected SplFileObject $file; + protected \SplFileObject $file; public function __construct(string $path, string $mode = 'rb') { - $this->file = new SplFileObject($path, $mode); + $this->file = new \SplFileObject($path, $mode); } - public function read(): DOMDocument + public function read(): \DOMDocument { - $dom = new DOMDocument(); + $dom = new \DOMDocument(); $this->file->rewind(); $fileSize = $this->file->getSize(); $fileContent = $this->file->fread($fileSize); @@ -41,13 +37,13 @@ public function read(): DOMDocument return $dom; } - public function write(DOMDocument $dom): void + public function write(\DOMDocument $dom): void { $content = $dom->saveXML(); $result = $this->file->fwrite($content); - if ($result === false) { - throw new RuntimeException('Could not write content to file'); + if (false === $result) { + throw new \RuntimeException('Could not write content to file'); } } } diff --git a/src/Logger/AbstractLogger.php b/src/Logger/AbstractLogger.php index f607a489..f349b5b3 100644 --- a/src/Logger/AbstractLogger.php +++ b/src/Logger/AbstractLogger.php @@ -17,7 +17,7 @@ use Psr\Log\LoggerInterface; /** - * Base logic for logger tasks, see inherited services for more information + * Base logic for logger tasks, see inherited services for more information. * * Used for simplified autowiring */ diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index eb3d206b..79228295 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -25,7 +25,7 @@ public function __construct( public function __invoke(LogRecord $record): LogRecord { - if (! empty($record->context)) { + if (!empty($record->context)) { $context = $this->normalizeRecordData($record->context); $record = new LogRecord( $record->datetime, @@ -58,7 +58,7 @@ protected function normalizeRecordData(array $record): array protected function addProcessInfoToRecord(array &$record): void { $processHistory = $this->processManager->getProcessHistory(); - if (! $processHistory) { + if (!$processHistory) { return; } @@ -70,7 +70,7 @@ protected function addProcessInfoToRecord(array &$record): void protected function addTaskInfoToRecord(array &$record): void { $taskConfiguration = $this->processManager->getTaskConfiguration(); - if (! $taskConfiguration) { + if (!$taskConfiguration) { return; } $this->addToRecord($record, 'task_code', $taskConfiguration->getCode()); diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 3f5e2594..d495e99a 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -30,17 +30,11 @@ use CleverAge\ProcessBundle\Model\TaskInterface; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Psr\EventDispatcher\EventDispatcherInterface; -use RuntimeException; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\ErrorHandler\Error\FatalError; -use Throwable; -use UnexpectedValueException; - -use function count; -use function in_array; /** - * Execute processes + * Execute processes. */ class ProcessManager { @@ -85,9 +79,10 @@ public function getTaskConfiguration(): ?TaskConfiguration } /** - * Execute a process with a given input and context + * Execute a process with a given input and context. * * This method decorates the real execution to add event & error handling + * * @see ProcessManager::doExecute */ public function execute(string $processCode, mixed $input = null, array $context = []): mixed @@ -106,7 +101,7 @@ public function execute(string $processCode, mixed $input = null, array $context new ProcessEvent($processCode, $input, $context, $result), ProcessEvent::EVENT_PROCESS_ENDED ); - } catch (Throwable $error) { + } catch (\Throwable $error) { $this->processLogger->critical('Critical process failure', [ 'error' => $error->getMessage(), ]); @@ -122,7 +117,7 @@ public function execute(string $processCode, mixed $input = null, array $context } /** - * Real process execution, with a given input and context + * Real process execution, with a given input and context. */ protected function doExecute(string $processCode, mixed $input = null, array $context = []): mixed { @@ -142,7 +137,7 @@ protected function doExecute(string $processCode, mixed $input = null, array $co $processConfiguration->getEntryPoint() ->getState() ->setInput($input); - } elseif ($input !== null) { + } elseif (null !== $input) { $this->processLogger->warning('Process has no entry point for input'); } @@ -150,7 +145,7 @@ protected function doExecute(string $processCode, mixed $input = null, array $co $taskList = array_reverse($processConfiguration->getTaskConfigurations()); $allowedTasks = $processConfiguration->getMainTaskGroup(); foreach ($taskList as $taskConfiguration) { - if (in_array($taskConfiguration->getCode(), $allowedTasks, true)) { + if (\in_array($taskConfiguration->getCode(), $allowedTasks, true)) { $this->resolve($taskConfiguration); } } @@ -176,7 +171,7 @@ protected function doExecute(string $processCode, mixed $input = null, array $co } /** - * Resolve a task, by checking if parents are resolved and processing roots and BlockingTasks + * Resolve a task, by checking if parents are resolved and processing roots and BlockingTasks. */ protected function resolve(TaskConfiguration $taskConfiguration): bool { @@ -190,14 +185,14 @@ protected function resolve(TaskConfiguration $taskConfiguration): bool // Resolve parents first $allParentsResolved = true; foreach ($taskConfiguration->getPreviousTasksConfigurations() as $previousTasksConfiguration) { - if (! $previousTasksConfiguration->getState()->isResolved()) { + if (!$previousTasksConfiguration->getState()->isResolved()) { $isResolved = $this->resolve($previousTasksConfiguration); $allParentsResolved = $allParentsResolved && $isResolved; } } - if (! $allParentsResolved) { - throw new UnexpectedValueException('Cannot resolve all parents'); + if (!$allParentsResolved) { + throw new \UnexpectedValueException('Cannot resolve all parents'); } $state->setStatus(ProcessState::STATUS_PROCESSING); @@ -223,14 +218,14 @@ protected function resolve(TaskConfiguration $taskConfiguration): bool } /** - * Fetch task service and run additional setup for InitializableTasks + * Fetch task service and run additional setup for InitializableTasks. */ protected function initialize(TaskConfiguration $taskConfiguration): void { $this->taskConfiguration = $taskConfiguration; - if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP - && (count($taskConfiguration->getErrorOutputs())) > 0) { + if (TaskConfiguration::STRATEGY_STOP === $taskConfiguration->getErrorStrategy() + && \count($taskConfiguration->getErrorOutputs()) > 0) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); @@ -243,12 +238,12 @@ protected function initialize(TaskConfiguration $taskConfiguration): void } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" ); } - if (! $task instanceof TaskInterface) { - throw new UnexpectedValueException( + if (!$task instanceof TaskInterface) { + throw new \UnexpectedValueException( "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" ); } @@ -258,7 +253,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $state = $taskConfiguration->getState(); try { $task->initialize($state); - } catch (Throwable $e) { + } catch (\Throwable $e) { $logContext = [ 'exception' => $e, ]; @@ -322,8 +317,8 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF // Run child items only if the state is not "skipped" and task is not blocking $task = $taskConfiguration->getTask(); $shouldContinue = - (! $task instanceof BlockingTaskInterface || $executionFlag === self::EXECUTE_PROCEED) - && ! $state->isSkipped(); + (!$task instanceof BlockingTaskInterface || self::EXECUTE_PROCEED === $executionFlag) + && !$state->isSkipped(); if ($shouldContinue) { if ($task instanceof IterableTaskInterface) { @@ -348,13 +343,13 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF if ($task instanceof IterableTaskInterface) { // Check if task has more items $hasMoreItem = $task->next($state); - if (! $hasMoreItem) { - if (! $this->hasProcessedIterable($taskConfiguration)) { + if (!$hasMoreItem) { + if (!$this->hasProcessedIterable($taskConfiguration)) { return; // This means the task is empty } // This means we are over iterating this task so we can remove it from registry $this->removeProcessedIterable($taskConfiguration); - if ($executionFlag !== self::EXECUTE_FLUSH) { + if (self::EXECUTE_FLUSH !== $executionFlag) { // This task is now finished, we may flush it to test if there is anything lasting $this->flush($taskConfiguration); } @@ -371,42 +366,42 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF protected function processExecution(TaskConfiguration $taskConfiguration, int $executionFlag): void { $task = $taskConfiguration->getTask(); - if ($task === null) { - throw new RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); + if (null === $task) { + throw new \RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); } $state = $taskConfiguration->getState(); try { - if ($executionFlag === self::EXECUTE_PROCESS) { + if (self::EXECUTE_PROCESS === $executionFlag) { $state->reset(false); $this->processLogger->debug("Processing task {$taskConfiguration->getCode()}"); $task->execute($state); if ($task instanceof BlockingTaskInterface) { $this->addProcessedBlocking($taskConfiguration); } - } elseif ($executionFlag === self::EXECUTE_PROCEED) { + } elseif (self::EXECUTE_PROCEED === $executionFlag) { $state->reset(true); - if (! $task instanceof BlockingTaskInterface) { + if (!$task instanceof BlockingTaskInterface) { // This exception should never be thrown - throw new UnexpectedValueException("Task {$taskConfiguration->getCode()} is not blocking"); + throw new \UnexpectedValueException("Task {$taskConfiguration->getCode()} is not blocking"); } $this->processLogger->debug("Proceeding task {$taskConfiguration->getCode()}"); $task->proceed($state); $this->removeProcessedBlocking($taskConfiguration); - } elseif ($executionFlag === self::EXECUTE_FLUSH) { + } elseif (self::EXECUTE_FLUSH === $executionFlag) { $state->reset(true); - if (! $task instanceof FlushableTaskInterface) { + if (!$task instanceof FlushableTaskInterface) { // This exception should never be thrown - throw new UnexpectedValueException("Task {$taskConfiguration->getCode()} is not flushable"); + throw new \UnexpectedValueException("Task {$taskConfiguration->getCode()} is not flushable"); } $this->processLogger->debug("Flushing task {$taskConfiguration->getCode()}"); $task->flush($state); } else { - throw new UnexpectedValueException("Unknown execution flag: {$executionFlag}"); + throw new \UnexpectedValueException("Unknown execution flag: {$executionFlag}"); } $exception = $state->getException(); - } catch (Throwable $e) { + } catch (\Throwable $e) { $exception = $e; } @@ -418,15 +413,15 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e $state->getErrorContext() ); $state->setException($exception); - if (! $state->hasErrorOutput()) { + if (!$state->hasErrorOutput()) { $state->setErrorOutput($state->getInput()); } - if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { + if (TaskConfiguration::STRATEGY_SKIP === $taskConfiguration->getErrorStrategy()) { $state->setSkipped(true); - } elseif ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { + } elseif (TaskConfiguration::STRATEGY_STOP === $taskConfiguration->getErrorStrategy()) { $state->stop($exception); } else { - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "Unknown error strategy '{$taskConfiguration->getErrorStrategy()}'" ); } @@ -434,7 +429,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e } /** - * Browse all children for FlushableTask until a BlockingTask is found + * Browse all children for FlushableTask until a BlockingTask is found. */ protected function flush(TaskConfiguration $taskConfiguration): void { @@ -466,7 +461,7 @@ protected function finalize(TaskConfiguration $taskConfiguration): void $state = $taskConfiguration->getState(); try { $task->finalize($taskConfiguration->getState()); - } catch (Throwable $e) { + } catch (\Throwable $e) { $logContext = [ 'exception' => $e, ]; @@ -515,7 +510,7 @@ protected function prepareNextProcess( } /** - * Save the state of the import process + * Save the state of the import process. */ protected function handleState(ProcessState $state): void { @@ -541,7 +536,7 @@ protected function endProcess(ProcessHistory $history): void } /** - * Validate a process + * Validate a process. */ protected function checkProcess(ProcessConfiguration $processConfiguration): void { @@ -554,7 +549,7 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check multi-branch processes foreach ($taskConfigurations as $taskConfiguration) { - if (! in_array($taskConfiguration->getCode(), $mainTaskList, true)) { + if (!\in_array($taskConfiguration->getCode(), $mainTaskList, true)) { // We won't throw an error to ease development... but there must be some kind of warning $state = $taskConfiguration->getState(); $logContext = [ @@ -570,14 +565,14 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check coherence for entry/end points $processConfiguration->getEndPoint(); - if ($entryPoint && ! in_array($entryPoint->getCode(), $mainTaskList, true)) { + if ($entryPoint && !\in_array($entryPoint->getCode(), $mainTaskList, true)) { throw InvalidProcessConfigurationException::createNotInMain( $processConfiguration, $entryPoint, $mainTaskList ); } - if ($endPoint && ! in_array($endPoint->getCode(), $mainTaskList, true)) { + if ($endPoint && !\in_array($endPoint->getCode(), $mainTaskList, true)) { throw InvalidProcessConfigurationException::createNotInMain( $processConfiguration, $endPoint, @@ -587,7 +582,7 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi } /** - * When an iterable task returns at least one element, it gets added here + * When an iterable task returns at least one element, it gets added here. */ protected function addProcessedIterable(TaskConfiguration $taskConfiguration): void { @@ -595,15 +590,15 @@ protected function addProcessedIterable(TaskConfiguration $taskConfiguration): v } /** - * If true this means that the tasks returned an element at least once + * If true this means that the tasks returned an element at least once. */ protected function hasProcessedIterable(TaskConfiguration $taskConfiguration): bool { - return array_key_exists($taskConfiguration->getCode(), $this->processedIterables); + return \array_key_exists($taskConfiguration->getCode(), $this->processedIterables); } /** - * Once everything was flushed, the task is resolved and can be removed from the stack + * Once everything was flushed, the task is resolved and can be removed from the stack. */ protected function removeProcessedIterable(TaskConfiguration $taskConfiguration): void { @@ -611,7 +606,7 @@ protected function removeProcessedIterable(TaskConfiguration $taskConfiguration) } /** - * Add blocking tasks that were just processed + * Add blocking tasks that were just processed. */ protected function addProcessedBlocking(TaskConfiguration $taskConfiguration): void { @@ -619,15 +614,15 @@ protected function addProcessedBlocking(TaskConfiguration $taskConfiguration): v } /** - * If true this means the task was processed normally but was never run with proceed + * If true this means the task was processed normally but was never run with proceed. */ protected function hasProcessedBlocking(TaskConfiguration $taskConfiguration): bool { - return array_key_exists($taskConfiguration->getCode(), $this->processedBlockings); + return \array_key_exists($taskConfiguration->getCode(), $this->processedBlockings); } /** - * Once a blocking task has been proceeded, we can remove it from the stack + * Once a blocking task has been proceeded, we can remove it from the stack. */ protected function removeProcessedBlocking(TaskConfiguration $taskConfiguration): void { diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 9eebbc38..1df3bae4 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -13,18 +13,17 @@ namespace CleverAge\ProcessBundle\Model; -use InvalidArgumentException; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Allow the task to configure it's options, set default basic options for errors handling + * Allow the task to configure it's options, set default basic options for errors handling. */ abstract class AbstractConfigurableTask implements InitializableTaskInterface { protected ?array $options = null; /** - * Only validate the options at initialization, ensuring that the task will not fail at runtime + * Only validate the options at initialization, ensuring that the task will not fail at runtime. */ public function initialize(ProcessState $state): void { @@ -33,7 +32,7 @@ public function initialize(ProcessState $state): void protected function getOptions(ProcessState $state): ?array { - if ($this->options === null) { + if (null === $this->options) { $resolver = new OptionsResolver(); $this->configureOptions($resolver); $this->options = $resolver->resolve($state->getContextualizedOptions()); @@ -45,8 +44,8 @@ protected function getOptions(ProcessState $state): ?array protected function getOption(ProcessState $state, string $code): mixed { $options = $this->getOptions($state); - if (! array_key_exists($code, $options)) { - throw new InvalidArgumentException("Missing option {$code}"); + if (!\array_key_exists($code, $options)) { + throw new \InvalidArgumentException("Missing option {$code}"); } return $options[$code]; diff --git a/src/Model/FinalizableTaskInterface.php b/src/Model/FinalizableTaskInterface.php index 8f47e907..44498d53 100644 --- a/src/Model/FinalizableTaskInterface.php +++ b/src/Model/FinalizableTaskInterface.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Model; /** - * Allow the task to be initialized before any execution is done + * Allow the task to be initialized before any execution is done. */ interface FinalizableTaskInterface extends TaskInterface { diff --git a/src/Model/FlushableTaskInterface.php b/src/Model/FlushableTaskInterface.php index cc4c9d60..8c9b8f03 100644 --- a/src/Model/FlushableTaskInterface.php +++ b/src/Model/FlushableTaskInterface.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Model; /** - * When iterations are over, this allows task that have some inner buffer to flush it to the output + * When iterations are over, this allows task that have some inner buffer to flush it to the output. */ interface FlushableTaskInterface extends TaskInterface { diff --git a/src/Model/InitializableTaskInterface.php b/src/Model/InitializableTaskInterface.php index 98212464..ac8cd529 100644 --- a/src/Model/InitializableTaskInterface.php +++ b/src/Model/InitializableTaskInterface.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Model; /** - * Allow the task to be initialized before any execution is done + * Allow the task to be initialized before any execution is done. */ interface InitializableTaskInterface extends TaskInterface { diff --git a/src/Model/IterableTaskInterface.php b/src/Model/IterableTaskInterface.php index cfbd63bb..e07008b4 100644 --- a/src/Model/IterableTaskInterface.php +++ b/src/Model/IterableTaskInterface.php @@ -14,14 +14,14 @@ namespace CleverAge\ProcessBundle\Model; /** - * Allow the task to be iterated over until "next" returns false + * Allow the task to be iterated over until "next" returns false. */ interface IterableTaskInterface extends TaskInterface { /** * Moves the internal pointer to the next element, * return true if the task has a next element - * return false if the task has terminated it's iteration + * return false if the task has terminated it's iteration. */ public function next(ProcessState $state): bool; } diff --git a/src/Model/ProcessHistory.php b/src/Model/ProcessHistory.php index e9c30b5b..be21d855 100644 --- a/src/Model/ProcessHistory.php +++ b/src/Model/ProcessHistory.php @@ -14,14 +14,11 @@ namespace CleverAge\ProcessBundle\Model; use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; -use DateTime; -use DateTimeInterface; -use Stringable; /** - * Logs information about a process + * Logs information about a process. */ -class ProcessHistory implements Stringable +class ProcessHistory implements \Stringable { final public const STATE_STARTED = 'started'; @@ -33,9 +30,9 @@ class ProcessHistory implements Stringable protected string $processCode; - protected ?DateTimeInterface $startDate; + protected ?\DateTimeInterface $startDate; - protected ?DateTimeInterface $endDate = null; + protected ?\DateTimeInterface $endDate = null; protected string $state = self::STATE_STARTED; @@ -45,16 +42,16 @@ public function __construct( ) { $this->id = microtime(true); $this->processCode = $processConfiguration->getCode(); - $this->startDate = new DateTime(); + $this->startDate = new \DateTime(); } public function __toString(): string { - $reference = $this->getProcessCode() . '[' . $this->getState() . ']'; + $reference = $this->getProcessCode().'['.$this->getState().']'; $time = $this->getStartDate() - ->format(DateTimeInterface::ATOM); + ->format(\DateTimeInterface::ATOM); - return $reference . ': ' . $time; + return $reference.': '.$time; } public function getId(): float @@ -72,12 +69,12 @@ public function getContext(): array return $this->context; } - public function getStartDate(): DateTimeInterface + public function getStartDate(): \DateTimeInterface { return $this->startDate; } - public function getEndDate(): ?DateTimeInterface + public function getEndDate(): ?\DateTimeInterface { return $this->endDate; } @@ -88,38 +85,38 @@ public function getState(): string } /** - * Set the process as failed + * Set the process as failed. */ public function setFailed(): void { - $this->endDate = new DateTime(); + $this->endDate = new \DateTime(); $this->state = self::STATE_FAILED; } /** - * Set the process as succeded + * Set the process as succeded. */ public function setSuccess(): void { - $this->endDate = new DateTime(); + $this->endDate = new \DateTime(); $this->state = self::STATE_SUCCESS; } /** - * Is true when the process is running + * Is true when the process is running. */ public function isStarted(): bool { - return $this->state === self::STATE_STARTED; + return self::STATE_STARTED === $this->state; } public function isFailed(): bool { - return $this->state === self::STATE_FAILED; + return self::STATE_FAILED === $this->state; } /** - * Get process duration in seconds + * Get process duration in seconds. */ public function getDuration(): ?int { diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index 0d3cba50..86b84f81 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -16,13 +16,9 @@ use CleverAge\ProcessBundle\Configuration\ProcessConfiguration; use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use CleverAge\ProcessBundle\Context\ContextualOptionResolver; -use RuntimeException; -use Throwable; -use UnexpectedValueException; -use function in_array; /** - * Used to pass information between tasks + * Used to pass information between tasks. */ class ProcessState { @@ -53,7 +49,7 @@ class ProcessState protected bool $stopped = false; - protected ?Throwable $exception = null; + protected ?\Throwable $exception = null; protected array $errorContext = []; @@ -83,7 +79,7 @@ public function setContextualOptionResolver(ContextualOptionResolver $contextual } /** - * Clone the current object and keep a back reference + * Clone the current object and keep a back reference. */ public function duplicate(): self { @@ -95,7 +91,7 @@ public function duplicate(): self /** * Reset the state object - * To be used before execution + * To be used before execution. */ public function reset(bool $cleanInput): void { @@ -167,7 +163,7 @@ public function hasErrorOutput(): bool return $this->hasErrorOutput; } - public function stop(Throwable $e = null): void + public function stop(?\Throwable $e = null): void { if ($e) { $this->setException($e); @@ -185,12 +181,12 @@ public function setStopped(bool $stopped): void $this->stopped = $stopped; } - public function getException(): ?Throwable + public function getException(): ?\Throwable { return $this->exception; } - public function setException(Throwable $exception = null): void + public function setException(?\Throwable $exception = null): void { $this->exception = $exception; } @@ -252,8 +248,8 @@ public function getStatus(): string public function setStatus(string $status): void { - if (! in_array($status, self::STATUS, true)) { - throw new UnexpectedValueException("Unknown status {$status}"); + if (!\in_array($status, self::STATUS, true)) { + throw new \UnexpectedValueException("Unknown status {$status}"); } $this->status = $status; @@ -261,7 +257,7 @@ public function setStatus(string $status): void public function isResolved(): bool { - return $this->status === self::STATUS_RESOLVED; + return self::STATUS_RESOLVED === $this->status; } public function getContext(): array @@ -272,7 +268,7 @@ public function getContext(): array public function setContext(array $context): void { if ($this->context) { - throw new RuntimeException('Once defined, context is immutable'); + throw new \RuntimeException('Once defined, context is immutable'); } $this->context = $context; @@ -280,7 +276,7 @@ public function setContext(array $context): void public function getContextualizedOptions(): ?array { - if (! $this->contextualizedOptions) { + if (!$this->contextualizedOptions) { $options = $this->getTaskConfiguration() ->getOptions(); $this->contextualizedOptions = $this->contextualOptionResolver->contextualizeOptions( @@ -295,7 +291,7 @@ public function getContextualizedOptions(): ?array public function getContextualizedOption(string $code, mixed $default = null): mixed { $contextualizedOptions = $this->getContextualizedOptions(); - if (array_key_exists($code, $contextualizedOptions)) { + if (\array_key_exists($code, $contextualizedOptions)) { return $contextualizedOptions[$code]; } diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index 7c9b7b78..d48ae6e1 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -13,7 +13,6 @@ namespace CleverAge\ProcessBundle\Model; -use RuntimeException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -47,14 +46,14 @@ public function __construct( $this->configureOptions($resolver); $this->options = $resolver->resolve($options); - $this->consolePath = $kernel->getProjectDir() . '/bin/console'; + $this->consolePath = $kernel->getProjectDir().'/bin/console'; $this->environment = $kernel->getEnvironment(); - $this->bufferPath = $kernel->getProjectDir() . '/var/cdm_buffer_' . uniqid('', true) . '.json-stream'; - $this->logDir = $kernel->getLogDir() . '/process'; + $this->bufferPath = $kernel->getProjectDir().'/var/cdm_buffer_'.uniqid('', true).'.json-stream'; + $this->logDir = $kernel->getLogDir().'/process'; } /** - * Prepare the process before start + * Prepare the process before start. * * @return $this */ @@ -66,22 +65,22 @@ public function buildProcess(): static 'nohup', $pathFinder->find(), $this->consolePath, - '--env=' . $this->environment, + '--env='.$this->environment, 'cleverage:process:execute', '--input-from-stdin', ]; $fs = new Filesystem(); $fs->mkdir($this->logDir); - if (! $fs->exists($this->consolePath)) { - throw new RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); + if (!$fs->exists($this->consolePath)) { + throw new \RuntimeException("Unable to resolve path to symfony console '{$this->consolePath}'"); } if ($this->options[self::OPTION_JSON_BUFFERING]) { - $arguments = [...$arguments, '--output=' . $this->bufferPath, '--output-format=json-stream']; + $arguments = [...$arguments, '--output='.$this->bufferPath, '--output-format=json-stream']; } - if (! empty($this->context)) { + if (!empty($this->context)) { foreach ($this->context as $key => $value) { $arguments[] = sprintf('--context=%s:%s', $key, $value); } @@ -96,7 +95,7 @@ public function buildProcess(): static } /** - * Start the process + * Start the process. * * @return $this */ @@ -108,7 +107,7 @@ public function start(): static } /** - * Stop the process + * Stop the process. * * @return $this */ @@ -155,7 +154,7 @@ public function getResult(): ?string } /** - * Available options for process launcher + * Available options for process launcher. */ protected function configureOptions(OptionsResolver $resolver): void { diff --git a/src/Model/TaskInterface.php b/src/Model/TaskInterface.php index 3f3d327c..ee236ecc 100644 --- a/src/Model/TaskInterface.php +++ b/src/Model/TaskInterface.php @@ -15,7 +15,7 @@ /** * Must be implemented by tasks services - * The service can read the input value from ProcessState and write it's output to it + * The service can read the input value from ProcessState and write it's output to it. * * @see ProcessState for more informations about available actions */ diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 84febcaf..0772fed5 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -17,14 +17,10 @@ use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException; use CleverAge\ProcessBundle\Exception\MissingProcessException; -use LogicException; use Psr\Log\LogLevel; -use function array_key_exists; -use function array_keys; -use function count; /** - * Build and holds all the process configurations + * Build and holds all the process configurations. */ class ProcessConfigurationRegistry { @@ -41,7 +37,7 @@ public function __construct( public function getProcessConfiguration(string $processCode): ProcessConfiguration { - if (! $this->hasProcessConfiguration($processCode)) { + if (!$this->hasProcessConfiguration($processCode)) { throw MissingProcessException::create($processCode); } $this->resolveConfiguration($processCode); @@ -54,7 +50,7 @@ public function getProcessConfiguration(string $processCode): ProcessConfigurati */ public function getProcessConfigurations(): array { - foreach (array_keys($this->rawConfiguration) as $processCode) { + foreach (\array_keys($this->rawConfiguration) as $processCode) { $this->resolveConfiguration($processCode); } @@ -63,25 +59,25 @@ public function getProcessConfigurations(): array public function hasProcessConfiguration(string $processCode): bool { - return array_key_exists($processCode, $this->rawConfiguration); + return \array_key_exists($processCode, $this->rawConfiguration); } protected function resolveConfiguration(string $processCode): void { - if (array_key_exists($processCode, $this->processConfigurations)) { + if (\array_key_exists($processCode, $this->processConfigurations)) { return; } $rawProcessConfiguration = $this->rawConfiguration[$processCode]; /** @var TaskConfiguration[] $taskConfigurations */ $taskConfigurations = []; foreach ($rawProcessConfiguration['tasks'] as $taskCode => $rawTaskConfiguration) { - if ((is_countable($rawTaskConfiguration['errors']) ? count($rawTaskConfiguration['errors']) : 0) > 0) { - if ((is_countable($rawTaskConfiguration['error_outputs']) ? count( + if ((is_countable($rawTaskConfiguration['errors']) ? \count($rawTaskConfiguration['errors']) : 0) > 0) { + if ((is_countable($rawTaskConfiguration['error_outputs']) ? \count( $rawTaskConfiguration['error_outputs'] ) : 0) > 0) { $m = "Don't define both 'errors' and 'error_outputs' for task {$taskCode}, these options "; $m .= "are the same, 'errors' is deprecated, just use the new one 'error_outputs'"; - throw new LogicException($m); + throw new \LogicException($m); } $rawTaskConfiguration['error_outputs'] = $rawTaskConfiguration['errors']; } diff --git a/src/Registry/TransformerRegistry.php b/src/Registry/TransformerRegistry.php index c67ab73e..7a32d627 100644 --- a/src/Registry/TransformerRegistry.php +++ b/src/Registry/TransformerRegistry.php @@ -15,10 +15,9 @@ use CleverAge\ProcessBundle\Exception\MissingTransformerException; use CleverAge\ProcessBundle\Transformer\TransformerInterface; -use UnexpectedValueException; /** - * Holds all tagged transformer services + * Holds all tagged transformer services. */ class TransformerRegistry { @@ -29,8 +28,8 @@ class TransformerRegistry public function addTransformer(TransformerInterface $transformer): void { - if (array_key_exists($transformer->getCode(), $this->transformers)) { - throw new UnexpectedValueException("Transformer {$transformer->getCode()} is already defined"); + if (\array_key_exists($transformer->getCode(), $this->transformers)) { + throw new \UnexpectedValueException("Transformer {$transformer->getCode()} is already defined"); } $this->transformers[$transformer->getCode()] = $transformer; } @@ -45,7 +44,7 @@ public function getTransformers(): array public function getTransformer(string $code): TransformerInterface { - if (! $this->hasTransformer($code)) { + if (!$this->hasTransformer($code)) { throw MissingTransformerException::create($code); } @@ -54,6 +53,6 @@ public function getTransformer(string $code): TransformerInterface public function hasTransformer(string $code): bool { - return array_key_exists($code, $this->transformers); + return \array_key_exists($code, $this->transformers); } } diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index 58855cfd..2cf265c9 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -18,14 +18,13 @@ use CleverAge\ProcessBundle\Model\ProcessState; use Iterator; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Base class to handle output iterations + * Base class to handle output iterations. */ abstract class AbstractIterableOutputTask extends AbstractConfigurableTask implements IterableTaskInterface { - protected ?Iterator $iterator = null; + protected ?\Iterator $iterator = null; public function execute(ProcessState $state): void { @@ -44,18 +43,18 @@ public function execute(ProcessState $state): void /** * Moves the internal pointer to the next element, * return true if the task has a next element - * return false if the task has terminated it's iteration + * return false if the task has terminated it's iteration. */ public function next(ProcessState $state): bool { - if (! $this->iterator) { + if (!$this->iterator) { return false; } $this->iterator->next(); $state->removeErrorContext('iterator_key'); - if (! $this->iterator->valid()) { + if (!$this->iterator->valid()) { // Reset the iterator to allow the following iteration $this->iterator = null; @@ -66,11 +65,11 @@ public function next(ProcessState $state): bool } /** - * Create or recreate an iterator from input + * Create or recreate an iterator from input. */ protected function handleIteratorFromInput(ProcessState $state): void { - if ($this->iterator instanceof Iterator) { + if ($this->iterator instanceof \Iterator) { if ($this->iterator->valid()) { return; // No action needed, execution is in progress } @@ -80,8 +79,8 @@ protected function handleIteratorFromInput(ProcessState $state): void // This should never be reached /** @phpstan-ignore-next-line */ - if ($this->iterator !== null) { - throw new UnexpectedValueException( + if (null !== $this->iterator) { + throw new \UnexpectedValueException( "At this point iterator should have been null, maybe it's a wrong type..." ); } @@ -90,11 +89,11 @@ protected function handleIteratorFromInput(ProcessState $state): void } /** - * Allow to not implement this method, not required by most tasks, removing inheritance would break back-compat + * Allow to not implement this method, not required by most tasks, removing inheritance would break back-compat. */ protected function configureOptions(OptionsResolver $resolver): void { } - abstract protected function initializeIterator(ProcessState $state): Iterator; + abstract protected function initializeIterator(ProcessState $state): \Iterator; } diff --git a/src/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php index 7acdd2dc..388cd419 100644 --- a/src/Task/AggregateIterableTask.php +++ b/src/Task/AggregateIterableTask.php @@ -15,10 +15,9 @@ use CleverAge\ProcessBundle\Model\BlockingTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use function count; /** - * Class AggregateIterableTask + * Class AggregateIterableTask. * * Aggregate the result of iterable tasks in an array */ @@ -33,7 +32,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (count($this->result) === 0) { + if (0 === \count($this->result)) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php index 0842cc36..59356525 100644 --- a/src/Task/ArrayMergeTask.php +++ b/src/Task/ArrayMergeTask.php @@ -16,14 +16,10 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\BlockingTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use InvalidArgumentException; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; -use function in_array; -use function is_array; /** - * Merge every input array, and return the result + * Merge every input array, and return the result. */ class ArrayMergeTask extends AbstractConfigurableTask implements BlockingTaskInterface { @@ -34,13 +30,13 @@ class ArrayMergeTask extends AbstractConfigurableTask implements BlockingTaskInt public function execute(ProcessState $state): void { $input = $state->getInput(); - if (! is_array($input)) { - throw new UnexpectedValueException('Input must be an array'); + if (!\is_array($input)) { + throw new \UnexpectedValueException('Input must be an array'); } $mergeFunction = $this->getOption($state, 'merge_function'); - if (! in_array($mergeFunction, self::MERGE_FUNC, true)) { - throw new InvalidArgumentException("Unknown merge function {$mergeFunction}"); + if (!\in_array($mergeFunction, self::MERGE_FUNC, true)) { + throw new \InvalidArgumentException("Unknown merge function {$mergeFunction}"); } $this->mergedOutput = $mergeFunction($this->mergedOutput, $input); } diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index e72562ba..31b569f0 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -20,7 +20,6 @@ use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use UnexpectedValueException; /** * @todo @vclavreul describe this task @@ -46,7 +45,7 @@ public function execute(ProcessState $state): void $missingColumns = []; foreach ($columns as $column) { - if (! isset($input[$column])) { + if (!isset($input[$column])) { $missingColumns[] = $column; continue; } @@ -64,14 +63,14 @@ public function execute(ProcessState $state): void } } - if (! empty($missingColumns)) { + if (!empty($missingColumns)) { $colStr = implode(', ', $missingColumns); $message = "Missing columns [{$colStr}] in input"; if ($this->getOption($state, 'ignore_missing')) { $this->logger->warning($message); } else { - throw new UnexpectedValueException($message); + throw new \UnexpectedValueException($message); } } } @@ -87,7 +86,7 @@ protected function addValueToAggregationGroup( string $referenceKey, string $aggregationKey ): void { - if (! isset($this->result[$column])) { + if (!isset($this->result[$column])) { $this->result[$column] = [ $referenceKey => $column, $aggregationKey => [], diff --git a/src/Task/ConstantIterableOutputTask.php b/src/Task/ConstantIterableOutputTask.php index 77310da9..7cf3875c 100644 --- a/src/Task/ConstantIterableOutputTask.php +++ b/src/Task/ConstantIterableOutputTask.php @@ -13,13 +13,11 @@ namespace CleverAge\ProcessBundle\Task; -use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; -use Iterator; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Always send the same output regardless of the input, only accepts array for values and iterate over it + * Always send the same output regardless of the input, only accepts array for values and iterate over it. */ class ConstantIterableOutputTask extends AbstractIterableOutputTask { @@ -29,8 +27,8 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('output', ['array']); } - protected function initializeIterator(ProcessState $state): Iterator + protected function initializeIterator(ProcessState $state): \Iterator { - return new ArrayIterator($this->getOption($state, 'output')); + return new \ArrayIterator($this->getOption($state, 'output')); } } diff --git a/src/Task/ConstantOutputTask.php b/src/Task/ConstantOutputTask.php index 6a0b6118..f53c9bc9 100644 --- a/src/Task/ConstantOutputTask.php +++ b/src/Task/ConstantOutputTask.php @@ -18,7 +18,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Always send the same output regardless of the input + * Always send the same output regardless of the input. */ class ConstantOutputTask extends AbstractConfigurableTask { diff --git a/src/Task/CounterTask.php b/src/Task/CounterTask.php index 500222a7..061cb945 100644 --- a/src/Task/CounterTask.php +++ b/src/Task/CounterTask.php @@ -20,7 +20,7 @@ /** * Count the number of times the task is processed and continue every N iteration (skip the rest of the time) - * Flush at the end with the actual count + * Flush at the end with the actual count. */ class CounterTask extends AbstractConfigurableTask implements FlushableTaskInterface { @@ -28,9 +28,9 @@ class CounterTask extends AbstractConfigurableTask implements FlushableTaskInter public function execute(ProcessState $state): void { - $this->counter++; + ++$this->counter; $modulo = $this->getOption($state, 'flush_every'); - if ($this->counter % $modulo === 0) { + if (0 === $this->counter % $modulo) { $state->setOutput($this->counter); } else { $state->setSkipped(true); @@ -38,12 +38,12 @@ public function execute(ProcessState $state): void } /** - * Condition is inversed during flush + * Condition is inversed during flush. */ public function flush(ProcessState $state): void { $modulo = $this->getOption($state, 'flush_every'); - if ($this->counter % $modulo === 0) { + if (0 === $this->counter % $modulo) { $state->setSkipped(true); } else { $state->setOutput($this->counter); diff --git a/src/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php index 8c482a0e..3c5c3796 100644 --- a/src/Task/Debug/DebugTask.php +++ b/src/Task/Debug/DebugTask.php @@ -18,7 +18,7 @@ use Symfony\Component\VarDumper\VarDumper; /** - * Dump the content of the input + * Dump the content of the input. * * @example https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.debug.yaml */ diff --git a/src/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php index ab3ab625..ca305446 100644 --- a/src/Task/Debug/DieTask.php +++ b/src/Task/Debug/DieTask.php @@ -17,7 +17,7 @@ use CleverAge\ProcessBundle\Model\TaskInterface; /** - * Class DieTask + * Class DieTask. * * Stops the process brutally * @@ -27,6 +27,6 @@ class DieTask implements TaskInterface { public function execute(ProcessState $state): never { - die(); + exit; } } diff --git a/src/Task/Debug/ErrorForwarderTask.php b/src/Task/Debug/ErrorForwarderTask.php index d04251f5..ae7dffdb 100644 --- a/src/Task/Debug/ErrorForwarderTask.php +++ b/src/Task/Debug/ErrorForwarderTask.php @@ -18,7 +18,7 @@ /** * This is a dummy task mostly intended for testing purpose. - * Forward any input to the error output + * Forward any input to the error output. */ class ErrorForwarderTask implements TaskInterface { diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php index 030f6cd7..dc33e317 100644 --- a/src/Task/Debug/MemInfoDumpTask.php +++ b/src/Task/Debug/MemInfoDumpTask.php @@ -19,7 +19,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Dump memory info to file using meminfo extension if available: https://github.com/BitOne/php-meminfo + * Dump memory info to file using meminfo extension if available: https://github.com/BitOne/php-meminfo. */ class MemInfoDumpTask extends AbstractConfigurableTask { @@ -30,10 +30,10 @@ public function __construct( public function execute(ProcessState $state): void { - if (function_exists('meminfo_dump')) { + if (\function_exists('meminfo_dump')) { gc_collect_cycles(); $handler = fopen($this->getOption($state, 'file_path'), 'wb'); - \meminfo_dump($handler); + meminfo_dump($handler); fclose($handler); } else { $this->logger->critical('meminfo PHP extension is not loaded'); diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php index 8ca66b96..8bae7dbc 100644 --- a/src/Task/Debug/StopwatchTask.php +++ b/src/Task/Debug/StopwatchTask.php @@ -19,7 +19,7 @@ use Symfony\Component\Stopwatch\Stopwatch; /** - * Ouputs the stopwatch the content of the input + * Ouputs the stopwatch the content of the input. */ class StopwatchTask implements TaskInterface { diff --git a/src/Task/DummyTask.php b/src/Task/DummyTask.php index 59d9db61..d3b900db 100644 --- a/src/Task/DummyTask.php +++ b/src/Task/DummyTask.php @@ -17,7 +17,7 @@ use CleverAge\ProcessBundle\Model\TaskInterface; /** - * Dummy task that pass the input to the output + * Dummy task that pass the input to the output. */ class DummyTask implements TaskInterface { diff --git a/src/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php index b17de298..0da1f97c 100644 --- a/src/Task/Event/EventDispatcherTask.php +++ b/src/Task/Event/EventDispatcherTask.php @@ -21,7 +21,7 @@ /** * Call the Symfony event dispatcher - * If defined as passive (which is the default), it automatically set the output from the input + * If defined as passive (which is the default), it automatically set the output from the input. */ class EventDispatcherTask extends AbstractConfigurableTask { diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index d82f273c..a441fe29 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -20,7 +20,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Generic abstract task to handle CSV resources + * Generic abstract task to handle CSV resources. */ abstract class AbstractCsvResourceTask extends AbstractConfigurableTask implements FinalizableTaskInterface { diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index 5b49a69c..26ec72e5 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -19,7 +19,7 @@ /** * Reads the file path from configuration and iterates over it - * Ignores any input + * Ignores any input. */ abstract class AbstractCsvTask extends AbstractCsvResourceTask { diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index 5fae26af..fa5287f0 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -16,13 +16,12 @@ use CleverAge\ProcessBundle\Filesystem\CsvFile; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use LogicException; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * Reads the file path from configuration and iterates over it - * Ignores any input + * Ignores any input. */ class CsvReaderTask extends AbstractCsvTask implements IterableTaskInterface { @@ -38,13 +37,13 @@ public function execute(ProcessState $state): void $this->csv = null; } - if (! $this->csv instanceof CsvFile) { + if (!$this->csv instanceof CsvFile) { $this->initFile($state); } $lineNumber = $this->csv->getLineNumber(); $output = $this->csv->readLine(); - if ($output === null) { + if (null === $output) { if ($this->getOption($state, 'log_empty_lines')) { $logContext = [ 'csv_file' => $this->csv->getFilePath(), @@ -64,18 +63,18 @@ public function execute(ProcessState $state): void /** * Moves the internal pointer to the next element, * return true if the task has a next element - * return false if the task has terminated it's iteration + * return false if the task has terminated it's iteration. */ public function next(ProcessState $state): bool { - if (! $this->csv instanceof CsvFile) { - throw new LogicException('No CSV File initialized'); + if (!$this->csv instanceof CsvFile) { + throw new \LogicException('No CSV File initialized'); } $state->removeErrorContext('csv_file'); $state->removeErrorContext('csv_line'); - return ! $this->csv->isEndOfFile(); + return !$this->csv->isEndOfFile(); } protected function getHeaders(ProcessState $state, array $options): ?array diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 0d700c3e..46ca8c4c 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -16,18 +16,17 @@ use CleverAge\ProcessBundle\Filesystem\CsvFile; use CleverAge\ProcessBundle\Filesystem\CsvResource; use CleverAge\ProcessBundle\Model\ProcessState; -use RuntimeException; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Split long CSV files into smaller ones, keeping the headers + * Split long CSV files into smaller ones, keeping the headers. */ class CsvSplitterTask extends InputCsvReaderTask { public function execute(ProcessState $state): void { $options = $this->getOptions($state); - if ($this->csv === null) { + if (null === $this->csv) { $headers = $this->getHeaders($state, $options); $csv = new CsvFile( $options['file_path'], @@ -48,11 +47,11 @@ public function execute(ProcessState $state): void /** * Moves the internal pointer to the next element, * return true if the task has a next element - * return false if the task has terminated it's iteration + * return false if the task has terminated it's iteration. */ public function next(ProcessState $state): bool { - if (! $this->csv instanceof CsvResource) { + if (!$this->csv instanceof CsvResource) { return false; } @@ -62,7 +61,7 @@ public function next(ProcessState $state): bool $this->csv = null; } - return ! $endOfFile; + return !$endOfFile; } public function finalize(ProcessState $state): void @@ -75,10 +74,10 @@ public function finalize(ProcessState $state): void protected function splitCsv(CsvFile $csv, int $maxLines): string { - $tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php_' . uniqid('process', false) . '.csv'; + $tmpFilePath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_'.uniqid('process', false).'.csv'; $tmpFile = fopen($tmpFilePath, 'wb+'); - if ($tmpFile === false) { - throw new RuntimeException("Unable to open temporary file {$tmpFilePath}"); + if (false === $tmpFile) { + throw new \RuntimeException("Unable to open temporary file {$tmpFilePath}"); } $splitCsv = new CsvResource( $tmpFile, @@ -89,9 +88,9 @@ protected function splitCsv(CsvFile $csv, int $maxLines): string ); $splitCsv->writeHeaders(); - while ($splitCsv->getLineNumber() < $maxLines && ! $csv->isEndOfFile()) { + while ($splitCsv->getLineNumber() < $maxLines && !$csv->isEndOfFile()) { $raw = $csv->readRaw(); - if ($raw === false) { + if (false === $raw) { continue; // This is probably an empty line, no harm to skip it } $splitCsv->writeRaw($raw); diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index 82a860c8..54b2db08 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -18,13 +18,10 @@ use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; - -use function is_array; /** * Reads the file path from configuration and iterates over it - * Ignores any input + * Ignores any input. * * @property CsvFile $csv */ @@ -32,9 +29,9 @@ class CsvWriterTask extends AbstractCsvTask implements BlockingTaskInterface { public function execute(ProcessState $state): void { - if (! $this->csv instanceof CsvFile) { + if (!$this->csv instanceof CsvFile) { $this->initFile($state); - if ($this->getOption($state, 'write_headers') && filesize($this->csv->getFilePath()) === 0) { + if ($this->getOption($state, 'write_headers') && 0 === filesize($this->csv->getFilePath())) { $this->csv->writeHeaders(); } } @@ -71,13 +68,13 @@ protected function configureOptions(OptionsResolver $resolver): void protected function getInput(ProcessState $state): array { $input = $state->getInput(); - if (! is_array($input)) { - throw new UnexpectedValueException('Input value is not an array'); + if (!\is_array($input)) { + throw new \UnexpectedValueException('Input value is not an array'); } $splitCharacter = $this->getOption($state, 'split_character'); foreach ($input as &$item) { - if (is_array($item)) { + if (\is_array($item)) { $item = implode($splitCharacter, $item); } } @@ -88,7 +85,7 @@ protected function getInput(ProcessState $state): array protected function getHeaders(ProcessState $state, array $options): ?array { $headers = $options['headers']; - if ($headers === null) { + if (null === $headers) { $headers = array_keys($state->getInput()); } diff --git a/src/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php index 11aac285..3e469b98 100644 --- a/src/Task/File/Csv/InputCsvReaderTask.php +++ b/src/Task/File/Csv/InputCsvReaderTask.php @@ -17,14 +17,14 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Reads the filepath from the input + * Reads the filepath from the input. */ class InputCsvReaderTask extends CsvReaderTask { protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); - if ($state->getInput() !== null) { + if (null !== $state->getInput()) { $options['file_path'] = $this->getFilePath($options, $state->getInput()); } @@ -42,15 +42,15 @@ protected function configureOptions(OptionsResolver $resolver): void } /** - * If there is no base_path, then the given path from input should be absolute + * If there is no base_path, then the given path from input should be absolute. */ protected function getFilePath(array $options, string $input): string { $basePath = $options['base_path']; - if ($basePath !== '') { - $basePath = rtrim((string) $options['base_path'], '/') . '/'; + if ('' !== $basePath) { + $basePath = rtrim((string) $options['base_path'], '/').'/'; } - return $basePath . $input; + return $basePath.$input; } } diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index ad3601bd..273dcbda 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -21,14 +21,9 @@ use League\Flysystem\MountManager; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; - -use function in_array; -use function is_array; -use function is_resource; /** - * Class FileFetchTask + * Class FileFetchTask. * * Copy (or move) file from one filesystem to another, using Flysystem * Either get files using a file regexp, or take files from input @@ -48,7 +43,7 @@ public function __construct( public function initialize(ProcessState $state): void { - if (! $this->mountManager) { + if (!$this->mountManager) { throw new ServiceNotFoundException('MountManager service not found, you need to install FlySystemBundle'); } // Configure options @@ -63,7 +58,7 @@ public function execute(ProcessState $state): void $this->findMatchingFiles($state); $file = current($this->matchingFiles); - if (! $file) { + if (!$file) { $state->setSkipped(true); return; @@ -85,24 +80,24 @@ protected function findMatchingFiles(ProcessState $state): void $filePattern = $this->getOption($state, 'file_pattern'); if ($filePattern) { foreach ($this->sourceFS->listContents('/') as $file) { - if ($file['type'] === 'file' + if ('file' === $file['type'] && preg_match($filePattern, (string) $file['path']) - && ! in_array($file['path'], $this->matchingFiles, true)) { + && !\in_array($file['path'], $this->matchingFiles, true)) { $this->matchingFiles[] = $file['path']; } } } else { $input = $state->getInput(); - if (! $input) { - throw new UnexpectedValueException('No pattern neither input provided for the Task'); + if (!$input) { + throw new \UnexpectedValueException('No pattern neither input provided for the Task'); } - if (is_array($input)) { + if (\is_array($input)) { foreach ($input as $file) { - if (! in_array($file, $this->matchingFiles, true)) { + if (!\in_array($file, $this->matchingFiles, true)) { $this->matchingFiles[] = $file; } } - } elseif (! in_array($input, $this->matchingFiles, true)) { + } elseif (!\in_array($input, $this->matchingFiles, true)) { $this->matchingFiles[] = $input; } } @@ -121,7 +116,7 @@ protected function doFileCopy(ProcessState $state, string $filename, bool $remov $result = false; } - if (is_resource($buffer)) { + if (\is_resource($buffer)) { fclose($buffer); } diff --git a/src/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php index bbdf9eca..93f1a6a7 100644 --- a/src/Task/File/FileMoverTask.php +++ b/src/Task/File/FileMoverTask.php @@ -17,10 +17,9 @@ use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Move the file passed as input, requires the destination path in options + * Move the file passed as input, requires the destination path in options. */ class FileMoverTask extends AbstractConfigurableTask { @@ -29,12 +28,12 @@ public function execute(ProcessState $state): void $options = $this->getOptions($state); $fs = new Filesystem(); $file = $state->getInput(); - if (! $fs->exists($file)) { - throw new UnexpectedValueException("File does not exists: '{$file}'"); + if (!$fs->exists($file)) { + throw new \UnexpectedValueException("File does not exists: '{$file}'"); } $dest = $options['destination']; if (is_dir($dest)) { - $dest = rtrim((string) $dest, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename((string) $file); + $dest = rtrim((string) $dest, \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR.basename((string) $file); } if ($options['autoincrement']) { $dest = $this->makeFilenameUnique($dest); @@ -61,10 +60,10 @@ protected function makeFilenameUnique(string $dest): string $i = 1; while ($fs->exists($dest)) { if (preg_match('/^(.*?)(-\d+)?(\.[^.]*)$/', $dest, $matches)) { - $dest = $matches[1] . '-' . $i . $matches[3]; + $dest = $matches[1].'-'.$i.$matches[3]; ++$i; } else { - $dest .= '-' . $i; // Fallback brutal mode + $dest .= '-'.$i; // Fallback brutal mode } } diff --git a/src/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php index e7382815..86833ca9 100644 --- a/src/Task/File/FileReaderTask.php +++ b/src/Task/File/FileReaderTask.php @@ -16,10 +16,9 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Read the whole file and output its content + * Read the whole file and output its content. */ class FileReaderTask extends AbstractConfigurableTask { @@ -28,12 +27,12 @@ public function execute(ProcessState $state): void $options = $this->getOptions($state); $filename = $options['filename']; - if (! file_exists($filename)) { - throw new UnexpectedValueException("File does not exists: '{$filename}'"); + if (!file_exists($filename)) { + throw new \UnexpectedValueException("File does not exists: '{$filename}'"); } - if (! is_readable($filename)) { - throw new UnexpectedValueException("File is not readable: '{$filename}'"); + if (!is_readable($filename)) { + throw new \UnexpectedValueException("File is not readable: '{$filename}'"); } $state->setOutput(file_get_contents($filename)); diff --git a/src/Task/File/FileRemoverTask.php b/src/Task/File/FileRemoverTask.php index e0527d6b..a87675f8 100644 --- a/src/Task/File/FileRemoverTask.php +++ b/src/Task/File/FileRemoverTask.php @@ -18,7 +18,7 @@ use Symfony\Component\Filesystem\Filesystem; /** - * Simply delete the file passed as input + * Simply delete the file passed as input. */ class FileRemoverTask implements TaskInterface { diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 55d64d9c..90183374 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use Iterator; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; @@ -26,14 +25,14 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Browse a folder an iterate each file for output + * Browse a folder an iterate each file for output. */ class FolderBrowserTask extends AbstractConfigurableTask implements IterableTaskInterface { /** - * @var Iterator|SplFileInfo[]|null + * @var \Iterator|SplFileInfo[]|null */ - protected Iterator|array|null $files = null; + protected \Iterator|array|null $files = null; public function __construct( protected LoggerInterface $logger @@ -43,7 +42,7 @@ public function __construct( public function execute(ProcessState $state): void { $options = $this->getOptions($state); - if ($this->files === null) { + if (null === $this->files) { $finder = new Finder(); $finder->files(); if ($options['name_pattern']) { @@ -53,7 +52,7 @@ public function execute(ProcessState $state): void $this->files->rewind(); } - if (! $this->files->valid()) { + if (!$this->files->valid()) { $this->logger->log($options['empty_log_level'], "No item found in path {$options['folder_path']}"); $state->setSkipped(true); $state->setErrorOutput($options['folder_path']); @@ -71,11 +70,11 @@ public function execute(ProcessState $state): void /** * Moves the internal pointer to the next element, * return true if the task has a next element - * return false if the task has terminated it's iteration + * return false if the task has terminated it's iteration. */ public function next(ProcessState $state): bool { - if (! $this->files) { + if (!$this->files) { return false; } $this->files->next(); @@ -91,12 +90,12 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'folder_path', static function (Options $options, $value) { - if (! is_dir($value)) { + if (!is_dir($value)) { throw new InvalidConfigurationException( "Folder path does not exists or is not a folder: '{$value}'" ); } - if (! is_readable($value)) { + if (!is_readable($value)) { throw new InvalidConfigurationException("Folder path is not readable: '{$value}'"); } diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index d3c88220..014ec7ba 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -15,12 +15,11 @@ use CleverAge\ProcessBundle\Model\FlushableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use LogicException; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Browse a folder with the path as an input and iterate each file for output + * Browse a folder with the path as an input and iterate each file for output. */ class InputFolderBrowserTask extends FolderBrowserTask implements FlushableTaskInterface { @@ -52,21 +51,21 @@ protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); if ($state->getInput()) { - $folderPath = $options['base_folder_path'] . $state->getInput(); + $folderPath = $options['base_folder_path'].$state->getInput(); if ($this->folderPath && $folderPath !== $this->folderPath) { - throw new LogicException( + throw new \LogicException( "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" ); } $this->folderPath = $folderPath; } - if (! is_dir($this->folderPath)) { + if (!is_dir($this->folderPath)) { throw new InvalidConfigurationException( "Folder path does not exists or is not a folder: '{$this->folderPath}'" ); } - if (! is_readable($this->folderPath)) { + if (!is_readable($this->folderPath)) { throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); } $options['folder_path'] = $this->folderPath; diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index a799cf0f..b2df06d5 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -23,7 +23,7 @@ class JsonStreamReaderTask implements IterableTaskInterface public function execute(ProcessState $state): void { - if ($this->file === null) { + if (null === $this->file) { $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); } @@ -42,7 +42,7 @@ public function next(ProcessState $state): bool $this->file = null; } - return ! $eof; + return !$eof; } protected function getFilePath(ProcessState $state): string diff --git a/src/Task/File/Xml/XmlReaderTask.php b/src/Task/File/Xml/XmlReaderTask.php index 81de9b3f..55261af7 100644 --- a/src/Task/File/Xml/XmlReaderTask.php +++ b/src/Task/File/Xml/XmlReaderTask.php @@ -20,7 +20,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Read an XML file + * Read an XML file. */ class XmlReaderTask extends AbstractConfigurableTask { @@ -31,7 +31,7 @@ public function __construct( public function execute(ProcessState $state): void { - if ($state->getInput() !== null) { + if (null !== $state->getInput()) { $this->logger->warning('Input has been ignored for XMLReaderTask'); } diff --git a/src/Task/File/Xml/XmlWriterTask.php b/src/Task/File/Xml/XmlWriterTask.php index e03d4621..8ce16255 100644 --- a/src/Task/File/Xml/XmlWriterTask.php +++ b/src/Task/File/Xml/XmlWriterTask.php @@ -16,13 +16,11 @@ use CleverAge\ProcessBundle\Filesystem\XmlFile; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use DOMDocument; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Write an XML file + * Write an XML file. */ class XmlWriterTask extends AbstractConfigurableTask { @@ -34,8 +32,8 @@ public function __construct( public function execute(ProcessState $state): void { $input = $state->getInput(); - if (! $input instanceof DOMDocument) { - throw new UnexpectedValueException('Input must be a \DOMDocument'); + if (!$input instanceof \DOMDocument) { + throw new \UnexpectedValueException('Input must be a \DOMDocument'); } $file = new XmlFile($this->getOption($state, 'file_path'), $this->getOption($state, 'mode')); diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php index 0a3788b1..2e10cb4e 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/YamlReaderTask.php @@ -13,19 +13,14 @@ namespace CleverAge\ProcessBundle\Task\File; -use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Task\AbstractIterableOutputTask; -use InvalidArgumentException; -use Iterator; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Yaml\Yaml; -use UnexpectedValueException; -use function is_array; /** - * Reads a YAML file and iterate over its root elements + * Reads a YAML file and iterate over its root elements. */ class YamlReaderTask extends AbstractIterableOutputTask { @@ -36,8 +31,8 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'file_path', static function (Options $options, $value) { - if (! file_exists($value)) { - throw new UnexpectedValueException("File not found: {$value}"); + if (!file_exists($value)) { + throw new \UnexpectedValueException("File not found: {$value}"); } return $value; @@ -45,14 +40,14 @@ static function (Options $options, $value) { ); } - protected function initializeIterator(ProcessState $state): Iterator + protected function initializeIterator(ProcessState $state): \Iterator { $filePath = $this->getOption($state, 'file_path'); $content = Yaml::parseFile($filePath); - if (! is_array($content)) { - throw new InvalidArgumentException("File content is not an array: {$filePath}"); + if (!\is_array($content)) { + throw new \InvalidArgumentException("File content is not an array: {$filePath}"); } - return new ArrayIterator($content); + return new \ArrayIterator($content); } } diff --git a/src/Task/File/YamlWriterTask.php b/src/Task/File/YamlWriterTask.php index dd913335..44922e5a 100644 --- a/src/Task/File/YamlWriterTask.php +++ b/src/Task/File/YamlWriterTask.php @@ -19,7 +19,7 @@ use Symfony\Component\Yaml\Yaml; /** - * Writes a YAML file from an array + * Writes a YAML file from an array. */ class YamlWriterTask extends AbstractConfigurableTask { diff --git a/src/Task/FilterTask.php b/src/Task/FilterTask.php index f8cb8dbc..07985b3d 100644 --- a/src/Task/FilterTask.php +++ b/src/Task/FilterTask.php @@ -22,7 +22,7 @@ /** * Skip inputs under given matching conditions * - equality is softly checked - * - unexisting key is the same as null + * - unexisting key is the same as null. */ class FilterTask extends AbstractConfigurableTask { @@ -37,7 +37,7 @@ public function initialize(ProcessState $state): void public function execute(ProcessState $state): void { $input = $state->getInput(); - if (! $this->checkCondition($input, $this->getOptions($state))) { + if (!$this->checkCondition($input, $this->getOptions($state))) { $state->setErrorOutput($input); $state->setSkipped(true); diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 97cab49c..97abf751 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -7,10 +7,8 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\BlockingTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; -use Exception; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use function count; /** * Attempt to aggregate inputs in an associative array with a key formed by configurable fields of the input. @@ -40,7 +38,7 @@ public function execute(ProcessState $state): void foreach ($groupByAccessors as $groupByAccessor) { try { $keyParts[] = $this->accessor->getValue($input, $groupByAccessor); - } catch (Exception $e) { + } catch (\Exception $e) { $state->addErrorContextValue('property', $groupByAccessor); $state->setException($e); @@ -54,7 +52,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (count($this->result) === 0) { + if (0 === \count($this->result)) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 689d1858..4793bbca 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -15,10 +15,7 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use RuntimeException; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; -use function in_array; /** * Wait for defined inputs before passing an aggregated output. @@ -33,21 +30,21 @@ class InputAggregatorTask extends AbstractConfigurableTask /** * Store inputs and once everything has been received, pass to next task - * Once an output has been generated this task is reset, and may wait for another loop + * Once an output has been generated this task is reset, and may wait for another loop. */ public function execute(ProcessState $state): void { $previousState = $state->getPreviousState(); - if (! $previousState || ! $previousState->getTaskConfiguration()) { - throw new UnexpectedValueException('This task cannot be used without a previous task'); + if (!$previousState || !$previousState->getTaskConfiguration()) { + throw new \UnexpectedValueException('This task cannot be used without a previous task'); } $inputCode = $this->getInputCode($state); - if (array_key_exists($inputCode, $this->inputs)) { + if (\array_key_exists($inputCode, $this->inputs)) { if ($this->getOption($state, 'clean_input_on_override')) { $this->inputs = []; } else { - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output" ); } @@ -60,7 +57,7 @@ public function execute(ProcessState $state): void $keepInputs = $this->getOption($state, 'keep_inputs'); // Only clear inputs that are not in the keep_inputs option foreach ($this->inputs as $inputCode => $value) { - if ($keepInputs !== null && in_array($inputCode, $keepInputs, true)) { + if (null !== $keepInputs && \in_array($inputCode, $keepInputs, true)) { continue; } unset($this->inputs[$inputCode]); @@ -83,32 +80,32 @@ protected function configureOptions(OptionsResolver $resolver): void } /** - * Map the previous task code to an input code + * Map the previous task code to an input code. */ protected function getInputCode(ProcessState $state): string { $previousState = $state->getPreviousState(); - if (! $previousState) { - throw new RuntimeException('No previous state for current task'); + if (!$previousState) { + throw new \RuntimeException('No previous state for current task'); } $previousTaskCode = $previousState->getTaskConfiguration() ->getCode(); $inputCodes = $this->getOption($state, 'input_codes'); - if (! array_key_exists($previousTaskCode, $inputCodes)) { - throw new UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); + if (!\array_key_exists($previousTaskCode, $inputCodes)) { + throw new \UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option"); } return $inputCodes[$previousTaskCode]; } /** - * Check if the received inputs match the defined mappings + * Check if the received inputs match the defined mappings. */ protected function isResolved(ProcessState $state): bool { $inputCodes = $this->getOption($state, 'input_codes'); foreach ($inputCodes as $inputCode) { - if (! array_key_exists($inputCode, $this->inputs)) { + if (!\array_key_exists($inputCode, $this->inputs)) { return false; } } diff --git a/src/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php index 6029dfa9..3151855d 100644 --- a/src/Task/InputIteratorTask.php +++ b/src/Task/InputIteratorTask.php @@ -13,31 +13,26 @@ namespace CleverAge\ProcessBundle\Task; -use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; -use Iterator; -use IteratorAggregate; -use UnexpectedValueException; -use function is_array; /** - * Iterates from the input of the previous task + * Iterates from the input of the previous task. */ class InputIteratorTask extends AbstractIterableOutputTask { - protected function initializeIterator(ProcessState $state): Iterator + protected function initializeIterator(ProcessState $state): \Iterator { $input = $state->getInput(); - if ($input instanceof Iterator) { + if ($input instanceof \Iterator) { return $input; } - if ($input instanceof IteratorAggregate) { + if ($input instanceof \IteratorAggregate) { return $input->getIterator(); } - if (is_array($input)) { - return new ArrayIterator($input); + if (\is_array($input)) { + return new \ArrayIterator($input); } - throw new UnexpectedValueException('Cannot create iterator from input'); + throw new \UnexpectedValueException('Cannot create iterator from input'); } } diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index 9a540138..fff5082b 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -18,17 +18,15 @@ use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; use Psr\Log\LoggerInterface; -use SplQueue; use Symfony\Component\OptionsResolver\OptionsResolver; -use function count; /** * A Batch task that iterate on flush - * It's mainly an example task since it's not useful as-is, but the processInput method may allow custom overrides + * It's mainly an example task since it's not useful as-is, but the processInput method may allow custom overrides. */ class IterableBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { - protected ?SplQueue $outputQueue = null; + protected ?\SplQueue $outputQueue = null; protected bool $flushMode = false; @@ -40,7 +38,7 @@ public function __construct( public function initialize(ProcessState $state): void { parent::initialize($state); - $this->outputQueue = new SplQueue(); + $this->outputQueue = new \SplQueue(); } public function flush(ProcessState $state): void @@ -58,12 +56,12 @@ public function execute(ProcessState $state): void $batchCount = $this->getOption($state, 'batch_count'); // Register new input - if (! $this->flushMode) { + if (!$this->flushMode) { $this->outputQueue->enqueue($this->processInput($state)); } // Detect flushing - if ($batchCount !== null && ($this->outputQueue === null ? 0 : count($this->outputQueue)) >= $batchCount) { + if (null !== $batchCount && (null === $this->outputQueue ? 0 : \count($this->outputQueue)) >= $batchCount) { $this->flushMode = true; } @@ -78,7 +76,7 @@ public function execute(ProcessState $state): void public function next(ProcessState $state): bool { // Stop flushing once over - if (! ($this->outputQueue === null ? 0 : count($this->outputQueue))) { + if (!(null === $this->outputQueue ? 0 : \count($this->outputQueue))) { $this->flushMode = false; } @@ -95,7 +93,7 @@ protected function configureOptions(OptionsResolver $resolver): void } /** - * Override this method to add a custom processing behavior + * Override this method to add a custom processing behavior. */ protected function processInput(ProcessState $state): mixed { diff --git a/src/Task/ObjectUpdaterTask.php b/src/Task/ObjectUpdaterTask.php index d5835892..55647e1c 100644 --- a/src/Task/ObjectUpdaterTask.php +++ b/src/Task/ObjectUpdaterTask.php @@ -17,10 +17,9 @@ use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use UnexpectedValueException; /** - * Takes an array containing an object and a value updates an object's property with this value, then return the object + * Takes an array containing an object and a value updates an object's property with this value, then return the object. */ class ObjectUpdaterTask extends AbstractConfigurableTask { @@ -32,11 +31,11 @@ public function __construct( public function execute(ProcessState $state): void { $input = $state->getInput(); - if (! array_key_exists('object', $input)) { - throw new UnexpectedValueException("Missing 'object' key in input array"); + if (!\array_key_exists('object', $input)) { + throw new \UnexpectedValueException("Missing 'object' key in input array"); } - if (! array_key_exists('value', $input)) { - throw new UnexpectedValueException("Missing 'value' key in input array"); + if (!\array_key_exists('value', $input)) { + throw new \UnexpectedValueException("Missing 'value' key in input array"); } $this->accessor->setValue($input['object'], $this->getOption($state, 'property_path'), $input['value']); $state->setOutput($input['object']); diff --git a/src/Task/Process/CommandRunnerTask.php b/src/Task/Process/CommandRunnerTask.php index fbd8f61d..7ad26553 100644 --- a/src/Task/Process/CommandRunnerTask.php +++ b/src/Task/Process/CommandRunnerTask.php @@ -20,7 +20,7 @@ use Symfony\Component\Process\Process; /** - * Launch a system command for each input, passing input to command + * Launch a system command for each input, passing input to command. */ class CommandRunnerTask extends AbstractConfigurableTask { diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 543d7b0d..4615c3c7 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -23,7 +23,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Execute one or many processes while chaining inputs in a iterable way + * Execute one or many processes while chaining inputs in a iterable way. */ class ProcessExecutorTask extends AbstractConfigurableTask { @@ -62,7 +62,7 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'process', function (Options $options, $processCode) { - if (! $this->processRegistry->hasProcessConfiguration($processCode)) { + if (!$this->processRegistry->hasProcessConfiguration($processCode)) { throw new InvalidConfigurationException("Unknown process {$processCode}"); } diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index bab2ab6f..1164f592 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -19,19 +19,14 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\SubprocessInstance; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; -use InvalidArgumentException; use Psr\Log\LoggerInterface; -use RuntimeException; -use SplQueue; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use function count; - /** - * Launch a new process for each input received, input must be a scalar, a resource or a \Traversable + * Launch a new process for each input received, input must be a scalar, a resource or a \Traversable. */ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableTaskInterface, IterableTaskInterface { @@ -40,7 +35,7 @@ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableT */ protected array $launchedProcesses = []; - protected SplQueue $finishedBuffers; + protected \SplQueue $finishedBuffers; protected bool $flushMode = false; @@ -49,7 +44,7 @@ public function __construct( protected ProcessConfigurationRegistry $processRegistry, protected KernelInterface $kernel ) { - $this->finishedBuffers = new SplQueue(); + $this->finishedBuffers = new \SplQueue(); } public function execute(ProcessState $state): void @@ -57,10 +52,10 @@ public function execute(ProcessState $state): void // TODO still not perfect, optimize and secure it $this->handleProcesses($state); // Handler processes first - if (! $this->flushMode) { + if (!$this->flushMode) { $this->handleInput($state); $state->setSkipped(true); - } elseif (! $this->finishedBuffers->isEmpty()) { + } elseif (!$this->finishedBuffers->isEmpty()) { $state->setOutput($this->finishedBuffers->dequeue()); // After dequeue, stop flush @@ -76,14 +71,14 @@ public function execute(ProcessState $state): void public function flush(ProcessState $state): void { $this->flushMode = true; - if (! $this->finishedBuffers->isEmpty()) { + if (!$this->finishedBuffers->isEmpty()) { $state->setOutput($this->finishedBuffers->dequeue()); } else { $state->setSkipped(true); } // After dequeue, stop flush - if ($this->finishedBuffers->isEmpty() && ! count($this->launchedProcesses)) { + if ($this->finishedBuffers->isEmpty() && !\count($this->launchedProcesses)) { $this->flushMode = false; } } @@ -101,7 +96,7 @@ public function next(ProcessState $state): bool // if we are in flush mode, we should wait for process to finish if ($this->flushMode) { - return count($this->launchedProcesses) > 0; + return \count($this->launchedProcesses) > 0; } usleep($this->getOption($state, 'sleep_on_finalize_interval')); @@ -112,7 +107,7 @@ public function next(ProcessState $state): bool protected function handleInput(ProcessState $state): void { $options = $this->getOptions($state); - while (count($this->launchedProcesses) >= $options['max_processes']) { + while (\count($this->launchedProcesses) >= $options['max_processes']) { $this->handleProcesses($state); usleep($options['sleep_interval']); } @@ -132,7 +127,7 @@ protected function handleInput(ProcessState $state): void protected function launchProcess(ProcessState $state): SubprocessInstance { - $input = $state->getInput() !== null ? (string) $state->getInput() : null; + $input = null !== $state->getInput() ? (string) $state->getInput() : null; $subprocess = new SubprocessInstance( $this->kernel, @@ -151,7 +146,7 @@ protected function launchProcess(ProcessState $state): SubprocessInstance protected function handleProcesses(ProcessState $state): void { foreach ($this->launchedProcesses as $key => $process) { - if (! $process->getProcess()->isTerminated()) { + if (!$process->getProcess()->isTerminated()) { // @todo handle incremental error output properly, specially for terminal where logs are lost echo $process->getProcess() ->getIncrementalErrorOutput(); @@ -171,11 +166,11 @@ protected function handleProcesses(ProcessState $state): void $this->logger->debug('Command terminated', $logContext); unset($this->launchedProcesses[$key]); - if ($process->getProcess()->getExitCode() !== 0) { + if (0 !== $process->getProcess()->getExitCode()) { $this->logger->critical($process->getProcess()->getErrorOutput(), $logContext); $this->killProcesses(); - throw new RuntimeException("Sub-process has failed: {$process->getProcess()->getExitCodeText()}"); + throw new \RuntimeException("Sub-process has failed: {$process->getProcess()->getExitCodeText()}"); } $result = $process->getResult(); @@ -191,7 +186,7 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'process', function (Options $options, $value) { - if (! $this->processRegistry->hasProcessConfiguration($value)) { + if (!$this->processRegistry->hasProcessConfiguration($value)) { throw new InvalidConfigurationException("Unknown process {$value}"); } @@ -226,9 +221,9 @@ function (Options $options, $value) { $resolver->setNormalizer( 'process_options', static function (Options $options, $value): int|float|string|bool|null { - if (! empty($value)) { + if (!empty($value)) { // Todo deprecation trigger - throw new InvalidArgumentException('Deprecated option, please contact support for help'); + throw new \InvalidArgumentException('Deprecated option, please contact support for help'); } return $value; @@ -237,7 +232,7 @@ static function (Options $options, $value): int|float|string|bool|null { } /** - * Kill all running processes + * Kill all running processes. */ protected function killProcesses(): void { diff --git a/src/Task/PropertyGetterTask.php b/src/Task/PropertyGetterTask.php index 0f0654c0..b7ab2616 100644 --- a/src/Task/PropertyGetterTask.php +++ b/src/Task/PropertyGetterTask.php @@ -15,13 +15,12 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use Exception; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Get a property on the input and return it with PropertyAccessor + * Get a property on the input and return it with PropertyAccessor. */ class PropertyGetterTask extends AbstractConfigurableTask { @@ -39,7 +38,7 @@ public function execute(ProcessState $state): void try { $output = $this->accessor->getValue($input, $property); - } catch (Exception $e) { + } catch (\Exception $e) { $state->addErrorContextValue('property', $property); $state->setException($e); diff --git a/src/Task/PropertySetterTask.php b/src/Task/PropertySetterTask.php index 7701d558..e89637ae 100644 --- a/src/Task/PropertySetterTask.php +++ b/src/Task/PropertySetterTask.php @@ -15,13 +15,12 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use Exception; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Accepts an object or an array as input and sets values from configuration + * Accepts an object or an array as input and sets values from configuration. */ class PropertySetterTask extends AbstractConfigurableTask { @@ -38,7 +37,7 @@ public function execute(ProcessState $state): void foreach ($options['values'] as $key => $value) { try { $this->accessor->setValue($input, $key, $value); - } catch (Exception $e) { + } catch (\Exception $e) { $state->addErrorContextValue('property', $key); $state->addErrorContextValue('value', $value); $state->setException($e); diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index d4cd840d..6fe0434b 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -15,18 +15,17 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use DateTime; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Count the time between 2 iterations + * Count the time between 2 iterations. */ class AdvancedStatCounterTask extends AbstractConfigurableTask { - protected ?DateTime $startedAt = null; + protected ?\DateTime $startedAt = null; - protected ?DateTime $lastUpdate = null; + protected ?\DateTime $lastUpdate = null; protected int $counter = 0; @@ -39,18 +38,18 @@ public function __construct( public function execute(ProcessState $state): void { - $now = new DateTime(); - if (! $this->startedAt) { + $now = new \DateTime(); + if (!$this->startedAt) { $this->startedAt = $now; $this->lastUpdate = $now; } if ($this->preInitCounter < $this->getOption($state, 'skip_first')) { - $this->preInitCounter++; + ++$this->preInitCounter; $state->setSkipped(true); return; } - if ($this->counter > 0 && $this->counter % $this->getOption($state, 'show_every') === 0) { + if ($this->counter > 0 && 0 === $this->counter % $this->getOption($state, 'show_every')) { $diff = $now->diff($this->lastUpdate); $fullText = "Last iteration {$diff->format('%H:%I:%S')} ago"; $items = $this->getOption($state, 'num_items') * $this->counter; @@ -68,7 +67,7 @@ public function execute(ProcessState $state): void } else { $state->setSkipped(true); } - $this->counter++; + ++$this->counter; } protected function configureOptions(OptionsResolver $resolver): void diff --git a/src/Task/Reporting/LoggerTask.php b/src/Task/Reporting/LoggerTask.php index 80c64dd0..2cb0e386 100644 --- a/src/Task/Reporting/LoggerTask.php +++ b/src/Task/Reporting/LoggerTask.php @@ -20,7 +20,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Class LoggerTask + * Class LoggerTask. * * Add custom log in state */ diff --git a/src/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php index da2be200..59b08823 100644 --- a/src/Task/Reporting/StatCounterTask.php +++ b/src/Task/Reporting/StatCounterTask.php @@ -18,7 +18,7 @@ use Psr\Log\LoggerInterface; /** - * Count the number of times the task was executed + * Count the number of times the task was executed. */ class StatCounterTask implements FinalizableTaskInterface { @@ -36,6 +36,6 @@ public function finalize(ProcessState $state): void public function execute(ProcessState $state): void { - $this->counter++; + ++$this->counter; } } diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index e4d1fc60..1dddf055 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -37,7 +37,7 @@ public function __construct( /** * Store inputs and once everything has been received, pass to next task - * Once an output has been generated this task is reset, and may wait for another loop + * Once an output has been generated this task is reset, and may wait for another loop. */ public function execute(ProcessState $state): void { @@ -47,7 +47,7 @@ public function execute(ProcessState $state): void $aggregateColumns = $this->getOption($state, 'aggregate_columns'); $aggregationKey = $this->getOption($state, 'aggregation_key'); - if (! array_key_exists($aggregateBy, $input)) { + if (!\array_key_exists($aggregateBy, $input)) { throw new InvalidProcessConfigurationException( "Array aggregator exception: missing column '{$aggregateBy}'" ); @@ -55,10 +55,10 @@ public function execute(ProcessState $state): void $inputAggregateBy = $input[$aggregateBy]; - if (! array_key_exists($inputAggregateBy, $this->result)) { + if (!\array_key_exists($inputAggregateBy, $this->result)) { $this->result[$inputAggregateBy] = $input; foreach ($aggregateColumns as $aggregateColumn) { - if (array_key_exists($aggregateColumn, $this->result[$inputAggregateBy])) { + if (\array_key_exists($aggregateColumn, $this->result[$inputAggregateBy])) { unset($this->result[$inputAggregateBy][$aggregateColumn]); } } @@ -66,7 +66,7 @@ public function execute(ProcessState $state): void $inputAggregateColumns = []; foreach ($aggregateColumns as $aggregateColumn) { - if (! array_key_exists($aggregateColumn, $input)) { + if (!\array_key_exists($aggregateColumn, $input)) { throw new InvalidProcessConfigurationException( "Array aggregator exception: missing column {$aggregateColumn}" ); diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index 9a4beb56..0d2cdb08 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -19,7 +19,7 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** - * Denormalize input to output with configurable class and format + * Denormalize input to output with configurable class and format. */ class DenormalizerTask extends AbstractConfigurableTask { diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 6c663c9d..0fcdb5c8 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -17,10 +17,9 @@ use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -use UnexpectedValueException; /** - * Normalize input to output with configurable format + * Normalize input to output with configurable format. */ class NormalizerTask extends AbstractConfigurableTask { @@ -33,8 +32,8 @@ public function execute(ProcessState $state): void { $options = $this->getOptions($state); - if (! $this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { - throw new UnexpectedValueException('Given value is not normalizable for format ' . $options['format']); + if (!$this->normalizer->supportsNormalization($state->getInput(), $options['format'])) { + throw new \UnexpectedValueException('Given value is not normalizable for format '.$options['format']); } $normalizedData = $this->normalizer->normalize( diff --git a/src/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php index 3f17035e..10c6377a 100644 --- a/src/Task/SimpleBatchTask.php +++ b/src/Task/SimpleBatchTask.php @@ -17,10 +17,9 @@ use CleverAge\ProcessBundle\Model\FlushableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; -use function count; /** - * Simple example of how to manage an internal buffer for batch processing + * Simple example of how to manage an internal buffer for batch processing. */ class SimpleBatchTask extends AbstractConfigurableTask implements FlushableTaskInterface { @@ -28,7 +27,7 @@ class SimpleBatchTask extends AbstractConfigurableTask implements FlushableTaskI public function flush(ProcessState $state): void { - if (count($this->elements) === 0) { + if (0 === \count($this->elements)) { $state->setSkipped(true); } else { $state->setOutput($this->elements); @@ -41,7 +40,7 @@ public function execute(ProcessState $state): void $batchCount = $this->getOption($state, 'batch_count'); $this->elements[] = $state->getInput(); - if ($batchCount !== null && count($this->elements) >= $batchCount) { + if (null !== $batchCount && \count($this->elements) >= $batchCount) { $state->setOutput($this->elements); $this->elements = []; } else { diff --git a/src/Task/SkipEmptyTask.php b/src/Task/SkipEmptyTask.php index 5f2d0ff9..8d2cbf61 100644 --- a/src/Task/SkipEmptyTask.php +++ b/src/Task/SkipEmptyTask.php @@ -18,7 +18,7 @@ /** * Allow to skip the execution on empty input. - * Useful when combined with an aggregator task + * Useful when combined with an aggregator task. */ class SkipEmptyTask implements TaskInterface { diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index ab3265e4..a313143b 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -13,21 +13,18 @@ namespace CleverAge\ProcessBundle\Task; -use ArrayIterator; use CleverAge\ProcessBundle\Model\ProcessState; -use Iterator; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Split a single line into multiple lines based on multiple columns and split characters + * Split a single line into multiple lines based on multiple columns and split characters. */ class SplitJoinLineTask extends AbstractIterableOutputTask { public function next(ProcessState $state): bool { $valid = parent::next($state); - if (! $valid) { + if (!$valid) { $this->iterator = null; } @@ -44,7 +41,7 @@ protected function configureOptions(OptionsResolver $resolver): void ]); } - protected function initializeIterator(ProcessState $state): Iterator + protected function initializeIterator(ProcessState $state): \Iterator { $originalLine = $state->getInput(); $options = $this->getOptions($state); @@ -56,8 +53,8 @@ protected function initializeIterator(ProcessState $state): Iterator $outputLines = []; foreach ($options['split_columns'] as $column) { - if (! array_key_exists($column, $originalLine)) { - throw new UnexpectedValueException("Missing column {$column}"); + if (!\array_key_exists($column, $originalLine)) { + throw new \UnexpectedValueException("Missing column {$column}"); } $columnValues = explode($options['split_character'], (string) $originalLine[$column]); foreach ($columnValues as $columnValue) { @@ -67,6 +64,6 @@ protected function initializeIterator(ProcessState $state): Iterator } } - return new ArrayIterator($outputLines); + return new \ArrayIterator($outputLines); } } diff --git a/src/Task/StopTask.php b/src/Task/StopTask.php index 911e4d49..16ed1ed4 100644 --- a/src/Task/StopTask.php +++ b/src/Task/StopTask.php @@ -17,7 +17,7 @@ use CleverAge\ProcessBundle\Model\TaskInterface; /** - * Allows to directly stop a process, marking it as failed + * Allows to directly stop a process, marking it as failed. */ class StopTask implements TaskInterface { diff --git a/src/Task/TransformerTask.php b/src/Task/TransformerTask.php index e072ab29..92d4ef02 100644 --- a/src/Task/TransformerTask.php +++ b/src/Task/TransformerTask.php @@ -23,7 +23,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Transform an array of data based on mapping and sub-transformers + * Transform an array of data based on mapping and sub-transformers. */ class TransformerTask extends AbstractConfigurableTask { diff --git a/src/Task/Validation/ValidatorTask.php b/src/Task/Validation/ValidatorTask.php index e9fe0b98..f8b842a2 100644 --- a/src/Task/Validation/ValidatorTask.php +++ b/src/Task/Validation/ValidatorTask.php @@ -22,10 +22,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\ConstraintViolationInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; -use UnexpectedValueException; /** - * Validate the input and pass it to the output + * Validate the input and pass it to the output. */ class ValidatorTask extends AbstractConfigurableTask { @@ -62,7 +61,7 @@ public function execute(ProcessState $state): void return; } - throw new UnexpectedValueException("{$violations->count()} constraint violations detected on validation"); + throw new \UnexpectedValueException("{$violations->count()} constraint violations detected on validation"); } $state->setOutput($state->getInput()); @@ -89,7 +88,7 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'log_errors', static function (Options $options, $value) { - if ($value === true) { + if (true === $value) { return LogLevel::CRITICAL; } @@ -105,7 +104,7 @@ static function (Options $options, $value) { $resolver->setNormalizer( 'constraints', static function (Options $options, $constraints): ?array { - if ($constraints === null) { + if (null === $constraints) { return null; } diff --git a/src/Transformer/ArrayElementTransformer.php b/src/Transformer/ArrayElementTransformer.php index 0c9e6b4a..49213a9b 100644 --- a/src/Transformer/ArrayElementTransformer.php +++ b/src/Transformer/ArrayElementTransformer.php @@ -16,13 +16,13 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Return the nth element of an array + * Return the nth element of an array. */ class ArrayElementTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): mixed { - return array_values(array_slice($value, $options['index'], 1))[0]; + return array_values(\array_slice($value, $options['index'], 1))[0]; } public function getCode(): string diff --git a/src/Transformer/ArrayFilterTransformer.php b/src/Transformer/ArrayFilterTransformer.php index 0a5e0d27..26146d0d 100644 --- a/src/Transformer/ArrayFilterTransformer.php +++ b/src/Transformer/ArrayFilterTransformer.php @@ -15,10 +15,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use UnexpectedValueException; /** - * Array filtering transformer, should match native array_filter behavior + * Array filtering transformer, should match native array_filter behavior. * * @see https://secure.php.net/manual/fr/function.array-filter.php */ @@ -36,8 +35,8 @@ public function __construct(PropertyAccessorInterface $accessor) */ public function transform(mixed $value, array $options = []): array { - if (! (is_iterable($value))) { - throw new UnexpectedValueException('Given value is not iterable'); + if (!is_iterable($value)) { + throw new \UnexpectedValueException('Given value is not iterable'); } $result = []; diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php index b32a81f1..4fd39050 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/ArrayFirstTransformer.php @@ -16,16 +16,16 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Return the first element of an array + * Return the first element of an array. */ class ArrayFirstTransformer implements ConfigurableTransformerInterface { /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): mixed { - if ($options['allow_not_iterable'] === false && ! is_iterable($value)) { + if (false === $options['allow_not_iterable'] && !is_iterable($value)) { return $value; } @@ -33,7 +33,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/ArrayLastTransformer.php b/src/Transformer/ArrayLastTransformer.php index 8f689752..f8b0b4c1 100644 --- a/src/Transformer/ArrayLastTransformer.php +++ b/src/Transformer/ArrayLastTransformer.php @@ -14,13 +14,13 @@ namespace CleverAge\ProcessBundle\Transformer; /** - * Return the last element of an array + * Return the last element of an array. */ class ArrayLastTransformer implements TransformerInterface { public function transform(mixed $value, array $options = []): mixed { - return array_values(array_slice($value, -1))[0]; + return array_values(\array_slice($value, -1))[0]; } public function getCode(): string diff --git a/src/Transformer/ArrayMapTransformer.php b/src/Transformer/ArrayMapTransformer.php index fe3bb18b..37bfd311 100644 --- a/src/Transformer/ArrayMapTransformer.php +++ b/src/Transformer/ArrayMapTransformer.php @@ -16,12 +16,9 @@ use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\OptionsResolver\OptionsResolver; -use Traversable; -use UnexpectedValueException; -use function is_array; /** - * Applies transformers to each element of an array + * Applies transformers to each element of an array. */ class ArrayMapTransformer implements ConfigurableTransformerInterface { @@ -33,19 +30,19 @@ public function __construct(TransformerRegistry $transformerRegistry) } /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): array { - if (! is_array($value) && ! $value instanceof Traversable) { - throw new UnexpectedValueException('Input value must be an array or traversable'); + if (!\is_array($value) && !$value instanceof \Traversable) { + throw new \UnexpectedValueException('Input value must be an array or traversable'); } $results = []; foreach ($value as $key => $item) { try { $item = $this->applyTransformers($options['transformers'], $item); - if ($item === null && $options['skip_null']) { + if (null === $item && $options['skip_null']) { continue; } $results[$key] = $item; @@ -59,7 +56,7 @@ public function transform(mixed $value, array $options = []): array } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/ArrayUnsetTransformer.php b/src/Transformer/ArrayUnsetTransformer.php index 0062e1b0..bdd782a7 100644 --- a/src/Transformer/ArrayUnsetTransformer.php +++ b/src/Transformer/ArrayUnsetTransformer.php @@ -14,18 +14,16 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; -use function is_array; /** - * Unset a key from an array + * Unset a key from an array. */ class ArrayUnsetTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): mixed { - if (! is_array($value)) { - throw new UnexpectedValueException('Given value is not an array'); + if (!\is_array($value)) { + throw new \UnexpectedValueException('Given value is not an array'); } unset($value[$options['key']]); diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 5a7dcc8c..727d9bb0 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -15,15 +15,11 @@ use CleverAge\ProcessBundle\Registry\TransformerRegistry; use DateTime; -use DateTimeInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use function implode; -use function is_string; -use function rawurlencode; class CachedTransformer implements ConfigurableTransformerInterface { @@ -45,16 +41,17 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('cache_key', 'string'); $resolver->setDefault('ttl', null); - $resolver->setAllowedTypes('ttl', ['null', 'string', DateTimeInterface::class]); + $resolver->setAllowedTypes('ttl', ['null', 'string', \DateTimeInterface::class]); $resolver->setNormalizer( 'ttl', function (Options $options, $value) { /** - * Best use is a relative date string like "+1 hour" + * Best use is a relative date string like "+1 hour". + * * @see https://www.php.net/manual/en/datetime.formats.relative.php */ - if (is_string($value)) { - $value = new DateTime($value); + if (\is_string($value)) { + $value = new \DateTime($value); } return $value; @@ -81,7 +78,7 @@ public function transform(mixed $value, array $options = []): mixed } $success = $this->cache->saveDeferred($cacheItem); - if (! $success) { + if (!$success) { $this->logger->warning('Cannot save cache item', [ 'cache_key' => $cacheKey, ]); @@ -111,10 +108,10 @@ protected function generateCacheKey(string $cacheKeyRoot, string $value, array $ { $value = $this->applyTransformers($options['key_transformers'], $value); - if (! is_string($value)) { + if (!\is_string($value)) { return false; } - return implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, rawurlencode($value)]); + return \implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, \rawurlencode($value)]); } } diff --git a/src/Transformer/CallbackTransformer.php b/src/Transformer/CallbackTransformer.php index 1056643f..3a5c89cc 100644 --- a/src/Transformer/CallbackTransformer.php +++ b/src/Transformer/CallbackTransformer.php @@ -16,32 +16,30 @@ use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use function call_user_func_array; -use function is_callable; /** - * Convert input based on a callback + * Convert input based on a callback. */ class CallbackTransformer implements ConfigurableTransformerInterface { /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): mixed { - if ((is_countable($options['additional_parameters']) ? count($options['additional_parameters']) : 0) - && ! (is_countable($options['right_parameters']) ? count($options['right_parameters']) : 0)) { + if ((is_countable($options['additional_parameters']) ? \count($options['additional_parameters']) : 0) + && !(is_countable($options['right_parameters']) ? \count($options['right_parameters']) : 0)) { $options['right_parameters'] = $options['additional_parameters']; } $parameters = $options['left_parameters']; array_push($parameters, $value, ...$options['right_parameters']); - return call_user_func_array($options['callback'], $parameters); + return \call_user_func_array($options['callback'], $parameters); } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { @@ -55,7 +53,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'callback', static function (Options $options, $value): callable { - if (! is_callable($value)) { + if (!\is_callable($value)) { throw new InvalidOptionsException('Callback option must be callable'); } @@ -79,7 +77,7 @@ static function (Options $options, $value) { if ($value) { @trigger_error( 'The "additional_parameters" option is deprecated. Use "right_parameters" instead.', - E_USER_DEPRECATED + \E_USER_DEPRECATED ); } diff --git a/src/Transformer/CastTransformer.php b/src/Transformer/CastTransformer.php index 6b36d844..7ce970ae 100644 --- a/src/Transformer/CastTransformer.php +++ b/src/Transformer/CastTransformer.php @@ -16,7 +16,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Cast a value to a different PHP type + * Cast a value to a different PHP type. */ class CastTransformer implements ConfigurableTransformerInterface { diff --git a/src/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php index a51f8e97..26bbf2e8 100644 --- a/src/Transformer/ConditionTrait.php +++ b/src/Transformer/ConditionTrait.php @@ -17,7 +17,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Configurable set of conditions to use in tasks or transformers options + * Configurable set of conditions to use in tasks or transformers options. */ trait ConditionTrait { @@ -25,30 +25,30 @@ trait ConditionTrait /** * Test the input with the given set of conditions - * True by default + * True by default. */ protected function checkCondition(mixed $input, array $conditions): bool { foreach ($conditions['match'] as $key => $value) { - if (! $this->checkValue($input, $key, $value)) { + if (!$this->checkValue($input, $key, $value)) { return false; } } foreach ($conditions['empty'] as $key => $value) { - if (! $this->checkEmpty($input, $key)) { + if (!$this->checkEmpty($input, $key)) { return false; } } foreach ($conditions['match_regexp'] as $key => $value) { - if (! $this->checkValue($input, $key, $value, true, true)) { + if (!$this->checkValue($input, $key, $value, true, true)) { return false; } } foreach ($conditions['not_match'] as $key => $value) { - if (! $this->checkValue($input, $key, $value, false)) { + if (!$this->checkValue($input, $key, $value, false)) { return false; } } @@ -60,7 +60,7 @@ protected function checkCondition(mixed $input, array $conditions): bool } foreach ($conditions['not_match_regexp'] as $key => $value) { - if (! $this->checkValue($input, $key, $value, false, true)) { + if (!$this->checkValue($input, $key, $value, false, true)) { return false; } } @@ -69,7 +69,7 @@ protected function checkCondition(mixed $input, array $conditions): bool } /** - * Configure available condition rules in a wrapper option + * Configure available condition rules in a wrapper option. */ protected function configureWrappedConditionOptions(string $wrapperKey, OptionsResolver $resolver): void { @@ -87,7 +87,7 @@ function (OptionsResolver $options, $value): array { } /** - * Configure available condition rules + * Configure available condition rules. */ protected function configureConditionOptions(OptionsResolver $resolver): void { @@ -104,7 +104,7 @@ protected function configureConditionOptions(OptionsResolver $resolver): void } /** - * Softly check if an input key match a value, or not + * Softly check if an input key match a value, or not. */ protected function checkValue( object|array $input, @@ -115,22 +115,22 @@ protected function checkValue( ): bool { $currentValue = $this->getValue($input, $key); - if ($shouldMatch && ! $regexpMode && $currentValue !== $value) { + if ($shouldMatch && !$regexpMode && $currentValue !== $value) { return false; } - if (! $shouldMatch && ! $regexpMode && $currentValue === $value) { + if (!$shouldMatch && !$regexpMode && $currentValue === $value) { return false; } if ($regexpMode) { $pregMatch = preg_match($value, (string) $currentValue); - if ($shouldMatch && ($pregMatch === false || $pregMatch === 0)) { + if ($shouldMatch && (false === $pregMatch || 0 === $pregMatch)) { return false; } - if (! $shouldMatch && ($pregMatch === false || $pregMatch > 0)) { + if (!$shouldMatch && (false === $pregMatch || $pregMatch > 0)) { return false; } } @@ -139,7 +139,7 @@ protected function checkValue( } /** - * Check if the input property is empty or not + * Check if the input property is empty or not. */ protected function checkEmpty(object|array $input, string $key): bool { @@ -149,11 +149,11 @@ protected function checkEmpty(object|array $input, string $key): bool } /** - * Soft value getter (return the value or null) + * Soft value getter (return the value or null). */ protected function getValue(object|array $input, string $key): mixed { - if ($key === '') { + if ('' === $key) { $currentValue = $input; } elseif ($this->accessor->isReadable($input, $key)) { $currentValue = $this->accessor->getValue($input, $key); diff --git a/src/Transformer/ConfigurableTransformerInterface.php b/src/Transformer/ConfigurableTransformerInterface.php index e3403b5f..19aad92f 100644 --- a/src/Transformer/ConfigurableTransformerInterface.php +++ b/src/Transformer/ConfigurableTransformerInterface.php @@ -16,7 +16,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Allows a service to configure the options for a transformer before running the transform function + * Allows a service to configure the options for a transformer before running the transform function. */ interface ConfigurableTransformerInterface extends TransformerInterface { diff --git a/src/Transformer/ConstantTransformer.php b/src/Transformer/ConstantTransformer.php index ba2c152b..3fa39842 100644 --- a/src/Transformer/ConstantTransformer.php +++ b/src/Transformer/ConstantTransformer.php @@ -17,7 +17,7 @@ /** * Return always the same value configured in options, redundant when used inside mapping except in certain useful - * circumstances + * circumstances. */ class ConstantTransformer implements ConfigurableTransformerInterface { @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver): void } /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): mixed { @@ -35,7 +35,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index bd42f79f..b478d0d5 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -14,41 +14,40 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Transform a value to another value based on a conversion table + * Transform a value to another value based on a conversion table. */ class ConvertValueTransformer implements ConfigurableTransformerInterface { /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): mixed { - if ($value === null) { + if (null === $value) { return null; } - if (! is_string($value) && ! is_int($value)) { // If not a valid array index - if (! $options['auto_cast']) { - $type = gettype($value); - throw new UnexpectedValueException( + if (!\is_string($value) && !\is_int($value)) { // If not a valid array index + if (!$options['auto_cast']) { + $type = \gettype($value); + throw new \UnexpectedValueException( "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" ); } - if (is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here - throw new UnexpectedValueException("Unexpected input of type 'array' in convert_value transformer"); + if (\is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here + throw new \UnexpectedValueException("Unexpected input of type 'array' in convert_value transformer"); } $value = (string) $value; // Let's cast it to string } - if (! array_key_exists($value, $options['map'])) { + if (!\array_key_exists($value, $options['map'])) { if ($options['keep_missing']) { return $value; } - if (! $options['ignore_missing']) { - throw new UnexpectedValueException("Missing value in map '{$value}'"); + if (!$options['ignore_missing']) { + throw new \UnexpectedValueException("Missing value in map '{$value}'"); } return null; @@ -58,7 +57,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/DateFormatTransformer.php b/src/Transformer/DateFormatTransformer.php index 9d5ca13d..1299fb4e 100644 --- a/src/Transformer/DateFormatTransformer.php +++ b/src/Transformer/DateFormatTransformer.php @@ -13,9 +13,7 @@ namespace CleverAge\ProcessBundle\Transformer; -use DateTimeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** * Transformer aiming to take a date as an input (object or string) and format it according to options. @@ -30,14 +28,14 @@ class DateFormatTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): mixed { - if (! $value) { + if (!$value) { return $value; } - if ($value instanceof DateTimeInterface) { + if ($value instanceof \DateTimeInterface) { $date = $value; } else { - throw new UnexpectedValueException('Given value cannot be parsed into a date'); + throw new \UnexpectedValueException('Given value cannot be parsed into a date'); } return $date->format($options['format']); diff --git a/src/Transformer/DateParserTransformer.php b/src/Transformer/DateParserTransformer.php index 664c2fb4..c1dc4077 100644 --- a/src/Transformer/DateParserTransformer.php +++ b/src/Transformer/DateParserTransformer.php @@ -13,12 +13,10 @@ namespace CleverAge\ProcessBundle\Transformer; -use DateTime; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Transformer aiming to take a date as an input (object or a format defined string) to strictly output aa \DateTime + * Transformer aiming to take a date as an input (object or a format defined string) to strictly output aa \DateTime. * * @example in YML config * transformers: @@ -29,14 +27,14 @@ class DateParserTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): mixed { - if (! $value || $value instanceof DateTime) { + if (!$value || $value instanceof \DateTime) { return $value; } - $date = DateTime::createFromFormat($options['format'], $value); + $date = \DateTime::createFromFormat($options['format'], $value); - if (! $date) { - throw new UnexpectedValueException('Given value cannot be parsed into a date'); + if (!$date) { + throw new \UnexpectedValueException('Given value cannot be parsed into a date'); } return $date; diff --git a/src/Transformer/DebugTransformer.php b/src/Transformer/DebugTransformer.php index fb5b8ac5..70593a50 100644 --- a/src/Transformer/DebugTransformer.php +++ b/src/Transformer/DebugTransformer.php @@ -16,7 +16,7 @@ use Symfony\Component\VarDumper\VarDumper; /** - * Simple dump in a transformer, passthrough for value + * Simple dump in a transformer, passthrough for value. */ class DebugTransformer implements TransformerInterface { diff --git a/src/Transformer/DefaultTransformer.php b/src/Transformer/DefaultTransformer.php index 3f10e43b..ca1e81cc 100644 --- a/src/Transformer/DefaultTransformer.php +++ b/src/Transformer/DefaultTransformer.php @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver): void public function transform(mixed $value, array $options = []): mixed { - if (! $value) { + if (!$value) { return $options['value']; } diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index f053b3ad..60a24f5d 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -17,7 +17,7 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** - * Denormalize the given value based on options + * Denormalize the given value based on options. */ class DenormalizeTransformer implements ConfigurableTransformerInterface { @@ -44,7 +44,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/EvaluatorTransformer.php b/src/Transformer/EvaluatorTransformer.php index aaeaa6c0..66c9a885 100644 --- a/src/Transformer/EvaluatorTransformer.php +++ b/src/Transformer/EvaluatorTransformer.php @@ -38,7 +38,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'expression', function (Options $options, $expression) { - if (is_array($options['variables'])) { + if (\is_array($options['variables'])) { return $this->language->parse($expression, $options['variables']); } diff --git a/src/Transformer/ExplodeTransformer.php b/src/Transformer/ExplodeTransformer.php index 06798e19..be06e117 100644 --- a/src/Transformer/ExplodeTransformer.php +++ b/src/Transformer/ExplodeTransformer.php @@ -16,13 +16,13 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Explode a string to an array based on a split character + * Explode a string to an array based on a split character. */ class ExplodeTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): array { - if ($value === null || $value === '') { + if (null === $value || '' === $value) { return []; } @@ -30,7 +30,7 @@ public function transform(mixed $value, array $options = []): array } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php index 6e463953..2456d508 100644 --- a/src/Transformer/ExpressionLanguageMapTransformer.php +++ b/src/Transformer/ExpressionLanguageMapTransformer.php @@ -17,10 +17,9 @@ use Symfony\Component\ExpressionLanguage\ParsedExpression; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Parse an input using the Expression Language and returning a specific value upon a specific condition + * Parse an input using the Expression Language and returning a specific value upon a specific condition. */ class ExpressionLanguageMapTransformer implements ConfigurableTransformerInterface { @@ -42,8 +41,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'map', function (Options $options, $values): array { - if (! is_array($values)) { - throw new UnexpectedValueException('The map must be an array'); + if (!\is_array($values)) { + throw new \UnexpectedValueException('The map must be an array'); } $resolver = new OptionsResolver(); $resolver->setRequired(['condition', 'output']); @@ -79,15 +78,15 @@ public function transform(mixed $value, array $options = []): mixed if ($options['keep_missing']) { return $value; } - if (! $options['ignore_missing']) { - throw new UnexpectedValueException("No expression accepting value '{$value}' in map"); + if (!$options['ignore_missing']) { + throw new \UnexpectedValueException("No expression accepting value '{$value}' in map"); } return null; } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/GenericTransformer.php b/src/Transformer/GenericTransformer.php index 35dad513..451d1d06 100644 --- a/src/Transformer/GenericTransformer.php +++ b/src/Transformer/GenericTransformer.php @@ -15,12 +15,11 @@ use CleverAge\ProcessBundle\Context\ContextualOptionResolver; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use InvalidArgumentException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * A generic class that can be used to create configuration-driven transformer instances + * A generic class that can be used to create configuration-driven transformer instances. */ class GenericTransformer implements ConfigurableTransformerInterface { @@ -40,7 +39,7 @@ public function __construct( } /** - * Register the generic options, and load the transformer list + * Register the generic options, and load the transformer list. */ public function initialize(string $code, array $options = []): void { @@ -54,7 +53,7 @@ public function initialize(string $code, array $options = []): void } /** - * Called on instance creation + * Called on instance creation. */ public function configureInitialOptions(OptionsResolver $resolver): void { @@ -75,12 +74,12 @@ public function configureInitialOptions(OptionsResolver $resolver): void } /** - * Called on process startup, prepare the real transformers + * Called on process startup, prepare the real transformers. */ public function configureOptions(OptionsResolver $resolver): void { foreach ($this->contextualOptions as $option => $optionConfig) { - if ($optionConfig['default'] !== null || $optionConfig['default_is_null']) { + if (null !== $optionConfig['default'] || $optionConfig['default_is_null']) { $resolver->setDefault($option, $optionConfig['default']); } @@ -92,8 +91,8 @@ public function configureOptions(OptionsResolver $resolver): void // Get the transformer list + apply transformer option resolution by context $this->configureTransformersOptions($resolver); $resolver->setNormalizer('transformers', function (Options $options, $transformerOptions): array { - if ($transformerOptions !== []) { - throw new InvalidArgumentException('Transformers option should not be used at this point'); + if ([] !== $transformerOptions) { + throw new \InvalidArgumentException('Transformers option should not be used at this point'); } $transformerOptions = $this->normalizeTransformerOptions($options, $this->preconfiguredTransformerOptions); @@ -113,7 +112,7 @@ public function getCode(): string } /** - * Get the real transformer from contextual options + generic definitions + * Get the real transformer from contextual options + generic definitions. */ public function normalizeTransformerOptions(Options $options, array $transformerOptions): array { @@ -126,7 +125,7 @@ public function normalizeTransformerOptions(Options $options, array $transformer } /** - * Available options for contextual_options + * Available options for contextual_options. */ public function configureContextualOptions(OptionsResolver $resolver): void { diff --git a/src/Transformer/HashTransformer.php b/src/Transformer/HashTransformer.php index 2f5db79a..150e6996 100644 --- a/src/Transformer/HashTransformer.php +++ b/src/Transformer/HashTransformer.php @@ -16,7 +16,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Use hash() function to generate hash value + * Use hash() function to generate hash value. */ class HashTransformer implements ConfigurableTransformerInterface { diff --git a/src/Transformer/ImplodeTransformer.php b/src/Transformer/ImplodeTransformer.php index 327ead0b..7f6ecb10 100644 --- a/src/Transformer/ImplodeTransformer.php +++ b/src/Transformer/ImplodeTransformer.php @@ -14,11 +14,9 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; -use function is_array; /** - * Implode multiple array values to a string, based on a split character + * Implode multiple array values to a string, based on a split character. */ class ImplodeTransformer implements ConfigurableTransformerInterface { @@ -31,8 +29,8 @@ public function configureOptions(OptionsResolver $resolver): void public function transform(mixed $value, array $options = []): string { - if (! is_array($value)) { - throw new UnexpectedValueException('Given value is not an array'); + if (!\is_array($value)) { + throw new \UnexpectedValueException('Given value is not an array'); } return implode($options['separator'], $value); diff --git a/src/Transformer/InstantiateTransformer.php b/src/Transformer/InstantiateTransformer.php index ceb8ed8f..ea3e7ca0 100644 --- a/src/Transformer/InstantiateTransformer.php +++ b/src/Transformer/InstantiateTransformer.php @@ -13,22 +13,20 @@ namespace CleverAge\ProcessBundle\Transformer; -use ReflectionClass; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; /** - * Instantiate a new object with parameters from the input array + * Instantiate a new object with parameters from the input array. */ class InstantiateTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): mixed { - if (! is_array($value)) { - throw new UnexpectedValueException('Input value must be an array for transformer instantiate'); + if (!\is_array($value)) { + throw new \UnexpectedValueException('Input value must be an array for transformer instantiate'); } - return (new ReflectionClass($options['class']))->newInstanceArgs($value); + return (new \ReflectionClass($options['class']))->newInstanceArgs($value); } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index 8d1893be..387e93dd 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -21,12 +21,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\Exception\RuntimeException; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use UnexpectedValueException; -use function is_array; -use function is_callable; /** - * Maps properties of an array/object to an other array/object + * Maps properties of an array/object to an other array/object. */ class MappingTransformer implements ConfigurableTransformerInterface { @@ -42,7 +39,7 @@ public function __construct( public function transform(mixed $value, array $options = []): mixed { - if (! empty($options['initial_value']) && $options['keep_input']) { + if (!empty($options['initial_value']) && $options['keep_input']) { throw new InvalidOptionsException( 'The options "initial_value" and "keep_input" can\'t be both enabled.' ); @@ -59,11 +56,11 @@ public function transform(mixed $value, array $options = []): mixed $ignoreMissingFlag = $mapping['ignore_missing'] || $options['ignore_missing']; // Prepare input value - if ($mapping['constant'] !== null) { + if (null !== $mapping['constant']) { $inputValue = $mapping['constant']; } elseif ($mapping['set_null']) { $inputValue = null; - } elseif (is_array($sourceProperty)) { + } elseif (\is_array($sourceProperty)) { $inputValue = []; foreach ($sourceProperty as $destKey => $srcKey) { try { @@ -111,14 +108,14 @@ public function transform(mixed $value, array $options = []): mixed } // Set transformed value into result - if (is_callable($options['merge_callback'])) { + if (\is_callable($options['merge_callback'])) { $options['merge_callback']($result, $targetProperty, $transformedValue); } elseif ($this->accessor->isWritable($result, $targetProperty)) { $this->accessor->setValue($result, $targetProperty, $transformedValue); - } elseif (is_array($result)) { + } elseif (\is_array($result)) { $result[$targetProperty] = $transformedValue; } else { - throw new UnexpectedValueException("Property '{$targetProperty}' is not writable"); + throw new \UnexpectedValueException("Property '{$targetProperty}' is not writable"); } } @@ -158,7 +155,7 @@ function (Options $options, $value): array { } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { @@ -183,11 +180,11 @@ protected function configureMappingOptions(OptionsResolver $resolver): void } /** - * Custom rules to get a value from an input object or array + * Custom rules to get a value from an input object or array. */ protected function extractInputValue(mixed $input, string $sourceProperty): mixed { - if ($sourceProperty === '.') { + if ('.' === $sourceProperty) { return $input; } @@ -195,7 +192,7 @@ protected function extractInputValue(mixed $input, string $sourceProperty): mixe } /** - * Wrap error handling when there is an property access error + * Wrap error handling when there is an property access error. * * @TODO WARNING there is no error if framework.property_access.throw_exception_on_invalid_index is false (which is * the default) diff --git a/src/Transformer/MultiReplaceTransformer.php b/src/Transformer/MultiReplaceTransformer.php index 2fa42461..f71ecfb3 100644 --- a/src/Transformer/MultiReplaceTransformer.php +++ b/src/Transformer/MultiReplaceTransformer.php @@ -16,7 +16,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Quickly replace a list of values in a string + * Quickly replace a list of values in a string. * * ##### Options * diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index d582fdf9..52958ad4 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -17,7 +17,7 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** - * Normalize the given value based on options + * Normalize the given value based on options. */ class NormalizeTransformer implements ConfigurableTransformerInterface { @@ -42,7 +42,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/PregFilterTransformer.php b/src/Transformer/PregFilterTransformer.php index 47f8806c..a794ce25 100644 --- a/src/Transformer/PregFilterTransformer.php +++ b/src/Transformer/PregFilterTransformer.php @@ -26,7 +26,7 @@ public function transform(mixed $value, array $options = []): array|string|null } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/PropertyAccessorTransformer.php b/src/Transformer/PropertyAccessorTransformer.php index 0014d6ce..bbe0eaab 100644 --- a/src/Transformer/PropertyAccessorTransformer.php +++ b/src/Transformer/PropertyAccessorTransformer.php @@ -17,7 +17,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Read a property from the input value and return it + * Read a property from the input value and return it. */ class PropertyAccessorTransformer implements ConfigurableTransformerInterface { @@ -28,11 +28,11 @@ public function __construct( public function transform(mixed $value, array $options = []): mixed { - if ($value === null && $options['ignore_null']) { + if (null === $value && $options['ignore_null']) { return null; } - if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $options['property_path'])) { + if ($options['ignore_missing'] && !$this->accessor->isReadable($value, $options['property_path'])) { return null; } @@ -40,7 +40,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/RecursivePropertySetterTransformer.php index f9f487ed..e623b988 100644 --- a/src/Transformer/RecursivePropertySetterTransformer.php +++ b/src/Transformer/RecursivePropertySetterTransformer.php @@ -14,13 +14,12 @@ namespace CleverAge\ProcessBundle\Transformer; use CleverAge\ProcessBundle\Exception\TransformerException; -use stdClass; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Read a property from the input value and return it + * Read a property from the input value and return it. */ class RecursivePropertySetterTransformer implements ConfigurableTransformerInterface { @@ -31,25 +30,25 @@ public function __construct( public function transform(mixed $value, array $options = []): mixed { - if ($value === null && $options['ignore_null']) { + if (null === $value && $options['ignore_null']) { return null; } - if ($options['ignore_missing'] && ! $this->accessor->isReadable($value, $options['iterator'])) { + if ($options['ignore_missing'] && !$this->accessor->isReadable($value, $options['iterator'])) { return null; } $iterable = $this->accessor->getValue($value, $options['iterator']); - if (! is_iterable($iterable)) { + if (!is_iterable($iterable)) { throw new TransformerException($options['iterator']); } $protertiesToSet = []; foreach ($options['set_properties'] as $propertyName => $propertyValuePath) { $protertiesValue = null; - if (! $options['ignore_missing'] || $this->accessor->isReadable($value, $propertyValuePath)) { + if (!$options['ignore_missing'] || $this->accessor->isReadable($value, $propertyValuePath)) { $protertiesValue = $this->accessor->getValue($value, $propertyValuePath); - if ($protertiesValue === null && ! $options['ignore_null']) { + if (null === $protertiesValue && !$options['ignore_null']) { throw new TransformerException($propertyValuePath); } } @@ -61,7 +60,7 @@ public function transform(mixed $value, array $options = []): mixed try { $this->accessor->setValue($item, $protertyName, $propertyValue); } catch (NoSuchPropertyException $e) { - if ($item instanceof stdClass) { + if ($item instanceof \stdClass) { $item = (object) array_merge((array) $item, [ $protertyName => $propertyValue, ]); @@ -76,7 +75,7 @@ public function transform(mixed $value, array $options = []): mixed } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index 2ce44a25..c3d68c5f 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -14,14 +14,13 @@ namespace CleverAge\ProcessBundle\Transformer; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use InvalidArgumentException; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\ExpressionLanguage\ParsedExpression; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Uses a set of rules to conditionally transform a value + * Uses a set of rules to conditionally transform a value. */ class RulesTransformer implements ConfigurableTransformerInterface { @@ -77,13 +76,13 @@ public function configureOptions(OptionsResolver $resolver): void foreach ($rules as $rule) { if ($rule['default']) { if ($hasFoundDefault) { - throw new InvalidArgumentException('Rules set cannot have more than 2 default rules'); + throw new \InvalidArgumentException('Rules set cannot have more than 2 default rules'); } $hasFoundDefault = true; } - if ($hasFoundDefault && $rule['condition'] !== null) { - throw new InvalidArgumentException('A conditional rule cannot be placed after a default rule'); + if ($hasFoundDefault && null !== $rule['condition']) { + throw new \InvalidArgumentException('A conditional rule cannot be placed after a default rule'); } } @@ -92,7 +91,7 @@ public function configureOptions(OptionsResolver $resolver): void } /** - * Configure options for one "rule" block + * Configure options for one "rule" block. */ public function configureRuleOptions(OptionsResolver $resolver, ?array $expressionVariables = null): void { @@ -107,16 +106,17 @@ public function configureRuleOptions(OptionsResolver $resolver, ?array $expressi $resolver->setAllowedTypes('set_null', 'bool'); $expressionNormalizer = function (Options $options, $expression) use ($expressionVariables) { - if (is_array($expressionVariables) && $expression !== null) { + if (\is_array($expressionVariables) && null !== $expression) { return $this->language->parse($expression, $expressionVariables); } + return $expression; }; $resolver->setNormalizer('condition', $expressionNormalizer); $resolver->setNormalizer('default', function (Options $options, $value) { if ($value && $options['condition']) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( 'A rule cannot have a condition and be the default in the same time' ); } @@ -128,11 +128,11 @@ public function configureRuleOptions(OptionsResolver $resolver, ?array $expressi } /** - * Test if a value match a rule + * Test if a value match a rule. */ protected function matchRule(mixed $value, string|ParsedExpression $rule, bool $useValueAsVariable): bool { - if ($rule['condition'] !== null) { + if (null !== $rule['condition']) { $expressionValues = $useValueAsVariable ? $value : [ 'value' => $value, ]; diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php index 34241a3e..505968ed 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/SlugifyTransformer.php @@ -15,16 +15,15 @@ use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Transliterator; /** - * Slugify a value + * Slugify a value. */ class SlugifyTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): string { - /** @var Transliterator $transliterator */ + /** @var \Transliterator $transliterator */ $transliterator = $options['transliterator']; $string = $transliterator->transliterate($value); @@ -39,7 +38,7 @@ public function transform(mixed $value, array $options = []): string } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { @@ -58,7 +57,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'transliterator', - static fn (Options $options, $value): ?Transliterator => Transliterator::create($value) + static fn (Options $options, $value): ?\Transliterator => \Transliterator::create($value) ); } } diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php index 8fb584e8..cf920733 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/SprintfTransformer.php @@ -14,16 +14,15 @@ namespace CleverAge\ProcessBundle\Transformer; use Symfony\Component\OptionsResolver\OptionsResolver; -use function is_array; /** - * Use sprintf() function to format string + * Use sprintf() function to format string. */ class SprintfTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, array $options = []): string { - if (! is_array($value)) { + if (!\is_array($value)) { $value = [$value]; } diff --git a/src/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php index d9401d2d..63a38eab 100644 --- a/src/Transformer/TransformerInterface.php +++ b/src/Transformer/TransformerInterface.php @@ -14,17 +14,17 @@ namespace CleverAge\ProcessBundle\Transformer; /** - * Transforms a value to an other + * Transforms a value to an other. */ interface TransformerInterface { /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): mixed; /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string; } diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 098453f5..23a03ae7 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -16,17 +16,15 @@ use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Closure; -use InvalidArgumentException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Throwable; trait TransformerTrait { protected ?TransformerRegistry $transformerRegistry = null; /** - * Transform the list of transformer codes + options into a list of Closure (better performances) + * Transform the list of transformer codes + options into a list of Closure (better performances). */ public function normalizeTransformers(Options $options, array $transformers): array { @@ -40,8 +38,8 @@ public function normalizeTransformers(Options $options, array $transformers): ar if ($transformer instanceof ConfigurableTransformerInterface) { $transformer->configureOptions($transformerOptionsResolver); $transformerOptions = $transformerOptionsResolver->resolve($transformerOptions); - } elseif (! empty($transformerOptions)) { - throw new InvalidArgumentException("Transformer {${$origTransformerCode}} should not have options"); + } elseif (!empty($transformerOptions)) { + throw new \InvalidArgumentException("Transformer {${$origTransformerCode}} should not have options"); } $closure = static fn ($value) => $transformer->transform($value, $transformerOptions); @@ -61,7 +59,7 @@ protected function applyTransformers(array $transformers, mixed $value): mixed foreach ($transformers as $transformerCode => $transformerClosure) { try { $value = $transformerClosure($value); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { throw new TransformerException($transformerCode, 0, $exception); } } @@ -85,7 +83,7 @@ protected function getCleanedTransfomerCode(string $transformerCode): string { $match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts); - if ($match === 1 && $this->transformerRegistry->hasTransformer($parts[1])) { + if (1 === $match && $this->transformerRegistry->hasTransformer($parts[1])) { return $parts[1]; } @@ -102,20 +100,20 @@ protected function configureTransformersOptions( } /** - * Check the options to always return an array, or fail on unexpected values + * Check the options to always return an array, or fail on unexpected values. */ private function checkTransformerOptions(mixed $transformerOptions, string $transformerCode): array { - if (is_array($transformerOptions)) { + if (\is_array($transformerOptions)) { return $transformerOptions; } - if ($transformerOptions === null) { + if (null === $transformerOptions) { return []; } $type = get_debug_type($transformerOptions); - throw new InvalidArgumentException( + throw new \InvalidArgumentException( "Options for transformer {$transformerCode} are invalid : found {$type}, expected array or null" ); } diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index c6d1c586..e0659510 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -18,19 +18,19 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Trim an input based on specific characters + * Trim an input based on specific characters. */ class TrimTransformer implements ConfigurableTransformerInterface { public function transform(mixed $value, ?array $options = []): ?string { - if ($options === null || $options === []) { + if (null === $options || [] === $options) { $options = [ 'charlist' => " \t\n\r\0\x0B", ]; } - if ($value === null) { + if (null === $value) { return null; } @@ -38,7 +38,7 @@ public function transform(mixed $value, ?array $options = []): ?string } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php index c74b3fc8..c0783a29 100644 --- a/src/Transformer/TypeSetterTransformer.php +++ b/src/Transformer/TypeSetterTransformer.php @@ -32,7 +32,7 @@ public function transform(mixed $value, array $options = []): mixed { $return = settype($value, $options['type']); - if ($return === true) { + if (true === $return) { return $value; } diff --git a/src/Transformer/UnsetTransformer.php b/src/Transformer/UnsetTransformer.php index 39c27718..736ea535 100644 --- a/src/Transformer/UnsetTransformer.php +++ b/src/Transformer/UnsetTransformer.php @@ -15,11 +15,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use UnexpectedValueException; -use function is_array; /** - * Unset a given property + * Unset a given property. */ class UnsetTransformer implements ConfigurableTransformerInterface { @@ -32,12 +30,12 @@ public function __construct(PropertyAccessorInterface $accessor) public function transform(mixed $value, array $options = []): array { - if (! is_array($value)) { - throw new UnexpectedValueException('Given value must be an array'); + if (!\is_array($value)) { + throw new \UnexpectedValueException('Given value must be an array'); } - if (! array_key_exists($options['property'], $value)) { - throw new UnexpectedValueException("Property {$options['property']} does not exists"); + if (!\array_key_exists($options['property'], $value)) { + throw new \UnexpectedValueException("Property {$options['property']} does not exists"); } if ($this->checkCondition($value, $options['condition'])) { diff --git a/src/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php index 46c5b9fc..d7a3e2ca 100644 --- a/src/Transformer/WrapperTransformer.php +++ b/src/Transformer/WrapperTransformer.php @@ -18,7 +18,7 @@ class WrapperTransformer implements ConfigurableTransformerInterface { /** - * Must return the transformed $value + * Must return the transformed $value. */ public function transform(mixed $value, array $options = []): array { @@ -36,7 +36,7 @@ public function configureOptions(OptionsResolver $resolver): void } /** - * Returns the unique code to identify the transformer + * Returns the unique code to identify the transformer. */ public function getCode(): string { diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index 20e32080..af291e59 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -14,21 +14,11 @@ namespace CleverAge\ProcessBundle\Transformer\Xml; use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; -use DOMAttr; -use DOMDocument; -use DOMNode; -use DOMText; -use DOMXPath; -use InvalidArgumentException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; -use function array_map; -use function is_array; -use function is_string; /** - * Manipulate XML elements using xpath + * Manipulate XML elements using xpath. */ class XpathEvaluatorTransformer implements ConfigurableTransformerInterface { @@ -38,12 +28,12 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('query', ['string', 'array']); $resolver->setNormalizer('query', function (Options $options, $value): string|array { // Basic case : a single query - if (is_string($value)) { + if (\is_string($value)) { return $value; } // Complex case : a list of subqueries, each can override root level options - if (is_array($value)) { + if (\is_array($value)) { $queryOptions = []; $queryResolver = new OptionsResolver(); $this->configureQueryOptions($queryResolver, $options); @@ -51,7 +41,7 @@ public function configureOptions(OptionsResolver $resolver): void $queryResolver->setAllowedTypes('subquery', 'string'); foreach ($value as $code => $subquery) { - if (is_string($subquery)) { + if (\is_string($subquery)) { $subquery = [ 'subquery' => $subquery, ]; @@ -64,7 +54,7 @@ public function configureOptions(OptionsResolver $resolver): void } // This should never be reached - throw new InvalidArgumentException('Unhandled query'); + throw new \InvalidArgumentException('Unhandled query'); }); // Use same options & defaults for root option level and subquery options @@ -75,7 +65,7 @@ public function configureOptions(OptionsResolver $resolver): void * Configure options about how to handle xpath query results. * Available at root and subquery level. */ - public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null): void + public function configureQueryOptions(OptionsResolver $resolver, ?Options $parentOptions = null): void { $resolver->setDefault('single_result', $parentOptions ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); @@ -89,15 +79,15 @@ public function configureQueryOptions(OptionsResolver $resolver, Options $parent public function transform(mixed $value, array $options = []): mixed { - if (! $value instanceof DOMNode) { - throw new UnexpectedValueException('Input should be a ' . DOMNode::class); + if (!$value instanceof \DOMNode) { + throw new \UnexpectedValueException('Input should be a '.\DOMNode::class); } $xpath = $this->buildXpath($value); $query = $options['query']; - if (is_array($query)) { - $result = array_map( + if (\is_array($query)) { + $result = \array_map( fn ($subquery): mixed => $this->query($xpath, $subquery['subquery'], $value, $subquery), $query ); @@ -113,14 +103,14 @@ public function getCode(): string return 'xpath_evaluator'; } - public function buildXpath(DOMNode $node): DOMXPath + public function buildXpath(\DOMNode $node): \DOMXPath { - $doc = $node instanceof DOMDocument ? $node : $node->ownerDocument; + $doc = $node instanceof \DOMDocument ? $node : $node->ownerDocument; - return new DOMXPath($doc); + return new \DOMXPath($doc); } - public function query(DOMXPath $xpath, string $query, DOMNode $node, array $options): mixed + public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $options): mixed { // TODO check if query is relative ? $nodeList = $xpath->query($query, $node); @@ -128,31 +118,31 @@ public function query(DOMXPath $xpath, string $query, DOMNode $node, array $opti // Convert results to text if ($options['unwrap_value']) { - $results = array_map(static function (DOMNode $item) use ($query): string { - if ($item instanceof DOMAttr) { + $results = \array_map(static function (\DOMNode $item) use ($query): string { + if ($item instanceof \DOMAttr) { return $item->value; } - if ($item instanceof DOMText) { + if ($item instanceof \DOMText) { // If you have an error, remember that you may need to use the "text()" xpath selector return $item->textContent; } - throw new UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); + throw new \UnexpectedValueException("Xpath result cannot be unwrapped for query '{$query}'"); }, $results); } // Unwrap the node list if ($options['single_result']) { - if (count($results) > 1) { - throw new UnexpectedValueException("There is too much results for query '{$query}'"); + if (\count($results) > 1) { + throw new \UnexpectedValueException("There is too much results for query '{$query}'"); } - if (! $options['ignore_missing'] && count($results) === 0) { - throw new UnexpectedValueException("There is not enough results for query '{$query}'"); + if (!$options['ignore_missing'] && 0 === \count($results)) { + throw new \UnexpectedValueException("There is not enough results for query '{$query}'"); } - if (count($results) === 1) { + if (1 === \count($results)) { $results = $results[0]; } else { $results = null; diff --git a/src/Validator/ConstraintLoader.php b/src/Validator/ConstraintLoader.php index d698c7c6..3bbb384b 100644 --- a/src/Validator/ConstraintLoader.php +++ b/src/Validator/ConstraintLoader.php @@ -15,8 +15,6 @@ use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Loader\AbstractLoader; -use function count; -use function is_array; class ConstraintLoader extends AbstractLoader { @@ -26,7 +24,8 @@ public function loadClassMetadata(ClassMetadata $metadata): bool } /** - * Build constraints from textual data + * Build constraints from textual data. + * * @see \Symfony\Component\Validator\Mapping\Loader\YamlFileLoader::parseNodes */ public function buildConstraints(array $nodes): array @@ -34,16 +33,16 @@ public function buildConstraints(array $nodes): array $values = []; foreach ($nodes as $name => $childNodes) { - if (is_numeric($name) && is_array($childNodes) && count($childNodes) === 1) { + if (is_numeric($name) && \is_array($childNodes) && 1 === \count($childNodes)) { $options = current($childNodes); - if (is_array($options)) { + if (\is_array($options)) { $options = $this->buildConstraints($options); } $values[] = $this->newConstraint(key($childNodes), $options); } else { - if (is_array($childNodes)) { + if (\is_array($childNodes)) { $childNodes = $this->buildConstraints($childNodes); } diff --git a/tests.old/AbstractProcessTest.php b/tests.old/AbstractProcessTest.php index 75e07ce8..d8a1be5f 100644 --- a/tests.old/AbstractProcessTest.php +++ b/tests.old/AbstractProcessTest.php @@ -24,7 +24,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Provide all necessary setup to test a process + * Provide all necessary setup to test a process. */ abstract class AbstractProcessTest extends KernelTestCase { @@ -44,7 +44,7 @@ abstract class AbstractProcessTest extends KernelTestCase protected $transformerRegistry; /** - * Initialize DI + * Initialize DI. */ protected function setUp(): void { @@ -60,7 +60,7 @@ protected function setUp(): void /** * Assert that an array of values match what's been registered in the standard queue - * It can also match task codes using the checkTask flag + * It can also match task codes using the checkTask flag. */ protected function assertDataQueue(array $expected, string $processName, bool $checkTask = true) { @@ -77,7 +77,7 @@ protected function assertDataQueue(array $expected, string $processName, bool $c foreach ($actualQueue as $key => $value) { self::assertArrayHasKey($key, $expected); if ($checkTask) { - if (array_key_exists('task', $expected[$key])) { + if (\array_key_exists('task', $expected[$key])) { self::assertEquals( $expected[$key]['task'], $value->getPreviousState() @@ -86,7 +86,7 @@ protected function assertDataQueue(array $expected, string $processName, bool $c "Task #{$key} does not match" ); } - if (array_key_exists('value', $expected[$key])) { + if (\array_key_exists('value', $expected[$key])) { self::assertEquals($expected[$key]['value'], $value->getInput(), "Value #{$key} does not match"); } } else { @@ -96,7 +96,7 @@ protected function assertDataQueue(array $expected, string $processName, bool $c } /** - * Returns the booted symfony container + * Returns the booted symfony container. * * Compatibility backport for symfony/phpunit-bridge that should work with v3 or v4 */ @@ -113,7 +113,7 @@ protected static function getContainer(): ContainerInterface } /** - * Helper method to configure options and test a transformation + * Helper method to configure options and test a transformation. */ protected function assertTransformation(string $transformerCode, mixed $expected, mixed $value, array $options = []) { @@ -122,9 +122,7 @@ protected function assertTransformation(string $transformerCode, mixed $expected } /** - * Transform some value using referenced transformer with given options - * - * @return mixed + * Transform some value using referenced transformer with given options. */ protected function transform(string $transformerCode, mixed $value, array $options = []) { diff --git a/tests.old/BasicTest.php b/tests.old/BasicTest.php index c365d557..de19e6a8 100644 --- a/tests.old/BasicTest.php +++ b/tests.old/BasicTest.php @@ -15,22 +15,22 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Test the basic behavior of the process + * Test the basic behavior of the process. */ class BasicTest extends AbstractProcessTest { /** - * Check that an unknown process produce the right error - * - * @expectedException \CleverAge\ProcessBundle\Exception\MissingProcessException + * Check that an unknown process produce the right error. */ public function testUnknownProcess(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\MissingProcessException::class); + $this->processManager->execute('test.unknown_test'); } /** - * Check that a known process can be executed and return defined output + * Check that a known process can be executed and return defined output. */ public function testSimpleProcess(): void { @@ -40,7 +40,7 @@ public function testSimpleProcess(): void } /** - * Assert that the error branch is not called + * Assert that the error branch is not called. */ public function testErrorProcess(): void { @@ -65,7 +65,7 @@ public function testErrorProcess(): void } /** - * Assert that the error branch is called, and blocking task are correctly working + * Assert that the error branch is called, and blocking task are correctly working. */ public function testErrorProcessBlocking(): void { @@ -93,16 +93,15 @@ public function testErrorProcessBlocking(): void ); } - /** - * @expectedException \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException - */ public function testFailingEntryPointWithAncestors(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException::class); + $this->processManager->execute('test.entry_point_with_ancestor'); } /** - * Check that the use of a string in task "outputs" or "errors" is possible + * Check that the use of a string in task "outputs" or "errors" is possible. */ public function testStringOutput(): void { diff --git a/tests.old/BlockingTaskTest.php b/tests.old/BlockingTaskTest.php index 2830d600..26111c29 100644 --- a/tests.old/BlockingTaskTest.php +++ b/tests.old/BlockingTaskTest.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Assert basic behavior for blocking tasks (using the aggregator implementation) + * Assert basic behavior for blocking tasks (using the aggregator implementation). */ class BlockingTaskTest extends AbstractProcessTest { @@ -43,7 +43,7 @@ public function testMultipleBlockingSolo(): void * Assert a process with multiple blocking tasks can execute properly. * Check * - a subsequent blocking task will be proceeded at least once - * - a subsequent blocking task will be proceeded at most once + * - a subsequent blocking task will be proceeded at most once. */ public function testMultipleBlocking(): void { @@ -54,7 +54,7 @@ public function testMultipleBlocking(): void /** * Assert when there is multiple iterations before a blocking that all are successfully resolved, and the blocking - * is executed only once + * is executed only once. */ public function testMultipleIterationBlocking(): void { @@ -72,7 +72,7 @@ public function testMultipleIterationBlocking(): void } /** - * Assert that if a blocking is never executed, it will automatically skip subsequent tasks + * Assert that if a blocking is never executed, it will automatically skip subsequent tasks. */ public function testBlockingEmptyData(): void { diff --git a/tests.old/CircularProcessTest.php b/tests.old/CircularProcessTest.php index b0ccc108..699a9bc7 100644 --- a/tests.old/CircularProcessTest.php +++ b/tests.old/CircularProcessTest.php @@ -15,41 +15,38 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Assert circular dependencies are correctly checked + * Assert circular dependencies are correctly checked. */ class CircularProcessTest extends AbstractProcessTest { - /** - * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException - */ public function testCircularProcess(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\CircularProcessException::class); + $this->processManager->execute('test.circular_process'); } - /** - * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException - */ public function testReversedCircularProcess(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\CircularProcessException::class); + $this->processManager->execute('test.circular_process.reversed'); } - /** - * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException - */ public function testSelfCircularProcess(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\CircularProcessException::class); + $this->processManager->execute('test.circular_process.self'); } /** - * A loop in an independent branch was sometime not properly detected - * - * @expectedException \CleverAge\ProcessBundle\Exception\CircularProcessException + * A loop in an independent branch was sometime not properly detected. */ public function testLongCircularProcess(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\CircularProcessException::class); + $this->processManager->execute('test.circular_process.long'); } } diff --git a/tests.old/ContextTest.php b/tests.old/ContextTest.php index 5c97d8cd..62a6a27e 100644 --- a/tests.old/ContextTest.php +++ b/tests.old/ContextTest.php @@ -14,12 +14,12 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Test context replacement mechanism + * Test context replacement mechanism. */ class ContextTest extends AbstractProcessTest { /** - * Assert a value can correctly passed through context + * Assert a value can correctly passed through context. */ public function testSimpleContext(): void { @@ -39,7 +39,7 @@ public function testSimpleContext(): void } /** - * Assert a value can correctly passed and merged into a string, through context + * Assert a value can correctly passed and merged into a string, through context. */ public function testContextMergedValue(): void { @@ -51,7 +51,7 @@ public function testContextMergedValue(): void } /** - * Assert 2 values can correctly passed and merged into a string, through context + * Assert 2 values can correctly passed and merged into a string, through context. */ public function testContextMultiValue(): void { @@ -68,12 +68,12 @@ public function testContextMultiValue(): void } /** - * Assert a complex value will fail while being merged into a string, through context - * - * @expectedException \RuntimeException + * Assert a complex value will fail while being merged into a string, through context. */ public function testContextCannotMergeValue(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute( 'test.context.merged_value', null, @@ -86,7 +86,7 @@ public function testContextCannotMergeValue(): void } /** - * Assert a complex value can correctly passed through context + * Assert a complex value can correctly passed through context. */ public function testComplexContext(): void { diff --git a/tests.old/EmptyProcessTest.php b/tests.old/EmptyProcessTest.php index ba77fd3a..c1445723 100644 --- a/tests.old/EmptyProcessTest.php +++ b/tests.old/EmptyProcessTest.php @@ -14,12 +14,12 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Check empty process behaviours + * Check empty process behaviours. */ class EmptyProcessTest extends AbstractProcessTest { /** - * Assert an empty process do not fail + * Assert an empty process do not fail. */ public function testEmptyProcess(): void { diff --git a/tests.old/ExceptionManagementTest.php b/tests.old/ExceptionManagementTest.php index 18428e74..449c437a 100644 --- a/tests.old/ExceptionManagementTest.php +++ b/tests.old/ExceptionManagementTest.php @@ -14,12 +14,12 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Asset the behavior of a process when there is an error + * Asset the behavior of a process when there is an error. */ class ExceptionManagementTest extends AbstractProcessTest { /** - * Assert errors in the middle of an iteration does not skip subsequent loops and does not spam "error" flow + * Assert errors in the middle of an iteration does not skip subsequent loops and does not spam "error" flow. */ public function testSetExceptionInTheMiddle(): void { diff --git a/tests.old/FlushableTaskTest.php b/tests.old/FlushableTaskTest.php index 5848aa67..e0b56f45 100644 --- a/tests.old/FlushableTaskTest.php +++ b/tests.old/FlushableTaskTest.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Assert basic behavior for flushable tasks (using the aggregator implementation) + * Assert basic behavior for flushable tasks (using the aggregator implementation). */ class FlushableTaskTest extends AbstractProcessTest { diff --git a/tests.old/IterableTaskTest.php b/tests.old/IterableTaskTest.php index 38761e5c..2b7e227b 100644 --- a/tests.old/IterableTaskTest.php +++ b/tests.old/IterableTaskTest.php @@ -16,7 +16,7 @@ class IterableTaskTest extends AbstractProcessTest { /** - * Check the execution order of a process containing one iterable loop and a blocking task + * Check the execution order of a process containing one iterable loop and a blocking task. */ public function testIterableProcess(): void { @@ -67,7 +67,7 @@ public function testIterableProcess(): void /** * Assert 2 iterators can run alone, without a subsequent blocking task - * Assert \CleverAge\ProcessBundle\Task\InputIteratorTask can correctly reset + * Assert \CleverAge\ProcessBundle\Task\InputIteratorTask can correctly reset. */ public function testDoubleIterableAlone(): void { @@ -97,7 +97,7 @@ public function testDoubleIterableAlone(): void } /** - * Assert the SplitJoinLineTask works the way it's supposed to + * Assert the SplitJoinLineTask works the way it's supposed to. */ public function testSplitJoinLine(): void { diff --git a/tests.old/MultiBranchProcessTest.php b/tests.old/MultiBranchProcessTest.php index b857db40..c4b8b43a 100644 --- a/tests.old/MultiBranchProcessTest.php +++ b/tests.old/MultiBranchProcessTest.php @@ -15,12 +15,12 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Assert multiple branch processes are correctly checked + * Assert multiple branch processes are correctly checked. */ class MultiBranchProcessTest extends AbstractProcessTest { /** - * Assert only one branch is called + * Assert only one branch is called. */ public function testMultiBranchProcess(): void { @@ -106,12 +106,12 @@ public function testMainGroupOrder(): void } /** - * Assert a task cannot be started if the process is not valid - * - * @expectedException \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException + * Assert a task cannot be started if the process is not valid. */ public function testMultiBranchProcessError(): void { + $this->setExpectedException(\CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException::class); + $this->processManager->execute('test.multi_branch_process_entry_end_error'); } } diff --git a/tests.old/MultiWorkflowTest.php b/tests.old/MultiWorkflowTest.php index 6b9b93e9..3a20f625 100644 --- a/tests.old/MultiWorkflowTest.php +++ b/tests.old/MultiWorkflowTest.php @@ -14,7 +14,7 @@ namespace CleverAge\ProcessBundle\Tests; /** - * Assert the behavior of multiple-branch workflow + * Assert the behavior of multiple-branch workflow. */ class MultiWorkflowTest extends AbstractProcessTest { diff --git a/tests.old/Task/FilterTaskTest.php b/tests.old/Task/FilterTaskTest.php index ebd9b8bd..8d6caf56 100644 --- a/tests.old/Task/FilterTaskTest.php +++ b/tests.old/Task/FilterTaskTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Assert the correct behavior of the filter task + * Assert the correct behavior of the filter task. */ class FilterTaskTest extends AbstractProcessTest { /** - * Assert simple matching/empty filters + * Assert simple matching/empty filters. */ public function testFilterMatch(): void { diff --git a/tests.old/Task/ProcessExecutorTaskTest.php b/tests.old/Task/ProcessExecutorTaskTest.php index 86e9f9b6..35309169 100644 --- a/tests.old/Task/ProcessExecutorTaskTest.php +++ b/tests.old/Task/ProcessExecutorTaskTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for the ProcessExecutorTask + * Tests for the ProcessExecutorTask. */ class ProcessExecutorTaskTest extends AbstractProcessTest { /** - * Assert the process executor correctly chain the input/output + * Assert the process executor correctly chain the input/output. */ public function testExecutor(): void { @@ -30,12 +30,12 @@ public function testExecutor(): void } /** - * Assert correct error if it doesn't match a good subprocess name - * - * @expectedException \RuntimeException + * Assert correct error if it doesn't match a good subprocess name. */ public function testExecutorError(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.process_execute_task.error'); } } diff --git a/tests.old/Task/StopTaskTest.php b/tests.old/Task/StopTaskTest.php index 167426c7..617824c3 100644 --- a/tests.old/Task/StopTaskTest.php +++ b/tests.old/Task/StopTaskTest.php @@ -18,7 +18,7 @@ class StopTaskTest extends AbstractProcessTest { /** - * Assert the iteration is stopped at the right time + * Assert the iteration is stopped at the right time. */ public function testIterableInterruption(): void { diff --git a/tests.old/Task/TransformerTaskTest.php b/tests.old/Task/TransformerTaskTest.php index 55ef5aa9..46bc3374 100644 --- a/tests.old/Task/TransformerTaskTest.php +++ b/tests.old/Task/TransformerTaskTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for the TransformerTask + * Tests for the TransformerTask. */ class TransformerTaskTest extends AbstractProcessTest { /** - * Assert a simple transformation, from one array to another + * Assert a simple transformation, from one array to another. */ public function testSimpleMapping(): void { @@ -33,17 +33,17 @@ public function testSimpleMapping(): void } /** - * Assert that if "ignore_missing" is false, then an error is thrown for missing fields - * - * @expectedException \RuntimeException + * Assert that if "ignore_missing" is false, then an error is thrown for missing fields. */ public function testMissingMapping(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.transformer_task.error', 'value'); } /** - * Assert we can use multiple times the same sub-transformer using # suffixes + * Assert we can use multiple times the same sub-transformer using # suffixes. */ public function testMultiSubtransformers(): void { diff --git a/tests.old/Task/ValidatorTaskTest.php b/tests.old/Task/ValidatorTaskTest.php index a464bc8e..efb1d62b 100644 --- a/tests.old/Task/ValidatorTaskTest.php +++ b/tests.old/Task/ValidatorTaskTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for the ValidatorTask + * Tests for the ValidatorTask. */ class ValidatorTaskTest extends AbstractProcessTest { /** - * Assert the input is Valid and no error is thrown + * Assert the input is Valid and no error is thrown. */ public function testSimpleValidation(): void { diff --git a/tests.old/Transformer/ArrayFilterTransformerTest.php b/tests.old/Transformer/ArrayFilterTransformerTest.php index 65644b89..3188289b 100644 --- a/tests.old/Transformer/ArrayFilterTransformerTest.php +++ b/tests.old/Transformer/ArrayFilterTransformerTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Test suite for ArrayFilterTransformer + * Test suite for ArrayFilterTransformer. */ class ArrayFilterTransformerTest extends AbstractProcessTest { /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testSimpleFilter(): void { @@ -54,7 +54,7 @@ public function testSimpleFilter(): void $nativeResult = array_filter( $input, - static fn ($item): bool => isset($item['filter_value']) && $item['filter_value'] === 'X' + static fn ($item): bool => isset($item['filter_value']) && 'X' === $item['filter_value'] ); // Note that to match native function, key are preserved diff --git a/tests.old/Transformer/CallbackTransformerTest.php b/tests.old/Transformer/CallbackTransformerTest.php index 93b51e0a..72795ae9 100644 --- a/tests.old/Transformer/CallbackTransformerTest.php +++ b/tests.old/Transformer/CallbackTransformerTest.php @@ -16,17 +16,17 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Test suite for CallbackTransformerTest + * Test suite for CallbackTransformerTest. */ class CallbackTransformerTest extends AbstractProcessTest { public static function doCallback(): string { - return implode('-', func_get_args()); + return implode('-', \func_get_args()); } /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testSimpleCallback(): void { @@ -38,7 +38,7 @@ public function testSimpleCallback(): void } /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testLeftParametersCallback(): void { @@ -50,7 +50,7 @@ public function testLeftParametersCallback(): void } /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testRightParametersCallback(): void { @@ -62,7 +62,7 @@ public function testRightParametersCallback(): void } /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testAdditionalParametersCallback(): void { @@ -74,7 +74,7 @@ public function testAdditionalParametersCallback(): void } /** - * Assert data is correctly filtered + * Assert data is correctly filtered. */ public function testLeftAndRightParametersCallback(): void { diff --git a/tests.old/Transformer/DateTransformersTest.php b/tests.old/Transformer/DateTransformersTest.php index e4f16b14..15eba89e 100644 --- a/tests.old/Transformer/DateTransformersTest.php +++ b/tests.old/Transformer/DateTransformersTest.php @@ -14,15 +14,14 @@ namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; -use DateTime; /** - * Tests for Date transformers + * Tests for Date transformers. */ class DateTransformersTest extends AbstractProcessTest { /** - * Assert a date string can be formatted into another string + * Assert a date string can be formatted into another string. */ public function testDateFormatString(): void { @@ -31,45 +30,45 @@ public function testDateFormatString(): void } /** - * Assert a date object can be formatted into a string + * Assert a date object can be formatted into a string. */ public function testDateFormatObject(): void { - $date = DateTime::createFromFormat(DATE_ATOM, '2001-01-02T00:00:00+00:00'); + $date = \DateTime::createFromFormat(\DATE_ATOM, '2001-01-02T00:00:00+00:00'); $result = $this->processManager->execute('test.date_transformers.date_format', $date); self::assertEquals('2001-01-02', $result); } /** - * Assert a date can be parsed using a given format + * Assert a date can be parsed using a given format. */ public function testDateParser(): void { - $date = DateTime::createFromFormat('d/m/Y', '01/01/2001'); + $date = \DateTime::createFromFormat('d/m/Y', '01/01/2001'); $result = $this->processManager->execute('test.date_transformers.date_parser', '2001-01-01'); // There could be a 1s difference, depending on execution time... $date->setTime(0, 0); $result->setTime(0, 0); - self::assertInstanceOf(DateTime::class, $result); - if ($result instanceof DateTime) { + self::assertInstanceOf(\DateTime::class, $result); + if ($result instanceof \DateTime) { self::assertEquals($date->getTimestamp(), $result->getTimestamp()); } } /** - * Assert that a date is not parsed if the format doesn't match - * - * @expectedException \RuntimeException + * Assert that a date is not parsed if the format doesn't match. */ public function testDateParserError(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.date_transformers.date_parser', '2001-01-01T00:00:00+00:00'); } /** - * Assert date parser & formatter can be chained to transform a date string into another + * Assert date parser & formatter can be chained to transform a date string into another. */ public function testDateParseFormat(): void { diff --git a/tests.old/Transformer/HashTransformerTest.php b/tests.old/Transformer/HashTransformerTest.php index e813339e..16c74980 100644 --- a/tests.old/Transformer/HashTransformerTest.php +++ b/tests.old/Transformer/HashTransformerTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for Hash transformer + * Tests for Hash transformer. */ class HashTransformerTest extends AbstractProcessTest { /** - * Assert a string can be hash in md5 + * Assert a string can be hash in md5. */ public function testMd5Hash(): void { @@ -30,7 +30,7 @@ public function testMd5Hash(): void } /** - * Assert a string can be hash in sha512 + * Assert a string can be hash in sha512. */ public function testSha512Hash(): void { diff --git a/tests.old/Transformer/MappingTransformerTest.php b/tests.old/Transformer/MappingTransformerTest.php index 3008482a..c3156adb 100644 --- a/tests.old/Transformer/MappingTransformerTest.php +++ b/tests.old/Transformer/MappingTransformerTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for the MappingTransformer + * Tests for the MappingTransformer. */ class MappingTransformerTest extends AbstractProcessTest { /** - * Assert a simple mapping transformation, from one array to another + * Assert a simple mapping transformation, from one array to another. */ public function testSimpleMapping(): void { @@ -35,19 +35,19 @@ public function testSimpleMapping(): void } /** - * Assert that if "ignore_missing" is false, then an error is thrown for missing fields - * - * @expectedException \RuntimeException + * Assert that if "ignore_missing" is false, then an error is thrown for missing fields. */ public function testMissingMapping(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.mapping_transformer.error', [ 'field' => 'value', ]); } /** - * Assert we can use multiple times the same sub-transformer using # suffixes + * Assert we can use multiple times the same sub-transformer using # suffixes. */ public function testMultiSubtransformers(): void { @@ -64,7 +64,7 @@ public function testMultiSubtransformers(): void } /** - * Assert we can use a deep property path as a key to generate a multi-depth array + * Assert we can use a deep property path as a key to generate a multi-depth array. */ public function testDeepMapping(): void { @@ -82,7 +82,7 @@ public function testDeepMapping(): void } /** - * Test the '.' source property path + * Test the '.' source property path. */ public function testFullInput(): void { @@ -98,7 +98,7 @@ public function testFullInput(): void } /** - * Test the '.' source property path inside an array of source codes + * Test the '.' source property path inside an array of source codes. */ public function testFullInputInArray(): void { @@ -117,7 +117,7 @@ public function testFullInputInArray(): void } /** - * Test that a source property can be an array with numeric keys (see commit e141cb61) + * Test that a source property can be an array with numeric keys (see commit e141cb61). */ public function testMultiSourceFieldInSequence(): void { diff --git a/tests.old/Transformer/RulesTransformerTest.php b/tests.old/Transformer/RulesTransformerTest.php index df4ffcc9..40375bbf 100644 --- a/tests.old/Transformer/RulesTransformerTest.php +++ b/tests.old/Transformer/RulesTransformerTest.php @@ -18,7 +18,7 @@ class RulesTransformerTest extends AbstractProcessTest { /** - * Assert basic rules types + * Assert basic rules types. */ public function testSimpleRule(): void { diff --git a/tests.old/Transformer/TransformerExceptionTest.php b/tests.old/Transformer/TransformerExceptionTest.php index 1f015c6c..7052ef9b 100644 --- a/tests.old/Transformer/TransformerExceptionTest.php +++ b/tests.old/Transformer/TransformerExceptionTest.php @@ -15,20 +15,18 @@ use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; -use Exception; -use RuntimeException; class TransformerExceptionTest extends AbstractProcessTest { /** - * Basic test cas with a simple error chain + * Basic test cas with a simple error chain. */ public function testErrorMessageChain(): void { - $origException = new Exception('OriginalError'); + $origException = new \Exception('OriginalError'); $transformerException = $origException; - for ($i = 0; $i < 10; $i++) { + for ($i = 0; $i < 10; ++$i) { $transformerException = new TransformerException("sub_transformer_{$i}", 0, $transformerException); } @@ -36,7 +34,7 @@ public function testErrorMessageChain(): void } /** - * Simple test case using a simulated error inside a mapping transformer and array_map transformers + * Simple test case using a simulated error inside a mapping transformer and array_map transformers. */ public function testDeepError(): void { @@ -52,7 +50,7 @@ public function testDeepError(): void $message = null; try { $this->processManager->execute('test.transformer_exception.deep', $input); - } catch (RuntimeException $exception) { + } catch (\RuntimeException $exception) { $message = $exception->getMessage(); } diff --git a/tests.old/Transformer/TypeSetterTransformerTest.php b/tests.old/Transformer/TypeSetterTransformerTest.php index a7f4dfdc..da8e88f1 100644 --- a/tests.old/Transformer/TypeSetterTransformerTest.php +++ b/tests.old/Transformer/TypeSetterTransformerTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for type setter transformer + * Tests for type setter transformer. */ class TypeSetterTransformerTest extends AbstractProcessTest { /** - * Assert int to int convertion + * Assert int to int convertion. */ public function testIntToInt(): void { @@ -30,7 +30,7 @@ public function testIntToInt(): void } /** - * Assert string to int convertion + * Assert string to int convertion. */ public function testStringToInt(): void { @@ -39,7 +39,7 @@ public function testStringToInt(): void } /** - * Assert int to string convertion + * Assert int to string convertion. */ public function testIntToString(): void { diff --git a/tests.old/Transformer/UnsetTransformerTest.php b/tests.old/Transformer/UnsetTransformerTest.php index 9f26fbd0..6562800f 100644 --- a/tests.old/Transformer/UnsetTransformerTest.php +++ b/tests.old/Transformer/UnsetTransformerTest.php @@ -16,12 +16,12 @@ use CleverAge\ProcessBundle\Tests\AbstractProcessTest; /** - * Tests for the UnsetTransformer + * Tests for the UnsetTransformer. */ class UnsetTransformerTest extends AbstractProcessTest { /** - * Assert the transformer can do a simple unset + * Assert the transformer can do a simple unset. */ public function testSimpleUnset(): void { @@ -38,7 +38,7 @@ public function testSimpleUnset(): void } /** - * Assert a few simple condition can trigger unset (or not) + * Assert a few simple condition can trigger unset (or not). */ public function testConditionalUnset(): void { @@ -82,22 +82,22 @@ public function testConditionalUnset(): void } /** - * Assert the transformer detect wrong types - * - * @expectedException \RuntimeException + * Assert the transformer detect wrong types. */ public function testWrongUnsetString(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.unset_transformer.simple', 'not an array'); } /** - * Assert the transformer detect wrong values - * - * @expectedException \RuntimeException + * Assert the transformer detect wrong values. */ public function testWrongUnsetMissingProperty(): void { + $this->setExpectedException(\RuntimeException::class); + $this->processManager->execute('test.unset_transformer.simple', ['no property found']); } } diff --git a/tests.old/Transformer/XpathEvaluatorTransformerTest.php b/tests.old/Transformer/XpathEvaluatorTransformerTest.php index f373c089..c0c808e4 100644 --- a/tests.old/Transformer/XpathEvaluatorTransformerTest.php +++ b/tests.old/Transformer/XpathEvaluatorTransformerTest.php @@ -15,17 +15,15 @@ namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; -use DOMDocument; -use DOMNodeList; /** - * Test the xpath_evaluator transformer + * Test the xpath_evaluator transformer. */ class XpathEvaluatorTransformerTest extends AbstractProcessTest { public function testSimpleQuery(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok'); $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ 'query' => '/a/text()', @@ -34,7 +32,7 @@ public function testSimpleQuery(): void public function testAttributeValueQuery(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ko'); $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ 'query' => '/node/@data', @@ -43,7 +41,7 @@ public function testAttributeValueQuery(): void public function testSubQuery(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -54,7 +52,7 @@ public function testSubQuery(): void public function testMultiResults(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -66,11 +64,11 @@ public function testMultiResults(): void public function testMultiResultsAsNodeList(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; - /** @var DOMNodeList $result */ + /** @var \DOMNodeList $result */ $result = $this->transform('xpath_evaluator', $node, [ 'query' => './c/text()', 'single_result' => false, @@ -85,7 +83,7 @@ public function testMultiResultsAsNodeList(): void public function testMultiQuery(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -96,7 +94,7 @@ public function testMultiQuery(): void public function testMultiQueryWithKey(): void { - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML('ok1ok2ok3'); $node = $domDocument->getElementsByTagName('b')[0]; @@ -130,7 +128,7 @@ public function testOverridableSubqueries(): void XML; - $domDocument = new DOMDocument(); + $domDocument = new \DOMDocument(); $domDocument->loadXML($xml); $node = $domDocument->getElementsByTagName('b')[0]; diff --git a/tests/Exception/MissingTransformerExceptionTest.php b/tests/Exception/MissingTransformerExceptionTest.php index 4e3631f1..b8a3f310 100644 --- a/tests/Exception/MissingTransformerExceptionTest.php +++ b/tests/Exception/MissingTransformerExceptionTest.php @@ -6,7 +6,6 @@ use CleverAge\ProcessBundle\Exception\MissingTransformerException; use PHPUnit\Framework\TestCase; -use UnexpectedValueException; class MissingTransformerExceptionTest extends TestCase { @@ -17,7 +16,7 @@ public function testCreate(): void { $exception = MissingTransformerException::create('my_transformer'); - $this->assertInstanceOf(UnexpectedValueException::class, $exception); + $this->assertInstanceOf(\UnexpectedValueException::class, $exception); $this->assertEquals('No transformer with code : my_transformer', $exception->getMessage()); } } diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/ArrayElementTransformerTest.php index c038dbb8..a8d4a841 100644 --- a/tests/Transformer/ArrayElementTransformerTest.php +++ b/tests/Transformer/ArrayElementTransformerTest.php @@ -13,9 +13,9 @@ namespace Transformer; +use CleverAge\ProcessBundle\Transformer\ArrayElementTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use CleverAge\ProcessBundle\Transformer\ArrayElementTransformer; class ArrayElementTransformerTest extends TestCase { diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/ArrayFirstTransformerTest.php index 90dad74b..d7daac4f 100644 --- a/tests/Transformer/ArrayFirstTransformerTest.php +++ b/tests/Transformer/ArrayFirstTransformerTest.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use TypeError; class ArrayFirstTransformerTest extends TestCase { @@ -39,7 +38,7 @@ public function testTransformReturnsFirstElementIfIterableAndAllowed(): void */ public function testTransformReturnsValueIfNotIterableAndAllowed(): void { - $this->expectException(TypeError::class); + $this->expectException(\TypeError::class); $transformer = new ArrayFirstTransformer(); $value = 'not_iterable_value'; diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index f9a1989b..c443184c 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Transformer\CastTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use ValueError; class CastTransformerTest extends TestCase { @@ -89,7 +88,7 @@ public function testCastToInvalidType(): void $value = '123'; $options = ['type' => 'invalid_type']; - $this->expectException(ValueError::class); + $this->expectException(\ValueError::class); $transformer->transform($value, $options); } diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index 35cdd88c..a57d4ae9 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -13,7 +13,6 @@ namespace Transformer; -use CleverAge\ProcessBundle\Transformer\ArrayElementTransformer; use CleverAge\ProcessBundle\Transformer\ConstantTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/DateFormatTransformerTest.php index 4277bf9b..2cb244d4 100644 --- a/tests/Transformer/DateFormatTransformerTest.php +++ b/tests/Transformer/DateFormatTransformerTest.php @@ -14,10 +14,8 @@ namespace Transformer; use CleverAge\ProcessBundle\Transformer\DateFormatTransformer; -use DateTime; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; class DateFormatTransformerTest extends TestCase { @@ -27,7 +25,7 @@ class DateFormatTransformerTest extends TestCase public function testTransformValidDate(): void { $transformer = new DateFormatTransformer(); - $value = new DateTime('2023-09-28'); + $value = new \DateTime('2023-09-28'); $options = ['format' => 'Y-m-d']; $transformedValue = $transformer->transform($value, $options); @@ -45,7 +43,7 @@ public function testTransformInvalidDate(): void $value = 'invalid_date'; $options = ['format' => 'Y-m-d']; - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $transformer->transform($value, $options); } diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/DateParserTransformerTest.php index 5ac7c4ef..f9f60d6e 100644 --- a/tests/Transformer/DateParserTransformerTest.php +++ b/tests/Transformer/DateParserTransformerTest.php @@ -14,10 +14,8 @@ namespace Transformer; use CleverAge\ProcessBundle\Transformer\DateParserTransformer; -use DateTime; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; class DateParserTransformerTest extends TestCase { @@ -32,7 +30,7 @@ public function testTransformValidDate(): void $transformedValue = $transformer->transform($value, $options); - $this->assertInstanceOf(DateTime::class, $transformedValue); + $this->assertInstanceOf(\DateTime::class, $transformedValue); $this->assertEquals('2023-09-28', $transformedValue->format('Y-m-d')); } @@ -45,7 +43,7 @@ public function testTransformInvalidDate(): void $value = 'invalid_date'; $options = ['format' => 'Y-m-d']; - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $transformer->transform($value, $options); } @@ -71,7 +69,7 @@ public function testTransformDateTimeObject(): void { // Arrange $transformer = new DateParserTransformer(); - $value = new DateTime('2023-09-28'); + $value = new \DateTime('2023-09-28'); $options = ['format' => 'Y-m-d']; $transformedValue = $transformer->transform($value, $options); diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/ImplodeTransformerTest.php index 934aa499..5757815c 100644 --- a/tests/Transformer/ImplodeTransformerTest.php +++ b/tests/Transformer/ImplodeTransformerTest.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\Transformer\ImplodeTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use UnexpectedValueException; class ImplodeTransformerTest extends TestCase { @@ -37,7 +36,7 @@ public function testTransform(): void */ public function testTransformWithInvalidValue(): void { - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $transformer = new ImplodeTransformer(); diff --git a/tests/Transformer/SprintfTransformerTest.php b/tests/Transformer/SprintfTransformerTest.php index 81b80b35..7761d4b5 100644 --- a/tests/Transformer/SprintfTransformerTest.php +++ b/tests/Transformer/SprintfTransformerTest.php @@ -9,7 +9,6 @@ class SprintfTransformerTest extends TestCase { - /** * @covers \CleverAge\ProcessBundle\Transformer\SprintfTransformer::transform */ From 9a1041094ed646abdf4f6ef3fcd75cb72f769524 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 16 Oct 2023 07:15:54 +0200 Subject: [PATCH 218/304] change phpcsfixer to symfony version --- .php-cs-fixer.dist.php | 62 ++++++++++--------- src/Command/ExecuteProcessCommand.php | 8 +-- src/Command/ListProcessCommand.php | 10 +-- src/Command/ProcessHelpCommand.php | 14 ++--- src/Exception/TransformerException.php | 2 +- src/Filesystem/CsvFile.php | 6 +- src/Filesystem/CsvResource.php | 16 ++--- src/Filesystem/FileStreamInterface.php | 2 +- src/Filesystem/JsonStreamFile.php | 2 +- src/Manager/ProcessManager.php | 35 ++--------- src/Model/ProcessState.php | 4 +- src/Registry/ProcessConfigurationRegistry.php | 7 +-- src/Task/AbstractIterableOutputTask.php | 6 +- src/Task/Debug/MemInfoDumpTask.php | 2 +- src/Task/File/FolderBrowserTask.php | 4 +- src/Task/File/InputFolderBrowserTask.php | 8 +-- src/Task/GroupByAggregateIterableTask.php | 9 +++ src/Task/InputAggregatorTask.php | 4 +- src/Task/Process/ProcessLauncherTask.php | 2 +- src/Task/RowAggregatorTask.php | 8 +-- src/Transformer/CachedTransformer.php | 4 +- src/Transformer/ConvertValueTransformer.php | 4 +- src/Transformer/MappingTransformer.php | 4 +- src/Transformer/RulesTransformer.php | 8 +-- src/Transformer/TransformerTrait.php | 4 +- .../Xml/XpathEvaluatorTransformer.php | 6 +- 26 files changed, 97 insertions(+), 144 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f1d55879..57b2a590 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,38 +1,44 @@ in(__DIR__) - ->ignoreDotFiles(true) - ->ignoreVCS(true) - ->exclude(['build', 'vendor']) - ->files() - ->name('*.php') -; +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) 2017-2023 Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -$config = new PhpCsFixer\Config(); +if (!file_exists(__DIR__.'/src')) { + exit(0); +} -return $config - ->setUsingCache(true) - ->setRiskyAllowed(true) - ->setFinder($finder) +$fileHeaderComment = <<<'EOF' +This file is part of the CleverAge/ProcessBundle package. + +Copyright (c) 2017-2023 Clever-Age + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +EOF; + +return (new PhpCsFixer\Config()) ->setRules([ + '@PHP71Migration' => true, + '@PHPUnit75Migration:risky' => true, '@Symfony' => true, '@Symfony:risky' => true, - '@PHPUnit48Migration:risky' => true, - 'array_syntax' => ['syntax' => 'short'], - 'fopen_flags' => false, - 'ordered_imports' => true, 'protected_to_private' => false, - // Part of @Symfony:risky in PHP-CS-Fixer 2.13.0. To be removed from the config file once upgrading - 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced', 'strict' => true], - // Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading - 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], - 'single_line_throw' => false, - // this must be disabled because the output of some tests include NBSP characters - 'non_printable_character' => false, - 'blank_line_between_import_groups' => false, - 'no_trailing_comma_in_singleline' => false, - 'nullable_type_declaration_for_default_null_value' => true, - 'phpdoc_to_comment' => false, + 'native_constant_invocation' => ['strict' => false], + 'header_comment' => ['header' => $fileHeaderComment], + 'modernize_strpos' => true, + 'get_class_to_class_keyword' => true, ]) + ->setRiskyAllowed(true) + ->setFinder( + (new PhpCsFixer\Finder()) + ->in(__DIR__.'/src') + ->append([__FILE__]) + ) + ->setCacheFile('.php-cs-fixer.cache') ; diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 895fa2b1..a34b9da0 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -141,9 +141,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { $output->writeln(json_encode($data, \JSON_THROW_ON_ERROR)); } else { - throw new \InvalidArgumentException( - sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) - ); + throw new \InvalidArgumentException(sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); } } } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { @@ -158,9 +156,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { - throw new \InvalidArgumentException( - sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format')) - ); + throw new \InvalidArgumentException(sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); } } } diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index f8be31c4..7865bddd 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -50,7 +50,7 @@ public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b): public function maxMessageLengthFilter(int $max, array $message): int { - return \max($max, \strlen($this->filterOutTags($message['output']))); + return max($max, \strlen($this->filterOutTags($message['output']))); } protected function configure(): void @@ -61,10 +61,10 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { $processConfigurations = $this->processConfigRegistry->getProcessConfigurations(); - \usort($processConfigurations, $this->processSorter(...)); + usort($processConfigurations, $this->processSorter(...)); - $publicCount = \array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); - $privateCount = \array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); + $publicCount = array_reduce($processConfigurations, $this->publicProcessCounter(...), 0); + $privateCount = array_reduce($processConfigurations, $this->privateProcessCounter(...), 0); $output->writeln( "There are {$publicCount} process configurations defined (and {$privateCount} private) :" ); @@ -87,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // Add process descriptions at a fixed position - $maxMessageLength = \array_reduce($messages, $this->maxMessageLengthFilter(...), 0); + $maxMessageLength = array_reduce($messages, $this->maxMessageLengthFilter(...), 0); $outputMessages = []; foreach ($messages as $message) { /** @var ProcessConfiguration $processConfiguration */ diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 25e3eb70..d6ecff7c 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -376,7 +376,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): foreach ($nextTasks as $nextTask) { $index = array_search(null, $branches, true); if (false !== $index && $index >= $origin) { - /** @var int $index */ + /* @var int $index */ $branches[$index] = $taskCode; $expandBranches[] = $index; } else { @@ -446,8 +446,8 @@ protected function writeBranches( OutputInterface $output, array $branches, string|iterable $comment = '', - ?callable $match = null, - string|callable|null $char = null + callable $match = null, + string|callable $char = null ): void { $output->write(str_repeat(' ', self::INDENT_SIZE)); @@ -525,14 +525,10 @@ protected function getTaskService(TaskConfiguration $taskConfiguration): TaskInt } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new \UnexpectedValueException( - "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" - ); + throw new \UnexpectedValueException("Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'"); } if (!$task instanceof TaskInterface) { - throw new \UnexpectedValueException( - "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" - ); + throw new \UnexpectedValueException("Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface"); } return $task; diff --git a/src/Exception/TransformerException.php b/src/Exception/TransformerException.php index 0a768b7f..3b8af365 100644 --- a/src/Exception/TransformerException.php +++ b/src/Exception/TransformerException.php @@ -23,7 +23,7 @@ class TransformerException extends \RuntimeException implements ProcessException public function __construct( protected string $transformerCode, int $code = 0, - ?\Throwable $previous = null + \Throwable $previous = null ) { parent::__construct('', $code, $previous); $this->updateMessage(); diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index d35c03d4..61bfadc1 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -29,7 +29,7 @@ public function __construct( string $delimiter = ',', string $enclosure = '"', string $escape = '\\', - ?array $headers = null, + array $headers = null, string $mode = 'rb' ) { if (!\in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { @@ -47,9 +47,7 @@ public function __construct( $readAllowedModes = ['r', 'r+', 'w+', 'a+', 'x+', 'c+']; if (null === $headers && !\in_array(str_replace('b', '', $mode), $readAllowedModes, true)) { // Cannot read headers if the file was just created - throw new \UnexpectedValueException( - "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" - ); + throw new \UnexpectedValueException("Invalid headers for {$this->getResourceName()}, you need to pass the headers manually"); } parent::__construct($resource, $delimiter, $enclosure, $escape, $headers); diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 894826e5..f8619076 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -44,7 +44,7 @@ public function __construct( protected string $delimiter = ',', protected string $enclosure = '"', protected string $escape = '\\', - ?array $headers = null + array $headers = null ) { if (!\is_resource($resource)) { $type = \gettype($resource); @@ -149,7 +149,7 @@ public function isEndOfFile(): bool /** * Warning, this function will return exactly the same value as the fgetcsv() function. */ - public function readRaw(?int $length = null): array|false + public function readRaw(int $length = null): array|false { $this->assertOpened(); ++$this->lineNumber; @@ -157,7 +157,7 @@ public function readRaw(?int $length = null): array|false return fgetcsv($this->handler, $length, $this->delimiter, $this->enclosure, $this->escape); } - public function readLine(?int $length = null): ?array + public function readLine(int $length = null): ?array { if ($this->seekCalled) { $filePosition = "at position {$this->tell()}"; @@ -290,7 +290,7 @@ protected function assertOpened(): void } } - protected function parseHeaders(?array $headers = null): array + protected function parseHeaders(array $headers = null): array { // If headers are not passed in the constructor but file is readable, try to read headers from file if (null === $headers) { @@ -308,15 +308,11 @@ protected function parseHeaders(?array $headers = null): array $this->manualHeaders = true; if (!\is_array($headers)) { - throw new \UnexpectedValueException( - "Invalid headers for {$this->getResourceName()}, you need to pass the headers manually" - ); + throw new \UnexpectedValueException("Invalid headers for {$this->getResourceName()}, you need to pass the headers manually"); } if (0 === \count($headers)) { - throw new \UnexpectedValueException( - "Empty headers for {$this->getResourceName()}, you need to pass the headers manually" - ); + throw new \UnexpectedValueException("Empty headers for {$this->getResourceName()}, you need to pass the headers manually"); } return $headers; diff --git a/src/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php index bc6f9997..ec799e22 100644 --- a/src/Filesystem/FileStreamInterface.php +++ b/src/Filesystem/FileStreamInterface.php @@ -27,7 +27,7 @@ public function getLineNumber(): int; public function isEndOfFile(): bool; - public function readLine(?int $length = null): ?array; + public function readLine(int $length = null): ?array; /** * This methods rewinds the file to the first line of data, skipping the headers. diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index 2051d63c..7eecc69e 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -65,7 +65,7 @@ public function isEndOfFile(): bool /** * Return an array containing current data and moving the file pointer. */ - public function readLine(?int $length = null): ?array + public function readLine(int $length = null): ?array { if ($this->isEndOfFile()) { return null; diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index d495e99a..82ede4cb 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -238,14 +238,10 @@ protected function initialize(TaskConfiguration $taskConfiguration): void } elseif ($this->container->has($serviceReference)) { $task = $this->container->get($serviceReference); } else { - throw new \UnexpectedValueException( - "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'" - ); + throw new \UnexpectedValueException("Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'"); } if (!$task instanceof TaskInterface) { - throw new \UnexpectedValueException( - "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface" - ); + throw new \UnexpectedValueException("Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface"); } $taskConfiguration->setTask($task); @@ -299,16 +295,7 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF $m .= " during process {$state->getTaskConfiguration() ->getCode()}"; $m .= " with message: '{$exception->getMessage()}'.\n"; - throw new FatalError( - $m, - -1, - [ - 'file' => $exception->getFile(), - 'line' => $exception->getLine(), - 'type' => 500, - 'message' => $exception->getMessage(), - ] - ); + throw new FatalError($m, -1, ['file' => $exception->getFile(), 'line' => $exception->getLine(), 'type' => 500, 'message' => $exception->getMessage()]); } return; @@ -421,9 +408,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e } elseif (TaskConfiguration::STRATEGY_STOP === $taskConfiguration->getErrorStrategy()) { $state->stop($exception); } else { - throw new \UnexpectedValueException( - "Unknown error strategy '{$taskConfiguration->getErrorStrategy()}'" - ); + throw new \UnexpectedValueException("Unknown error strategy '{$taskConfiguration->getErrorStrategy()}'"); } } } @@ -566,18 +551,10 @@ protected function checkProcess(ProcessConfiguration $processConfiguration): voi // Check coherence for entry/end points $processConfiguration->getEndPoint(); if ($entryPoint && !\in_array($entryPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain( - $processConfiguration, - $entryPoint, - $mainTaskList - ); + throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $entryPoint, $mainTaskList); } if ($endPoint && !\in_array($endPoint->getCode(), $mainTaskList, true)) { - throw InvalidProcessConfigurationException::createNotInMain( - $processConfiguration, - $endPoint, - $mainTaskList - ); + throw InvalidProcessConfigurationException::createNotInMain($processConfiguration, $endPoint, $mainTaskList); } } diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index 86b84f81..1ede98fd 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -163,7 +163,7 @@ public function hasErrorOutput(): bool return $this->hasErrorOutput; } - public function stop(?\Throwable $e = null): void + public function stop(\Throwable $e = null): void { if ($e) { $this->setException($e); @@ -186,7 +186,7 @@ public function getException(): ?\Throwable return $this->exception; } - public function setException(?\Throwable $exception = null): void + public function setException(\Throwable $exception = null): void { $this->exception = $exception; } diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 0772fed5..a6ff4d5c 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -50,7 +50,7 @@ public function getProcessConfiguration(string $processCode): ProcessConfigurati */ public function getProcessConfigurations(): array { - foreach (\array_keys($this->rawConfiguration) as $processCode) { + foreach (array_keys($this->rawConfiguration) as $processCode) { $this->resolveConfiguration($processCode); } @@ -137,10 +137,7 @@ protected function resolveConfiguration(string $processCode): void // #106 - entry point should not have an ancestor if ($processConfig->getEntryPoint() && $processConfig->getEntryPoint()->getPreviousTasksConfigurations()) { - throw InvalidProcessConfigurationException::createEntryPointHasAncestors( - $processConfig, - $processConfig->getEntryPoint() - ); + throw InvalidProcessConfigurationException::createEntryPointHasAncestors($processConfig, $processConfig->getEntryPoint()); } $this->processConfigurations[$processCode] = $processConfig; diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index 2cf265c9..30531215 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -78,11 +78,9 @@ protected function handleIteratorFromInput(ProcessState $state): void } // This should never be reached - /** @phpstan-ignore-next-line */ + /* @phpstan-ignore-next-line */ if (null !== $this->iterator) { - throw new \UnexpectedValueException( - "At this point iterator should have been null, maybe it's a wrong type..." - ); + throw new \UnexpectedValueException("At this point iterator should have been null, maybe it's a wrong type..."); } $this->iterator = $this->initializeIterator($state); diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php index dc33e317..d0a4f5a5 100644 --- a/src/Task/Debug/MemInfoDumpTask.php +++ b/src/Task/Debug/MemInfoDumpTask.php @@ -32,7 +32,7 @@ public function execute(ProcessState $state): void { if (\function_exists('meminfo_dump')) { gc_collect_cycles(); - $handler = fopen($this->getOption($state, 'file_path'), 'wb'); + $handler = fopen($this->getOption($state, 'file_path'), 'w'); meminfo_dump($handler); fclose($handler); } else { diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 90183374..1f07cca8 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -91,9 +91,7 @@ protected function configureOptions(OptionsResolver $resolver): void 'folder_path', static function (Options $options, $value) { if (!is_dir($value)) { - throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '{$value}'" - ); + throw new InvalidConfigurationException("Folder path does not exists or is not a folder: '{$value}'"); } if (!is_readable($value)) { throw new InvalidConfigurationException("Folder path is not readable: '{$value}'"); diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index 014ec7ba..2b090f59 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -53,17 +53,13 @@ protected function getOptions(ProcessState $state): array if ($state->getInput()) { $folderPath = $options['base_folder_path'].$state->getInput(); if ($this->folderPath && $folderPath !== $this->folderPath) { - throw new \LogicException( - "Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}" - ); + throw new \LogicException("Folder path '{$folderPath}' already initialized with a different value {$this->folderPath}"); } $this->folderPath = $folderPath; } if (!is_dir($this->folderPath)) { - throw new InvalidConfigurationException( - "Folder path does not exists or is not a folder: '{$this->folderPath}'" - ); + throw new InvalidConfigurationException("Folder path does not exists or is not a folder: '{$this->folderPath}'"); } if (!is_readable($this->folderPath)) { throw new InvalidConfigurationException("Folder path is not readable: '{$this->folderPath}'"); diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 97abf751..57e85e16 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) 2017-2023 Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace CleverAge\ProcessBundle\Task; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 4793bbca..5e68f598 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -44,9 +44,7 @@ public function execute(ProcessState $state): void if ($this->getOption($state, 'clean_input_on_override')) { $this->inputs = []; } else { - throw new \UnexpectedValueException( - "The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output" - ); + throw new \UnexpectedValueException("The output from input '{$inputCode}' has already been defined, please use an aggregator if you have an iterable output"); } } diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index 1164f592..6191c297 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -59,7 +59,7 @@ public function execute(ProcessState $state): void $state->setOutput($this->finishedBuffers->dequeue()); // After dequeue, stop flush - /** @phpstan-ignore-next-line */ + /* @phpstan-ignore-next-line */ if ($this->finishedBuffers->isEmpty()) { $this->flushMode = false; } diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index 1dddf055..3a9f9b65 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -48,9 +48,7 @@ public function execute(ProcessState $state): void $aggregationKey = $this->getOption($state, 'aggregation_key'); if (!\array_key_exists($aggregateBy, $input)) { - throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column '{$aggregateBy}'" - ); + throw new InvalidProcessConfigurationException("Array aggregator exception: missing column '{$aggregateBy}'"); } $inputAggregateBy = $input[$aggregateBy]; @@ -67,9 +65,7 @@ public function execute(ProcessState $state): void $inputAggregateColumns = []; foreach ($aggregateColumns as $aggregateColumn) { if (!\array_key_exists($aggregateColumn, $input)) { - throw new InvalidProcessConfigurationException( - "Array aggregator exception: missing column {$aggregateColumn}" - ); + throw new InvalidProcessConfigurationException("Array aggregator exception: missing column {$aggregateColumn}"); } $inputAggregateColumns[$aggregateColumn] = $input[$aggregateColumn]; } diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 727d9bb0..5f774355 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -45,7 +45,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer( 'ttl', function (Options $options, $value) { - /** + /* * Best use is a relative date string like "+1 hour". * * @see https://www.php.net/manual/en/datetime.formats.relative.php @@ -112,6 +112,6 @@ protected function generateCacheKey(string $cacheKeyRoot, string $value, array $ return false; } - return \implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, \rawurlencode($value)]); + return implode(self::CACHE_SEPARATOR, [$cacheKeyRoot, rawurlencode($value)]); } } diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index b478d0d5..22e1546a 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -32,9 +32,7 @@ public function transform(mixed $value, array $options = []): mixed if (!\is_string($value) && !\is_int($value)) { // If not a valid array index if (!$options['auto_cast']) { $type = \gettype($value); - throw new \UnexpectedValueException( - "Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string" - ); + throw new \UnexpectedValueException("Value of type {$type} is not a valid array index, set auto_cast to true to cast it to a string"); } if (\is_array($value)) { // Array to string conversion is a simple notice so we need to catch it here throw new \UnexpectedValueException("Unexpected input of type 'array' in convert_value transformer"); diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index 387e93dd..c5788d73 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -40,9 +40,7 @@ public function __construct( public function transform(mixed $value, array $options = []): mixed { if (!empty($options['initial_value']) && $options['keep_input']) { - throw new InvalidOptionsException( - 'The options "initial_value" and "keep_input" can\'t be both enabled.' - ); + throw new InvalidOptionsException('The options "initial_value" and "keep_input" can\'t be both enabled.'); } $result = $options['initial_value']; diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index c3d68c5f..a0b75775 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -93,7 +93,7 @@ public function configureOptions(OptionsResolver $resolver): void /** * Configure options for one "rule" block. */ - public function configureRuleOptions(OptionsResolver $resolver, ?array $expressionVariables = null): void + public function configureRuleOptions(OptionsResolver $resolver, array $expressionVariables = null): void { $resolver->setDefaults([ 'condition' => null, @@ -116,9 +116,7 @@ public function configureRuleOptions(OptionsResolver $resolver, ?array $expressi $resolver->setNormalizer('condition', $expressionNormalizer); $resolver->setNormalizer('default', function (Options $options, $value) { if ($value && $options['condition']) { - throw new \InvalidArgumentException( - 'A rule cannot have a condition and be the default in the same time' - ); + throw new \InvalidArgumentException('A rule cannot have a condition and be the default in the same time'); } return $value; @@ -140,7 +138,7 @@ protected function matchRule(mixed $value, string|ParsedExpression $rule, bool $ return $this->language->evaluate($rule['condition'], $expressionValues); } - /** @noinspection PhpStrictTypeCheckingInspection */ + /* @noinspection PhpStrictTypeCheckingInspection */ return $rule['default']; } } diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 23a03ae7..0c59a75b 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -113,8 +113,6 @@ private function checkTransformerOptions(mixed $transformerOptions, string $tran $type = get_debug_type($transformerOptions); - throw new \InvalidArgumentException( - "Options for transformer {$transformerCode} are invalid : found {$type}, expected array or null" - ); + throw new \InvalidArgumentException("Options for transformer {$transformerCode} are invalid : found {$type}, expected array or null"); } } diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index af291e59..ccaf0afa 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -65,7 +65,7 @@ public function configureOptions(OptionsResolver $resolver): void * Configure options about how to handle xpath query results. * Available at root and subquery level. */ - public function configureQueryOptions(OptionsResolver $resolver, ?Options $parentOptions = null): void + public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null): void { $resolver->setDefault('single_result', $parentOptions ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); @@ -87,7 +87,7 @@ public function transform(mixed $value, array $options = []): mixed $query = $options['query']; if (\is_array($query)) { - $result = \array_map( + $result = array_map( fn ($subquery): mixed => $this->query($xpath, $subquery['subquery'], $value, $subquery), $query ); @@ -118,7 +118,7 @@ public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $op // Convert results to text if ($options['unwrap_value']) { - $results = \array_map(static function (\DOMNode $item) use ($query): string { + $results = array_map(static function (\DOMNode $item) use ($query): string { if ($item instanceof \DOMAttr) { return $item->value; } From 2c456014ab74eefa1db30a48150d9c931bf80a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Tonon?= Date: Thu, 14 Dec 2023 11:07:18 +0100 Subject: [PATCH 219/304] [Fix]Bad type on process property --- src/Task/Process/ProcessExecutorTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 543d7b0d..0f118885 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -27,7 +27,7 @@ */ class ProcessExecutorTask extends AbstractConfigurableTask { - protected ?array $process = null; + protected ?string $process = null; public function __construct( protected ProcessManager $processManager, From 5e0464a42658a3441962d44b12437524e598110d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Tonon?= Date: Thu, 21 Dec 2023 09:06:21 +0100 Subject: [PATCH 220/304] [133] Error: bad implementation for InstantiateTransformer --- Transformer/InstantiateTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transformer/InstantiateTransformer.php b/Transformer/InstantiateTransformer.php index 5c2312ef..7164cc07 100644 --- a/Transformer/InstantiateTransformer.php +++ b/Transformer/InstantiateTransformer.php @@ -19,7 +19,7 @@ */ class InstantiateTransformer implements ConfigurableTransformerInterface { - public function transform(mixed $value, array $options = []) + public function transform($value, array $options = []) { if (!is_array($value)) { throw new \UnexpectedValueException('Input value must be an array for transformer instantiate'); From e4bfef9cb27e36aabe976ede350a28d04c027969 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 29 Feb 2024 11:08:23 +0100 Subject: [PATCH 221/304] Update ProcessConfiguration.php Fix deprecation "Deprecated: Implicit conversion from float 1.5 to int loses precision" --- Configuration/ProcessConfiguration.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Configuration/ProcessConfiguration.php b/Configuration/ProcessConfiguration.php index f452148e..509e0f23 100644 --- a/Configuration/ProcessConfiguration.php +++ b/Configuration/ProcessConfiguration.php @@ -347,9 +347,8 @@ protected function sortDependencies(array $dependencies): array return $dependencies; } - /** @var int $midOffset */ $midOffset = \count($dependencies) / 2; - $midTaskCode = $dependencies[$midOffset]; + $midTaskCode = $dependencies[(int)$midOffset]; $midTask = $this->getTaskConfiguration($midTaskCode); $previousTasks = []; From 4a6b58d5e1f1362da14201ecda363bc384592e55 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 25 Apr 2024 20:10:42 +0200 Subject: [PATCH 222/304] update copyright --- src/CleverAgeProcessBundle.php | 2 +- src/Command/ExecuteProcessCommand.php | 2 +- src/Command/ListProcessCommand.php | 2 +- src/Command/ProcessHelpCommand.php | 2 +- src/Configuration/ProcessConfiguration.php | 2 +- src/Configuration/TaskConfiguration.php | 2 +- src/Context/ContextualOptionResolver.php | 2 +- src/DependencyInjection/CleverAgeProcessExtension.php | 2 +- .../Compiler/CheckSerializerCompilerPass.php | 2 +- src/DependencyInjection/Compiler/RegistryCompilerPass.php | 2 +- src/DependencyInjection/Configuration.php | 2 +- src/Event/ConsoleProcessEvent.php | 2 +- src/Event/EventDispatcherTaskEvent.php | 2 +- src/Event/ProcessEvent.php | 2 +- src/EventListener/DataQueueEventListener.php | 2 +- src/Exception/CircularProcessException.php | 2 +- src/Exception/InvalidProcessConfigurationException.php | 2 +- src/Exception/MissingProcessException.php | 2 +- src/Exception/MissingTaskConfigurationException.php | 2 +- src/Exception/MissingTransformerException.php | 2 +- src/Exception/ProcessExceptionInterface.php | 2 +- src/Exception/TransformerException.php | 2 +- src/ExpressionLanguage/PhpFunctionProvider.php | 2 +- src/Filesystem/CsvFile.php | 2 +- src/Filesystem/CsvResource.php | 2 +- src/Filesystem/FileStreamInterface.php | 2 +- src/Filesystem/JsonStreamFile.php | 2 +- src/Filesystem/SeekableFileInterface.php | 2 +- src/Filesystem/StructuredFileInterface.php | 2 +- src/Filesystem/WritableFileInterface.php | 2 +- src/Filesystem/WritableStructuredFileInterface.php | 2 +- src/Filesystem/XmlFile.php | 2 +- src/Logger/AbstractLogger.php | 2 +- src/Logger/AbstractProcessor.php | 2 +- src/Logger/ProcessLogger.php | 2 +- src/Logger/ProcessProcessor.php | 2 +- src/Logger/TaskLogger.php | 2 +- src/Logger/TaskProcessor.php | 2 +- src/Logger/TransformerProcessor.php | 2 +- src/Manager/ProcessManager.php | 2 +- src/Model/AbstractConfigurableTask.php | 2 +- src/Model/BlockingTaskInterface.php | 2 +- src/Model/FinalizableTaskInterface.php | 2 +- src/Model/FlushableTaskInterface.php | 2 +- src/Model/InitializableTaskInterface.php | 2 +- src/Model/IterableTaskInterface.php | 2 +- src/Model/ProcessHistory.php | 2 +- src/Model/ProcessState.php | 2 +- src/Model/SubprocessInstance.php | 2 +- src/Model/TaskInterface.php | 2 +- src/Registry/ProcessConfigurationRegistry.php | 2 +- src/Registry/TransformerRegistry.php | 2 +- src/Task/AbstractIterableOutputTask.php | 2 +- src/Task/AggregateIterableTask.php | 2 +- src/Task/ArrayMergeTask.php | 2 +- src/Task/ColumnAggregatorTask.php | 2 +- src/Task/ConstantIterableOutputTask.php | 2 +- src/Task/ConstantOutputTask.php | 2 +- src/Task/CounterTask.php | 2 +- src/Task/Debug/DebugTask.php | 2 +- src/Task/Debug/DieTask.php | 4 +++- src/Task/Debug/ErrorForwarderTask.php | 2 +- src/Task/Debug/MemInfoDumpTask.php | 2 +- src/Task/Debug/StopwatchTask.php | 2 +- src/Task/DummyTask.php | 2 +- src/Task/Event/EventDispatcherTask.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/AbstractCsvTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 2 +- src/Task/File/Csv/CsvSplitterTask.php | 2 +- src/Task/File/Csv/CsvWriterTask.php | 2 +- src/Task/File/Csv/InputCsvReaderTask.php | 2 +- src/Task/File/FileFetchTask.php | 2 +- src/Task/File/FileMoverTask.php | 2 +- src/Task/File/FileReaderTask.php | 2 +- src/Task/File/FileRemoverTask.php | 2 +- src/Task/File/FileWriterTask.php | 2 +- src/Task/File/FolderBrowserTask.php | 2 +- src/Task/File/InputFolderBrowserTask.php | 2 +- src/Task/File/JsonStream/JsonStreamReaderTask.php | 2 +- src/Task/File/Xml/XmlReaderTask.php | 2 +- src/Task/File/Xml/XmlWriterTask.php | 2 +- src/Task/File/YamlReaderTask.php | 2 +- src/Task/File/YamlWriterTask.php | 2 +- src/Task/FilterTask.php | 2 +- src/Task/GroupByAggregateIterableTask.php | 2 +- src/Task/InputAggregatorTask.php | 2 +- src/Task/InputIteratorTask.php | 2 +- src/Task/IterableBatchTask.php | 2 +- src/Task/ObjectUpdaterTask.php | 2 +- src/Task/Process/CommandRunnerTask.php | 2 +- src/Task/Process/ProcessExecutorTask.php | 2 +- src/Task/Process/ProcessLauncherTask.php | 2 +- src/Task/PropertyGetterTask.php | 2 +- src/Task/PropertySetterTask.php | 2 +- src/Task/Reporting/AdvancedStatCounterTask.php | 2 +- src/Task/Reporting/LoggerTask.php | 2 +- src/Task/Reporting/StatCounterTask.php | 2 +- src/Task/RowAggregatorTask.php | 2 +- src/Task/Serialization/DenormalizerTask.php | 2 +- src/Task/Serialization/DeserializerTask.php | 2 +- src/Task/Serialization/NormalizerTask.php | 2 +- src/Task/Serialization/SerializerTask.php | 2 +- src/Task/SimpleBatchTask.php | 2 +- src/Task/SkipEmptyTask.php | 2 +- src/Task/SplitJoinLineTask.php | 2 +- src/Task/StopTask.php | 2 +- src/Task/TransformerTask.php | 2 +- src/Task/Validation/ValidatorTask.php | 2 +- src/Transformer/ArrayElementTransformer.php | 2 +- src/Transformer/ArrayFilterTransformer.php | 2 +- src/Transformer/ArrayFirstTransformer.php | 2 +- src/Transformer/ArrayLastTransformer.php | 2 +- src/Transformer/ArrayMapTransformer.php | 2 +- src/Transformer/ArrayUnsetTransformer.php | 2 +- src/Transformer/CachedTransformer.php | 2 +- src/Transformer/CallbackTransformer.php | 2 +- src/Transformer/CastTransformer.php | 2 +- src/Transformer/ConditionTrait.php | 2 +- src/Transformer/ConfigurableTransformerInterface.php | 2 +- src/Transformer/ConstantTransformer.php | 2 +- src/Transformer/ConvertValueTransformer.php | 2 +- src/Transformer/DateFormatTransformer.php | 2 +- src/Transformer/DateParserTransformer.php | 2 +- src/Transformer/DebugTransformer.php | 2 +- src/Transformer/DefaultTransformer.php | 2 +- src/Transformer/DenormalizeTransformer.php | 2 +- src/Transformer/EvaluatorTransformer.php | 2 +- src/Transformer/ExplodeTransformer.php | 2 +- src/Transformer/ExpressionLanguageMapTransformer.php | 2 +- src/Transformer/GenericTransformer.php | 2 +- src/Transformer/HashTransformer.php | 2 +- src/Transformer/ImplodeTransformer.php | 2 +- src/Transformer/InstantiateTransformer.php | 2 +- src/Transformer/MappingTransformer.php | 2 +- src/Transformer/MultiReplaceTransformer.php | 2 +- src/Transformer/NormalizeTransformer.php | 2 +- src/Transformer/PregFilterTransformer.php | 2 +- src/Transformer/PropertyAccessorTransformer.php | 2 +- src/Transformer/RecursivePropertySetterTransformer.php | 2 +- src/Transformer/RulesTransformer.php | 2 +- src/Transformer/SlugifyTransformer.php | 2 +- src/Transformer/SprintfTransformer.php | 2 +- src/Transformer/TransformerInterface.php | 2 +- src/Transformer/TransformerTrait.php | 2 +- src/Transformer/TrimTransformer.php | 2 +- src/Transformer/TypeSetterTransformer.php | 2 +- src/Transformer/UnsetTransformer.php | 2 +- src/Transformer/WrapperTransformer.php | 2 +- src/Transformer/Xml/XpathEvaluatorTransformer.php | 2 +- src/Validator/ConstraintLoader.php | 2 +- tests/Transformer/ArrayElementTransformerTest.php | 2 +- tests/Transformer/ArrayFirstTransformerTest.php | 2 +- tests/Transformer/CastTransformerTest.php | 2 +- tests/Transformer/ConstantTransformerTest.php | 2 +- tests/Transformer/DateFormatTransformerTest.php | 2 +- tests/Transformer/DateParserTransformerTest.php | 2 +- tests/Transformer/DebugTransformerTest.php | 2 +- tests/Transformer/DefaultTransformerTest.php | 2 +- tests/Transformer/ExplodeTransformerTest.php | 2 +- tests/Transformer/ImplodeTransformerTest.php | 2 +- tests/Transformer/MultiReplaceTransformerTest.php | 2 +- tests/Transformer/TrimTransformerTest.php | 2 +- tests/Transformer/WrapperTransformerTest.php | 2 +- 164 files changed, 166 insertions(+), 164 deletions(-) diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 4b1d95aa..27904639 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index a34b9da0..8a4f488a 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index 7865bddd..fcca76c1 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index d6ecff7c..8fe4a510 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 8d0de248..8aa0c979 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index ae3535b6..6a59d872 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Context/ContextualOptionResolver.php b/src/Context/ContextualOptionResolver.php index caf52aa5..a5bad58f 100644 --- a/src/Context/ContextualOptionResolver.php +++ b/src/Context/ContextualOptionResolver.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index b3844903..ebe8ef15 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 2c7d010f..0cd8e0f4 100644 --- a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php index e414ee08..517bb2d5 100644 --- a/src/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/src/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 4d3b03a1..be337f93 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php index 5acb2320..f09c4303 100644 --- a/src/Event/ConsoleProcessEvent.php +++ b/src/Event/ConsoleProcessEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Event/EventDispatcherTaskEvent.php b/src/Event/EventDispatcherTaskEvent.php index 1646ab0c..0d6b4394 100644 --- a/src/Event/EventDispatcherTaskEvent.php +++ b/src/Event/EventDispatcherTaskEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Event/ProcessEvent.php b/src/Event/ProcessEvent.php index a3eb6b96..f3b79d11 100644 --- a/src/Event/ProcessEvent.php +++ b/src/Event/ProcessEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/EventListener/DataQueueEventListener.php b/src/EventListener/DataQueueEventListener.php index 84d8283e..6f48ab5c 100644 --- a/src/EventListener/DataQueueEventListener.php +++ b/src/EventListener/DataQueueEventListener.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php index 9f2e5453..c4ff2516 100644 --- a/src/Exception/CircularProcessException.php +++ b/src/Exception/CircularProcessException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php index 4dedd34a..80a34779 100644 --- a/src/Exception/InvalidProcessConfigurationException.php +++ b/src/Exception/InvalidProcessConfigurationException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php index ee11dbb4..3642ee67 100644 --- a/src/Exception/MissingProcessException.php +++ b/src/Exception/MissingProcessException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php index 679666b9..0445891c 100644 --- a/src/Exception/MissingTaskConfigurationException.php +++ b/src/Exception/MissingTaskConfigurationException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php index 381e36f1..a0ea2772 100644 --- a/src/Exception/MissingTransformerException.php +++ b/src/Exception/MissingTransformerException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/ProcessExceptionInterface.php b/src/Exception/ProcessExceptionInterface.php index 8d73f959..f4f39edf 100644 --- a/src/Exception/ProcessExceptionInterface.php +++ b/src/Exception/ProcessExceptionInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/TransformerException.php b/src/Exception/TransformerException.php index 3b8af365..0c88e44a 100644 --- a/src/Exception/TransformerException.php +++ b/src/Exception/TransformerException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/ExpressionLanguage/PhpFunctionProvider.php b/src/ExpressionLanguage/PhpFunctionProvider.php index 0fb1e48f..4d157b01 100644 --- a/src/ExpressionLanguage/PhpFunctionProvider.php +++ b/src/ExpressionLanguage/PhpFunctionProvider.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 61bfadc1..529096ae 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index f8619076..bab85e4e 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php index ec799e22..542799cd 100644 --- a/src/Filesystem/FileStreamInterface.php +++ b/src/Filesystem/FileStreamInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index 7eecc69e..5fa7d4f0 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/SeekableFileInterface.php b/src/Filesystem/SeekableFileInterface.php index bb9d0ae3..2d7ca906 100644 --- a/src/Filesystem/SeekableFileInterface.php +++ b/src/Filesystem/SeekableFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/StructuredFileInterface.php b/src/Filesystem/StructuredFileInterface.php index 827b8607..70ce3026 100644 --- a/src/Filesystem/StructuredFileInterface.php +++ b/src/Filesystem/StructuredFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/WritableFileInterface.php b/src/Filesystem/WritableFileInterface.php index 91f6e794..2509c329 100644 --- a/src/Filesystem/WritableFileInterface.php +++ b/src/Filesystem/WritableFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/WritableStructuredFileInterface.php b/src/Filesystem/WritableStructuredFileInterface.php index 5ba4f51a..e6e283eb 100644 --- a/src/Filesystem/WritableStructuredFileInterface.php +++ b/src/Filesystem/WritableStructuredFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/XmlFile.php b/src/Filesystem/XmlFile.php index 8218f181..194a6248 100644 --- a/src/Filesystem/XmlFile.php +++ b/src/Filesystem/XmlFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/AbstractLogger.php b/src/Logger/AbstractLogger.php index f349b5b3..804d11cd 100644 --- a/src/Logger/AbstractLogger.php +++ b/src/Logger/AbstractLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index 79228295..544c7508 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/ProcessLogger.php b/src/Logger/ProcessLogger.php index 1e350415..7565d9ef 100644 --- a/src/Logger/ProcessLogger.php +++ b/src/Logger/ProcessLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/ProcessProcessor.php b/src/Logger/ProcessProcessor.php index 1c2ea6b4..35d1f3a4 100644 --- a/src/Logger/ProcessProcessor.php +++ b/src/Logger/ProcessProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TaskLogger.php b/src/Logger/TaskLogger.php index b5176467..cb00efd3 100644 --- a/src/Logger/TaskLogger.php +++ b/src/Logger/TaskLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index cd0b0950..7a262eb1 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index d10b25a2..cc8cb65e 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 82ede4cb..d0b2751c 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 1df3bae4..309af297 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/BlockingTaskInterface.php b/src/Model/BlockingTaskInterface.php index c4124a70..ad0bb7fb 100644 --- a/src/Model/BlockingTaskInterface.php +++ b/src/Model/BlockingTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/FinalizableTaskInterface.php b/src/Model/FinalizableTaskInterface.php index 44498d53..063ce14c 100644 --- a/src/Model/FinalizableTaskInterface.php +++ b/src/Model/FinalizableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/FlushableTaskInterface.php b/src/Model/FlushableTaskInterface.php index 8c9b8f03..757fb5ba 100644 --- a/src/Model/FlushableTaskInterface.php +++ b/src/Model/FlushableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/InitializableTaskInterface.php b/src/Model/InitializableTaskInterface.php index ac8cd529..9cb9a5eb 100644 --- a/src/Model/InitializableTaskInterface.php +++ b/src/Model/InitializableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/IterableTaskInterface.php b/src/Model/IterableTaskInterface.php index e07008b4..7d17856b 100644 --- a/src/Model/IterableTaskInterface.php +++ b/src/Model/IterableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/ProcessHistory.php b/src/Model/ProcessHistory.php index be21d855..419f1927 100644 --- a/src/Model/ProcessHistory.php +++ b/src/Model/ProcessHistory.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index 1ede98fd..abbb2567 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index d48ae6e1..fb444e53 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/TaskInterface.php b/src/Model/TaskInterface.php index ee236ecc..748e282d 100644 --- a/src/Model/TaskInterface.php +++ b/src/Model/TaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index a6ff4d5c..6c403cda 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Registry/TransformerRegistry.php b/src/Registry/TransformerRegistry.php index 7a32d627..3ab519fb 100644 --- a/src/Registry/TransformerRegistry.php +++ b/src/Registry/TransformerRegistry.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index 30531215..b2c8f7f2 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php index 388cd419..f4fcc122 100644 --- a/src/Task/AggregateIterableTask.php +++ b/src/Task/AggregateIterableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php index 59356525..6e20e7fd 100644 --- a/src/Task/ArrayMergeTask.php +++ b/src/Task/ArrayMergeTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index 31b569f0..033e14e2 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ConstantIterableOutputTask.php b/src/Task/ConstantIterableOutputTask.php index 7cf3875c..415e1164 100644 --- a/src/Task/ConstantIterableOutputTask.php +++ b/src/Task/ConstantIterableOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ConstantOutputTask.php b/src/Task/ConstantOutputTask.php index f53c9bc9..040b882d 100644 --- a/src/Task/ConstantOutputTask.php +++ b/src/Task/ConstantOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/CounterTask.php b/src/Task/CounterTask.php index 061cb945..df16e969 100644 --- a/src/Task/CounterTask.php +++ b/src/Task/CounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php index 3c5c3796..2f3dce09 100644 --- a/src/Task/Debug/DebugTask.php +++ b/src/Task/Debug/DebugTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php index ca305446..1884d133 100644 --- a/src/Task/Debug/DieTask.php +++ b/src/Task/Debug/DieTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,6 +15,7 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\TaskInterface; +use Symfony\Component\Console\Helper\Helper; /** * Class DieTask. @@ -27,6 +28,7 @@ class DieTask implements TaskInterface { public function execute(ProcessState $state): never { + var_dump(Helper::formatMemory(memory_get_peak_usage(true))); exit; } } diff --git a/src/Task/Debug/ErrorForwarderTask.php b/src/Task/Debug/ErrorForwarderTask.php index ae7dffdb..80f235ed 100644 --- a/src/Task/Debug/ErrorForwarderTask.php +++ b/src/Task/Debug/ErrorForwarderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php index d0a4f5a5..a793c680 100644 --- a/src/Task/Debug/MemInfoDumpTask.php +++ b/src/Task/Debug/MemInfoDumpTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php index 8bae7dbc..8bbaf85e 100644 --- a/src/Task/Debug/StopwatchTask.php +++ b/src/Task/Debug/StopwatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/DummyTask.php b/src/Task/DummyTask.php index d3b900db..71b9f4fe 100644 --- a/src/Task/DummyTask.php +++ b/src/Task/DummyTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php index 0da1f97c..1233fb6b 100644 --- a/src/Task/Event/EventDispatcherTask.php +++ b/src/Task/Event/EventDispatcherTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index a441fe29..6d4d5416 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index 26ec72e5..a1c2f884 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index fa5287f0..2a0c9e85 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 46ca8c4c..8cbc3b8b 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index 54b2db08..813013e5 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php index 3e469b98..b819548a 100644 --- a/src/Task/File/Csv/InputCsvReaderTask.php +++ b/src/Task/File/Csv/InputCsvReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index 273dcbda..e9cb12c5 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php index 93f1a6a7..81cf17c2 100644 --- a/src/Task/File/FileMoverTask.php +++ b/src/Task/File/FileMoverTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php index 86833ca9..ea69db22 100644 --- a/src/Task/File/FileReaderTask.php +++ b/src/Task/File/FileReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileRemoverTask.php b/src/Task/File/FileRemoverTask.php index a87675f8..03e68145 100644 --- a/src/Task/File/FileRemoverTask.php +++ b/src/Task/File/FileRemoverTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileWriterTask.php b/src/Task/File/FileWriterTask.php index e135da74..d3dc0740 100644 --- a/src/Task/File/FileWriterTask.php +++ b/src/Task/File/FileWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 1f07cca8..6eeb8e5d 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index 2b090f59..5d1fb90b 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index b2df06d5..9f77ab0d 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Xml/XmlReaderTask.php b/src/Task/File/Xml/XmlReaderTask.php index 55261af7..69535635 100644 --- a/src/Task/File/Xml/XmlReaderTask.php +++ b/src/Task/File/Xml/XmlReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Xml/XmlWriterTask.php b/src/Task/File/Xml/XmlWriterTask.php index 8ce16255..64548f33 100644 --- a/src/Task/File/Xml/XmlWriterTask.php +++ b/src/Task/File/Xml/XmlWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php index 2e10cb4e..67174114 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/YamlReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/YamlWriterTask.php b/src/Task/File/YamlWriterTask.php index 44922e5a..0fa18844 100644 --- a/src/Task/File/YamlWriterTask.php +++ b/src/Task/File/YamlWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/FilterTask.php b/src/Task/FilterTask.php index 07985b3d..38715c3c 100644 --- a/src/Task/FilterTask.php +++ b/src/Task/FilterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 57e85e16..3d676ca3 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 5e68f598..28ccf5e4 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php index 3151855d..301c24b3 100644 --- a/src/Task/InputIteratorTask.php +++ b/src/Task/InputIteratorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index fff5082b..15f46e24 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ObjectUpdaterTask.php b/src/Task/ObjectUpdaterTask.php index 55647e1c..8136b7bd 100644 --- a/src/Task/ObjectUpdaterTask.php +++ b/src/Task/ObjectUpdaterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Process/CommandRunnerTask.php b/src/Task/Process/CommandRunnerTask.php index 7ad26553..999e5573 100644 --- a/src/Task/Process/CommandRunnerTask.php +++ b/src/Task/Process/CommandRunnerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 302eb9e3..e9a515c2 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index 6191c297..1661b87f 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/PropertyGetterTask.php b/src/Task/PropertyGetterTask.php index b7ab2616..a898f4ea 100644 --- a/src/Task/PropertyGetterTask.php +++ b/src/Task/PropertyGetterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/PropertySetterTask.php b/src/Task/PropertySetterTask.php index e89637ae..56be23f8 100644 --- a/src/Task/PropertySetterTask.php +++ b/src/Task/PropertySetterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index 6fe0434b..fed1243c 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Reporting/LoggerTask.php b/src/Task/Reporting/LoggerTask.php index 2cb0e386..dc73bbd9 100644 --- a/src/Task/Reporting/LoggerTask.php +++ b/src/Task/Reporting/LoggerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php index 59b08823..21bc005d 100644 --- a/src/Task/Reporting/StatCounterTask.php +++ b/src/Task/Reporting/StatCounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index 3a9f9b65..163b1bfc 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index 0d2cdb08..975b573a 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Serialization/DeserializerTask.php b/src/Task/Serialization/DeserializerTask.php index 2ee80ac3..1287eeff 100644 --- a/src/Task/Serialization/DeserializerTask.php +++ b/src/Task/Serialization/DeserializerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 0fcdb5c8..2e7d43d3 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Serialization/SerializerTask.php b/src/Task/Serialization/SerializerTask.php index f8158270..054208cb 100644 --- a/src/Task/Serialization/SerializerTask.php +++ b/src/Task/Serialization/SerializerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php index 10c6377a..e0173bc7 100644 --- a/src/Task/SimpleBatchTask.php +++ b/src/Task/SimpleBatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/SkipEmptyTask.php b/src/Task/SkipEmptyTask.php index 8d2cbf61..b649864a 100644 --- a/src/Task/SkipEmptyTask.php +++ b/src/Task/SkipEmptyTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index a313143b..6079d851 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/StopTask.php b/src/Task/StopTask.php index 16ed1ed4..c7ab909a 100644 --- a/src/Task/StopTask.php +++ b/src/Task/StopTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/TransformerTask.php b/src/Task/TransformerTask.php index 92d4ef02..64502a71 100644 --- a/src/Task/TransformerTask.php +++ b/src/Task/TransformerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Validation/ValidatorTask.php b/src/Task/Validation/ValidatorTask.php index f8b842a2..efd82b10 100644 --- a/src/Task/Validation/ValidatorTask.php +++ b/src/Task/Validation/ValidatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayElementTransformer.php b/src/Transformer/ArrayElementTransformer.php index 49213a9b..86cff75e 100644 --- a/src/Transformer/ArrayElementTransformer.php +++ b/src/Transformer/ArrayElementTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayFilterTransformer.php b/src/Transformer/ArrayFilterTransformer.php index 26146d0d..2a942149 100644 --- a/src/Transformer/ArrayFilterTransformer.php +++ b/src/Transformer/ArrayFilterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php index 4fd39050..9d1f3739 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/ArrayFirstTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayLastTransformer.php b/src/Transformer/ArrayLastTransformer.php index f8b0b4c1..e227143e 100644 --- a/src/Transformer/ArrayLastTransformer.php +++ b/src/Transformer/ArrayLastTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayMapTransformer.php b/src/Transformer/ArrayMapTransformer.php index 37bfd311..4e3f7fb3 100644 --- a/src/Transformer/ArrayMapTransformer.php +++ b/src/Transformer/ArrayMapTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayUnsetTransformer.php b/src/Transformer/ArrayUnsetTransformer.php index bdd782a7..e4527269 100644 --- a/src/Transformer/ArrayUnsetTransformer.php +++ b/src/Transformer/ArrayUnsetTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 5f774355..522fda98 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/CallbackTransformer.php b/src/Transformer/CallbackTransformer.php index 3a5c89cc..94e695f8 100644 --- a/src/Transformer/CallbackTransformer.php +++ b/src/Transformer/CallbackTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/CastTransformer.php b/src/Transformer/CastTransformer.php index 7ce970ae..8b099a5a 100644 --- a/src/Transformer/CastTransformer.php +++ b/src/Transformer/CastTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php index 26bbf2e8..a65bda4d 100644 --- a/src/Transformer/ConditionTrait.php +++ b/src/Transformer/ConditionTrait.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConfigurableTransformerInterface.php b/src/Transformer/ConfigurableTransformerInterface.php index 19aad92f..f5112455 100644 --- a/src/Transformer/ConfigurableTransformerInterface.php +++ b/src/Transformer/ConfigurableTransformerInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConstantTransformer.php b/src/Transformer/ConstantTransformer.php index 3fa39842..9a234fcf 100644 --- a/src/Transformer/ConstantTransformer.php +++ b/src/Transformer/ConstantTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index 22e1546a..fc974174 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DateFormatTransformer.php b/src/Transformer/DateFormatTransformer.php index 1299fb4e..464ae658 100644 --- a/src/Transformer/DateFormatTransformer.php +++ b/src/Transformer/DateFormatTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DateParserTransformer.php b/src/Transformer/DateParserTransformer.php index c1dc4077..9553e1f6 100644 --- a/src/Transformer/DateParserTransformer.php +++ b/src/Transformer/DateParserTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DebugTransformer.php b/src/Transformer/DebugTransformer.php index 70593a50..9d6bcfc2 100644 --- a/src/Transformer/DebugTransformer.php +++ b/src/Transformer/DebugTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DefaultTransformer.php b/src/Transformer/DefaultTransformer.php index ca1e81cc..1ce9b633 100644 --- a/src/Transformer/DefaultTransformer.php +++ b/src/Transformer/DefaultTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index 60a24f5d..529f7dfb 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/EvaluatorTransformer.php b/src/Transformer/EvaluatorTransformer.php index 66c9a885..9a33db73 100644 --- a/src/Transformer/EvaluatorTransformer.php +++ b/src/Transformer/EvaluatorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ExplodeTransformer.php b/src/Transformer/ExplodeTransformer.php index be06e117..65b79427 100644 --- a/src/Transformer/ExplodeTransformer.php +++ b/src/Transformer/ExplodeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php index 2456d508..9bfb65b0 100644 --- a/src/Transformer/ExpressionLanguageMapTransformer.php +++ b/src/Transformer/ExpressionLanguageMapTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/GenericTransformer.php b/src/Transformer/GenericTransformer.php index 451d1d06..e033e281 100644 --- a/src/Transformer/GenericTransformer.php +++ b/src/Transformer/GenericTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/HashTransformer.php b/src/Transformer/HashTransformer.php index 150e6996..c1fc610f 100644 --- a/src/Transformer/HashTransformer.php +++ b/src/Transformer/HashTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ImplodeTransformer.php b/src/Transformer/ImplodeTransformer.php index 7f6ecb10..fb08288e 100644 --- a/src/Transformer/ImplodeTransformer.php +++ b/src/Transformer/ImplodeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/InstantiateTransformer.php b/src/Transformer/InstantiateTransformer.php index ea3e7ca0..8da6c2f8 100644 --- a/src/Transformer/InstantiateTransformer.php +++ b/src/Transformer/InstantiateTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index c5788d73..3ed3bc4e 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/MultiReplaceTransformer.php b/src/Transformer/MultiReplaceTransformer.php index f71ecfb3..90d87424 100644 --- a/src/Transformer/MultiReplaceTransformer.php +++ b/src/Transformer/MultiReplaceTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index 52958ad4..5cd57635 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/PregFilterTransformer.php b/src/Transformer/PregFilterTransformer.php index a794ce25..5a6d4f11 100644 --- a/src/Transformer/PregFilterTransformer.php +++ b/src/Transformer/PregFilterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/PropertyAccessorTransformer.php b/src/Transformer/PropertyAccessorTransformer.php index bbe0eaab..4e37c2fc 100644 --- a/src/Transformer/PropertyAccessorTransformer.php +++ b/src/Transformer/PropertyAccessorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/RecursivePropertySetterTransformer.php index e623b988..9d06e256 100644 --- a/src/Transformer/RecursivePropertySetterTransformer.php +++ b/src/Transformer/RecursivePropertySetterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index a0b75775..a68c4bec 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php index 505968ed..491eb52f 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/SlugifyTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php index cf920733..e496d193 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/SprintfTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php index 63a38eab..34cd402b 100644 --- a/src/Transformer/TransformerInterface.php +++ b/src/Transformer/TransformerInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 0c59a75b..e3874aa0 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index e0659510..f9966f7d 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php index c0783a29..a9e621fc 100644 --- a/src/Transformer/TypeSetterTransformer.php +++ b/src/Transformer/TypeSetterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/UnsetTransformer.php b/src/Transformer/UnsetTransformer.php index 736ea535..05d98d60 100644 --- a/src/Transformer/UnsetTransformer.php +++ b/src/Transformer/UnsetTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php index d7a3e2ca..6f55e294 100644 --- a/src/Transformer/WrapperTransformer.php +++ b/src/Transformer/WrapperTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index ccaf0afa..035f0382 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Validator/ConstraintLoader.php b/src/Validator/ConstraintLoader.php index 3bbb384b..d767dc15 100644 --- a/src/Validator/ConstraintLoader.php +++ b/src/Validator/ConstraintLoader.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/ArrayElementTransformerTest.php index a8d4a841..c8cf14ad 100644 --- a/tests/Transformer/ArrayElementTransformerTest.php +++ b/tests/Transformer/ArrayElementTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/ArrayFirstTransformerTest.php index d7daac4f..44fe23d5 100644 --- a/tests/Transformer/ArrayFirstTransformerTest.php +++ b/tests/Transformer/ArrayFirstTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index c443184c..055884f0 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index a57d4ae9..7524c42a 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/DateFormatTransformerTest.php index 2cb244d4..502c92e0 100644 --- a/tests/Transformer/DateFormatTransformerTest.php +++ b/tests/Transformer/DateFormatTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/DateParserTransformerTest.php index f9f60d6e..2a605eab 100644 --- a/tests/Transformer/DateParserTransformerTest.php +++ b/tests/Transformer/DateParserTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php index 2076d77e..36f55766 100644 --- a/tests/Transformer/DebugTransformerTest.php +++ b/tests/Transformer/DebugTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php index 2d749d33..afbf7470 100644 --- a/tests/Transformer/DefaultTransformerTest.php +++ b/tests/Transformer/DefaultTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ExplodeTransformerTest.php b/tests/Transformer/ExplodeTransformerTest.php index 63188e90..b18474d6 100644 --- a/tests/Transformer/ExplodeTransformerTest.php +++ b/tests/Transformer/ExplodeTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/ImplodeTransformerTest.php index 5757815c..3efbf4ce 100644 --- a/tests/Transformer/ImplodeTransformerTest.php +++ b/tests/Transformer/ImplodeTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php index 9a2ee68b..5fc0d59d 100644 --- a/tests/Transformer/MultiReplaceTransformerTest.php +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/TrimTransformerTest.php index 1c6a1dc4..8b590b75 100644 --- a/tests/Transformer/TrimTransformerTest.php +++ b/tests/Transformer/TrimTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php index d1785e4b..5f5437f6 100644 --- a/tests/Transformer/WrapperTransformerTest.php +++ b/tests/Transformer/WrapperTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. From 42a7293ac8c8faa8e8c436ab770212e94ebf036b Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 25 Apr 2024 20:17:43 +0200 Subject: [PATCH 223/304] update copyright --- .php-cs-fixer.dist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 57b2a590..4f96866e 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2023 Clever-Age + * Copyright (c) 2017-2024 Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,7 +16,7 @@ $fileHeaderComment = <<<'EOF' This file is part of the CleverAge/ProcessBundle package. -Copyright (c) 2017-2023 Clever-Age +Copyright (c) 2017-2024 Clever-Age For the full copyright and license information, please view the LICENSE file that was distributed with this source code. From 650343dcc3af035e387ff815da485d1fae377dca Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Thu, 25 Apr 2024 21:37:43 +0200 Subject: [PATCH 224/304] more tests --- .../Xml/XpathEvaluatorTransformer.php | 1 - .../XpathEvaluatorTransformerTest.php | 60 -------- .../MissingTransformerExceptionTest.php | 5 +- .../ArrayElementTransformerTest.php | 9 +- .../Transformer/ArrayFirstTransformerTest.php | 13 +- tests/Transformer/CastTransformerTest.php | 17 ++- tests/Transformer/ConstantTransformerTest.php | 11 +- .../Transformer/DateFormatTransformerTest.php | 13 +- .../Transformer/DateParserTransformerTest.php | 15 +- tests/Transformer/DebugTransformerTest.php | 7 +- tests/Transformer/DefaultTransformerTest.php | 11 +- tests/Transformer/ExplodeTransformerTest.php | 13 +- tests/Transformer/ImplodeTransformerTest.php | 13 +- .../MultiReplaceTransformerTest.php | 13 +- tests/Transformer/SprintfTransformerTest.php | 7 +- tests/Transformer/TrimTransformerTest.php | 13 +- tests/Transformer/WrapperTransformerTest.php | 13 +- .../XpathEvaluatorTransformerTest.php | 136 ++++++++++++++++++ 18 files changed, 245 insertions(+), 125 deletions(-) create mode 100644 tests/Transformer/XpathEvaluatorTransformerTest.php diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index 035f0382..e4952d21 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -112,7 +112,6 @@ public function buildXpath(\DOMNode $node): \DOMXPath public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $options): mixed { - // TODO check if query is relative ? $nodeList = $xpath->query($query, $node); $results = iterator_to_array($nodeList); diff --git a/tests.old/Transformer/XpathEvaluatorTransformerTest.php b/tests.old/Transformer/XpathEvaluatorTransformerTest.php index c0c808e4..a1cc61ec 100644 --- a/tests.old/Transformer/XpathEvaluatorTransformerTest.php +++ b/tests.old/Transformer/XpathEvaluatorTransformerTest.php @@ -21,66 +21,6 @@ */ class XpathEvaluatorTransformerTest extends AbstractProcessTest { - public function testSimpleQuery(): void - { - $domDocument = new \DOMDocument(); - $domDocument->loadXML('ok'); - $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ - 'query' => '/a/text()', - ]); - } - - public function testAttributeValueQuery(): void - { - $domDocument = new \DOMDocument(); - $domDocument->loadXML('ko'); - $this->assertTransformation('xpath_evaluator', 'ok', $domDocument, [ - 'query' => '/node/@data', - ]); - } - - public function testSubQuery(): void - { - $domDocument = new \DOMDocument(); - $domDocument->loadXML('ok'); - - $node = $domDocument->getElementsByTagName('b')[0]; - $this->assertTransformation('xpath_evaluator', 'ok', $node, [ - 'query' => './c/text()', - ]); - } - - public function testMultiResults(): void - { - $domDocument = new \DOMDocument(); - $domDocument->loadXML('ok1ok2ok3'); - - $node = $domDocument->getElementsByTagName('b')[0]; - $this->assertTransformation('xpath_evaluator', ['ok1', 'ok2', 'ok3'], $node, [ - 'query' => './c/text()', - 'single_result' => false, - ]); - } - - public function testMultiResultsAsNodeList(): void - { - $domDocument = new \DOMDocument(); - $domDocument->loadXML('ok1ok2ok3'); - - $node = $domDocument->getElementsByTagName('b')[0]; - /** @var \DOMNodeList $result */ - $result = $this->transform('xpath_evaluator', $node, [ - 'query' => './c/text()', - 'single_result' => false, - 'unwrap_value' => false, - ]); - - self::assertCount(3, $result); - self::assertEquals('ok1', $result[0]->textContent); - self::assertEquals('ok2', $result[1]->textContent); - self::assertEquals('ok3', $result[2]->textContent); - } - public function testMultiQuery(): void { $domDocument = new \DOMDocument(); diff --git a/tests/Exception/MissingTransformerExceptionTest.php b/tests/Exception/MissingTransformerExceptionTest.php index b8a3f310..fad77c86 100644 --- a/tests/Exception/MissingTransformerExceptionTest.php +++ b/tests/Exception/MissingTransformerExceptionTest.php @@ -7,10 +7,13 @@ use CleverAge\ProcessBundle\Exception\MissingTransformerException; use PHPUnit\Framework\TestCase; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Exception\MissingTransformerException + */ class MissingTransformerExceptionTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Exception\MissingTransformerException::create + * @covers ::create */ public function testCreate(): void { diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/ArrayElementTransformerTest.php index c8cf14ad..6895a9c8 100644 --- a/tests/Transformer/ArrayElementTransformerTest.php +++ b/tests/Transformer/ArrayElementTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer + */ class ArrayElementTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer::transform + * @covers ::transform */ public function testTransformReturnsNthElementFromArray(): void { @@ -34,7 +37,7 @@ public function testTransformReturnsNthElementFromArray(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptionsSetsRequiredOptions(): void { @@ -50,7 +53,7 @@ public function testConfigureOptionsSetsRequiredOptions(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/ArrayFirstTransformerTest.php index 44fe23d5..07b87049 100644 --- a/tests/Transformer/ArrayFirstTransformerTest.php +++ b/tests/Transformer/ArrayFirstTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer + */ class ArrayFirstTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::transform + * @covers ::transform */ public function testTransformReturnsFirstElementIfIterableAndAllowed(): void { @@ -34,7 +37,7 @@ public function testTransformReturnsFirstElementIfIterableAndAllowed(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::transform + * @covers ::transform */ public function testTransformReturnsValueIfNotIterableAndAllowed(): void { @@ -50,7 +53,7 @@ public function testTransformReturnsValueIfNotIterableAndAllowed(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::transform + * @covers ::transform */ public function testTransformThrowsExceptionIfNotIterableAndNotAllowed(): void { @@ -64,7 +67,7 @@ public function testTransformThrowsExceptionIfNotIterableAndNotAllowed(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { @@ -76,7 +79,7 @@ public function testGetCodeReturnsCorrectCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptionsSetsDefaultOptions(): void { diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index 055884f0..5a667646 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\CastTransformer + */ class CastTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + * @covers ::transform */ public function testCastToInt(): void { @@ -35,7 +38,7 @@ public function testCastToInt(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + * @covers ::transform */ public function testCastToFloat(): void { @@ -50,7 +53,7 @@ public function testCastToFloat(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + * @covers ::transform */ public function testCastToString(): void { @@ -65,7 +68,7 @@ public function testCastToString(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + * @covers ::transform */ public function testCastToBool(): void { @@ -80,7 +83,7 @@ public function testCastToBool(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::transform + * @covers ::transform */ public function testCastToInvalidType(): void { @@ -94,7 +97,7 @@ public function testCastToInvalidType(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptionsSetsRequiredOptions(): void { @@ -110,7 +113,7 @@ public function testConfigureOptionsSetsRequiredOptions(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\CastTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index 7524c42a..9d291e37 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ConstantTransformer + */ class ConstantTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -34,7 +37,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::transform + * @covers ::transform */ public function testTransformWithNullValue(): void { @@ -48,7 +51,7 @@ public function testTransformWithNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { @@ -61,7 +64,7 @@ public function testConfigureOptions(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ConstantTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/DateFormatTransformerTest.php index 502c92e0..6baf4821 100644 --- a/tests/Transformer/DateFormatTransformerTest.php +++ b/tests/Transformer/DateFormatTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DateFormatTransformer + */ class DateFormatTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::transform + * @covers ::transform */ public function testTransformValidDate(): void { @@ -35,7 +38,7 @@ public function testTransformValidDate(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::transform + * @covers ::transform */ public function testTransformInvalidDate(): void { @@ -49,7 +52,7 @@ public function testTransformInvalidDate(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::transform + * @covers ::transform */ public function testTransformNullValue(): void { @@ -64,7 +67,7 @@ public function testTransformNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::getCode + * @covers ::getCode */ public function testGetCode(): void { @@ -76,7 +79,7 @@ public function testGetCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateFormatTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/DateParserTransformerTest.php index 2a605eab..7ac7a7d6 100644 --- a/tests/Transformer/DateParserTransformerTest.php +++ b/tests/Transformer/DateParserTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DateParserTransformer + */ class DateParserTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + * @covers ::transform */ public function testTransformValidDate(): void { @@ -35,7 +38,7 @@ public function testTransformValidDate(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + * @covers ::transform */ public function testTransformInvalidDate(): void { @@ -49,7 +52,7 @@ public function testTransformInvalidDate(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + * @covers ::transform */ public function testTransformNullValue(): void { @@ -63,7 +66,7 @@ public function testTransformNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::transform + * @covers ::transform */ public function testTransformDateTimeObject(): void { @@ -78,7 +81,7 @@ public function testTransformDateTimeObject(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::getCode + * @covers ::getCode */ public function testGetCode(): void { @@ -90,7 +93,7 @@ public function testGetCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DateParserTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php index 36f55766..5af9744e 100644 --- a/tests/Transformer/DebugTransformerTest.php +++ b/tests/Transformer/DebugTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\VarDumper; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DebugTransformer + */ class DebugTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\DebugTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -37,7 +40,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DebugTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php index afbf7470..64a71cfe 100644 --- a/tests/Transformer/DefaultTransformerTest.php +++ b/tests/Transformer/DefaultTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DefaultTransformer + */ class DefaultTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::transform + * @covers ::transform */ public function testTransformWithNonNullValue(): void { @@ -34,7 +37,7 @@ public function testTransformWithNonNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::transform + * @covers ::transform */ public function testTransformWithNullValue(): void { @@ -48,7 +51,7 @@ public function testTransformWithNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { @@ -64,7 +67,7 @@ public function testConfigureOptions(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\DefaultTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/ExplodeTransformerTest.php b/tests/Transformer/ExplodeTransformerTest.php index b18474d6..b454c27a 100644 --- a/tests/Transformer/ExplodeTransformerTest.php +++ b/tests/Transformer/ExplodeTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ExplodeTransformer + */ class ExplodeTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -32,7 +35,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::transform + * @covers ::transform */ public function testTransformWithEmptyString(): void { @@ -44,7 +47,7 @@ public function testTransformWithEmptyString(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::transform + * @covers ::transform */ public function testTransformWithNullValue(): void { @@ -56,7 +59,7 @@ public function testTransformWithNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::getCode + * @covers ::getCode */ public function testGetCode(): void { @@ -68,7 +71,7 @@ public function testGetCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ExplodeTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/ImplodeTransformerTest.php index 3efbf4ce..0a3751d4 100644 --- a/tests/Transformer/ImplodeTransformerTest.php +++ b/tests/Transformer/ImplodeTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ImplodeTransformer + */ class ImplodeTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -32,7 +35,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::transform + * @covers ::transform */ public function testTransformWithInvalidValue(): void { @@ -44,7 +47,7 @@ public function testTransformWithInvalidValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::transform + * @covers ::transform */ public function testTransformWithDefaultSeparator(): void { @@ -56,7 +59,7 @@ public function testTransformWithDefaultSeparator(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::getCode + * @covers ::getCode */ public function testGetCode(): void { @@ -68,7 +71,7 @@ public function testGetCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\ImplodeTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php index 5fc0d59d..8a3c58c6 100644 --- a/tests/Transformer/MultiReplaceTransformerTest.php +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer + */ class MultiReplaceTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -39,7 +42,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::transform + * @covers ::transform */ public function testTransformWithEmptyReplaceMapping(): void { @@ -55,7 +58,7 @@ public function testTransformWithEmptyReplaceMapping(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::transform + * @covers ::transform */ public function testTransformWithNullValue(): void { @@ -74,7 +77,7 @@ public function testTransformWithNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptions(): void { @@ -91,7 +94,7 @@ public function testConfigureOptions(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { diff --git a/tests/Transformer/SprintfTransformerTest.php b/tests/Transformer/SprintfTransformerTest.php index 7761d4b5..59397a0f 100644 --- a/tests/Transformer/SprintfTransformerTest.php +++ b/tests/Transformer/SprintfTransformerTest.php @@ -7,10 +7,13 @@ use CleverAge\ProcessBundle\Transformer\SprintfTransformer; use PHPUnit\Framework\TestCase; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\SprintfTransformer + */ class SprintfTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\SprintfTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -23,7 +26,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\SprintfTransformer::getCode + * @covers ::getCode */ public function testCode(): void { diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/TrimTransformerTest.php index 8b590b75..62aca460 100644 --- a/tests/Transformer/TrimTransformerTest.php +++ b/tests/Transformer/TrimTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\TrimTransformer + */ class TrimTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform + * @covers ::transform */ public function testTransformTrimsStringWithDefaultCharlist(): void { @@ -33,7 +36,7 @@ public function testTransformTrimsStringWithDefaultCharlist(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform + * @covers ::transform */ public function testTransformTrimsStringWithCustomCharlist(): void { @@ -47,7 +50,7 @@ public function testTransformTrimsStringWithCustomCharlist(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::transform + * @covers ::transform */ public function testTransformReturnsNullForNullValue(): void { @@ -60,7 +63,7 @@ public function testTransformReturnsNullForNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { @@ -72,7 +75,7 @@ public function testGetCodeReturnsCorrectCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\TrimTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptionsSetsDefaultOptions(): void { diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php index 5f5437f6..4699f7a3 100644 --- a/tests/Transformer/WrapperTransformerTest.php +++ b/tests/Transformer/WrapperTransformerTest.php @@ -17,10 +17,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\WrapperTransformer + */ class WrapperTransformerTest extends TestCase { /** - * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::transform + * @covers ::transform */ public function testTransform(): void { @@ -36,7 +39,7 @@ public function testTransform(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::transform + * @covers ::transform */ public function testTransformWithIntegerWrapperKey(): void { @@ -52,7 +55,7 @@ public function testTransformWithIntegerWrapperKey(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::transform + * @covers ::transform */ public function testTransformWithNullValue(): void { @@ -68,7 +71,7 @@ public function testTransformWithNullValue(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::getCode + * @covers ::getCode */ public function testGetCodeReturnsCorrectCode(): void { @@ -80,7 +83,7 @@ public function testGetCodeReturnsCorrectCode(): void } /** - * @covers \CleverAge\ProcessBundle\Transformer\WrapperTransformer::configureOptions + * @covers ::configureOptions */ public function testConfigureOptionsSetsDefaultOptions(): void { diff --git a/tests/Transformer/XpathEvaluatorTransformerTest.php b/tests/Transformer/XpathEvaluatorTransformerTest.php new file mode 100644 index 00000000..50fda077 --- /dev/null +++ b/tests/Transformer/XpathEvaluatorTransformerTest.php @@ -0,0 +1,136 @@ +loadXML('ok'); + + $transformer = new XpathEvaluatorTransformer(); + $xpath = $transformer->buildXpath($domDocument); + + $this->assertInstanceOf(\DOMXPath::class, $xpath); + + $options = ['query' => '/a/text()', 'single_result' => true, 'ignore_missing' => true, 'unwrap_value' => true]; + + $queryResult = $transformer->query($xpath, '/a/text()', $domDocument, $options); + $this->assertEquals('ok', $queryResult); + + $result = $transformer->transform($domDocument, $options); + $this->assertEquals('ok', $result); + } + + /** + * @covers ::buildXpath + * @covers ::query + * @covers ::transform + */ + public function testAttributeValueQuery(): void + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ko'); + + $transformer = new XpathEvaluatorTransformer(); + $options = ['query' => '/node/@data', 'single_result' => true, 'ignore_missing' => true, 'unwrap_value' => true]; + + $result = $transformer->transform($domDocument, $options); + $this->assertEquals('ok', $result); + } + + /** + * @covers ::buildXpath + * @covers ::query + * @covers ::transform + */ + public function testSubQuery(): void + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok'); + $node = $domDocument->getElementsByTagName('b')[0]; + + $transformer = new XpathEvaluatorTransformer(); + $options = ['query' => './c/text()', 'single_result' => true, 'ignore_missing' => true, 'unwrap_value' => true]; + + $result = $transformer->transform($node, $options); + $this->assertEquals('ok', $result); + } + + /** + * @covers ::buildXpath + * @covers ::query + * @covers ::transform + */ + public function testMultiResults(): void + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + + $transformer = new XpathEvaluatorTransformer(); + $options = ['query' => './c/text()', 'single_result' => false, 'ignore_missing' => true, 'unwrap_value' => true]; + + $result = $transformer->transform($node, $options); + $this->assertEquals(['ok1', 'ok2', 'ok3'], $result); + } + + /** + * @covers ::buildXpath + * @covers ::query + * @covers ::transform + */ + public function testMultiResultsAsNodeList(): void + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML('ok1ok2ok3'); + + $node = $domDocument->getElementsByTagName('b')[0]; + + $transformer = new XpathEvaluatorTransformer(); + $options = ['query' => './c/text()', 'single_result' => false, 'ignore_missing' => true, 'unwrap_value' => false]; + + $result = $transformer->transform($node, $options); + + self::assertCount(3, $result); + self::assertEquals('ok1', $result[0]->textContent); + self::assertEquals('ok2', $result[1]->textContent); + self::assertEquals('ok3', $result[2]->textContent); + } + + /** + * @covers ::getCode + */ + public function testGetCodeReturnsCorrectCode(): void + { + $transformer = new XpathEvaluatorTransformer(); + + $code = $transformer->getCode(); + + $this->assertEquals('xpath_evaluator', $code); + } +} From 0c59a1fb5a5af98f99af57423332be73c1e8456a Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Thu, 20 Jun 2024 19:14:40 +0200 Subject: [PATCH 225/304] switch to php8.1 --- composer.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 7195245c..d43fa4b6 100644 --- a/composer.json +++ b/composer.json @@ -57,30 +57,30 @@ "symfony/polyfill-php81": "*" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-json": "*", "ext-dom": "*", "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", "league/flysystem-bundle": "^3.1", - "symfony/config": "^6.3", - "symfony/console": "^6.3", - "symfony/dependency-injection": "^6.3", + "symfony/config": "^7.1", + "symfony/console": "^7.1", + "symfony/dependency-injection": "^7.1", "symfony/event-dispatcher-contracts": "^3", - "symfony/expression-language": "^6.3", - "symfony/form": "^6.3", - "symfony/framework-bundle": "^6.3", - "symfony/messenger": "^6.3", + "symfony/expression-language": "^7.1", + "symfony/form": "^7.1", + "symfony/framework-bundle": "^7.1", + "symfony/messenger": "^7.1", "symfony/monolog-bundle": "~3.3", - "symfony/options-resolver": "^6.3", - "symfony/process": "^6.3", - "symfony/property-access": "^6.3", - "symfony/scheduler": "^6.3", - "symfony/serializer": "^6.3", - "symfony/stopwatch": "^6.3", - "symfony/validator": "^6.3", - "symfony/yaml": "^6.3" + "symfony/options-resolver": "^7.1", + "symfony/process": "^7.1", + "symfony/property-access": "^7.1", + "symfony/scheduler": "^7.1", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^7.1", + "symfony/validator": "^7.1", + "symfony/yaml": "^7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", From 407b09cfc58149e0ce4f0a88d9e2504c5d98fd9c Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Thu, 20 Jun 2024 19:23:03 +0200 Subject: [PATCH 226/304] update rector --- rector.php | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/rector.php b/rector.php index bc0c62e5..5a4479b2 100644 --- a/rector.php +++ b/rector.php @@ -2,25 +2,20 @@ declare(strict_types=1); -use Rector\Config\RectorConfig; -use Rector\Core\ValueObject\PhpVersion; -use Rector\Set\ValueObject\LevelSetList; -use Rector\Set\ValueObject\SetList; -use Rector\Symfony\Set\SymfonyLevelSetList; - -return static function (RectorConfig $rectorConfig): void { - $rectorConfig->parallel(); - $rectorConfig->importNames(); - $rectorConfig->importShortClasses(); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) 2017-2024 Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ - $rectorConfig->paths([__DIR__.'/src']); - $rectorConfig->skip([__DIR__.'/src/Resources/tests']); - - $rectorConfig->sets([ - SetList::TYPE_DECLARATION, - LevelSetList::UP_TO_PHP_81, - SymfonyLevelSetList::UP_TO_SYMFONY_63, - ]); +use Rector\Config\RectorConfig; - $rectorConfig->phpVersion(PhpVersion::PHP_81); -}; +return RectorConfig::configure() + ->withPaths([__DIR__.'/src', __DIR__.'/tests']) + ->withPhpSets(php82: true) + ->withAttributesSets(symfony: true) + ->withImportNames(removeUnusedImports: true) +; From f779cc1af4b99aece084cd2907f2257be1694b1f Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Thu, 20 Jun 2024 20:16:28 +0200 Subject: [PATCH 227/304] fix symfony versions --- composer.json | 32 ++++++++++++++++---------------- src/CleverAgeProcessBundle.php | 13 ++++--------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index d43fa4b6..a1d4119c 100644 --- a/composer.json +++ b/composer.json @@ -57,30 +57,30 @@ "symfony/polyfill-php81": "*" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "ext-json": "*", "ext-dom": "*", "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", "league/flysystem-bundle": "^3.1", - "symfony/config": "^7.1", - "symfony/console": "^7.1", - "symfony/dependency-injection": "^7.1", + "symfony/config": "^6.4|^7.1", + "symfony/console": "^6.4|^7.1", + "symfony/dependency-injection": "^6.4|^7.1", "symfony/event-dispatcher-contracts": "^3", - "symfony/expression-language": "^7.1", - "symfony/form": "^7.1", - "symfony/framework-bundle": "^7.1", - "symfony/messenger": "^7.1", + "symfony/expression-language": "^6.4|^7.1", + "symfony/form": "^6.4|^7.1", + "symfony/framework-bundle": "^6.4|^7.1", + "symfony/messenger": "^6.4|^7.1", "symfony/monolog-bundle": "~3.3", - "symfony/options-resolver": "^7.1", - "symfony/process": "^7.1", - "symfony/property-access": "^7.1", - "symfony/scheduler": "^7.1", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^7.1", - "symfony/validator": "^7.1", - "symfony/yaml": "^7.1" + "symfony/options-resolver": "^6.4|^7.1", + "symfony/process": "^6.4|^7.1", + "symfony/property-access": "^6.4|^7.1", + "symfony/scheduler": "^6.4|^7.1", + "symfony/serializer": "^6.4|^7.1", + "symfony/stopwatch": "^6.4|^7.1", + "symfony/validator": "^6.4|^7.1", + "symfony/yaml": "^6.4|^7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 27904639..da03e1ce 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -16,25 +16,20 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\HttpKernel\Bundle\AbstractBundle; -class CleverAgeProcessBundle extends Bundle +class CleverAgeProcessBundle extends AbstractBundle { /** * Adding compiler passes to inject services into registry. */ public function build(ContainerBuilder $container): void { - parent::build($container); - $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), - PassConfig::TYPE_BEFORE_OPTIMIZATION, - 0 + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') ); - $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); + $container->addCompilerPass(new CheckSerializerCompilerPass()); } } From e823b6afad0de505020d19819b2da46ed6dba83c Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Thu, 27 Jun 2024 19:30:55 +0200 Subject: [PATCH 228/304] fix bundle --- src/CleverAgeProcessBundle.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index da03e1ce..27904639 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -16,20 +16,25 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\Bundle\AbstractBundle; +use Symfony\Component\HttpKernel\Bundle\Bundle; -class CleverAgeProcessBundle extends AbstractBundle +class CleverAgeProcessBundle extends Bundle { /** * Adding compiler passes to inject services into registry. */ public function build(ContainerBuilder $container): void { + parent::build($container); + $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), + PassConfig::TYPE_BEFORE_OPTIMIZATION, + 0 ); - $container->addCompilerPass(new CheckSerializerCompilerPass()); + $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); } } From 6713d7639e003c0c74663f9fa0be8844cde5b8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Zagrodnicki?= Date: Tue, 10 Sep 2024 11:57:10 +0200 Subject: [PATCH 229/304] Check process code before process execution registering --- src/Command/ExecuteProcessCommand.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 8a4f488a..73fec99a 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -16,7 +16,9 @@ use CleverAge\ProcessBundle\Event\ConsoleProcessEvent; use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; +use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -40,7 +42,8 @@ class ExecuteProcessCommand extends Command public function __construct( protected ProcessManager $processManager, - protected EventDispatcherInterface $eventDispatcher + protected EventDispatcherInterface $eventDispatcher, + protected ProcessConfigurationRegistry $processRegistry, ) { parent::__construct(); } @@ -86,6 +89,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->eventDispatcher->dispatch(new ConsoleProcessEvent($input, $output, $inputData, $context)); foreach ($input->getArgument('processCodes') as $code) { + if (!$this->processRegistry->hasProcessConfiguration($code)) { + throw new InvalidConfigurationException("Unknown process {$code}"); + } + if (!$output->isQuiet()) { $output->writeln("Starting process '{$code}'..."); } From f18d5ee8def91a6dcceedd3d841386d896b15d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Zagrodnicki?= Date: Wed, 2 Oct 2024 10:36:38 +0200 Subject: [PATCH 230/304] Fix Rules Transformer --- src/Transformer/RulesTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index a68c4bec..4e19338c 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -128,7 +128,7 @@ public function configureRuleOptions(OptionsResolver $resolver, array $expressio /** * Test if a value match a rule. */ - protected function matchRule(mixed $value, string|ParsedExpression $rule, bool $useValueAsVariable): bool + protected function matchRule(mixed $value, array $rule, bool $useValueAsVariable): bool { if (null !== $rule['condition']) { $expressionValues = $useValueAsVariable ? $value : [ From de8c42b71b67433c4e77c5d12b0b9ea195f8ae3f Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 16 Oct 2024 11:04:45 +0200 Subject: [PATCH 231/304] #139 Remove unused ecs.php --- ecs.php | 24 ------------------------ phpstan.neon | 1 - 2 files changed, 25 deletions(-) delete mode 100644 ecs.php diff --git a/ecs.php b/ecs.php deleted file mode 100644 index 69fb8167..00000000 --- a/ecs.php +++ /dev/null @@ -1,24 +0,0 @@ -rule(LineLengthFixer::class); - - $ecsConfig->sets([ - SetList::CLEAN_CODE, - SetList::SYMPLIFY, - SetList::COMMON, - SetList::PSR_12, - SetList::DOCTRINE_ANNOTATIONS, - ]); - - $ecsConfig->paths([__DIR__.'/src']); - - $ecsConfig->skip([AssignmentInConditionSniff::class]); -}; diff --git a/phpstan.neon b/phpstan.neon index a9f5c7bc..244b173e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,7 +3,6 @@ parameters: paths: - src excludePaths: - - ecs.php - vendor/* - tests/* - rector.php From 1c33118c2ef5a7109f1d9a5d325dd55a4f17608a Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 09:54:12 +0200 Subject: [PATCH 232/304] #140 Move ISSUE_TEMPLATE & PULL_REQUEST_TEMPLATE to proper .github directory. Fix github notifications workflow due to RocketChat/Rocket.Chat.GitHub.Action.Notification deprecation. Add quality & test github workflows. --- .../ISSUE_TEMPLATE.md | 0 .../PULL_REQUEST_TEMPLATE.md | 0 .github/workflows/notifications.yml | 2 +- .github/workflows/quality.yml | 62 ++++++++++++++++ .github/workflows/test.yml | 74 +++++++++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) rename ISSUE_TEMPLATE.md => .github/ISSUE_TEMPLATE.md (100%) rename PULL_REQUEST_TEMPLATE.md => .github/PULL_REQUEST_TEMPLATE.md (100%) create mode 100644 .github/workflows/quality.yml create mode 100644 .github/workflows/test.yml diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md similarity index 100% rename from ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/workflows/notifications.yml b/.github/workflows/notifications.yml index 00aa3926..dd59e3a5 100644 --- a/.github/workflows/notifications.yml +++ b/.github/workflows/notifications.yml @@ -16,7 +16,7 @@ jobs: run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//} - name: Rocket.Chat Notification - uses: RocketChat/Rocket.Chat.GitHub.Action.Notification@1.1.1 + uses: madalozzo/Rocket.Chat.GitHub.Action.Notification@v2 with: type: success job_name: "[cleverage/process-bundle](https://github.com/cleverage/process-bundle) : ${{ steps.get_tag.outputs.TAG }} has been released" diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 00000000..9f1580fe --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,62 @@ +name: Quality + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHPStan + run: vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github + + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHP-CS-Fixer + run: vendor/bin/php-cs-fixer fix --diff --dry-run --show-progress=none + + rector: + name: Rector + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: Rector + run: vendor/bin/rector --no-progress-bar --dry-run diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..78aa3aa8 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,74 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + test: + name: PHP ${{ matrix.php-version }} + ${{ matrix.dependencies }} + ${{ matrix.variant }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.allowed-to-fail }} + env: + SYMFONY_REQUIRE: ${{matrix.symfony-require}} + + strategy: + matrix: + php-version: + - '8.2' + - '8.3' + dependencies: [highest] + allowed-to-fail: [false] + symfony-require: [''] + variant: [normal] + include: + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: pcov + tools: composer:v2, flex + - name: Add PHPUnit matcher + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Install variant + if: matrix.variant != 'normal' && !startsWith(matrix.variant, 'symfony/symfony') + run: composer require ${{ matrix.variant }} --no-update + - name: Install Composer dependencies (${{ matrix.dependencies }}) + uses: ramsey/composer-install@v3 + with: + dependency-versions: ${{ matrix.dependencies }} + - name: Run Tests with coverage + run: make coverage + #- name: Send coverage to Codecov + # uses: codecov/codecov-action@v4 + # with: + # files: build/logs/clover.xml From c725b1030c5e9d432c7ed58602d80151a701510e Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 09:59:45 +0200 Subject: [PATCH 233/304] #138 Update README & CONTRIBUTING --- CONTRIBUTING.md | 1 - README.md | 115 ++++++++++++++++++++++++++++-------------------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06b24c8f..0a4b6a92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,5 +14,4 @@ When a feature should be deprecated, or when you have a breaking change for a fu * Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v4.0', E_USER_DEPRECATED);` You can check which deprecation notice is triggered in tests -* `make shell` * `SYMFONY_DEPRECATIONS_HELPER=0 ./vendor/bin/phpunit` diff --git a/README.md b/README.md index da35666a..28cbc9ab 100644 --- a/README.md +++ b/README.md @@ -6,58 +6,79 @@ CleverAge/ProcessBundle This bundle allows to configure series of tasks to be performed on a certain order. Basically, it will greatly ease the configuration of import and exports but can do much more. -Compatible with every [currently supported Symfony versions](https://symfony.com/releases). +Compatible with [Symfony stable version and latest Long-Term Support (LTS) release](https://symfony.com/releases). -## Index +Demo project can be found on [there](https://github.com/cleverage/process-bundle-ui-demo). + +## Documentation - [Quick start](doc/01-quick_start.md) - [Task types](doc/02-task_types.md) - [Custom tasks and development](doc/03-custom_tasks.md) - [Advanced workflow](doc/04-advanced_workflow.md) -- [Contribute](CONTRIBUTING.md) - Cookbooks - - [Common Setup](doc/cookbooks/01-common_setup.md) - - [Transformations] - - [Flow manipulation] - - [Dummy tasks] - - [Debugging] - - [Logging] - - [Subprocess] - - [File manipulation] - - [Direct call (in controller)] - - [Performances monitoring](doc/cookbooks/performances_monitoring.md) - - [Memory usage analysis](doc/cookbooks/memory_usage_graph.md) + - [Common Setup](doc/cookbooks/01-common_setup.md) + - [Transformations] + - [Flow manipulation] + - [Dummy tasks] + - [Debugging] + - [Logging] + - [Subprocess] + - [File manipulation] + - [Direct call (in controller)] + - [Performances monitoring](doc/cookbooks/performances_monitoring.md) + - [Memory usage analysis](doc/cookbooks/memory_usage_graph.md) - Reference - - [Process definition](doc/reference/01-process_definition.md) - - [Task definition](doc/reference/02-task_definition.md) - - Basic and debug - - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) - - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) - - [DebugTask](doc/reference/tasks/debug_task.md) - - [DieTask](doc/reference/tasks/die_task.md) - - [DummyTask](doc/reference/tasks/dummy_task.md) - - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) - - Data manipulation and transformations - - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) - - [NormalizerTask](doc/reference/tasks/normalizer_task.md) - - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) - - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) - - [TransformerTask](doc/reference/tasks/transformer_task.md) - - File/CSV - - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) - - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) - - File/XML - - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) - - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) - - Flow manipulation - - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) - - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) - - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) - - Transformers - - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) - - [MappingTransformer](doc/reference/transformers/mapping_transformer.md) - - [RulesTransformer](doc/reference/transformers/rules_transformer.md) - - [DateFormatTransformer](doc/reference/transformers/date_format.md) - - [DateParserTransformer](doc/reference/transformers/date_parser.md) - - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) - - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) + - [Process definition](doc/reference/01-process_definition.md) + - [Task definition](doc/reference/02-task_definition.md) + - Basic and debug + - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) + - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) + - [DebugTask](doc/reference/tasks/debug_task.md) + - [DieTask](doc/reference/tasks/die_task.md) + - [DummyTask](doc/reference/tasks/dummy_task.md) + - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) + - Data manipulation and transformations + - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) + - [NormalizerTask](doc/reference/tasks/normalizer_task.md) + - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) + - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) + - [TransformerTask](doc/reference/tasks/transformer_task.md) + - File/CSV + - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) + - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) + - File/XML + - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) + - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) + - Flow manipulation + - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) + - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) + - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) + - Transformers + - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) + - [MappingTransformer](doc/reference/transformers/mapping_transformer.md) + - [RulesTransformer](doc/reference/transformers/rules_transformer.md) + - [DateFormatTransformer](doc/reference/transformers/date_format.md) + - [DateParserTransformer](doc/reference/transformers/date_parser.md) + - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) + - Other bridges + - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) + - [Eav](https://github.com/cleverage/eav-process-bundle) + - [Soap](https://github.com/cleverage/soap-process-bundle) + - [Another Soap](https://github.com/cleverage/process-soap-bundle) + - [Rest](https://github.com/cleverage/rest-process-bundle) + - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) + - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) + - [Cache](https://github.com/cleverage/cache-process-bundle) + - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) +- [UI](https://github.com/cleverage/processuibundle) + +## Support & Contribution + +For general support and questions, please use [Github](https://github.com/cleverage/process-bundle/issues). +If you think you found a bug or you have a feature idea to propose, feel free to open an issue after looking at the [contributing](CONTRIBUTING.md) guide. + +## License + +This bundle is under the MIT license. +For the whole copyright, see the [LICENSE](LICENSE) file distributed with this source code. From 57dd03f8a642ab17acd0f990ec5fc9ad16f6887b Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 16 Oct 2024 17:06:30 +0200 Subject: [PATCH 234/304] #139 Update Makefile & .docker for local standalone usage --- .docker/compose.yaml | 12 +++++++++ .docker/php/Dockerfile | 29 ++++++++++++++++++++++ .docker/php/conf.d/dev.ini | 5 ++++ Dockerfile | 29 ---------------------- Makefile | 51 +++++++++++++++++++++++++++++++++----- 5 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 .docker/compose.yaml create mode 100644 .docker/php/Dockerfile create mode 100644 .docker/php/conf.d/dev.ini delete mode 100644 Dockerfile diff --git a/.docker/compose.yaml b/.docker/compose.yaml new file mode 100644 index 00000000..9c311377 --- /dev/null +++ b/.docker/compose.yaml @@ -0,0 +1,12 @@ +x-build-args: &build-args + UID: "${UID:-1000}" + GID: "${GID:-1000}" + +services: + php: + build: + context: php + args: + <<: *build-args + volumes: + - ../:/var/www diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile new file mode 100644 index 00000000..f98c3ba0 --- /dev/null +++ b/.docker/php/Dockerfile @@ -0,0 +1,29 @@ +FROM php:8.2-fpm-alpine + +ARG UID +ARG GID + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" +COPY /conf.d/ "$PHP_INI_DIR/conf.d/" + +RUN apk update && apk add \ + tzdata \ + shadow \ + nano \ + bash \ + icu-dev \ + && docker-php-ext-configure intl \ + && docker-php-ext-install intl opcache \ + && docker-php-ext-enable opcache + +RUN ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \ + && sed -i "s/^;date.timezone =.*/date.timezone = Europe\/Paris/" $PHP_INI_DIR/php.ini + +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +RUN usermod -u $UID www-data \ + && groupmod -g $GID www-data + +USER www-data:www-data + +WORKDIR /var/www diff --git a/.docker/php/conf.d/dev.ini b/.docker/php/conf.d/dev.ini new file mode 100644 index 00000000..2a141bea --- /dev/null +++ b/.docker/php/conf.d/dev.ini @@ -0,0 +1,5 @@ +display_errors = 1 +error_reporting = E_ALL + +opcache.validate_timestamps = 1 +opcache.revalidate_freq = 0 diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 5ed590e7..00000000 --- a/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -ARG PHP_VERSION=8.1 -FROM php:${PHP_VERSION}-cli - -# Basic tools -RUN apt-get update -RUN apt-get install -y wget git zip unzip - -# Composer install -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer - -# PHP setup -RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" -COPY Resources/tests/environment/php/conf.ini "$PHP_INI_DIR/conf.d/" - -# Basic sample symfony app install -ARG SF_ENV=sf5 -ENV APP_ENV test -RUN mkdir /app -WORKDIR /app -ENV HOME /app -COPY Resources/tests/environment/${SF_ENV}/composer.json /app -RUN composer install - -# Additionnal config files for a test env -COPY phpstan.neon /app/ -COPY Resources/tests/environment/${SF_ENV} /app/ - -# Drop the process-bundle sources into this folder -RUN mkdir /src-cleverage_process diff --git a/Makefile b/Makefile index e9e753c2..d41ff83a 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,50 @@ .ONESHELL: SHELL := /bin/bash -test: - php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html coverage-report +DOCKER_RUN_PHP = docker compose -f .docker/compose.yaml run --rm php "bash" "-c" +DOCKER_COMPOSE = docker compose -f .docker/compose.yaml -linter: #[Linter] - vendor/bin/php-cs-fixer fix +start: upd #[Global] Start application -phpstan: #[Phpstan] - vendor/bin/phpstan +src/vendor: #[Composer] install dependencies + $(DOCKER_RUN_PHP) "composer install --no-interaction" + +upd: #[Docker] Start containers detached + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans --detach + +up: #[Docker] Start containers + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans + +stop: #[Docker] Down containers + $(DOCKER_COMPOSE) stop + +down: #[Docker] Down containers + $(DOCKER_COMPOSE) down + +build: #[Docker] Build containers + $(DOCKER_COMPOSE) build + +ps: # [Docker] Show running containers + $(DOCKER_COMPOSE) ps + +bash: #[Docker] Connect to php container with current host user + $(DOCKER_COMPOSE) exec php bash + +logs: #[Docker] Show logs + $(DOCKER_COMPOSE) logs -f + +phpstan: #[Quality] Run PHPStan + $(DOCKER_RUN_PHP) "vendor/bin/phpstan --no-progress --memory-limit=1G analyse" + +php-cs-fixer: #[Quality] Run PHP-CS-Fixer + $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --dry-run --verbose" + +rector: #[Quality] Run Rector + $(DOCKER_RUN_PHP) "vendor/bin/rector --dry-run" + +phpunit: #[Tests] Run PHPUnit + $(DOCKER_RUN_PHP) "vendor/bin/phpunit" From eae6e14f2c08b33524557c758615703c5515fdc2 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 10:22:11 +0200 Subject: [PATCH 235/304] #139 Update rector configuration & apply it. --- Makefile | 2 +- rector.php | 33 ++++++++++++------- src/Command/ProcessHelpCommand.php | 30 ++++++++--------- src/Configuration/ProcessConfiguration.php | 4 +-- src/Configuration/TaskConfiguration.php | 2 +- .../Compiler/RegistryCompilerPass.php | 2 +- src/DependencyInjection/Configuration.php | 4 +-- src/Exception/TransformerException.php | 2 +- src/Filesystem/CsvResource.php | 10 ++---- src/Logger/AbstractProcessor.php | 10 +++--- src/Manager/ProcessManager.php | 12 +++---- src/Model/ProcessHistory.php | 2 +- src/Model/ProcessState.php | 2 +- src/Model/SubprocessInstance.php | 6 ++-- src/Task/AbstractIterableOutputTask.php | 2 +- src/Task/AggregateIterableTask.php | 2 +- src/Task/ColumnAggregatorTask.php | 2 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/AbstractCsvTask.php | 3 +- src/Task/File/Csv/CsvSplitterTask.php | 2 +- src/Task/File/FileFetchTask.php | 2 +- .../File/JsonStream/JsonStreamReaderTask.php | 2 +- src/Task/GroupByAggregateIterableTask.php | 2 +- src/Task/InputAggregatorTask.php | 4 +-- src/Task/IterableBatchTask.php | 4 +-- src/Task/Process/ProcessLauncherTask.php | 4 +-- .../Reporting/AdvancedStatCounterTask.php | 2 +- src/Task/SimpleBatchTask.php | 2 +- src/Transformer/SlugifyTransformer.php | 2 +- src/Transformer/TransformerTrait.php | 2 +- src/Transformer/TypeSetterTransformer.php | 2 +- .../Xml/XpathEvaluatorTransformer.php | 14 +++----- 32 files changed, 89 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index d41ff83a..efe85520 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ php-cs-fixer: #[Quality] Run PHP-CS-Fixer $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --dry-run --verbose" rector: #[Quality] Run Rector - $(DOCKER_RUN_PHP) "vendor/bin/rector --dry-run" + $(DOCKER_RUN_PHP) "vendor/bin/rector" phpunit: #[Tests] Run PHPUnit $(DOCKER_RUN_PHP) "vendor/bin/phpunit" diff --git a/rector.php b/rector.php index 5a4479b2..72a24086 100644 --- a/rector.php +++ b/rector.php @@ -2,20 +2,29 @@ declare(strict_types=1); -/* - * This file is part of the CleverAge/ProcessBundle package. - * - * Copyright (c) 2017-2024 Clever-Age - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - use Rector\Config\RectorConfig; +use Rector\Set\ValueObject\LevelSetList; +use Rector\Symfony\Set\SymfonySetList; +use Rector\ValueObject\PhpVersion; return RectorConfig::configure() - ->withPaths([__DIR__.'/src', __DIR__.'/tests']) + ->withPhpVersion(PhpVersion::PHP_82) + ->withPaths([ + __DIR__.'/src', + __DIR__.'/tests', + ]) ->withPhpSets(php82: true) - ->withAttributesSets(symfony: true) - ->withImportNames(removeUnusedImports: true) + // here we can define, what prepared sets of rules will be applied + ->withPreparedSets( + deadCode: true, + codeQuality: true + ) + ->withSets([ + LevelSetList::UP_TO_PHP_82, + SymfonySetList::SYMFONY_64, + SymfonySetList::SYMFONY_71, + SymfonySetList::SYMFONY_CODE_QUALITY, + SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, + SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES, + ]) ; diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index 8fe4a510..e1e446c3 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -83,13 +83,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); $output->writeln(''); - if ($process->getDescription()) { + if ($process->getDescription() !== '' && $process->getDescription() !== '0') { $output->writeln('Description:'); $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); $output->writeln(''); } - if ($process->getHelp()) { + if ($process->getHelp() !== '' && $process->getHelp() !== '0') { $output->writeln('Help:'); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { @@ -116,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $branches = array_filter($branches); - if (!empty($branches)) { + if ($branches !== []) { $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } @@ -136,7 +136,7 @@ protected function findBestNextTask( $taskCandidates = []; foreach ($taskList as $taskCode) { $task = $process->getTaskConfiguration($taskCode); - if (empty($task->getPreviousTasksConfigurations())) { + if ($task->getPreviousTasksConfigurations() === []) { return $taskCode; } @@ -156,7 +156,7 @@ protected function findBestNextTask( } } - if (empty($taskCandidates)) { + if ($taskCandidates === []) { throw new \UnexpectedValueException('Cannot find a task to output'); } @@ -175,7 +175,7 @@ protected function findBestNextTask( $weight += $key; } - if (!empty($task->getPreviousTasksConfigurations())) { + if ($task->getPreviousTasksConfigurations() !== []) { $weight /= \count($task->getPreviousTasksConfigurations()); } @@ -194,7 +194,7 @@ protected function findBestNextTask( // If a few tasks have the same weight, return the tasks with the lowest number of children $childCounts = []; - foreach ($equalWeights as $taskCode => $weight) { + foreach (array_keys($equalWeights) as $taskCode) { $task = $process->getTaskConfiguration($taskCode); $childCounts[$taskCode] = $this->getTaskChildrenCount($task); } @@ -243,7 +243,7 @@ protected function resolveBranchOutput( } // Check previous branches - if (empty($previousTasks)) { + if ($previousTasks === []) { $branches[] = $task->getCode(); } elseif (1 === \count($previousTasks)) { $prevTask = current($previousTasks) @@ -292,7 +292,7 @@ protected function resolveBranchOutput( } // Merge branches - if (!empty($branchesToMerge)) { + if ($branchesToMerge !== []) { $this->writeBranches($output, $branches); $this->writeBranches( @@ -322,7 +322,7 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches): } ); - foreach ($branches as $i => $branchTask) { + foreach (array_keys($branches) as $i) { if (\in_array($i, $branchesToMerge, true)) { $branches[$i] = null; } @@ -423,7 +423,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) ); } - if (empty($nextTasks)) { + if ($nextTasks === []) { foreach ($branches as $i => $branchTask) { if ($branchTask === $taskCode) { $branches[$i] = null; @@ -467,7 +467,7 @@ protected function writeBranches( } // Str_pad does not work with unicode ? - $noFormatStrLen = mb_strlen(preg_replace('/<[^>]*>/', '', (string) $str)); + $noFormatStrLen = mb_strlen((string) preg_replace('/<[^>]*>/', '', (string) $str)); for ($j = $noFormatStrLen; $j < self::BRANCH_SIZE; ++$j) { $str .= ' '; } @@ -499,15 +499,15 @@ protected function getTaskDescription(TaskConfiguration $task): string $subprocess[] = $task->getOption('process'); } - if (\count($interfaces)) { + if ($interfaces !== []) { $description .= ' ('.implode(', ', $interfaces).')'; } - if (\count($subprocess)) { + if ($subprocess !== []) { $description .= ' {'.implode(', ', $subprocess).'}'; } - if ($task->getDescription()) { + if ($task->getDescription() !== '' && $task->getDescription() !== '0') { $description .= " {$task->getDescription()}"; } diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 52db1a8c..0db330e6 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -164,12 +164,12 @@ public function getMainTask(): ?TaskConfiguration $entryTask = $this->getEntryPoint(); // If there's no entry point, we might use the end point - if (!$entryTask) { + if (!$entryTask instanceof TaskConfiguration) { $entryTask = $this->getEndPoint(); } // By default use the first defined task - if (!$entryTask) { + if (!$entryTask instanceof TaskConfiguration) { $entryTask = reset($this->taskConfigurations); } diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index 6a59d872..16698a14 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -188,7 +188,7 @@ public function setInErrorBranch(bool $inErrorBranch): void public function isRoot(): bool { - return empty($this->getPreviousTasksConfigurations()) && !$this->isInErrorBranch(); + return $this->getPreviousTasksConfigurations() === [] && !$this->isInErrorBranch(); } /** diff --git a/src/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php index 517bb2d5..4ca029ac 100644 --- a/src/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/src/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -41,7 +41,7 @@ public function process(ContainerBuilder $container): void $definition = $container->findDefinition($this->registry); $taggedServices = $container->findTaggedServiceIds($this->tag); - foreach ($taggedServices as $id => $tags) { + foreach (array_keys($taggedServices) as $id) { $definition->addMethodCall($this->method, [new Reference($id)]); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index be337f93..dd83b428 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -77,7 +77,7 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition): v ->arrayNode('contextual_options') ->prototype('variable') ->end() - ?->end() + ->end() ->arrayNode('transformers') ->prototype('variable') ->end() @@ -110,7 +110,7 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition): void ->scalarNode('entry_point') ->defaultNull() ->end() - ?->scalarNode('end_point') + ->scalarNode('end_point') ->defaultNull() ->end() ?->scalarNode('description') diff --git a/src/Exception/TransformerException.php b/src/Exception/TransformerException.php index 0c88e44a..334606d2 100644 --- a/src/Exception/TransformerException.php +++ b/src/Exception/TransformerException.php @@ -46,7 +46,7 @@ protected function updateMessage(): void } else { $m = sprintf("Transformation '%s' have failed", $this->transformerCode); } - if ($this->getPrevious()) { + if ($this->getPrevious() instanceof \Throwable) { $m .= ": {$this->getPrevious() ->getMessage()}"; } diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index bab85e4e..75ee03f4 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -159,11 +159,7 @@ public function readRaw(int $length = null): array|false public function readLine(int $length = null): ?array { - if ($this->seekCalled) { - $filePosition = "at position {$this->tell()}"; - } else { - $filePosition = "on line {$this->getLineNumber()}"; - } + $filePosition = $this->seekCalled ? "at position {$this->tell()}" : "on line {$this->getLineNumber()}"; $values = $this->readRaw($length); if (false === $values) { @@ -295,7 +291,7 @@ protected function parseHeaders(array $headers = null): array // If headers are not passed in the constructor but file is readable, try to read headers from file if (null === $headers) { $autoHeaders = $this->readRaw(); - if (false === $autoHeaders || 0 === \count($autoHeaders)) { + if (false === $autoHeaders || [] === $autoHeaders) { throw new \UnexpectedValueException("Unable to read headers for {$this->getResourceName()}"); } // Remove BOM if any @@ -311,7 +307,7 @@ protected function parseHeaders(array $headers = null): array throw new \UnexpectedValueException("Invalid headers for {$this->getResourceName()}, you need to pass the headers manually"); } - if (0 === \count($headers)) { + if ([] === $headers) { throw new \UnexpectedValueException("Empty headers for {$this->getResourceName()}, you need to pass the headers manually"); } diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index 544c7508..110b0fbe 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -13,7 +13,9 @@ namespace CleverAge\ProcessBundle\Logger; +use CleverAge\ProcessBundle\Configuration\TaskConfiguration; use CleverAge\ProcessBundle\Manager\ProcessManager; +use CleverAge\ProcessBundle\Model\ProcessHistory; use Monolog\LogRecord; class AbstractProcessor @@ -25,7 +27,7 @@ public function __construct( public function __invoke(LogRecord $record): LogRecord { - if (!empty($record->context)) { + if ($record->context !== []) { $context = $this->normalizeRecordData($record->context); $record = new LogRecord( $record->datetime, @@ -58,7 +60,7 @@ protected function normalizeRecordData(array $record): array protected function addProcessInfoToRecord(array &$record): void { $processHistory = $this->processManager->getProcessHistory(); - if (!$processHistory) { + if (!$processHistory instanceof ProcessHistory) { return; } @@ -70,7 +72,7 @@ protected function addProcessInfoToRecord(array &$record): void protected function addTaskInfoToRecord(array &$record): void { $taskConfiguration = $this->processManager->getTaskConfiguration(); - if (!$taskConfiguration) { + if (!$taskConfiguration instanceof TaskConfiguration) { return; } $this->addToRecord($record, 'task_code', $taskConfiguration->getCode()); @@ -82,7 +84,7 @@ protected function addTaskInfoToRecord(array &$record): void $this->addToRecord($record, 'error', $state->getErrorOutput()); } - if ($state->getException()) { + if ($state->getException() instanceof \Throwable) { $this->addToRecord($record, 'exception', $state->getException()); } } diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index d0b2751c..145630a9 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -133,7 +133,7 @@ protected function doExecute(string $processCode, mixed $input = null, array $co } // If defined, set the input of a task - if ($processConfiguration->getEntryPoint()) { + if ($processConfiguration->getEntryPoint() instanceof TaskConfiguration) { $processConfiguration->getEntryPoint() ->getState() ->setInput($input); @@ -159,7 +159,7 @@ protected function doExecute(string $processCode, mixed $input = null, array $co // If defined, return the output of a task $returnValue = null; - if ($processConfiguration->getEndPoint()) { + if ($processConfiguration->getEndPoint() instanceof TaskConfiguration) { $returnValue = $processConfiguration->getEndPoint() ->getState() ->getOutput(); @@ -225,7 +225,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = $taskConfiguration; if (TaskConfiguration::STRATEGY_STOP === $taskConfiguration->getErrorStrategy() - && \count($taskConfiguration->getErrorOutputs()) > 0) { + && $taskConfiguration->getErrorOutputs() !== []) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); @@ -289,7 +289,7 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF } if ($state->isStopped()) { $exception = $state->getException(); - if ($exception) { + if ($exception instanceof \Throwable) { $m = "Process {$state->getProcessConfiguration() ->getCode()} has failed"; $m .= " during process {$state->getTaskConfiguration() @@ -353,7 +353,7 @@ protected function process(TaskConfiguration $taskConfiguration, int $executionF protected function processExecution(TaskConfiguration $taskConfiguration, int $executionFlag): void { $task = $taskConfiguration->getTask(); - if (null === $task) { + if (!$task instanceof TaskInterface) { throw new \RuntimeException("Missing task for configuration {$taskConfiguration->getCode()}"); } $state = $taskConfiguration->getState(); @@ -393,7 +393,7 @@ protected function processExecution(TaskConfiguration $taskConfiguration, int $e } // Manage exception catching and setting the same - if ($exception) { + if ($exception instanceof \Throwable) { $this->taskLogger->log( $taskConfiguration->getLogLevel(), $exception->getMessage(), diff --git a/src/Model/ProcessHistory.php b/src/Model/ProcessHistory.php index 419f1927..77f23986 100644 --- a/src/Model/ProcessHistory.php +++ b/src/Model/ProcessHistory.php @@ -120,7 +120,7 @@ public function isFailed(): bool */ public function getDuration(): ?int { - if ($this->getEndDate()) { + if ($this->getEndDate() instanceof \DateTimeInterface) { return $this->getEndDate() ->getTimestamp() - $this->getStartDate() ->getTimestamp(); diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index abbb2567..9b314304 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -165,7 +165,7 @@ public function hasErrorOutput(): bool public function stop(\Throwable $e = null): void { - if ($e) { + if ($e instanceof \Throwable) { $this->setException($e); } $this->setStopped(true); diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index fb444e53..a26ae6d8 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -80,10 +80,8 @@ public function buildProcess(): static $arguments = [...$arguments, '--output='.$this->bufferPath, '--output-format=json-stream']; } - if (!empty($this->context)) { - foreach ($this->context as $key => $value) { - $arguments[] = sprintf('--context=%s:%s', $key, $value); - } + foreach ($this->context as $key => $value) { + $arguments[] = sprintf('--context=%s:%s', $key, $value); } $arguments[] = $this->processCode; diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index b2c8f7f2..e1776e6f 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -47,7 +47,7 @@ public function execute(ProcessState $state): void */ public function next(ProcessState $state): bool { - if (!$this->iterator) { + if (!$this->iterator instanceof \Iterator) { return false; } $this->iterator->next(); diff --git a/src/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php index f4fcc122..4d4b850f 100644 --- a/src/Task/AggregateIterableTask.php +++ b/src/Task/AggregateIterableTask.php @@ -32,7 +32,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (0 === \count($this->result)) { + if ([] === $this->result) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index 033e14e2..0e00f7a7 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -63,7 +63,7 @@ public function execute(ProcessState $state): void } } - if (!empty($missingColumns)) { + if ($missingColumns !== []) { $colStr = implode(', ', $missingColumns); $message = "Missing columns [{$colStr}] in input"; diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index 6d4d5416..1b6ac24f 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -35,7 +35,7 @@ public function finalize(ProcessState $state): void protected function initFile(ProcessState $state): void { - if ($this->csv) { + if ($this->csv instanceof CsvResource) { return; } $options = $this->getOptions($state); diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index a1c2f884..ddef722e 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -14,6 +14,7 @@ namespace CleverAge\ProcessBundle\Task\File\Csv; use CleverAge\ProcessBundle\Filesystem\CsvFile; +use CleverAge\ProcessBundle\Filesystem\CsvResource; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -25,7 +26,7 @@ abstract class AbstractCsvTask extends AbstractCsvResourceTask { protected function initFile(ProcessState $state): void { - if ($this->csv) { + if ($this->csv instanceof CsvResource) { return; } $options = $this->getOptions($state); diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 8cbc3b8b..83b16c6b 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -26,7 +26,7 @@ class CsvSplitterTask extends InputCsvReaderTask public function execute(ProcessState $state): void { $options = $this->getOptions($state); - if (null === $this->csv) { + if (!$this->csv instanceof CsvResource) { $headers = $this->getHeaders($state, $options); $csv = new CsvFile( $options['file_path'], diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index e9cb12c5..2fc166c1 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -43,7 +43,7 @@ public function __construct( public function initialize(ProcessState $state): void { - if (!$this->mountManager) { + if (!$this->mountManager instanceof MountManager) { throw new ServiceNotFoundException('MountManager service not found, you need to install FlySystemBundle'); } // Configure options diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index 9f77ab0d..effff1fe 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -23,7 +23,7 @@ class JsonStreamReaderTask implements IterableTaskInterface public function execute(ProcessState $state): void { - if (null === $this->file) { + if (!$this->file instanceof JsonStreamFile) { $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); } diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index 3d676ca3..d521e329 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -61,7 +61,7 @@ public function execute(ProcessState $state): void public function proceed(ProcessState $state): void { - if (0 === \count($this->result)) { + if ([] === $this->result) { $state->setSkipped(true); } else { $state->setOutput($this->result); diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 28ccf5e4..0aeea05f 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -54,7 +54,7 @@ public function execute(ProcessState $state): void $state->setOutput($this->inputs); $keepInputs = $this->getOption($state, 'keep_inputs'); // Only clear inputs that are not in the keep_inputs option - foreach ($this->inputs as $inputCode => $value) { + foreach (array_keys($this->inputs) as $inputCode) { if (null !== $keepInputs && \in_array($inputCode, $keepInputs, true)) { continue; } @@ -83,7 +83,7 @@ protected function configureOptions(OptionsResolver $resolver): void protected function getInputCode(ProcessState $state): string { $previousState = $state->getPreviousState(); - if (!$previousState) { + if (!$previousState instanceof ProcessState) { throw new \RuntimeException('No previous state for current task'); } $previousTaskCode = $previousState->getTaskConfiguration() diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index 15f46e24..4e9a5ed0 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -61,7 +61,7 @@ public function execute(ProcessState $state): void } // Detect flushing - if (null !== $batchCount && (null === $this->outputQueue ? 0 : \count($this->outputQueue)) >= $batchCount) { + if (null !== $batchCount && ($this->outputQueue instanceof \SplQueue ? \count($this->outputQueue) : 0) >= $batchCount) { $this->flushMode = true; } @@ -76,7 +76,7 @@ public function execute(ProcessState $state): void public function next(ProcessState $state): bool { // Stop flushing once over - if (!(null === $this->outputQueue ? 0 : \count($this->outputQueue))) { + if (($this->outputQueue instanceof \SplQueue ? \count($this->outputQueue) : 0) === 0) { $this->flushMode = false; } diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index 1661b87f..a3c3f5cc 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -78,7 +78,7 @@ public function flush(ProcessState $state): void } // After dequeue, stop flush - if ($this->finishedBuffers->isEmpty() && !\count($this->launchedProcesses)) { + if ($this->finishedBuffers->isEmpty() && $this->launchedProcesses === []) { $this->flushMode = false; } } @@ -96,7 +96,7 @@ public function next(ProcessState $state): bool // if we are in flush mode, we should wait for process to finish if ($this->flushMode) { - return \count($this->launchedProcesses) > 0; + return $this->launchedProcesses !== []; } usleep($this->getOption($state, 'sleep_on_finalize_interval')); diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index fed1243c..3f2eb47c 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -39,7 +39,7 @@ public function __construct( public function execute(ProcessState $state): void { $now = new \DateTime(); - if (!$this->startedAt) { + if (!$this->startedAt instanceof \DateTime) { $this->startedAt = $now; $this->lastUpdate = $now; } diff --git a/src/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php index e0173bc7..9db576ba 100644 --- a/src/Task/SimpleBatchTask.php +++ b/src/Task/SimpleBatchTask.php @@ -27,7 +27,7 @@ class SimpleBatchTask extends AbstractConfigurableTask implements FlushableTaskI public function flush(ProcessState $state): void { - if (0 === \count($this->elements)) { + if ([] === $this->elements) { $state->setSkipped(true); } else { $state->setOutput($this->elements); diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php index 491eb52f..b5dd77cf 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/SlugifyTransformer.php @@ -28,7 +28,7 @@ public function transform(mixed $value, array $options = []): string $string = $transliterator->transliterate($value); return trim( - preg_replace( + (string) preg_replace( $options['replace'], (string) $options['separator'], strtolower(trim(strip_tags($string))) diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index e3874aa0..4079603f 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -52,7 +52,7 @@ public function normalizeTransformers(Options $options, array $transformers): ar protected function applyTransformers(array $transformers, mixed $value): mixed { // Quick return for better perfs - if (empty($transformers)) { + if ($transformers === []) { return $value; } diff --git a/src/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php index a9e621fc..202384d0 100644 --- a/src/Transformer/TypeSetterTransformer.php +++ b/src/Transformer/TypeSetterTransformer.php @@ -32,7 +32,7 @@ public function transform(mixed $value, array $options = []): mixed { $return = settype($value, $options['type']); - if (true === $return) { + if ($return) { return $value; } diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index e4952d21..9b5964e8 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -67,13 +67,13 @@ public function configureOptions(OptionsResolver $resolver): void */ public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null): void { - $resolver->setDefault('single_result', $parentOptions ? $parentOptions['single_result'] : true); + $resolver->setDefault('single_result', $parentOptions instanceof Options ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); - $resolver->setDefault('ignore_missing', $parentOptions ? $parentOptions['ignore_missing'] : true); + $resolver->setDefault('ignore_missing', $parentOptions instanceof Options ? $parentOptions['ignore_missing'] : true); $resolver->setAllowedTypes('ignore_missing', 'bool'); - $resolver->setDefault('unwrap_value', $parentOptions ? $parentOptions['unwrap_value'] : true); + $resolver->setDefault('unwrap_value', $parentOptions instanceof Options ? $parentOptions['unwrap_value'] : true); $resolver->setAllowedTypes('unwrap_value', 'bool'); } @@ -137,15 +137,11 @@ public function query(\DOMXPath $xpath, string $query, \DOMNode $node, array $op throw new \UnexpectedValueException("There is too much results for query '{$query}'"); } - if (!$options['ignore_missing'] && 0 === \count($results)) { + if (!$options['ignore_missing'] && [] === $results) { throw new \UnexpectedValueException("There is not enough results for query '{$query}'"); } - if (1 === \count($results)) { - $results = $results[0]; - } else { - $results = null; - } + $results = 1 === \count($results) ? $results[0] : null; } return $results; From d8eb15f90c8b099e4cc1864bcfbf78ad9749c2a3 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 09:31:11 +0200 Subject: [PATCH 236/304] #139 #130 Update phpstan configuration & apply it : - Replace Psr\EventDispatcher\EventDispatcherInterface by Symfony\Component\EventDispatcher\EventDispatcherInterface - Fix Configuration than can't use coalescent operators - Fix typing & remove useless code --- phpstan.neon | 7 ++----- src/Command/ExecuteProcessCommand.php | 2 +- src/DependencyInjection/Configuration.php | 12 ++++++------ src/Filesystem/CsvResource.php | 2 +- src/Logger/AbstractLogger.php | 2 +- src/Manager/ProcessManager.php | 2 +- src/Resources/config/services/event.yaml | 4 ---- src/Task/Event/EventDispatcherTask.php | 2 +- src/Task/File/Csv/CsvSplitterTask.php | 2 +- tests.old/ProcessManagerTest.php | 2 +- 10 files changed, 15 insertions(+), 22 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 244b173e..e374f1ba 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,11 +2,8 @@ parameters: level: 6 paths: - src + - tests excludePaths: - - vendor/* - - tests/* - - rector.php - - var/* - src/Resources/tests/* ignoreErrors: - '#type has no value type specified in iterable type#' @@ -20,4 +17,4 @@ parameters: checkGenericClassInNonGenericObjectType: false reportUnmatchedIgnoredErrors: false inferPrivatePropertyTypeFromConstructor: true - treatPhpDocTypesAsCertain: false \ No newline at end of file + treatPhpDocTypesAsCertain: false diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 73fec99a..2f170323 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -17,7 +17,6 @@ use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; use CleverAge\ProcessBundle\Manager\ProcessManager; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; -use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -25,6 +24,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\VarDumper\VarDumper; use Symfony\Component\Yaml\Parser; diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index dd83b428..5921ec28 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -81,7 +81,7 @@ protected function appendTransformerConfigDefinition(NodeBuilder $definition): v ->arrayNode('transformers') ->prototype('variable') ->end() - ?->end(); + ->end(); } /** @@ -113,19 +113,19 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition): void ->scalarNode('end_point') ->defaultNull() ->end() - ?->scalarNode('description') + ->scalarNode('description') ->defaultValue('') ->end() - ?->scalarNode('help') + ->scalarNode('help') ->defaultValue('') ->end() - ?->scalarNode('public') + ->scalarNode('public') ->defaultTrue() ->end() - ?->arrayNode('options') + ->arrayNode('options') ->prototype('variable') ->end() - ?->end(); + ->end(); /** @var ArrayNodeDefinition $tasksArrayDefinition */ $tasksArrayDefinition = $definition diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 75ee03f4..87937572 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -40,7 +40,7 @@ class CsvResource implements WritableStructuredFileInterface, SeekableFileInterf protected bool $seekCalled = false; public function __construct( - $resource, + mixed $resource, protected string $delimiter = ',', protected string $enclosure = '"', protected string $escape = '\\', diff --git a/src/Logger/AbstractLogger.php b/src/Logger/AbstractLogger.php index 804d11cd..1f84fdde 100644 --- a/src/Logger/AbstractLogger.php +++ b/src/Logger/AbstractLogger.php @@ -28,7 +28,7 @@ public function __construct( ) { } - public function log($level, $message, array $context = []): void + public function log($level, string|\Stringable $message, array $context = []): void { $this->logger->log($level, $message, $context); } diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index 145630a9..e8d71865 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -29,9 +29,9 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\TaskInterface; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; -use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Execute processes. diff --git a/src/Resources/config/services/event.yaml b/src/Resources/config/services/event.yaml index b5a218a1..f4a5bb70 100644 --- a/src/Resources/config/services/event.yaml +++ b/src/Resources/config/services/event.yaml @@ -1,8 +1,4 @@ services: - Symfony\Contracts\EventDispatcher\EventDispatcherInterface: - public: false - autowire: true - CleverAge\ProcessBundle\EventListener\DataQueueEventListener: public: false tags: diff --git a/src/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php index 1233fb6b..6771c16d 100644 --- a/src/Task/Event/EventDispatcherTask.php +++ b/src/Task/Event/EventDispatcherTask.php @@ -16,7 +16,7 @@ use CleverAge\ProcessBundle\Event\EventDispatcherTaskEvent; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; -use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 83b16c6b..12e1b7a1 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -72,7 +72,7 @@ public function finalize(ProcessState $state): void } } - protected function splitCsv(CsvFile $csv, int $maxLines): string + protected function splitCsv(CsvResource $csv, int $maxLines): string { $tmpFilePath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_'.uniqid('process', false).'.csv'; $tmpFile = fopen($tmpFilePath, 'wb+'); diff --git a/tests.old/ProcessManagerTest.php b/tests.old/ProcessManagerTest.php index 42c49450..3d019b5e 100644 --- a/tests.old/ProcessManagerTest.php +++ b/tests.old/ProcessManagerTest.php @@ -21,7 +21,7 @@ use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Prophecy\Argument\Token\TypeToken; use Prophecy\Prophecy\MethodProphecy; -use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; class ProcessManagerTest extends AbstractProcessTest { From 29fac79332aeca1498e9c6ed8dbdc8c3109accee Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 10:30:20 +0200 Subject: [PATCH 237/304] #139 Update php-cs-fixer configuration & apply it. --- .php-cs-fixer.dist.php | 14 ++++--- Makefile | 2 +- src/CleverAgeProcessBundle.php | 2 +- src/Command/ExecuteProcessCommand.php | 12 +++--- src/Command/ListProcessCommand.php | 4 +- src/Command/ProcessHelpCommand.php | 38 +++++++++---------- src/Configuration/ProcessConfiguration.php | 4 +- src/Configuration/TaskConfiguration.php | 6 +-- src/Context/ContextualOptionResolver.php | 4 +- .../CleverAgeProcessExtension.php | 2 +- .../Compiler/CheckSerializerCompilerPass.php | 2 +- .../Compiler/RegistryCompilerPass.php | 4 +- src/DependencyInjection/Configuration.php | 4 +- src/Event/ConsoleProcessEvent.php | 4 +- src/Event/EventDispatcherTaskEvent.php | 4 +- src/Event/ProcessEvent.php | 4 +- src/EventListener/DataQueueEventListener.php | 2 +- src/Exception/CircularProcessException.php | 2 +- .../InvalidProcessConfigurationException.php | 6 +-- src/Exception/MissingProcessException.php | 2 +- .../MissingTaskConfigurationException.php | 2 +- src/Exception/MissingTransformerException.php | 2 +- src/Exception/ProcessExceptionInterface.php | 2 +- src/Exception/TransformerException.php | 8 ++-- .../PhpFunctionProvider.php | 4 +- src/Filesystem/CsvFile.php | 10 ++--- src/Filesystem/CsvResource.php | 10 ++--- src/Filesystem/FileStreamInterface.php | 4 +- src/Filesystem/JsonStreamFile.php | 4 +- src/Filesystem/SeekableFileInterface.php | 2 +- src/Filesystem/StructuredFileInterface.php | 2 +- src/Filesystem/WritableFileInterface.php | 2 +- .../WritableStructuredFileInterface.php | 2 +- src/Filesystem/XmlFile.php | 2 +- src/Logger/AbstractLogger.php | 4 +- src/Logger/AbstractProcessor.php | 6 +-- src/Logger/ProcessLogger.php | 2 +- src/Logger/ProcessProcessor.php | 2 +- src/Logger/TaskLogger.php | 2 +- src/Logger/TaskProcessor.php | 2 +- src/Logger/TransformerProcessor.php | 2 +- src/Manager/ProcessManager.php | 10 ++--- src/Model/AbstractConfigurableTask.php | 2 +- src/Model/BlockingTaskInterface.php | 2 +- src/Model/FinalizableTaskInterface.php | 2 +- src/Model/FlushableTaskInterface.php | 2 +- src/Model/InitializableTaskInterface.php | 2 +- src/Model/IterableTaskInterface.php | 2 +- src/Model/ProcessHistory.php | 4 +- src/Model/ProcessState.php | 8 ++-- src/Model/SubprocessInstance.php | 6 +-- src/Model/TaskInterface.php | 2 +- src/Registry/ProcessConfigurationRegistry.php | 4 +- src/Registry/TransformerRegistry.php | 2 +- src/Task/AbstractIterableOutputTask.php | 2 +- src/Task/AggregateIterableTask.php | 2 +- src/Task/ArrayMergeTask.php | 2 +- src/Task/ColumnAggregatorTask.php | 8 ++-- src/Task/ConstantIterableOutputTask.php | 2 +- src/Task/ConstantOutputTask.php | 2 +- src/Task/CounterTask.php | 2 +- src/Task/Debug/DebugTask.php | 2 +- src/Task/Debug/DieTask.php | 2 +- src/Task/Debug/ErrorForwarderTask.php | 2 +- src/Task/Debug/MemInfoDumpTask.php | 4 +- src/Task/Debug/StopwatchTask.php | 4 +- src/Task/DummyTask.php | 2 +- src/Task/Event/EventDispatcherTask.php | 4 +- src/Task/File/Csv/AbstractCsvResourceTask.php | 2 +- src/Task/File/Csv/AbstractCsvTask.php | 2 +- src/Task/File/Csv/CsvReaderTask.php | 4 +- src/Task/File/Csv/CsvSplitterTask.php | 2 +- src/Task/File/Csv/CsvWriterTask.php | 2 +- src/Task/File/Csv/InputCsvReaderTask.php | 2 +- src/Task/File/FileFetchTask.php | 6 +-- src/Task/File/FileMoverTask.php | 2 +- src/Task/File/FileReaderTask.php | 2 +- src/Task/File/FileRemoverTask.php | 2 +- src/Task/File/FileWriterTask.php | 2 +- src/Task/File/FolderBrowserTask.php | 4 +- src/Task/File/InputFolderBrowserTask.php | 2 +- .../File/JsonStream/JsonStreamReaderTask.php | 2 +- src/Task/File/Xml/XmlReaderTask.php | 4 +- src/Task/File/Xml/XmlWriterTask.php | 4 +- src/Task/File/YamlReaderTask.php | 2 +- src/Task/File/YamlWriterTask.php | 2 +- src/Task/FilterTask.php | 2 +- src/Task/GroupByAggregateIterableTask.php | 4 +- src/Task/InputAggregatorTask.php | 2 +- src/Task/InputIteratorTask.php | 2 +- src/Task/IterableBatchTask.php | 4 +- src/Task/ObjectUpdaterTask.php | 4 +- src/Task/Process/CommandRunnerTask.php | 4 +- src/Task/Process/ProcessExecutorTask.php | 4 +- src/Task/Process/ProcessLauncherTask.php | 8 ++-- src/Task/PropertyGetterTask.php | 4 +- src/Task/PropertySetterTask.php | 4 +- .../Reporting/AdvancedStatCounterTask.php | 4 +- src/Task/Reporting/LoggerTask.php | 4 +- src/Task/Reporting/StatCounterTask.php | 4 +- src/Task/RowAggregatorTask.php | 4 +- src/Task/Serialization/DenormalizerTask.php | 4 +- src/Task/Serialization/DeserializerTask.php | 4 +- src/Task/Serialization/NormalizerTask.php | 4 +- src/Task/Serialization/SerializerTask.php | 4 +- src/Task/SimpleBatchTask.php | 2 +- src/Task/SkipEmptyTask.php | 2 +- src/Task/SplitJoinLineTask.php | 2 +- src/Task/StopTask.php | 2 +- src/Task/TransformerTask.php | 4 +- src/Task/Validation/ValidatorTask.php | 4 +- src/Transformer/ArrayElementTransformer.php | 2 +- src/Transformer/ArrayFilterTransformer.php | 2 +- src/Transformer/ArrayFirstTransformer.php | 2 +- src/Transformer/ArrayLastTransformer.php | 2 +- src/Transformer/ArrayMapTransformer.php | 2 +- src/Transformer/ArrayUnsetTransformer.php | 2 +- src/Transformer/CachedTransformer.php | 4 +- src/Transformer/CallbackTransformer.php | 2 +- src/Transformer/CastTransformer.php | 2 +- src/Transformer/ConditionTrait.php | 4 +- .../ConfigurableTransformerInterface.php | 2 +- src/Transformer/ConstantTransformer.php | 2 +- src/Transformer/ConvertValueTransformer.php | 2 +- src/Transformer/DateFormatTransformer.php | 2 +- src/Transformer/DateParserTransformer.php | 2 +- src/Transformer/DebugTransformer.php | 2 +- src/Transformer/DefaultTransformer.php | 2 +- src/Transformer/DenormalizeTransformer.php | 4 +- src/Transformer/EvaluatorTransformer.php | 2 +- src/Transformer/ExplodeTransformer.php | 2 +- .../ExpressionLanguageMapTransformer.php | 4 +- src/Transformer/GenericTransformer.php | 4 +- src/Transformer/HashTransformer.php | 2 +- src/Transformer/ImplodeTransformer.php | 2 +- src/Transformer/InstantiateTransformer.php | 2 +- src/Transformer/MappingTransformer.php | 4 +- src/Transformer/MultiReplaceTransformer.php | 2 +- src/Transformer/NormalizeTransformer.php | 4 +- src/Transformer/PregFilterTransformer.php | 2 +- .../PropertyAccessorTransformer.php | 4 +- .../RecursivePropertySetterTransformer.php | 4 +- src/Transformer/RulesTransformer.php | 6 +-- src/Transformer/SlugifyTransformer.php | 2 +- src/Transformer/SprintfTransformer.php | 2 +- src/Transformer/TransformerInterface.php | 2 +- src/Transformer/TransformerTrait.php | 6 +-- src/Transformer/TrimTransformer.php | 2 +- src/Transformer/TypeSetterTransformer.php | 2 +- src/Transformer/UnsetTransformer.php | 2 +- src/Transformer/WrapperTransformer.php | 2 +- .../Xml/XpathEvaluatorTransformer.php | 4 +- src/Validator/ConstraintLoader.php | 2 +- .../MissingTransformerExceptionTest.php | 9 +++++ .../ArrayElementTransformerTest.php | 2 +- .../Transformer/ArrayFirstTransformerTest.php | 2 +- tests/Transformer/CastTransformerTest.php | 2 +- tests/Transformer/ConstantTransformerTest.php | 2 +- .../Transformer/DateFormatTransformerTest.php | 2 +- .../Transformer/DateParserTransformerTest.php | 2 +- tests/Transformer/DebugTransformerTest.php | 2 +- tests/Transformer/DefaultTransformerTest.php | 2 +- tests/Transformer/ExplodeTransformerTest.php | 2 +- tests/Transformer/ImplodeTransformerTest.php | 2 +- .../MultiReplaceTransformerTest.php | 2 +- tests/Transformer/SprintfTransformerTest.php | 9 +++++ tests/Transformer/TrimTransformerTest.php | 2 +- tests/Transformer/WrapperTransformerTest.php | 2 +- .../XpathEvaluatorTransformerTest.php | 2 +- 169 files changed, 301 insertions(+), 281 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 4f96866e..b994793f 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -3,7 +3,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,17 +14,18 @@ } $fileHeaderComment = <<<'EOF' -This file is part of the CleverAge/ProcessBundle package. + This file is part of the CleverAge/ProcessBundle package. -Copyright (c) 2017-2024 Clever-Age + Copyright (c) Clever-Age -For the full copyright and license information, please view the LICENSE -file that was distributed with this source code. -EOF; + For the full copyright and license information, please view the LICENSE + file that was distributed with this source code. + EOF; return (new PhpCsFixer\Config()) ->setRules([ '@PHP71Migration' => true, + '@PHP82Migration' => true, '@PHPUnit75Migration:risky' => true, '@Symfony' => true, '@Symfony:risky' => true, @@ -38,6 +39,7 @@ ->setFinder( (new PhpCsFixer\Finder()) ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') ->append([__FILE__]) ) ->setCacheFile('.php-cs-fixer.cache') diff --git a/Makefile b/Makefile index efe85520..3461c159 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ phpstan: #[Quality] Run PHPStan $(DOCKER_RUN_PHP) "vendor/bin/phpstan --no-progress --memory-limit=1G analyse" php-cs-fixer: #[Quality] Run PHP-CS-Fixer - $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --dry-run --verbose" + $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --verbose" rector: #[Quality] Run Rector $(DOCKER_RUN_PHP) "vendor/bin/rector" diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 27904639..10838026 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Command/ExecuteProcessCommand.php b/src/Command/ExecuteProcessCommand.php index 2f170323..088428f5 100644 --- a/src/Command/ExecuteProcessCommand.php +++ b/src/Command/ExecuteProcessCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -92,7 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (!$this->processRegistry->hasProcessConfiguration($code)) { throw new InvalidConfigurationException("Unknown process {$code}"); } - + if (!$output->isQuiet()) { $output->writeln("Starting process '{$code}'..."); } @@ -123,7 +123,7 @@ protected function parseContextValues(InputInterface $input): array preg_match($pattern, (string) $contextValue, $parts); if (3 !== \count($parts) || $parts[0] !== $contextValue) { - throw new \InvalidArgumentException(sprintf('Invalid context %s', $contextValue)); + throw new \InvalidArgumentException(\sprintf('Invalid context %s', $contextValue)); } $context[$parts[1]] = $parser->parse($parts[2]); } @@ -148,7 +148,7 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { $output->writeln(json_encode($data, \JSON_THROW_ON_ERROR)); } else { - throw new \InvalidArgumentException(sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); + throw new \InvalidArgumentException(\sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); } } } elseif (self::OUTPUT_FORMAT_JSON === $input->getOption('output-format')) { @@ -160,10 +160,10 @@ protected function handleOutputData(mixed $data, InputInterface $input, OutputIn } if (isset($outputFile) && $output->isVerbose()) { - $output->writeln(sprintf("Output stored in '%s'", $input->getOption('output'))); + $output->writeln(\sprintf("Output stored in '%s'", $input->getOption('output'))); } } else { - throw new \InvalidArgumentException(sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); + throw new \InvalidArgumentException(\sprintf("Cannot handle data output with format '%s'", $input->getOption('output-format'))); } } } diff --git a/src/Command/ListProcessCommand.php b/src/Command/ListProcessCommand.php index fcca76c1..01fdf997 100644 --- a/src/Command/ListProcessCommand.php +++ b/src/Command/ListProcessCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,7 +28,7 @@ class ListProcessCommand extends Command { public function __construct( - protected ProcessConfigurationRegistry $processConfigRegistry + protected ProcessConfigurationRegistry $processConfigRegistry, ) { parent::__construct(); } diff --git a/src/Command/ProcessHelpCommand.php b/src/Command/ProcessHelpCommand.php index e1e446c3..ea22e351 100644 --- a/src/Command/ProcessHelpCommand.php +++ b/src/Command/ProcessHelpCommand.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -61,7 +61,7 @@ class ProcessHelpCommand extends Command public function __construct( protected ProcessConfigurationRegistry $processConfigRegistry, - protected ContainerInterface $container + protected ContainerInterface $container, ) { parent::__construct(); } @@ -83,13 +83,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(str_repeat(' ', self::INDENT_SIZE).$processCode); $output->writeln(''); - if ($process->getDescription() !== '' && $process->getDescription() !== '0') { + if ('' !== $process->getDescription() && '0' !== $process->getDescription()) { $output->writeln('Description:'); $output->writeln(str_repeat(' ', self::INDENT_SIZE).$process->getDescription()); $output->writeln(''); } - if ($process->getHelp() !== '' && $process->getHelp() !== '0') { + if ('' !== $process->getHelp() && '0' !== $process->getHelp()) { $output->writeln('Help:'); $helpLines = array_filter(explode("\n", $process->getHelp())); foreach ($helpLines as $helpLine) { @@ -116,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $branches = array_filter($branches); - if ($branches !== []) { + if ([] !== $branches) { $branchStr = '['.implode(', ', $branches).']'; $output->writeln("All branches are not resolved : {$branchStr}"); } @@ -130,13 +130,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int protected function findBestNextTask( array $branches, array $taskList, - ProcessConfiguration $process - ): int|null|string { + ProcessConfiguration $process, + ): int|string|null { // Get resolvable tasks $taskCandidates = []; foreach ($taskList as $taskCode) { $task = $process->getTaskConfiguration($taskCode); - if ($task->getPreviousTasksConfigurations() === []) { + if ([] === $task->getPreviousTasksConfigurations()) { return $taskCode; } @@ -156,7 +156,7 @@ protected function findBestNextTask( } } - if ($taskCandidates === []) { + if ([] === $taskCandidates) { throw new \UnexpectedValueException('Cannot find a task to output'); } @@ -175,7 +175,7 @@ protected function findBestNextTask( $weight += $key; } - if ($task->getPreviousTasksConfigurations() !== []) { + if ([] !== $task->getPreviousTasksConfigurations()) { $weight /= \count($task->getPreviousTasksConfigurations()); } @@ -228,7 +228,7 @@ protected function resolveBranchOutput( array &$branches, string $taskCode, ProcessConfiguration $process, - OutputInterface $output + OutputInterface $output, ): void { $task = $process->getTaskConfiguration($taskCode); $branchesToMerge = []; @@ -243,7 +243,7 @@ protected function resolveBranchOutput( } // Check previous branches - if ($previousTasks === []) { + if ([] === $previousTasks) { $branches[] = $task->getCode(); } elseif (1 === \count($previousTasks)) { $prevTask = current($previousTasks) @@ -292,7 +292,7 @@ protected function resolveBranchOutput( } // Merge branches - if ($branchesToMerge !== []) { + if ([] !== $branchesToMerge) { $this->writeBranches($output, $branches); $this->writeBranches( @@ -423,7 +423,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final) ); } - if ($nextTasks === []) { + if ([] === $nextTasks) { foreach ($branches as $i => $branchTask) { if ($branchTask === $taskCode) { $branches[$i] = null; @@ -446,8 +446,8 @@ protected function writeBranches( OutputInterface $output, array $branches, string|iterable $comment = '', - callable $match = null, - string|callable $char = null + ?callable $match = null, + string|callable|null $char = null, ): void { $output->write(str_repeat(' ', self::INDENT_SIZE)); @@ -499,15 +499,15 @@ protected function getTaskDescription(TaskConfiguration $task): string $subprocess[] = $task->getOption('process'); } - if ($interfaces !== []) { + if ([] !== $interfaces) { $description .= ' ('.implode(', ', $interfaces).')'; } - if ($subprocess !== []) { + if ([] !== $subprocess) { $description .= ' {'.implode(', ', $subprocess).'}'; } - if ($task->getDescription() !== '' && $task->getDescription() !== '0') { + if ('' !== $task->getDescription() && '0' !== $task->getDescription()) { $description .= " {$task->getDescription()}"; } diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 0db330e6..421680f7 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -33,7 +33,7 @@ public function __construct( protected ?string $endPoint = null, protected string $description = '', protected string $help = '', - protected bool $public = true + protected bool $public = true, ) { } diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index 16698a14..feabfa7c 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -58,7 +58,7 @@ public function __construct( protected array $outputs = [], protected array $errorOutputs = [], protected string $errorStrategy = self::STRATEGY_SKIP, - protected string $logLevel = LogLevel::CRITICAL + protected string $logLevel = LogLevel::CRITICAL, ) { $this->logErrors = LogLevel::DEBUG !== $logLevel; // @deprecated, remove me in next version } @@ -188,7 +188,7 @@ public function setInErrorBranch(bool $inErrorBranch): void public function isRoot(): bool { - return $this->getPreviousTasksConfigurations() === [] && !$this->isInErrorBranch(); + return [] === $this->getPreviousTasksConfigurations() && !$this->isInErrorBranch(); } /** diff --git a/src/Context/ContextualOptionResolver.php b/src/Context/ContextualOptionResolver.php index a5bad58f..067e3509 100644 --- a/src/Context/ContextualOptionResolver.php +++ b/src/Context/ContextualOptionResolver.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,7 +27,7 @@ public function contextualizeOption(mixed $value, array $context): mixed } if (\is_string($value)) { - $pattern = sprintf('/{{[ ]*(%s){1}[ ]*}}/', implode('|', array_keys($context))); + $pattern = \sprintf('/{{[ ]*(%s){1}[ ]*}}/', implode('|', array_keys($context))); $matches = []; $result = preg_match($pattern, $value, $matches); diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index ebe8ef15..d6b650c5 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php index 0cd8e0f4..93006b1e 100644 --- a/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php +++ b/src/DependencyInjection/Compiler/CheckSerializerCompilerPass.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/DependencyInjection/Compiler/RegistryCompilerPass.php b/src/DependencyInjection/Compiler/RegistryCompilerPass.php index 4ca029ac..9de12c25 100644 --- a/src/DependencyInjection/Compiler/RegistryCompilerPass.php +++ b/src/DependencyInjection/Compiler/RegistryCompilerPass.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class RegistryCompilerPass implements CompilerPassInterface public function __construct( protected ?string $registry = null, protected ?string $tag = null, - protected ?string $method = null + protected ?string $method = null, ) { } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 5921ec28..fee9cb58 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,7 +28,7 @@ class Configuration implements ConfigurationInterface { public function __construct( - protected string $root = 'clever_age_process' + protected string $root = 'clever_age_process', ) { } diff --git a/src/Event/ConsoleProcessEvent.php b/src/Event/ConsoleProcessEvent.php index f09c4303..e404e071 100644 --- a/src/Event/ConsoleProcessEvent.php +++ b/src/Event/ConsoleProcessEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,7 +26,7 @@ public function __construct( private readonly InputInterface $consoleInput, private readonly OutputInterface $consoleOutput, private readonly mixed $processInput, - private readonly array $processContext + private readonly array $processContext, ) { } diff --git a/src/Event/EventDispatcherTaskEvent.php b/src/Event/EventDispatcherTaskEvent.php index 0d6b4394..e148e973 100644 --- a/src/Event/EventDispatcherTaskEvent.php +++ b/src/Event/EventDispatcherTaskEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,7 +19,7 @@ class EventDispatcherTaskEvent extends Event { public function __construct( - protected ProcessState $state + protected ProcessState $state, ) { } diff --git a/src/Event/ProcessEvent.php b/src/Event/ProcessEvent.php index f3b79d11..6c7b297f 100644 --- a/src/Event/ProcessEvent.php +++ b/src/Event/ProcessEvent.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -31,7 +31,7 @@ public function __construct( protected mixed $processInput = null, protected array $processContext = [], protected mixed $processOutput = null, - protected ?\Throwable $processError = null + protected ?\Throwable $processError = null, ) { } diff --git a/src/EventListener/DataQueueEventListener.php b/src/EventListener/DataQueueEventListener.php index 6f48ab5c..b405d886 100644 --- a/src/EventListener/DataQueueEventListener.php +++ b/src/EventListener/DataQueueEventListener.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/CircularProcessException.php b/src/Exception/CircularProcessException.php index c4ff2516..81939d49 100644 --- a/src/Exception/CircularProcessException.php +++ b/src/Exception/CircularProcessException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/InvalidProcessConfigurationException.php b/src/Exception/InvalidProcessConfigurationException.php index 80a34779..aecaab1f 100644 --- a/src/Exception/InvalidProcessConfigurationException.php +++ b/src/Exception/InvalidProcessConfigurationException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class InvalidProcessConfigurationException extends \UnexpectedValueException imp public static function createNotInMain( ProcessConfiguration $processConfiguration, TaskConfiguration $taskConfig, - array $mainTaskList + array $mainTaskList, ): self { $taskListStr = '['.implode(', ', $mainTaskList).']'; @@ -35,7 +35,7 @@ public static function createNotInMain( public static function createEntryPointHasAncestors( ProcessConfiguration $processConfiguration, - TaskConfiguration $taskConfig + TaskConfiguration $taskConfig, ): self { return new self( "The entry-point '{$taskConfig->getCode()}' cannot have an ancestor (from process: {$processConfiguration->getCode()})" diff --git a/src/Exception/MissingProcessException.php b/src/Exception/MissingProcessException.php index 3642ee67..045372f9 100644 --- a/src/Exception/MissingProcessException.php +++ b/src/Exception/MissingProcessException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/MissingTaskConfigurationException.php b/src/Exception/MissingTaskConfigurationException.php index 0445891c..ab1b3c77 100644 --- a/src/Exception/MissingTaskConfigurationException.php +++ b/src/Exception/MissingTaskConfigurationException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/MissingTransformerException.php b/src/Exception/MissingTransformerException.php index a0ea2772..565ef481 100644 --- a/src/Exception/MissingTransformerException.php +++ b/src/Exception/MissingTransformerException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/ProcessExceptionInterface.php b/src/Exception/ProcessExceptionInterface.php index f4f39edf..a0b539f8 100644 --- a/src/Exception/ProcessExceptionInterface.php +++ b/src/Exception/ProcessExceptionInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Exception/TransformerException.php b/src/Exception/TransformerException.php index 334606d2..5ce332df 100644 --- a/src/Exception/TransformerException.php +++ b/src/Exception/TransformerException.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -23,7 +23,7 @@ class TransformerException extends \RuntimeException implements ProcessException public function __construct( protected string $transformerCode, int $code = 0, - \Throwable $previous = null + ?\Throwable $previous = null, ) { parent::__construct('', $code, $previous); $this->updateMessage(); @@ -38,13 +38,13 @@ public function setTargetProperty(string $targetProperty): void protected function updateMessage(): void { if (isset($this->targetProperty)) { - $m = sprintf( + $m = \sprintf( "For target property '%s', transformation '%s' have failed", $this->targetProperty, $this->transformerCode ); } else { - $m = sprintf("Transformation '%s' have failed", $this->transformerCode); + $m = \sprintf("Transformation '%s' have failed", $this->transformerCode); } if ($this->getPrevious() instanceof \Throwable) { $m .= ": {$this->getPrevious() diff --git a/src/ExpressionLanguage/PhpFunctionProvider.php b/src/ExpressionLanguage/PhpFunctionProvider.php index 4d157b01..9a2632b7 100644 --- a/src/ExpressionLanguage/PhpFunctionProvider.php +++ b/src/ExpressionLanguage/PhpFunctionProvider.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,7 +22,7 @@ class PhpFunctionProvider implements ExpressionFunctionProviderInterface { public function __construct( - protected array $functions + protected array $functions, ) { } diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 529096ae..1dc892ce 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,13 +29,13 @@ public function __construct( string $delimiter = ',', string $enclosure = '"', string $escape = '\\', - array $headers = null, - string $mode = 'rb' + ?array $headers = null, + string $mode = 'rb', ) { if (!\in_array($filePath, ['php://stdin', 'php://stdout', 'php://stderr'], true)) { $dirname = \dirname($this->filePath); - if (!@mkdir($dirname, 0755, true) && !is_dir($dirname)) { - throw new \RuntimeException(sprintf('Directory "%s" was not created', $dirname)); + if (!@mkdir($dirname, 0o755, true) && !is_dir($dirname)) { + throw new \RuntimeException(\sprintf('Directory "%s" was not created', $dirname)); } } diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 87937572..97dc8b83 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -44,7 +44,7 @@ public function __construct( protected string $delimiter = ',', protected string $enclosure = '"', protected string $escape = '\\', - array $headers = null + ?array $headers = null, ) { if (!\is_resource($resource)) { $type = \gettype($resource); @@ -149,7 +149,7 @@ public function isEndOfFile(): bool /** * Warning, this function will return exactly the same value as the fgetcsv() function. */ - public function readRaw(int $length = null): array|false + public function readRaw(?int $length = null): array|false { $this->assertOpened(); ++$this->lineNumber; @@ -157,7 +157,7 @@ public function readRaw(int $length = null): array|false return fgetcsv($this->handler, $length, $this->delimiter, $this->enclosure, $this->escape); } - public function readLine(int $length = null): ?array + public function readLine(?int $length = null): ?array { $filePosition = $this->seekCalled ? "at position {$this->tell()}" : "on line {$this->getLineNumber()}"; $values = $this->readRaw($length); @@ -286,7 +286,7 @@ protected function assertOpened(): void } } - protected function parseHeaders(array $headers = null): array + protected function parseHeaders(?array $headers = null): array { // If headers are not passed in the constructor but file is readable, try to read headers from file if (null === $headers) { diff --git a/src/Filesystem/FileStreamInterface.php b/src/Filesystem/FileStreamInterface.php index 542799cd..65b5b819 100644 --- a/src/Filesystem/FileStreamInterface.php +++ b/src/Filesystem/FileStreamInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,7 +27,7 @@ public function getLineNumber(): int; public function isEndOfFile(): bool; - public function readLine(int $length = null): ?array; + public function readLine(?int $length = null): ?array; /** * This methods rewinds the file to the first line of data, skipping the headers. diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index 5fa7d4f0..cd4359e0 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -65,7 +65,7 @@ public function isEndOfFile(): bool /** * Return an array containing current data and moving the file pointer. */ - public function readLine(int $length = null): ?array + public function readLine(?int $length = null): ?array { if ($this->isEndOfFile()) { return null; diff --git a/src/Filesystem/SeekableFileInterface.php b/src/Filesystem/SeekableFileInterface.php index 2d7ca906..f647ce7f 100644 --- a/src/Filesystem/SeekableFileInterface.php +++ b/src/Filesystem/SeekableFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/StructuredFileInterface.php b/src/Filesystem/StructuredFileInterface.php index 70ce3026..15e7db2e 100644 --- a/src/Filesystem/StructuredFileInterface.php +++ b/src/Filesystem/StructuredFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/WritableFileInterface.php b/src/Filesystem/WritableFileInterface.php index 2509c329..a4a61376 100644 --- a/src/Filesystem/WritableFileInterface.php +++ b/src/Filesystem/WritableFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/WritableStructuredFileInterface.php b/src/Filesystem/WritableStructuredFileInterface.php index e6e283eb..62ce9c82 100644 --- a/src/Filesystem/WritableStructuredFileInterface.php +++ b/src/Filesystem/WritableStructuredFileInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Filesystem/XmlFile.php b/src/Filesystem/XmlFile.php index 194a6248..99f20607 100644 --- a/src/Filesystem/XmlFile.php +++ b/src/Filesystem/XmlFile.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/AbstractLogger.php b/src/Logger/AbstractLogger.php index 1f84fdde..0a0ca91f 100644 --- a/src/Logger/AbstractLogger.php +++ b/src/Logger/AbstractLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ abstract class AbstractLogger extends BaseAbstractLogger { public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Logger/AbstractProcessor.php b/src/Logger/AbstractProcessor.php index 110b0fbe..715167ab 100644 --- a/src/Logger/AbstractProcessor.php +++ b/src/Logger/AbstractProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,13 +21,13 @@ class AbstractProcessor { public function __construct( - protected ProcessManager $processManager + protected ProcessManager $processManager, ) { } public function __invoke(LogRecord $record): LogRecord { - if ($record->context !== []) { + if ([] !== $record->context) { $context = $this->normalizeRecordData($record->context); $record = new LogRecord( $record->datetime, diff --git a/src/Logger/ProcessLogger.php b/src/Logger/ProcessLogger.php index 7565d9ef..5b17b68c 100644 --- a/src/Logger/ProcessLogger.php +++ b/src/Logger/ProcessLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/ProcessProcessor.php b/src/Logger/ProcessProcessor.php index 35d1f3a4..819ddf1b 100644 --- a/src/Logger/ProcessProcessor.php +++ b/src/Logger/ProcessProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TaskLogger.php b/src/Logger/TaskLogger.php index cb00efd3..8bee634e 100644 --- a/src/Logger/TaskLogger.php +++ b/src/Logger/TaskLogger.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index 7a262eb1..ac4a7d3b 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index cc8cb65e..8a61c301 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Manager/ProcessManager.php b/src/Manager/ProcessManager.php index e8d71865..e561366f 100644 --- a/src/Manager/ProcessManager.php +++ b/src/Manager/ProcessManager.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -64,7 +64,7 @@ public function __construct( protected TaskLogger $taskLogger, protected ProcessConfigurationRegistry $processConfigurationRegistry, protected ContextualOptionResolver $contextualOptionResolver, - protected EventDispatcherInterface $eventDispatcher + protected EventDispatcherInterface $eventDispatcher, ) { } @@ -225,7 +225,7 @@ protected function initialize(TaskConfiguration $taskConfiguration): void $this->taskConfiguration = $taskConfiguration; if (TaskConfiguration::STRATEGY_STOP === $taskConfiguration->getErrorStrategy() - && $taskConfiguration->getErrorOutputs() !== []) { + && [] !== $taskConfiguration->getErrorOutputs()) { $m = "Task configuration {$taskConfiguration->getCode()} has error outputs "; $m .= "but it's error strategy 'stop' implies they will never be reached."; $this->taskLogger->debug($m); @@ -460,7 +460,7 @@ protected function finalize(TaskConfiguration $taskConfiguration): void protected function initializeStates( ProcessConfiguration $processConfiguration, - array $context = [] + array $context = [], ): ProcessHistory { $processHistory = new ProcessHistory($processConfiguration, $context); @@ -479,7 +479,7 @@ protected function initializeStates( protected function prepareNextProcess( TaskConfiguration $previousTaskConfiguration, TaskConfiguration $nextTaskConfiguration, - bool $isError = false + bool $isError = false, ): void { if ($isError) { $input = $previousTaskConfiguration->getState() diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 309af297..149eae24 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/BlockingTaskInterface.php b/src/Model/BlockingTaskInterface.php index ad0bb7fb..5236f8ae 100644 --- a/src/Model/BlockingTaskInterface.php +++ b/src/Model/BlockingTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/FinalizableTaskInterface.php b/src/Model/FinalizableTaskInterface.php index 063ce14c..c71bed9b 100644 --- a/src/Model/FinalizableTaskInterface.php +++ b/src/Model/FinalizableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/FlushableTaskInterface.php b/src/Model/FlushableTaskInterface.php index 757fb5ba..8f56f5fa 100644 --- a/src/Model/FlushableTaskInterface.php +++ b/src/Model/FlushableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/InitializableTaskInterface.php b/src/Model/InitializableTaskInterface.php index 9cb9a5eb..434f60b2 100644 --- a/src/Model/InitializableTaskInterface.php +++ b/src/Model/InitializableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/IterableTaskInterface.php b/src/Model/IterableTaskInterface.php index 7d17856b..08b34111 100644 --- a/src/Model/IterableTaskInterface.php +++ b/src/Model/IterableTaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Model/ProcessHistory.php b/src/Model/ProcessHistory.php index 77f23986..1149c99b 100644 --- a/src/Model/ProcessHistory.php +++ b/src/Model/ProcessHistory.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -38,7 +38,7 @@ class ProcessHistory implements \Stringable public function __construct( ProcessConfiguration $processConfiguration, - protected array $context = [] + protected array $context = [], ) { $this->id = microtime(true); $this->processCode = $processConfiguration->getCode(); diff --git a/src/Model/ProcessState.php b/src/Model/ProcessState.php index 9b314304..b6ec5c9d 100644 --- a/src/Model/ProcessState.php +++ b/src/Model/ProcessState.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -69,7 +69,7 @@ class ProcessState public function __construct( protected ProcessConfiguration $processConfiguration, - protected ProcessHistory $processHistory + protected ProcessHistory $processHistory, ) { } @@ -163,7 +163,7 @@ public function hasErrorOutput(): bool return $this->hasErrorOutput; } - public function stop(\Throwable $e = null): void + public function stop(?\Throwable $e = null): void { if ($e instanceof \Throwable) { $this->setException($e); @@ -186,7 +186,7 @@ public function getException(): ?\Throwable return $this->exception; } - public function setException(\Throwable $exception = null): void + public function setException(?\Throwable $exception = null): void { $this->exception = $exception; } diff --git a/src/Model/SubprocessInstance.php b/src/Model/SubprocessInstance.php index a26ae6d8..35b05d5c 100644 --- a/src/Model/SubprocessInstance.php +++ b/src/Model/SubprocessInstance.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -40,7 +40,7 @@ public function __construct( protected string $processCode, protected ?string $input, protected array $context = [], - array $options = [] + array $options = [], ) { $resolver = new OptionsResolver(); $this->configureOptions($resolver); @@ -81,7 +81,7 @@ public function buildProcess(): static } foreach ($this->context as $key => $value) { - $arguments[] = sprintf('--context=%s:%s', $key, $value); + $arguments[] = \sprintf('--context=%s:%s', $key, $value); } $arguments[] = $this->processCode; diff --git a/src/Model/TaskInterface.php b/src/Model/TaskInterface.php index 748e282d..0e0c0a28 100644 --- a/src/Model/TaskInterface.php +++ b/src/Model/TaskInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Registry/ProcessConfigurationRegistry.php b/src/Registry/ProcessConfigurationRegistry.php index 6c403cda..2c5c9fa4 100644 --- a/src/Registry/ProcessConfigurationRegistry.php +++ b/src/Registry/ProcessConfigurationRegistry.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -31,7 +31,7 @@ class ProcessConfigurationRegistry public function __construct( protected array $rawConfiguration, - protected string $defaultErrorStrategy + protected string $defaultErrorStrategy, ) { } diff --git a/src/Registry/TransformerRegistry.php b/src/Registry/TransformerRegistry.php index 3ab519fb..9fd4fbff 100644 --- a/src/Registry/TransformerRegistry.php +++ b/src/Registry/TransformerRegistry.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/AbstractIterableOutputTask.php b/src/Task/AbstractIterableOutputTask.php index e1776e6f..8e8ccb7a 100644 --- a/src/Task/AbstractIterableOutputTask.php +++ b/src/Task/AbstractIterableOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/AggregateIterableTask.php b/src/Task/AggregateIterableTask.php index 4d4b850f..893d2206 100644 --- a/src/Task/AggregateIterableTask.php +++ b/src/Task/AggregateIterableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ArrayMergeTask.php b/src/Task/ArrayMergeTask.php index 6e20e7fd..a00e45ae 100644 --- a/src/Task/ArrayMergeTask.php +++ b/src/Task/ArrayMergeTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ColumnAggregatorTask.php b/src/Task/ColumnAggregatorTask.php index 0e00f7a7..829753b3 100644 --- a/src/Task/ColumnAggregatorTask.php +++ b/src/Task/ColumnAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -32,7 +32,7 @@ class ColumnAggregatorTask extends AbstractConfigurableTask implements BlockingT public function __construct( PropertyAccessorInterface $accessor, - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { $this->accessor = $accessor; } @@ -63,7 +63,7 @@ public function execute(ProcessState $state): void } } - if ($missingColumns !== []) { + if ([] !== $missingColumns) { $colStr = implode(', ', $missingColumns); $message = "Missing columns [{$colStr}] in input"; @@ -84,7 +84,7 @@ protected function addValueToAggregationGroup( mixed $column, mixed $input, string $referenceKey, - string $aggregationKey + string $aggregationKey, ): void { if (!isset($this->result[$column])) { $this->result[$column] = [ diff --git a/src/Task/ConstantIterableOutputTask.php b/src/Task/ConstantIterableOutputTask.php index 415e1164..60eeeb56 100644 --- a/src/Task/ConstantIterableOutputTask.php +++ b/src/Task/ConstantIterableOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/ConstantOutputTask.php b/src/Task/ConstantOutputTask.php index 040b882d..7037cafa 100644 --- a/src/Task/ConstantOutputTask.php +++ b/src/Task/ConstantOutputTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/CounterTask.php b/src/Task/CounterTask.php index df16e969..9b2020e5 100644 --- a/src/Task/CounterTask.php +++ b/src/Task/CounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php index 2f3dce09..dfe1d284 100644 --- a/src/Task/Debug/DebugTask.php +++ b/src/Task/Debug/DebugTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php index 1884d133..cc307cd5 100644 --- a/src/Task/Debug/DieTask.php +++ b/src/Task/Debug/DieTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/ErrorForwarderTask.php b/src/Task/Debug/ErrorForwarderTask.php index 80f235ed..9dbc1da8 100644 --- a/src/Task/Debug/ErrorForwarderTask.php +++ b/src/Task/Debug/ErrorForwarderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php index a793c680..23d4c251 100644 --- a/src/Task/Debug/MemInfoDumpTask.php +++ b/src/Task/Debug/MemInfoDumpTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class MemInfoDumpTask extends AbstractConfigurableTask { public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php index 8bbaf85e..ecf39e46 100644 --- a/src/Task/Debug/StopwatchTask.php +++ b/src/Task/Debug/StopwatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class StopwatchTask implements TaskInterface { public function __construct( protected LoggerInterface $logger, - private readonly Stopwatch $stopwatch + private readonly Stopwatch $stopwatch, ) { } diff --git a/src/Task/DummyTask.php b/src/Task/DummyTask.php index 71b9f4fe..7cb1bcae 100644 --- a/src/Task/DummyTask.php +++ b/src/Task/DummyTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/Event/EventDispatcherTask.php b/src/Task/Event/EventDispatcherTask.php index 6771c16d..fcf8bc92 100644 --- a/src/Task/Event/EventDispatcherTask.php +++ b/src/Task/Event/EventDispatcherTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,7 +26,7 @@ class EventDispatcherTask extends AbstractConfigurableTask { public function __construct( - protected EventDispatcherInterface $eventDispatcher + protected EventDispatcherInterface $eventDispatcher, ) { } diff --git a/src/Task/File/Csv/AbstractCsvResourceTask.php b/src/Task/File/Csv/AbstractCsvResourceTask.php index 1b6ac24f..a0ed37b9 100644 --- a/src/Task/File/Csv/AbstractCsvResourceTask.php +++ b/src/Task/File/Csv/AbstractCsvResourceTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index ddef722e..dd7d0cf9 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index 2a0c9e85..afe16bd8 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,7 +26,7 @@ class CsvReaderTask extends AbstractCsvTask implements IterableTaskInterface { public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 12e1b7a1..234017a4 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index 813013e5..d1145dec 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php index b819548a..7afc735c 100644 --- a/src/Task/File/Csv/InputCsvReaderTask.php +++ b/src/Task/File/Csv/InputCsvReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php index 2fc166c1..f7a695ef 100644 --- a/src/Task/File/FileFetchTask.php +++ b/src/Task/File/FileFetchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -37,7 +37,7 @@ class FileFetchTask extends AbstractConfigurableTask implements IterableTaskInte protected array $matchingFiles = []; public function __construct( - protected ?MountManager $mountManager = null + protected ?MountManager $mountManager = null, ) { } @@ -121,7 +121,7 @@ protected function doFileCopy(ProcessState $state, string $filename, bool $remov } if ($removeSource) { - $this->sourceFS->delete(sprintf('%s://%s', $prefixFrom, $filename)); + $this->sourceFS->delete(\sprintf('%s://%s', $prefixFrom, $filename)); } return $result ? $filename : null; diff --git a/src/Task/File/FileMoverTask.php b/src/Task/File/FileMoverTask.php index 81cf17c2..e9070cd1 100644 --- a/src/Task/File/FileMoverTask.php +++ b/src/Task/File/FileMoverTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileReaderTask.php b/src/Task/File/FileReaderTask.php index ea69db22..2261acbe 100644 --- a/src/Task/File/FileReaderTask.php +++ b/src/Task/File/FileReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileRemoverTask.php b/src/Task/File/FileRemoverTask.php index 03e68145..dda53166 100644 --- a/src/Task/File/FileRemoverTask.php +++ b/src/Task/File/FileRemoverTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FileWriterTask.php b/src/Task/File/FileWriterTask.php index d3dc0740..5378099b 100644 --- a/src/Task/File/FileWriterTask.php +++ b/src/Task/File/FileWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/FolderBrowserTask.php b/src/Task/File/FolderBrowserTask.php index 6eeb8e5d..6668c3eb 100644 --- a/src/Task/File/FolderBrowserTask.php +++ b/src/Task/File/FolderBrowserTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -35,7 +35,7 @@ class FolderBrowserTask extends AbstractConfigurableTask implements IterableTask protected \Iterator|array|null $files = null; public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index 5d1fb90b..2d6bb67b 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index effff1fe..8db6fc26 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/Xml/XmlReaderTask.php b/src/Task/File/Xml/XmlReaderTask.php index 69535635..236420a1 100644 --- a/src/Task/File/Xml/XmlReaderTask.php +++ b/src/Task/File/Xml/XmlReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class XmlReaderTask extends AbstractConfigurableTask { public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/File/Xml/XmlWriterTask.php b/src/Task/File/Xml/XmlWriterTask.php index 64548f33..6c88226a 100644 --- a/src/Task/File/Xml/XmlWriterTask.php +++ b/src/Task/File/Xml/XmlWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class XmlWriterTask extends AbstractConfigurableTask { public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/YamlReaderTask.php index 67174114..7b587e7e 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/YamlReaderTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/File/YamlWriterTask.php b/src/Task/File/YamlWriterTask.php index 0fa18844..208ef2fe 100644 --- a/src/Task/File/YamlWriterTask.php +++ b/src/Task/File/YamlWriterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/FilterTask.php b/src/Task/FilterTask.php index 38715c3c..8ea0abae 100644 --- a/src/Task/FilterTask.php +++ b/src/Task/FilterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/GroupByAggregateIterableTask.php b/src/Task/GroupByAggregateIterableTask.php index d521e329..b92e2f18 100644 --- a/src/Task/GroupByAggregateIterableTask.php +++ b/src/Task/GroupByAggregateIterableTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -33,7 +33,7 @@ class GroupByAggregateIterableTask extends AbstractConfigurableTask implements B protected array $result = []; public function __construct( - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Task/InputAggregatorTask.php b/src/Task/InputAggregatorTask.php index 0aeea05f..c5b68fa3 100644 --- a/src/Task/InputAggregatorTask.php +++ b/src/Task/InputAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/InputIteratorTask.php b/src/Task/InputIteratorTask.php index 301c24b3..a079626d 100644 --- a/src/Task/InputIteratorTask.php +++ b/src/Task/InputIteratorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index 4e9a5ed0..9b751fba 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -31,7 +31,7 @@ class IterableBatchTask extends AbstractConfigurableTask implements FlushableTas protected bool $flushMode = false; public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/ObjectUpdaterTask.php b/src/Task/ObjectUpdaterTask.php index 8136b7bd..30a53641 100644 --- a/src/Task/ObjectUpdaterTask.php +++ b/src/Task/ObjectUpdaterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class ObjectUpdaterTask extends AbstractConfigurableTask { public function __construct( - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Task/Process/CommandRunnerTask.php b/src/Task/Process/CommandRunnerTask.php index 999e5573..a988ff3e 100644 --- a/src/Task/Process/CommandRunnerTask.php +++ b/src/Task/Process/CommandRunnerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class CommandRunnerTask extends AbstractConfigurableTask { public function __construct( - protected KernelInterface $kernel + protected KernelInterface $kernel, ) { } diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index e9a515c2..12d3789b 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -32,7 +32,7 @@ class ProcessExecutorTask extends AbstractConfigurableTask public function __construct( protected ProcessManager $processManager, protected ProcessConfigurationRegistry $processRegistry, - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index a3c3f5cc..8b3c4aad 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -42,7 +42,7 @@ class ProcessLauncherTask extends AbstractConfigurableTask implements FlushableT public function __construct( protected LoggerInterface $logger, protected ProcessConfigurationRegistry $processRegistry, - protected KernelInterface $kernel + protected KernelInterface $kernel, ) { $this->finishedBuffers = new \SplQueue(); } @@ -78,7 +78,7 @@ public function flush(ProcessState $state): void } // After dequeue, stop flush - if ($this->finishedBuffers->isEmpty() && $this->launchedProcesses === []) { + if ($this->finishedBuffers->isEmpty() && [] === $this->launchedProcesses) { $this->flushMode = false; } } @@ -96,7 +96,7 @@ public function next(ProcessState $state): bool // if we are in flush mode, we should wait for process to finish if ($this->flushMode) { - return $this->launchedProcesses !== []; + return [] !== $this->launchedProcesses; } usleep($this->getOption($state, 'sleep_on_finalize_interval')); diff --git a/src/Task/PropertyGetterTask.php b/src/Task/PropertyGetterTask.php index a898f4ea..10d97f85 100644 --- a/src/Task/PropertyGetterTask.php +++ b/src/Task/PropertyGetterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,7 +26,7 @@ class PropertyGetterTask extends AbstractConfigurableTask { public function __construct( protected LoggerInterface $logger, - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Task/PropertySetterTask.php b/src/Task/PropertySetterTask.php index 56be23f8..2117b4c9 100644 --- a/src/Task/PropertySetterTask.php +++ b/src/Task/PropertySetterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,7 +26,7 @@ class PropertySetterTask extends AbstractConfigurableTask { public function __construct( protected LoggerInterface $logger, - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Task/Reporting/AdvancedStatCounterTask.php b/src/Task/Reporting/AdvancedStatCounterTask.php index 3f2eb47c..e7d85b16 100644 --- a/src/Task/Reporting/AdvancedStatCounterTask.php +++ b/src/Task/Reporting/AdvancedStatCounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -32,7 +32,7 @@ class AdvancedStatCounterTask extends AbstractConfigurableTask protected int $preInitCounter = 0; public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/Reporting/LoggerTask.php b/src/Task/Reporting/LoggerTask.php index dc73bbd9..f990a2c6 100644 --- a/src/Task/Reporting/LoggerTask.php +++ b/src/Task/Reporting/LoggerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,7 +28,7 @@ class LoggerTask extends AbstractConfigurableTask { public function __construct( protected LoggerInterface $logger, - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Task/Reporting/StatCounterTask.php b/src/Task/Reporting/StatCounterTask.php index 21bc005d..c12285c1 100644 --- a/src/Task/Reporting/StatCounterTask.php +++ b/src/Task/Reporting/StatCounterTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,7 +25,7 @@ class StatCounterTask implements FinalizableTaskInterface protected int $counter = 0; public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/RowAggregatorTask.php b/src/Task/RowAggregatorTask.php index 163b1bfc..c43317d3 100644 --- a/src/Task/RowAggregatorTask.php +++ b/src/Task/RowAggregatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -31,7 +31,7 @@ class RowAggregatorTask extends AbstractConfigurableTask implements BlockingTask protected array $result = []; public function __construct( - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { } diff --git a/src/Task/Serialization/DenormalizerTask.php b/src/Task/Serialization/DenormalizerTask.php index 975b573a..6edecc00 100644 --- a/src/Task/Serialization/DenormalizerTask.php +++ b/src/Task/Serialization/DenormalizerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class DenormalizerTask extends AbstractConfigurableTask { public function __construct( - protected DenormalizerInterface $denormalizer + protected DenormalizerInterface $denormalizer, ) { } diff --git a/src/Task/Serialization/DeserializerTask.php b/src/Task/Serialization/DeserializerTask.php index 1287eeff..654a535d 100644 --- a/src/Task/Serialization/DeserializerTask.php +++ b/src/Task/Serialization/DeserializerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,7 +21,7 @@ class DeserializerTask extends AbstractConfigurableTask { public function __construct( - protected SerializerInterface $serializer + protected SerializerInterface $serializer, ) { } diff --git a/src/Task/Serialization/NormalizerTask.php b/src/Task/Serialization/NormalizerTask.php index 2e7d43d3..8c43ed1b 100644 --- a/src/Task/Serialization/NormalizerTask.php +++ b/src/Task/Serialization/NormalizerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class NormalizerTask extends AbstractConfigurableTask { public function __construct( - protected NormalizerInterface $normalizer + protected NormalizerInterface $normalizer, ) { } diff --git a/src/Task/Serialization/SerializerTask.php b/src/Task/Serialization/SerializerTask.php index 054208cb..644447b0 100644 --- a/src/Task/Serialization/SerializerTask.php +++ b/src/Task/Serialization/SerializerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,7 +21,7 @@ class SerializerTask extends AbstractConfigurableTask { public function __construct( - protected SerializerInterface $serializer + protected SerializerInterface $serializer, ) { } diff --git a/src/Task/SimpleBatchTask.php b/src/Task/SimpleBatchTask.php index 9db576ba..b022dd70 100644 --- a/src/Task/SimpleBatchTask.php +++ b/src/Task/SimpleBatchTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/SkipEmptyTask.php b/src/Task/SkipEmptyTask.php index b649864a..1663e28f 100644 --- a/src/Task/SkipEmptyTask.php +++ b/src/Task/SkipEmptyTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index 6079d851..6d695c5b 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/StopTask.php b/src/Task/StopTask.php index c7ab909a..c8945cd8 100644 --- a/src/Task/StopTask.php +++ b/src/Task/StopTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Task/TransformerTask.php b/src/Task/TransformerTask.php index 64502a71..f04d8832 100644 --- a/src/Task/TransformerTask.php +++ b/src/Task/TransformerTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -33,7 +33,7 @@ class TransformerTask extends AbstractConfigurableTask public function __construct( protected LoggerInterface $logger, - TransformerRegistry $transformerRegistry + TransformerRegistry $transformerRegistry, ) { $this->transformerRegistry = $transformerRegistry; } diff --git a/src/Task/Validation/ValidatorTask.php b/src/Task/Validation/ValidatorTask.php index efd82b10..ae7510b6 100644 --- a/src/Task/Validation/ValidatorTask.php +++ b/src/Task/Validation/ValidatorTask.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -30,7 +30,7 @@ class ValidatorTask extends AbstractConfigurableTask { public function __construct( protected LoggerInterface $logger, - protected ValidatorInterface $validator + protected ValidatorInterface $validator, ) { } diff --git a/src/Transformer/ArrayElementTransformer.php b/src/Transformer/ArrayElementTransformer.php index 86cff75e..beb4cdf5 100644 --- a/src/Transformer/ArrayElementTransformer.php +++ b/src/Transformer/ArrayElementTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayFilterTransformer.php b/src/Transformer/ArrayFilterTransformer.php index 2a942149..0464e98f 100644 --- a/src/Transformer/ArrayFilterTransformer.php +++ b/src/Transformer/ArrayFilterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/ArrayFirstTransformer.php index 9d1f3739..238c09c7 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/ArrayFirstTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayLastTransformer.php b/src/Transformer/ArrayLastTransformer.php index e227143e..3d8d8a2b 100644 --- a/src/Transformer/ArrayLastTransformer.php +++ b/src/Transformer/ArrayLastTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayMapTransformer.php b/src/Transformer/ArrayMapTransformer.php index 4e3f7fb3..767848f3 100644 --- a/src/Transformer/ArrayMapTransformer.php +++ b/src/Transformer/ArrayMapTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ArrayUnsetTransformer.php b/src/Transformer/ArrayUnsetTransformer.php index e4527269..fd79556d 100644 --- a/src/Transformer/ArrayUnsetTransformer.php +++ b/src/Transformer/ArrayUnsetTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 522fda98..53439e21 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -30,7 +30,7 @@ class CachedTransformer implements ConfigurableTransformerInterface public function __construct( TransformerRegistry $transformerRegistry, protected CacheItemPoolInterface $cache, - protected LoggerInterface $logger + protected LoggerInterface $logger, ) { $this->transformerRegistry = $transformerRegistry; } diff --git a/src/Transformer/CallbackTransformer.php b/src/Transformer/CallbackTransformer.php index 94e695f8..88e1f275 100644 --- a/src/Transformer/CallbackTransformer.php +++ b/src/Transformer/CallbackTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/CastTransformer.php b/src/Transformer/CastTransformer.php index 8b099a5a..559af464 100644 --- a/src/Transformer/CastTransformer.php +++ b/src/Transformer/CastTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConditionTrait.php b/src/Transformer/ConditionTrait.php index a65bda4d..d5e2dec0 100644 --- a/src/Transformer/ConditionTrait.php +++ b/src/Transformer/ConditionTrait.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -111,7 +111,7 @@ protected function checkValue( string $key, mixed $value, bool $shouldMatch = true, - bool $regexpMode = false + bool $regexpMode = false, ): bool { $currentValue = $this->getValue($input, $key); diff --git a/src/Transformer/ConfigurableTransformerInterface.php b/src/Transformer/ConfigurableTransformerInterface.php index f5112455..af44c693 100644 --- a/src/Transformer/ConfigurableTransformerInterface.php +++ b/src/Transformer/ConfigurableTransformerInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConstantTransformer.php b/src/Transformer/ConstantTransformer.php index 9a234fcf..ec0ae7ca 100644 --- a/src/Transformer/ConstantTransformer.php +++ b/src/Transformer/ConstantTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ConvertValueTransformer.php b/src/Transformer/ConvertValueTransformer.php index fc974174..e9a7775b 100644 --- a/src/Transformer/ConvertValueTransformer.php +++ b/src/Transformer/ConvertValueTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DateFormatTransformer.php b/src/Transformer/DateFormatTransformer.php index 464ae658..b3462e05 100644 --- a/src/Transformer/DateFormatTransformer.php +++ b/src/Transformer/DateFormatTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DateParserTransformer.php b/src/Transformer/DateParserTransformer.php index 9553e1f6..3ebbe009 100644 --- a/src/Transformer/DateParserTransformer.php +++ b/src/Transformer/DateParserTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DebugTransformer.php b/src/Transformer/DebugTransformer.php index 9d6bcfc2..16f11174 100644 --- a/src/Transformer/DebugTransformer.php +++ b/src/Transformer/DebugTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DefaultTransformer.php b/src/Transformer/DefaultTransformer.php index 1ce9b633..96a847be 100644 --- a/src/Transformer/DefaultTransformer.php +++ b/src/Transformer/DefaultTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/DenormalizeTransformer.php index 529f7dfb..aabf2a84 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/DenormalizeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,7 +22,7 @@ class DenormalizeTransformer implements ConfigurableTransformerInterface { public function __construct( - protected DenormalizerInterface $denormalizer + protected DenormalizerInterface $denormalizer, ) { } diff --git a/src/Transformer/EvaluatorTransformer.php b/src/Transformer/EvaluatorTransformer.php index 9a33db73..33ceba2b 100644 --- a/src/Transformer/EvaluatorTransformer.php +++ b/src/Transformer/EvaluatorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ExplodeTransformer.php b/src/Transformer/ExplodeTransformer.php index 65b79427..71c838f5 100644 --- a/src/Transformer/ExplodeTransformer.php +++ b/src/Transformer/ExplodeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ExpressionLanguageMapTransformer.php b/src/Transformer/ExpressionLanguageMapTransformer.php index 9bfb65b0..0356e9a3 100644 --- a/src/Transformer/ExpressionLanguageMapTransformer.php +++ b/src/Transformer/ExpressionLanguageMapTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class ExpressionLanguageMapTransformer implements ConfigurableTransformerInterface { public function __construct( - protected ExpressionLanguage $language + protected ExpressionLanguage $language, ) { } diff --git a/src/Transformer/GenericTransformer.php b/src/Transformer/GenericTransformer.php index e033e281..f1863aa4 100644 --- a/src/Transformer/GenericTransformer.php +++ b/src/Transformer/GenericTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -33,7 +33,7 @@ class GenericTransformer implements ConfigurableTransformerInterface public function __construct( protected ContextualOptionResolver $contextualOptionResolver, - TransformerRegistry $transformerRegistry + TransformerRegistry $transformerRegistry, ) { $this->transformerRegistry = $transformerRegistry; } diff --git a/src/Transformer/HashTransformer.php b/src/Transformer/HashTransformer.php index c1fc610f..9c3bf4bc 100644 --- a/src/Transformer/HashTransformer.php +++ b/src/Transformer/HashTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/ImplodeTransformer.php b/src/Transformer/ImplodeTransformer.php index fb08288e..be117356 100644 --- a/src/Transformer/ImplodeTransformer.php +++ b/src/Transformer/ImplodeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/InstantiateTransformer.php b/src/Transformer/InstantiateTransformer.php index 8da6c2f8..223be69b 100644 --- a/src/Transformer/InstantiateTransformer.php +++ b/src/Transformer/InstantiateTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/MappingTransformer.php b/src/Transformer/MappingTransformer.php index 3ed3bc4e..ff8b0001 100644 --- a/src/Transformer/MappingTransformer.php +++ b/src/Transformer/MappingTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -32,7 +32,7 @@ class MappingTransformer implements ConfigurableTransformerInterface public function __construct( TransformerRegistry $transformerRegistry, protected LoggerInterface $logger, - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { $this->transformerRegistry = $transformerRegistry; } diff --git a/src/Transformer/MultiReplaceTransformer.php b/src/Transformer/MultiReplaceTransformer.php index 90d87424..5ff4b927 100644 --- a/src/Transformer/MultiReplaceTransformer.php +++ b/src/Transformer/MultiReplaceTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/NormalizeTransformer.php index 5cd57635..904f7476 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/NormalizeTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,7 +22,7 @@ class NormalizeTransformer implements ConfigurableTransformerInterface { public function __construct( - protected NormalizerInterface $normalizer + protected NormalizerInterface $normalizer, ) { } diff --git a/src/Transformer/PregFilterTransformer.php b/src/Transformer/PregFilterTransformer.php index 5a6d4f11..361dd119 100644 --- a/src/Transformer/PregFilterTransformer.php +++ b/src/Transformer/PregFilterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/PropertyAccessorTransformer.php b/src/Transformer/PropertyAccessorTransformer.php index 4e37c2fc..ebb7f6ab 100644 --- a/src/Transformer/PropertyAccessorTransformer.php +++ b/src/Transformer/PropertyAccessorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,7 +22,7 @@ class PropertyAccessorTransformer implements ConfigurableTransformerInterface { public function __construct( - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/RecursivePropertySetterTransformer.php index 9d06e256..6f7767e9 100644 --- a/src/Transformer/RecursivePropertySetterTransformer.php +++ b/src/Transformer/RecursivePropertySetterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,7 +24,7 @@ class RecursivePropertySetterTransformer implements ConfigurableTransformerInterface { public function __construct( - protected PropertyAccessorInterface $accessor + protected PropertyAccessorInterface $accessor, ) { } diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index 4e19338c..22115368 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,7 +28,7 @@ class RulesTransformer implements ConfigurableTransformerInterface public function __construct( TransformerRegistry $transformerRegistry, - protected ExpressionLanguage $language + protected ExpressionLanguage $language, ) { $this->transformerRegistry = $transformerRegistry; } @@ -93,7 +93,7 @@ public function configureOptions(OptionsResolver $resolver): void /** * Configure options for one "rule" block. */ - public function configureRuleOptions(OptionsResolver $resolver, array $expressionVariables = null): void + public function configureRuleOptions(OptionsResolver $resolver, ?array $expressionVariables = null): void { $resolver->setDefaults([ 'condition' => null, diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/SlugifyTransformer.php index b5dd77cf..970d7adf 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/SlugifyTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/SprintfTransformer.php index e496d193..f075b518 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/SprintfTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php index 34cd402b..7cf44d54 100644 --- a/src/Transformer/TransformerInterface.php +++ b/src/Transformer/TransformerInterface.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TransformerTrait.php b/src/Transformer/TransformerTrait.php index 4079603f..4bea4f87 100644 --- a/src/Transformer/TransformerTrait.php +++ b/src/Transformer/TransformerTrait.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -52,7 +52,7 @@ public function normalizeTransformers(Options $options, array $transformers): ar protected function applyTransformers(array $transformers, mixed $value): mixed { // Quick return for better perfs - if ($transformers === []) { + if ([] === $transformers) { return $value; } @@ -92,7 +92,7 @@ protected function getCleanedTransfomerCode(string $transformerCode): string protected function configureTransformersOptions( OptionsResolver $resolver, - string $optionName = 'transformers' + string $optionName = 'transformers', ): void { $resolver->setDefault($optionName, []); $resolver->setAllowedTypes($optionName, ['array']); diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/TrimTransformer.php index f9966f7d..121b16d0 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/TrimTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/TypeSetterTransformer.php b/src/Transformer/TypeSetterTransformer.php index 202384d0..64804d8a 100644 --- a/src/Transformer/TypeSetterTransformer.php +++ b/src/Transformer/TypeSetterTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/UnsetTransformer.php b/src/Transformer/UnsetTransformer.php index 05d98d60..112f4ad0 100644 --- a/src/Transformer/UnsetTransformer.php +++ b/src/Transformer/UnsetTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/WrapperTransformer.php b/src/Transformer/WrapperTransformer.php index 6f55e294..297e7253 100644 --- a/src/Transformer/WrapperTransformer.php +++ b/src/Transformer/WrapperTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/src/Transformer/Xml/XpathEvaluatorTransformer.php b/src/Transformer/Xml/XpathEvaluatorTransformer.php index 9b5964e8..74b378a4 100644 --- a/src/Transformer/Xml/XpathEvaluatorTransformer.php +++ b/src/Transformer/Xml/XpathEvaluatorTransformer.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -65,7 +65,7 @@ public function configureOptions(OptionsResolver $resolver): void * Configure options about how to handle xpath query results. * Available at root and subquery level. */ - public function configureQueryOptions(OptionsResolver $resolver, Options $parentOptions = null): void + public function configureQueryOptions(OptionsResolver $resolver, ?Options $parentOptions = null): void { $resolver->setDefault('single_result', $parentOptions instanceof Options ? $parentOptions['single_result'] : true); $resolver->setAllowedTypes('single_result', 'bool'); diff --git a/src/Validator/ConstraintLoader.php b/src/Validator/ConstraintLoader.php index d767dc15..e2adab9b 100644 --- a/src/Validator/ConstraintLoader.php +++ b/src/Validator/ConstraintLoader.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Exception/MissingTransformerExceptionTest.php b/tests/Exception/MissingTransformerExceptionTest.php index fad77c86..6b30730b 100644 --- a/tests/Exception/MissingTransformerExceptionTest.php +++ b/tests/Exception/MissingTransformerExceptionTest.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Exception; use CleverAge\ProcessBundle\Exception\MissingTransformerException; diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/ArrayElementTransformerTest.php index 6895a9c8..a3c9e36e 100644 --- a/tests/Transformer/ArrayElementTransformerTest.php +++ b/tests/Transformer/ArrayElementTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/ArrayFirstTransformerTest.php index 07b87049..596c2bf0 100644 --- a/tests/Transformer/ArrayFirstTransformerTest.php +++ b/tests/Transformer/ArrayFirstTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index 5a667646..9eac2bba 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index 9d291e37..e03734b3 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/DateFormatTransformerTest.php index 6baf4821..8a0408e1 100644 --- a/tests/Transformer/DateFormatTransformerTest.php +++ b/tests/Transformer/DateFormatTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/DateParserTransformerTest.php index 7ac7a7d6..15e142b6 100644 --- a/tests/Transformer/DateParserTransformerTest.php +++ b/tests/Transformer/DateParserTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php index 5af9744e..0be796f9 100644 --- a/tests/Transformer/DebugTransformerTest.php +++ b/tests/Transformer/DebugTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php index 64a71cfe..39eb1209 100644 --- a/tests/Transformer/DefaultTransformerTest.php +++ b/tests/Transformer/DefaultTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ExplodeTransformerTest.php b/tests/Transformer/ExplodeTransformerTest.php index b454c27a..f0518338 100644 --- a/tests/Transformer/ExplodeTransformerTest.php +++ b/tests/Transformer/ExplodeTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/ImplodeTransformerTest.php index 0a3751d4..6037dd79 100644 --- a/tests/Transformer/ImplodeTransformerTest.php +++ b/tests/Transformer/ImplodeTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php index 8a3c58c6..c21a9833 100644 --- a/tests/Transformer/MultiReplaceTransformerTest.php +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/SprintfTransformerTest.php b/tests/Transformer/SprintfTransformerTest.php index 59397a0f..4b4f7996 100644 --- a/tests/Transformer/SprintfTransformerTest.php +++ b/tests/Transformer/SprintfTransformerTest.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Transformer; use CleverAge\ProcessBundle\Transformer\SprintfTransformer; diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/TrimTransformerTest.php index 62aca460..7ee5609f 100644 --- a/tests/Transformer/TrimTransformerTest.php +++ b/tests/Transformer/TrimTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php index 4699f7a3..c89ee2d3 100644 --- a/tests/Transformer/WrapperTransformerTest.php +++ b/tests/Transformer/WrapperTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/tests/Transformer/XpathEvaluatorTransformerTest.php b/tests/Transformer/XpathEvaluatorTransformerTest.php index 50fda077..5f4dfd2c 100644 --- a/tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/tests/Transformer/XpathEvaluatorTransformerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the CleverAge/ProcessBundle package. * - * Copyright (c) 2017-2024 Clever-Age + * Copyright (c) Clever-Age * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. From 76b5894158a1e44b000e20c697cf897d0135d8ec Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 16 Oct 2024 15:35:09 +0200 Subject: [PATCH 238/304] #129 Remove wrong replace configuration on composer.json. Add missing suggest. --- composer.json | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index a1d4119c..5f337773 100644 --- a/composer.json +++ b/composer.json @@ -47,15 +47,6 @@ "CleverAge\\ProcessBundle\\Tests\\": "tests/" } }, - "replace": { - "symfony/polyfill-ctype": "*", - "symfony/polyfill-iconv": "*", - "symfony/polyfill-php72": "*", - "symfony/polyfill-php73": "*", - "symfony/polyfill-php74": "*", - "symfony/polyfill-php80": "*", - "symfony/polyfill-php81": "*" - }, "require": { "php": ">=8.1", "ext-json": "*", @@ -94,10 +85,14 @@ }, "suggest": { "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", - "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", - "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", + "cleverage/eav-process-bundle": "Dedicated bundle for EAV dependencies for the process bundle", "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", - "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle" + "cleverage/process-soap-bundle": "Another dedicated bundle for Soap dependencies for the process bundle", + "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", + "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle", + "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", + "cleverage/cache-process-bundle": "Dedicated bundle for cache handling for the process bundle", + "cleverage/processuibundle": "A simple UX for cleverage/processbundle using EasyAdmin\n\n" }, "config": { "allow-plugins": { From 8d0da4ae5eac8d6105ce903639f91ad68a04f19f Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 15:45:44 +0200 Subject: [PATCH 239/304] #138 Update CHANGELOG with v3.2.9+ versions --- CHANGELOG.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4129a633..f2d96fc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,53 @@ +v4.0 +------ + +### Changes + +* Update Makefile & .docker for local standalone usage +* Update rector, phpstan & php-cs-fixer configurations & apply it. + +### Fixes + +* [#129](https://github.com/cleverage/process-bundle/issues/129) Remove wrong replace configuration on composer.json. Add missing suggest. +* Miscellaneous fixes, show full diff : https://github.com/cleverage/process-bundle/compare/v4.0.0-rc2...v4.0.0 + +v4.0-RC2 +------ + +## BC breaks + +* Bump php version to >=8.2 +* Bump symfony version to ^6.4|^7.1 + +### Fixes + +* Miscellaneous fixes, show full diff : https://github.com/cleverage/process-bundle/compare/v4.0.0-rc1...v4.0.0-rc2 + +v4.0-RC1 +------ + +## BC breaks + +* Bump php version to >=8.1 +* Bump symfony version to ^6.3 + +## Changes +* Add some phpunit tests +* Apply Rector & Phpstan +* Add StopwatchTask +* Change directory structure. Move Symfony code to /src, documentation to /doc, and tests to /tests. + +### Fixes + +* Miscellaneous fixes, show full diff : https://github.com/cleverage/process-bundle/compare/v3.2.9...v4.0.0-rc1 + +v3.2.9 +------ + +### Fixes + +https://github.com/cleverage/process-bundle/compare/v3.2.8...v3.2.9 + v3.2.8 ------ From 7248fae0150fd69f3dcbe6a07b257ded28f4d66b Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 15:52:14 +0200 Subject: [PATCH 240/304] #139 Re-apply php-cs-fixer due to previous merge from v3.2-dev branch --- src/Configuration/ProcessConfiguration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 421680f7..37b06baf 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -244,7 +244,7 @@ protected function sortDependencies(array $dependencies): array } $midOffset = round(\count($dependencies) / 2); - $midTaskCode = $dependencies[(int)$midOffset]; + $midTaskCode = $dependencies[(int) $midOffset]; $midTask = $this->getTaskConfiguration($midTaskCode); $previousTasks = []; From 2a91d78d0cdf08cc1ccb6513d1724afbbc0d32d3 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 15:55:17 +0200 Subject: [PATCH 241/304] #140 Fix test github workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 78aa3aa8..2d7e7a41 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -67,7 +67,7 @@ jobs: with: dependency-versions: ${{ matrix.dependencies }} - name: Run Tests with coverage - run: make coverage + run: vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/logs/clover.xml #- name: Send coverage to Codecov # uses: codecov/codecov-action@v4 # with: From f19ca0c04ee0c68902fc9ee2df7ee5e2dbfd5413 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 16:04:07 +0200 Subject: [PATCH 242/304] #140 Fix notifications github workflow --- .github/workflows/notifications.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/notifications.yml b/.github/workflows/notifications.yml index dd59e3a5..dc3d0581 100644 --- a/.github/workflows/notifications.yml +++ b/.github/workflows/notifications.yml @@ -13,10 +13,10 @@ jobs: steps: - name: Get the tag short reference id: get_tag - run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//} + run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT - name: Rocket.Chat Notification - uses: madalozzo/Rocket.Chat.GitHub.Action.Notification@v2 + uses: madalozzo/Rocket.Chat.GitHub.Action.Notification@master with: type: success job_name: "[cleverage/process-bundle](https://github.com/cleverage/process-bundle) : ${{ steps.get_tag.outputs.TAG }} has been released" From 28bfd60db499fae50dda4368e41cdbaf7d86fd93 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 17 Oct 2024 17:07:27 +0200 Subject: [PATCH 243/304] #141 Remove FileFetchTask, use cleverage/flysystem-process-bundle instead. league/flysystem-bundle is not required anymore. --- CHANGELOG.md | 11 ++- composer.json | 1 - src/Task/File/FileFetchTask.php | 142 -------------------------------- 3 files changed, 8 insertions(+), 146 deletions(-) delete mode 100644 src/Task/File/FileFetchTask.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f2d96fc9..d34a73c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,19 @@ v4.0 ------ +## BC breaks + +* Remove FileFetchTask, use cleverage/flysystem-process-bundle instead. + ### Changes * Update Makefile & .docker for local standalone usage -* Update rector, phpstan & php-cs-fixer configurations & apply it. +* Update rector, phpstan & php-cs-fixer configurations & apply it +* league/flysystem-bundle is not required anymore ### Fixes -* [#129](https://github.com/cleverage/process-bundle/issues/129) Remove wrong replace configuration on composer.json. Add missing suggest. +* [#129](https://github.com/cleverage/process-bundle/issues/129) Remove wrong replace configuration on composer.json. Add missing suggest * Miscellaneous fixes, show full diff : https://github.com/cleverage/process-bundle/compare/v4.0.0-rc2...v4.0.0 v4.0-RC2 @@ -35,7 +40,7 @@ v4.0-RC1 * Add some phpunit tests * Apply Rector & Phpstan * Add StopwatchTask -* Change directory structure. Move Symfony code to /src, documentation to /doc, and tests to /tests. +* Change directory structure. Move Symfony code to /src, documentation to /doc, and tests to /tests ### Fixes diff --git a/composer.json b/composer.json index 5f337773..3a00935f 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,6 @@ "ext-intl": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", - "league/flysystem-bundle": "^3.1", "symfony/config": "^6.4|^7.1", "symfony/console": "^6.4|^7.1", "symfony/dependency-injection": "^6.4|^7.1", diff --git a/src/Task/File/FileFetchTask.php b/src/Task/File/FileFetchTask.php deleted file mode 100644 index f7a695ef..00000000 --- a/src/Task/File/FileFetchTask.php +++ /dev/null @@ -1,142 +0,0 @@ -mountManager instanceof MountManager) { - throw new ServiceNotFoundException('MountManager service not found, you need to install FlySystemBundle'); - } - // Configure options - parent::initialize($state); - - $this->sourceFS = new Filesystem($this->getOption($state, 'source_filesystem')); - $this->destinationFS = new Filesystem($this->getOption($state, 'destination_filesystem')); - } - - public function execute(ProcessState $state): void - { - $this->findMatchingFiles($state); - - $file = current($this->matchingFiles); - if (!$file) { - $state->setSkipped(true); - - return; - } - - $this->doFileCopy($state, $file, $this->getOption($state, 'remove_source')); - $state->setOutput($file); - } - - public function next(ProcessState $state): bool - { - $this->findMatchingFiles($state); - - return next($this->matchingFiles); - } - - protected function findMatchingFiles(ProcessState $state): void - { - $filePattern = $this->getOption($state, 'file_pattern'); - if ($filePattern) { - foreach ($this->sourceFS->listContents('/') as $file) { - if ('file' === $file['type'] - && preg_match($filePattern, (string) $file['path']) - && !\in_array($file['path'], $this->matchingFiles, true)) { - $this->matchingFiles[] = $file['path']; - } - } - } else { - $input = $state->getInput(); - if (!$input) { - throw new \UnexpectedValueException('No pattern neither input provided for the Task'); - } - if (\is_array($input)) { - foreach ($input as $file) { - if (!\in_array($file, $this->matchingFiles, true)) { - $this->matchingFiles[] = $file; - } - } - } elseif (!\in_array($input, $this->matchingFiles, true)) { - $this->matchingFiles[] = $input; - } - } - } - - protected function doFileCopy(ProcessState $state, string $filename, bool $removeSource): string|bool|null - { - $prefixFrom = $this->getOption($state, 'source_filesystem'); - - $buffer = $this->sourceFS->readStream($filename); - - try { - $this->destinationFS->writeStream($filename, $buffer); - $result = true; - } catch (FilesystemException) { - $result = false; - } - - if (\is_resource($buffer)) { - fclose($buffer); - } - - if ($removeSource) { - $this->sourceFS->delete(\sprintf('%s://%s', $prefixFrom, $filename)); - } - - return $result ? $filename : null; - } - - protected function configureOptions(OptionsResolver $resolver): void - { - $resolver->setRequired(['source_filesystem', 'destination_filesystem']); - $resolver->setAllowedTypes('source_filesystem', 'string'); - $resolver->setAllowedTypes('destination_filesystem', 'string'); - - $resolver->setDefault('file_pattern', null); - $resolver->setAllowedTypes('file_pattern', ['string', 'null']); - - $resolver->setDefault('remove_source', false); - $resolver->setAllowedTypes('remove_source', 'boolean'); - } -} From b7afaab1cb344437398fd30a9e91cda5a207c657 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 18 Oct 2024 11:08:55 +0200 Subject: [PATCH 244/304] #142 Refactor : * YamlReaderTask & YamlWriterTask namespaces changed to `CleverAge\ProcessBundle\Task\File\Yaml` * Array***Transformers namespaces changed to `CleverAge\ProcessBundle\Transformer\Array` * NormalizeTransformer & DenormalizeTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Serialization` * DateFormatTransformer & DateParserTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Date` * ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` * InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` --- CHANGELOG.md | 10 ++++++++-- src/Task/File/{ => Yaml}/YamlReaderTask.php | 2 +- src/Task/File/{ => Yaml}/YamlWriterTask.php | 2 +- .../{ => Array}/ArrayElementTransformer.php | 3 ++- src/Transformer/{ => Array}/ArrayFilterTransformer.php | 4 +++- src/Transformer/{ => Array}/ArrayFirstTransformer.php | 3 ++- src/Transformer/{ => Array}/ArrayLastTransformer.php | 4 +++- src/Transformer/{ => Array}/ArrayMapTransformer.php | 4 +++- src/Transformer/{ => Array}/ArrayUnsetTransformer.php | 3 ++- src/Transformer/{ => Date}/DateFormatTransformer.php | 3 ++- src/Transformer/{ => Date}/DateParserTransformer.php | 3 ++- .../{ => Object}/InstantiateTransformer.php | 3 ++- .../{ => Object}/PropertyAccessorTransformer.php | 3 ++- .../RecursivePropertySetterTransformer.php | 3 ++- .../{ => Serialization}/DenormalizeTransformer.php | 3 ++- .../{ => Serialization}/NormalizeTransformer.php | 3 ++- src/Transformer/{ => String}/ExplodeTransformer.php | 3 ++- src/Transformer/{ => String}/HashTransformer.php | 3 ++- src/Transformer/{ => String}/ImplodeTransformer.php | 3 ++- src/Transformer/{ => String}/SlugifyTransformer.php | 3 ++- src/Transformer/{ => String}/SprintfTransformer.php | 3 ++- src/Transformer/{ => String}/TrimTransformer.php | 3 ++- .../{ => Array}/ArrayElementTransformerTest.php | 6 +++--- .../{ => Array}/ArrayFirstTransformerTest.php | 6 +++--- tests/Transformer/CastTransformerTest.php | 2 +- tests/Transformer/ConstantTransformerTest.php | 2 +- .../{ => Date}/DateFormatTransformerTest.php | 6 +++--- .../{ => Date}/DateParserTransformerTest.php | 6 +++--- tests/Transformer/DebugTransformerTest.php | 2 +- tests/Transformer/DefaultTransformerTest.php | 2 +- tests/Transformer/MultiReplaceTransformerTest.php | 2 +- .../{ => String}/ExplodeTransformerTest.php | 6 +++--- .../{ => String}/ImplodeTransformerTest.php | 6 +++--- .../{ => String}/SprintfTransformerTest.php | 6 +++--- tests/Transformer/{ => String}/TrimTransformerTest.php | 6 +++--- tests/Transformer/WrapperTransformerTest.php | 2 +- .../{ => Xml}/XpathEvaluatorTransformerTest.php | 2 +- 37 files changed, 82 insertions(+), 54 deletions(-) rename src/Task/File/{ => Yaml}/YamlReaderTask.php (96%) rename src/Task/File/{ => Yaml}/YamlWriterTask.php (95%) rename src/Transformer/{ => Array}/ArrayElementTransformer.php (87%) rename src/Transformer/{ => Array}/ArrayFilterTransformer.php (89%) rename src/Transformer/{ => Array}/ArrayFirstTransformer.php (89%) rename src/Transformer/{ => Array}/ArrayLastTransformer.php (83%) rename src/Transformer/{ => Array}/ArrayMapTransformer.php (91%) rename src/Transformer/{ => Array}/ArrayUnsetTransformer.php (88%) rename src/Transformer/{ => Date}/DateFormatTransformer.php (91%) rename src/Transformer/{ => Date}/DateParserTransformer.php (90%) rename src/Transformer/{ => Object}/InstantiateTransformer.php (89%) rename src/Transformer/{ => Object}/PropertyAccessorTransformer.php (92%) rename src/Transformer/{ => Object}/RecursivePropertySetterTransformer.php (96%) rename src/Transformer/{ => Serialization}/DenormalizeTransformer.php (91%) rename src/Transformer/{ => Serialization}/NormalizeTransformer.php (90%) rename src/Transformer/{ => String}/ExplodeTransformer.php (88%) rename src/Transformer/{ => String}/HashTransformer.php (88%) rename src/Transformer/{ => String}/ImplodeTransformer.php (89%) rename src/Transformer/{ => String}/SlugifyTransformer.php (92%) rename src/Transformer/{ => String}/SprintfTransformer.php (88%) rename src/Transformer/{ => String}/TrimTransformer.php (90%) rename tests/Transformer/{ => Array}/ArrayElementTransformerTest.php (90%) rename tests/Transformer/{ => Array}/ArrayFirstTransformerTest.php (93%) rename tests/Transformer/{ => Date}/DateFormatTransformerTest.php (94%) rename tests/Transformer/{ => Date}/DateParserTransformerTest.php (94%) rename tests/Transformer/{ => String}/ExplodeTransformerTest.php (90%) rename tests/Transformer/{ => String}/ImplodeTransformerTest.php (90%) rename tests/Transformer/{ => String}/SprintfTransformerTest.php (82%) rename tests/Transformer/{ => String}/TrimTransformerTest.php (90%) rename tests/Transformer/{ => Xml}/XpathEvaluatorTransformerTest.php (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d34a73c5..b2623808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,19 @@ v4.0 ## BC breaks -* Remove FileFetchTask, use cleverage/flysystem-process-bundle instead. +* Remove FileFetchTask, use `cleverage/flysystem-process-bundle` instead. +* YamlReaderTask & YamlWriterTask namespaces changed to `CleverAge\ProcessBundle\Task\File\Yaml` +* Array***Transformers namespaces changed to `CleverAge\ProcessBundle\Transformer\Array` +* NormalizeTransformer & DenormalizeTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Serialization` +* DateFormatTransformer & DateParserTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Date` +* ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` +* InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` ### Changes * Update Makefile & .docker for local standalone usage * Update rector, phpstan & php-cs-fixer configurations & apply it -* league/flysystem-bundle is not required anymore +* `league/flysystem-bundle` is not required anymore ### Fixes diff --git a/src/Task/File/YamlReaderTask.php b/src/Task/File/Yaml/YamlReaderTask.php similarity index 96% rename from src/Task/File/YamlReaderTask.php rename to src/Task/File/Yaml/YamlReaderTask.php index 7b587e7e..13277cf1 100644 --- a/src/Task/File/YamlReaderTask.php +++ b/src/Task/File/Yaml/YamlReaderTask.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\File; +namespace CleverAge\ProcessBundle\Task\File\Yaml; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Task\AbstractIterableOutputTask; diff --git a/src/Task/File/YamlWriterTask.php b/src/Task/File/Yaml/YamlWriterTask.php similarity index 95% rename from src/Task/File/YamlWriterTask.php rename to src/Task/File/Yaml/YamlWriterTask.php index 208ef2fe..f557cae2 100644 --- a/src/Task/File/YamlWriterTask.php +++ b/src/Task/File/Yaml/YamlWriterTask.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Task\File; +namespace CleverAge\ProcessBundle\Task\File\Yaml; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; diff --git a/src/Transformer/ArrayElementTransformer.php b/src/Transformer/Array/ArrayElementTransformer.php similarity index 87% rename from src/Transformer/ArrayElementTransformer.php rename to src/Transformer/Array/ArrayElementTransformer.php index beb4cdf5..933e12a8 100644 --- a/src/Transformer/ArrayElementTransformer.php +++ b/src/Transformer/Array/ArrayElementTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/ArrayFilterTransformer.php b/src/Transformer/Array/ArrayFilterTransformer.php similarity index 89% rename from src/Transformer/ArrayFilterTransformer.php rename to src/Transformer/Array/ArrayFilterTransformer.php index 0464e98f..a755a985 100644 --- a/src/Transformer/ArrayFilterTransformer.php +++ b/src/Transformer/Array/ArrayFilterTransformer.php @@ -11,8 +11,10 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; +use CleverAge\ProcessBundle\Transformer\ConditionTrait; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; diff --git a/src/Transformer/ArrayFirstTransformer.php b/src/Transformer/Array/ArrayFirstTransformer.php similarity index 89% rename from src/Transformer/ArrayFirstTransformer.php rename to src/Transformer/Array/ArrayFirstTransformer.php index 238c09c7..fef817e4 100644 --- a/src/Transformer/ArrayFirstTransformer.php +++ b/src/Transformer/Array/ArrayFirstTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/ArrayLastTransformer.php b/src/Transformer/Array/ArrayLastTransformer.php similarity index 83% rename from src/Transformer/ArrayLastTransformer.php rename to src/Transformer/Array/ArrayLastTransformer.php index 3d8d8a2b..c2389852 100644 --- a/src/Transformer/ArrayLastTransformer.php +++ b/src/Transformer/Array/ArrayLastTransformer.php @@ -11,7 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; + +use CleverAge\ProcessBundle\Transformer\TransformerInterface; /** * Return the last element of an array. diff --git a/src/Transformer/ArrayMapTransformer.php b/src/Transformer/Array/ArrayMapTransformer.php similarity index 91% rename from src/Transformer/ArrayMapTransformer.php rename to src/Transformer/Array/ArrayMapTransformer.php index 767848f3..1263a9f7 100644 --- a/src/Transformer/ArrayMapTransformer.php +++ b/src/Transformer/Array/ArrayMapTransformer.php @@ -11,10 +11,12 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; use CleverAge\ProcessBundle\Exception\TransformerException; use CleverAge\ProcessBundle\Registry\TransformerRegistry; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; +use CleverAge\ProcessBundle\Transformer\TransformerTrait; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/ArrayUnsetTransformer.php b/src/Transformer/Array/ArrayUnsetTransformer.php similarity index 88% rename from src/Transformer/ArrayUnsetTransformer.php rename to src/Transformer/Array/ArrayUnsetTransformer.php index fd79556d..0e2bcf29 100644 --- a/src/Transformer/ArrayUnsetTransformer.php +++ b/src/Transformer/Array/ArrayUnsetTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Array; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/DateFormatTransformer.php b/src/Transformer/Date/DateFormatTransformer.php similarity index 91% rename from src/Transformer/DateFormatTransformer.php rename to src/Transformer/Date/DateFormatTransformer.php index b3462e05..e60324a0 100644 --- a/src/Transformer/DateFormatTransformer.php +++ b/src/Transformer/Date/DateFormatTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Date; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/DateParserTransformer.php b/src/Transformer/Date/DateParserTransformer.php similarity index 90% rename from src/Transformer/DateParserTransformer.php rename to src/Transformer/Date/DateParserTransformer.php index 3ebbe009..a891ff40 100644 --- a/src/Transformer/DateParserTransformer.php +++ b/src/Transformer/Date/DateParserTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Date; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/InstantiateTransformer.php b/src/Transformer/Object/InstantiateTransformer.php similarity index 89% rename from src/Transformer/InstantiateTransformer.php rename to src/Transformer/Object/InstantiateTransformer.php index 223be69b..41993a58 100644 --- a/src/Transformer/InstantiateTransformer.php +++ b/src/Transformer/Object/InstantiateTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Object; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/PropertyAccessorTransformer.php b/src/Transformer/Object/PropertyAccessorTransformer.php similarity index 92% rename from src/Transformer/PropertyAccessorTransformer.php rename to src/Transformer/Object/PropertyAccessorTransformer.php index ebb7f6ab..90e59b29 100644 --- a/src/Transformer/PropertyAccessorTransformer.php +++ b/src/Transformer/Object/PropertyAccessorTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Object; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; diff --git a/src/Transformer/RecursivePropertySetterTransformer.php b/src/Transformer/Object/RecursivePropertySetterTransformer.php similarity index 96% rename from src/Transformer/RecursivePropertySetterTransformer.php rename to src/Transformer/Object/RecursivePropertySetterTransformer.php index 6f7767e9..b42c1df7 100644 --- a/src/Transformer/RecursivePropertySetterTransformer.php +++ b/src/Transformer/Object/RecursivePropertySetterTransformer.php @@ -11,9 +11,10 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Object; use CleverAge\ProcessBundle\Exception\TransformerException; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; diff --git a/src/Transformer/DenormalizeTransformer.php b/src/Transformer/Serialization/DenormalizeTransformer.php similarity index 91% rename from src/Transformer/DenormalizeTransformer.php rename to src/Transformer/Serialization/DenormalizeTransformer.php index aabf2a84..f939b074 100644 --- a/src/Transformer/DenormalizeTransformer.php +++ b/src/Transformer/Serialization/DenormalizeTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Serialization; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; diff --git a/src/Transformer/NormalizeTransformer.php b/src/Transformer/Serialization/NormalizeTransformer.php similarity index 90% rename from src/Transformer/NormalizeTransformer.php rename to src/Transformer/Serialization/NormalizeTransformer.php index 904f7476..f23293a6 100644 --- a/src/Transformer/NormalizeTransformer.php +++ b/src/Transformer/Serialization/NormalizeTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\Serialization; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; diff --git a/src/Transformer/ExplodeTransformer.php b/src/Transformer/String/ExplodeTransformer.php similarity index 88% rename from src/Transformer/ExplodeTransformer.php rename to src/Transformer/String/ExplodeTransformer.php index 71c838f5..32542a43 100644 --- a/src/Transformer/ExplodeTransformer.php +++ b/src/Transformer/String/ExplodeTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/HashTransformer.php b/src/Transformer/String/HashTransformer.php similarity index 88% rename from src/Transformer/HashTransformer.php rename to src/Transformer/String/HashTransformer.php index 9c3bf4bc..4082b845 100644 --- a/src/Transformer/HashTransformer.php +++ b/src/Transformer/String/HashTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/ImplodeTransformer.php b/src/Transformer/String/ImplodeTransformer.php similarity index 89% rename from src/Transformer/ImplodeTransformer.php rename to src/Transformer/String/ImplodeTransformer.php index be117356..e005c67c 100644 --- a/src/Transformer/ImplodeTransformer.php +++ b/src/Transformer/String/ImplodeTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/SlugifyTransformer.php b/src/Transformer/String/SlugifyTransformer.php similarity index 92% rename from src/Transformer/SlugifyTransformer.php rename to src/Transformer/String/SlugifyTransformer.php index 970d7adf..7d23bf92 100644 --- a/src/Transformer/SlugifyTransformer.php +++ b/src/Transformer/String/SlugifyTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/src/Transformer/SprintfTransformer.php b/src/Transformer/String/SprintfTransformer.php similarity index 88% rename from src/Transformer/SprintfTransformer.php rename to src/Transformer/String/SprintfTransformer.php index f075b518..7013c72b 100644 --- a/src/Transformer/SprintfTransformer.php +++ b/src/Transformer/String/SprintfTransformer.php @@ -11,8 +11,9 @@ * file that was distributed with this source code. */ -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/src/Transformer/TrimTransformer.php b/src/Transformer/String/TrimTransformer.php similarity index 90% rename from src/Transformer/TrimTransformer.php rename to src/Transformer/String/TrimTransformer.php index 121b16d0..95627dd6 100644 --- a/src/Transformer/TrimTransformer.php +++ b/src/Transformer/String/TrimTransformer.php @@ -13,8 +13,9 @@ namespace Transformer; -namespace CleverAge\ProcessBundle\Transformer; +namespace CleverAge\ProcessBundle\Transformer\String; +use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** diff --git a/tests/Transformer/ArrayElementTransformerTest.php b/tests/Transformer/Array/ArrayElementTransformerTest.php similarity index 90% rename from tests/Transformer/ArrayElementTransformerTest.php rename to tests/Transformer/Array/ArrayElementTransformerTest.php index a3c9e36e..fa98f00d 100644 --- a/tests/Transformer/ArrayElementTransformerTest.php +++ b/tests/Transformer/Array/ArrayElementTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\Array; -use CleverAge\ProcessBundle\Transformer\ArrayElementTransformer; +use CleverAge\ProcessBundle\Transformer\Array\ArrayElementTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ArrayElementTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Array\ArrayElementTransformer */ class ArrayElementTransformerTest extends TestCase { diff --git a/tests/Transformer/ArrayFirstTransformerTest.php b/tests/Transformer/Array/ArrayFirstTransformerTest.php similarity index 93% rename from tests/Transformer/ArrayFirstTransformerTest.php rename to tests/Transformer/Array/ArrayFirstTransformerTest.php index 596c2bf0..1b04a7fc 100644 --- a/tests/Transformer/ArrayFirstTransformerTest.php +++ b/tests/Transformer/Array/ArrayFirstTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\Array; -use CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer; +use CleverAge\ProcessBundle\Transformer\Array\ArrayFirstTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ArrayFirstTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Array\ArrayFirstTransformer */ class ArrayFirstTransformerTest extends TestCase { diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index 9eac2bba..215a6f47 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\CastTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index e03734b3..9a36ba94 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\ConstantTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/DateFormatTransformerTest.php b/tests/Transformer/Date/DateFormatTransformerTest.php similarity index 94% rename from tests/Transformer/DateFormatTransformerTest.php rename to tests/Transformer/Date/DateFormatTransformerTest.php index 8a0408e1..09ecf3ab 100644 --- a/tests/Transformer/DateFormatTransformerTest.php +++ b/tests/Transformer/Date/DateFormatTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\Date; -use CleverAge\ProcessBundle\Transformer\DateFormatTransformer; +use CleverAge\ProcessBundle\Transformer\Date\DateFormatTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DateFormatTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Date\DateFormatTransformer */ class DateFormatTransformerTest extends TestCase { diff --git a/tests/Transformer/DateParserTransformerTest.php b/tests/Transformer/Date/DateParserTransformerTest.php similarity index 94% rename from tests/Transformer/DateParserTransformerTest.php rename to tests/Transformer/Date/DateParserTransformerTest.php index 15e142b6..860d0487 100644 --- a/tests/Transformer/DateParserTransformerTest.php +++ b/tests/Transformer/Date/DateParserTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\Date; -use CleverAge\ProcessBundle\Transformer\DateParserTransformer; +use CleverAge\ProcessBundle\Transformer\Date\DateParserTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DateParserTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Date\DateParserTransformer */ class DateParserTransformerTest extends TestCase { diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php index 0be796f9..4dd9c5b2 100644 --- a/tests/Transformer/DebugTransformerTest.php +++ b/tests/Transformer/DebugTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\DebugTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php index 39eb1209..7817b0df 100644 --- a/tests/Transformer/DefaultTransformerTest.php +++ b/tests/Transformer/DefaultTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\DefaultTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php index c21a9833..6eb2a852 100644 --- a/tests/Transformer/MultiReplaceTransformerTest.php +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/ExplodeTransformerTest.php b/tests/Transformer/String/ExplodeTransformerTest.php similarity index 90% rename from tests/Transformer/ExplodeTransformerTest.php rename to tests/Transformer/String/ExplodeTransformerTest.php index f0518338..cb698dd8 100644 --- a/tests/Transformer/ExplodeTransformerTest.php +++ b/tests/Transformer/String/ExplodeTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\String; -use CleverAge\ProcessBundle\Transformer\ExplodeTransformer; +use CleverAge\ProcessBundle\Transformer\String\ExplodeTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ExplodeTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\ExplodeTransformer */ class ExplodeTransformerTest extends TestCase { diff --git a/tests/Transformer/ImplodeTransformerTest.php b/tests/Transformer/String/ImplodeTransformerTest.php similarity index 90% rename from tests/Transformer/ImplodeTransformerTest.php rename to tests/Transformer/String/ImplodeTransformerTest.php index 6037dd79..5a1a72b7 100644 --- a/tests/Transformer/ImplodeTransformerTest.php +++ b/tests/Transformer/String/ImplodeTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\String; -use CleverAge\ProcessBundle\Transformer\ImplodeTransformer; +use CleverAge\ProcessBundle\Transformer\String\ImplodeTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ImplodeTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\ImplodeTransformer */ class ImplodeTransformerTest extends TestCase { diff --git a/tests/Transformer/SprintfTransformerTest.php b/tests/Transformer/String/SprintfTransformerTest.php similarity index 82% rename from tests/Transformer/SprintfTransformerTest.php rename to tests/Transformer/String/SprintfTransformerTest.php index 4b4f7996..4648e893 100644 --- a/tests/Transformer/SprintfTransformerTest.php +++ b/tests/Transformer/String/SprintfTransformerTest.php @@ -11,13 +11,13 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\String; -use CleverAge\ProcessBundle\Transformer\SprintfTransformer; +use CleverAge\ProcessBundle\Transformer\String\SprintfTransformer; use PHPUnit\Framework\TestCase; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\SprintfTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\SprintfTransformer */ class SprintfTransformerTest extends TestCase { diff --git a/tests/Transformer/TrimTransformerTest.php b/tests/Transformer/String/TrimTransformerTest.php similarity index 90% rename from tests/Transformer/TrimTransformerTest.php rename to tests/Transformer/String/TrimTransformerTest.php index 7ee5609f..8bd4b6e0 100644 --- a/tests/Transformer/TrimTransformerTest.php +++ b/tests/Transformer/String/TrimTransformerTest.php @@ -11,14 +11,14 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\String; -use CleverAge\ProcessBundle\Transformer\TrimTransformer; +use CleverAge\ProcessBundle\Transformer\String\TrimTransformer; use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\TrimTransformer + * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\TrimTransformer */ class TrimTransformerTest extends TestCase { diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php index c89ee2d3..84cac9a2 100644 --- a/tests/Transformer/WrapperTransformerTest.php +++ b/tests/Transformer/WrapperTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer; use CleverAge\ProcessBundle\Transformer\WrapperTransformer; use PHPUnit\Framework\TestCase; diff --git a/tests/Transformer/XpathEvaluatorTransformerTest.php b/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php similarity index 98% rename from tests/Transformer/XpathEvaluatorTransformerTest.php rename to tests/Transformer/Xml/XpathEvaluatorTransformerTest.php index 5f4dfd2c..baf16a5f 100644 --- a/tests/Transformer/XpathEvaluatorTransformerTest.php +++ b/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php @@ -11,7 +11,7 @@ * file that was distributed with this source code. */ -namespace Transformer; +namespace CleverAge\ProcessBundle\Tests\Transformer\Xml; use CleverAge\ProcessBundle\Transformer\Xml\XpathEvaluatorTransformer; use PHPUnit\Framework\TestCase; From 7524cf5f3bee50aadf6231fae6ec78187851f8b2 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 18 Oct 2024 11:10:07 +0200 Subject: [PATCH 245/304] #138 Update README with all missing Tasks & Transformers --- README.md | 128 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 28cbc9ab..5ad04ac2 100644 --- a/README.md +++ b/README.md @@ -34,42 +34,120 @@ Demo project can be found on [there](https://github.com/cleverage/process-bundle - Basic and debug - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) + - [CounterTask] - [DebugTask](doc/reference/tasks/debug_task.md) - [DieTask](doc/reference/tasks/die_task.md) - [DummyTask](doc/reference/tasks/dummy_task.md) + - [ErrorForwarderTask] - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) - - Data manipulation and transformations - - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) - - [NormalizerTask](doc/reference/tasks/normalizer_task.md) - - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) - - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) - - [TransformerTask](doc/reference/tasks/transformer_task.md) - - File/CSV - - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) - - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) - - File/XML - - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) - - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) - - Flow manipulation - - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) - - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) - - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) + - [MemInfoDumpTask] + - [StopwatchTask] + - Data manipulation and transformations + - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) + - [NormalizerTask](doc/reference/tasks/normalizer_task.md) + - [DeserializerTask] + - [SerializerTask] + - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) + - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) + - [ObjectUpdaterTask] + - [SplitJoinLineTask] + - [TransformerTask](doc/reference/tasks/transformer_task.md) + - [ValidatorTask] + - File/CSV + - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) + - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) + - [CSVSplitterTask] + - [InputCsvReaderTask] + - File/JsonStream + - [JsonStreamReaderTask] + - File/XML + - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) + - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) + - File/Yaml + - [YamlReaderTask] + - [YamlWriterTask] + - File + - [FileMoverTask] + - [FileReaderTask] + - [FileRemoverTask] + - [FileWriterTask] + - [FolderBrowserTask] + - [InputFolderBrowserTask] + - Flow manipulation + - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) + - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) + - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) + - [ArrayMergeTask] + - [ColumnAggregatorTask] + - [RowAggregatorTask] + - [FilterTask] + - [GroupByAggregateIterableTask] + - [SimpleBatchTask] + - [IterableBatchTask] + - [SkipEmptyTask] + - [StopTask] + - Process + - [CommandRunnerTask] + - [ProcessExecutorTask] + - [ProcessLauncherTask] + - Reporting + - [AdvancedStatCounterTask] + - [LoggerTask] + - [StatCounterTask] - Transformers - - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) + - Basic and debug + - [CachedTransformer] + - [CallbackTransformer] + - [CastTransformer] + - [ConstantTransformer] + - [ConvertValueTransformer] + - [DebugTransformer] + - [DefaultTransformer] + - [GenericTransformer] + - [EvaluatorTransformer] + - [ExpressionLanguageMapTransformer] - [MappingTransformer](doc/reference/transformers/mapping_transformer.md) + - [MultiReplaceTransformer] + - [PregFilterTransformer] - [RulesTransformer](doc/reference/transformers/rules_transformer.md) + - [TypeSetterTransformer] + - [UnsetTransformer] + - [WrapperTransformer] + - Array + - [ArrayElementTransformer] + - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) + - [ArrayFirstTransformer] + - [ArrayLastTransformer] + - [ArrayMapTransformer] + - [ArrayUnsetTransformer] + - Date - [DateFormatTransformer](doc/reference/transformers/date_format.md) - [DateParserTransformer](doc/reference/transformers/date_parser.md) + - Object + - [InstantiateTransformer] + - [PropertyAccessorTransformer] + - [RecursivePropertySetterTransformer] + - Serialization + - [DenormalizeTransformer] + - [NormalizeTransformer] + - String + - [ExplodeTransformer] + - [HashTransformer] + - [ImplodeTransformer] + - [SlugifyTransformer] + - [SprintfTransformer] + - [TrimTransformer] + - XML - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) - Other bridges - - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) - - [Eav](https://github.com/cleverage/eav-process-bundle) - - [Soap](https://github.com/cleverage/soap-process-bundle) - - [Another Soap](https://github.com/cleverage/process-soap-bundle) - - [Rest](https://github.com/cleverage/rest-process-bundle) - - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) - - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) - - [Cache](https://github.com/cleverage/cache-process-bundle) + - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) + - [Eav](https://github.com/cleverage/eav-process-bundle) + - [Soap](https://github.com/cleverage/soap-process-bundle) + - [Another Soap](https://github.com/cleverage/process-soap-bundle) + - [Rest](https://github.com/cleverage/rest-process-bundle) + - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) + - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) + - [Cache](https://github.com/cleverage/cache-process-bundle) - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) - [UI](https://github.com/cleverage/processuibundle) From 49c24c291300fc955200e866c561801e779ce8ed Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 18 Oct 2024 14:27:24 +0200 Subject: [PATCH 246/304] Update CHANGELOG with issue links for v4.0 --- CHANGELOG.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2623808..fc6049b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,19 +3,20 @@ v4.0 ## BC breaks -* Remove FileFetchTask, use `cleverage/flysystem-process-bundle` instead. -* YamlReaderTask & YamlWriterTask namespaces changed to `CleverAge\ProcessBundle\Task\File\Yaml` -* Array***Transformers namespaces changed to `CleverAge\ProcessBundle\Transformer\Array` -* NormalizeTransformer & DenormalizeTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Serialization` -* DateFormatTransformer & DateParserTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Date` -* ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` -* InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` +* [#142](https://github.com/cleverage/process-bundle/issues/142) Remove FileFetchTask, use `cleverage/flysystem-process-bundle` instead. +* [#142](https://github.com/cleverage/process-bundle/issues/142) YamlReaderTask & YamlWriterTask namespaces changed to `CleverAge\ProcessBundle\Task\File\Yaml` +* [#142](https://github.com/cleverage/process-bundle/issues/142) Array***Transformers namespaces changed to `CleverAge\ProcessBundle\Transformer\Array` +* [#142](https://github.com/cleverage/process-bundle/issues/142) NormalizeTransformer & DenormalizeTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Serialization` +* [#142](https://github.com/cleverage/process-bundle/issues/142) DateFormatTransformer & DateParserTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Date` +* [#142](https://github.com/cleverage/process-bundle/issues/142) ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` +* [#142](https://github.com/cleverage/process-bundle/issues/142) InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` ### Changes -* Update Makefile & .docker for local standalone usage -* Update rector, phpstan & php-cs-fixer configurations & apply it -* `league/flysystem-bundle` is not required anymore +* [#139](https://github.com/cleverage/process-bundle/issues/139Update) Makefile & .docker for local standalone usage +* [#139](https://github.com/cleverage/process-bundle/issues/139Update) Update rector, phpstan & php-cs-fixer configurations & apply it +* [#141](https://github.com/cleverage/process-bundle/issues/141) `league/flysystem-bundle` is not required anymore +* [#130](https://github.com/cleverage/process-bundle/issues/130) EventDispatcherInterface service declaration breaks dependency injection ### Fixes From bdea76352df563305ac0d3ec10039d31eaa0711b Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Mon, 21 Oct 2024 15:22:23 +0200 Subject: [PATCH 247/304] #148 Update directory structure according to Symfony best practices --- .../config => config}/services/command.yaml | 0 .../Resources/config => config}/services/event.yaml | 0 .../services/expression_language.yaml | 0 .../config => config}/services/logger.yaml | 0 .../config => config}/services/manager.yaml | 0 .../config => config}/services/registry.yaml | 0 {src/Resources/config => config}/services/task.yaml | 0 .../config => config}/services/transformer.yaml | 0 {doc => docs}/01-quick_start.md | 0 {doc => docs}/02-task_types.md | 0 {doc => docs}/03-custom_tasks.md | 0 {doc => docs}/04-advanced_workflow.md | 0 {doc => docs}/05-good_practices.md | 0 {doc => docs}/06-testing.md | 0 {doc => docs}/basic-etl.png | Bin {doc => docs}/cookbooks/01-common_setup.md | 0 {doc => docs}/cookbooks/memory_usage_graph.md | 0 {doc => docs}/cookbooks/performances_monitoring.md | 0 docs/index.md | 0 {doc => docs}/reference/01-process_definition.md | 0 {doc => docs}/reference/02-task_definition.md | 0 .../reference/03-generic_transformers_definition.md | 0 {doc => docs}/reference/tasks/_template.md | 0 .../reference/tasks/aggregate_iterable_task.md | 0 .../tasks/constant_iterable_output_task.md | 0 .../reference/tasks/constant_output_task.md | 0 {doc => docs}/reference/tasks/csv_reader_task.md | 0 {doc => docs}/reference/tasks/csv_writer_task.md | 0 {doc => docs}/reference/tasks/debug_task.md | 0 {doc => docs}/reference/tasks/denormalizer_task.md | 0 {doc => docs}/reference/tasks/die_task.md | 0 {doc => docs}/reference/tasks/dummy_task.md | 0 .../reference/tasks/event_dispatcher_task.md | 0 .../reference/tasks/input_aggregator_task.md | 0 .../reference/tasks/input_iterator_task.md | 0 .../reference/tasks/iterable_batch_task.md | 0 {doc => docs}/reference/tasks/normalizer_task.md | 0 .../reference/tasks/property_getter_task.md | 0 .../reference/tasks/property_setter_task.md | 0 {doc => docs}/reference/tasks/transformer_task.md | 0 {doc => docs}/reference/tasks/xml_reader_task.md | 0 {doc => docs}/reference/tasks/xml_writer_task.md | 0 {doc => docs}/reference/traits/condition_trait.md | 0 {doc => docs}/reference/traits/transformer_trait.md | 0 {doc => docs}/reference/transformers/_template.md | 0 .../transformers/array_filter_transformer.md | 0 {doc => docs}/reference/transformers/date_format.md | 0 {doc => docs}/reference/transformers/date_parser.md | 0 .../reference/transformers/mapping_transformer.md | 0 .../reference/transformers/rules_transformer.md | 0 .../reference/transformers/xpath_evaluator.md | 0 src/CleverAgeProcessBundle.php | 12 +++++++----- .../CleverAgeProcessExtension.php | 6 ++---- 53 files changed, 9 insertions(+), 9 deletions(-) rename {src/Resources/config => config}/services/command.yaml (100%) rename {src/Resources/config => config}/services/event.yaml (100%) rename {src/Resources/config => config}/services/expression_language.yaml (100%) rename {src/Resources/config => config}/services/logger.yaml (100%) rename {src/Resources/config => config}/services/manager.yaml (100%) rename {src/Resources/config => config}/services/registry.yaml (100%) rename {src/Resources/config => config}/services/task.yaml (100%) rename {src/Resources/config => config}/services/transformer.yaml (100%) rename {doc => docs}/01-quick_start.md (100%) rename {doc => docs}/02-task_types.md (100%) rename {doc => docs}/03-custom_tasks.md (100%) rename {doc => docs}/04-advanced_workflow.md (100%) rename {doc => docs}/05-good_practices.md (100%) rename {doc => docs}/06-testing.md (100%) rename {doc => docs}/basic-etl.png (100%) rename {doc => docs}/cookbooks/01-common_setup.md (100%) rename {doc => docs}/cookbooks/memory_usage_graph.md (100%) rename {doc => docs}/cookbooks/performances_monitoring.md (100%) create mode 100644 docs/index.md rename {doc => docs}/reference/01-process_definition.md (100%) rename {doc => docs}/reference/02-task_definition.md (100%) rename {doc => docs}/reference/03-generic_transformers_definition.md (100%) rename {doc => docs}/reference/tasks/_template.md (100%) rename {doc => docs}/reference/tasks/aggregate_iterable_task.md (100%) rename {doc => docs}/reference/tasks/constant_iterable_output_task.md (100%) rename {doc => docs}/reference/tasks/constant_output_task.md (100%) rename {doc => docs}/reference/tasks/csv_reader_task.md (100%) rename {doc => docs}/reference/tasks/csv_writer_task.md (100%) rename {doc => docs}/reference/tasks/debug_task.md (100%) rename {doc => docs}/reference/tasks/denormalizer_task.md (100%) rename {doc => docs}/reference/tasks/die_task.md (100%) rename {doc => docs}/reference/tasks/dummy_task.md (100%) rename {doc => docs}/reference/tasks/event_dispatcher_task.md (100%) rename {doc => docs}/reference/tasks/input_aggregator_task.md (100%) rename {doc => docs}/reference/tasks/input_iterator_task.md (100%) rename {doc => docs}/reference/tasks/iterable_batch_task.md (100%) rename {doc => docs}/reference/tasks/normalizer_task.md (100%) rename {doc => docs}/reference/tasks/property_getter_task.md (100%) rename {doc => docs}/reference/tasks/property_setter_task.md (100%) rename {doc => docs}/reference/tasks/transformer_task.md (100%) rename {doc => docs}/reference/tasks/xml_reader_task.md (100%) rename {doc => docs}/reference/tasks/xml_writer_task.md (100%) rename {doc => docs}/reference/traits/condition_trait.md (100%) rename {doc => docs}/reference/traits/transformer_trait.md (100%) rename {doc => docs}/reference/transformers/_template.md (100%) rename {doc => docs}/reference/transformers/array_filter_transformer.md (100%) rename {doc => docs}/reference/transformers/date_format.md (100%) rename {doc => docs}/reference/transformers/date_parser.md (100%) rename {doc => docs}/reference/transformers/mapping_transformer.md (100%) rename {doc => docs}/reference/transformers/rules_transformer.md (100%) rename {doc => docs}/reference/transformers/xpath_evaluator.md (100%) diff --git a/src/Resources/config/services/command.yaml b/config/services/command.yaml similarity index 100% rename from src/Resources/config/services/command.yaml rename to config/services/command.yaml diff --git a/src/Resources/config/services/event.yaml b/config/services/event.yaml similarity index 100% rename from src/Resources/config/services/event.yaml rename to config/services/event.yaml diff --git a/src/Resources/config/services/expression_language.yaml b/config/services/expression_language.yaml similarity index 100% rename from src/Resources/config/services/expression_language.yaml rename to config/services/expression_language.yaml diff --git a/src/Resources/config/services/logger.yaml b/config/services/logger.yaml similarity index 100% rename from src/Resources/config/services/logger.yaml rename to config/services/logger.yaml diff --git a/src/Resources/config/services/manager.yaml b/config/services/manager.yaml similarity index 100% rename from src/Resources/config/services/manager.yaml rename to config/services/manager.yaml diff --git a/src/Resources/config/services/registry.yaml b/config/services/registry.yaml similarity index 100% rename from src/Resources/config/services/registry.yaml rename to config/services/registry.yaml diff --git a/src/Resources/config/services/task.yaml b/config/services/task.yaml similarity index 100% rename from src/Resources/config/services/task.yaml rename to config/services/task.yaml diff --git a/src/Resources/config/services/transformer.yaml b/config/services/transformer.yaml similarity index 100% rename from src/Resources/config/services/transformer.yaml rename to config/services/transformer.yaml diff --git a/doc/01-quick_start.md b/docs/01-quick_start.md similarity index 100% rename from doc/01-quick_start.md rename to docs/01-quick_start.md diff --git a/doc/02-task_types.md b/docs/02-task_types.md similarity index 100% rename from doc/02-task_types.md rename to docs/02-task_types.md diff --git a/doc/03-custom_tasks.md b/docs/03-custom_tasks.md similarity index 100% rename from doc/03-custom_tasks.md rename to docs/03-custom_tasks.md diff --git a/doc/04-advanced_workflow.md b/docs/04-advanced_workflow.md similarity index 100% rename from doc/04-advanced_workflow.md rename to docs/04-advanced_workflow.md diff --git a/doc/05-good_practices.md b/docs/05-good_practices.md similarity index 100% rename from doc/05-good_practices.md rename to docs/05-good_practices.md diff --git a/doc/06-testing.md b/docs/06-testing.md similarity index 100% rename from doc/06-testing.md rename to docs/06-testing.md diff --git a/doc/basic-etl.png b/docs/basic-etl.png similarity index 100% rename from doc/basic-etl.png rename to docs/basic-etl.png diff --git a/doc/cookbooks/01-common_setup.md b/docs/cookbooks/01-common_setup.md similarity index 100% rename from doc/cookbooks/01-common_setup.md rename to docs/cookbooks/01-common_setup.md diff --git a/doc/cookbooks/memory_usage_graph.md b/docs/cookbooks/memory_usage_graph.md similarity index 100% rename from doc/cookbooks/memory_usage_graph.md rename to docs/cookbooks/memory_usage_graph.md diff --git a/doc/cookbooks/performances_monitoring.md b/docs/cookbooks/performances_monitoring.md similarity index 100% rename from doc/cookbooks/performances_monitoring.md rename to docs/cookbooks/performances_monitoring.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..e69de29b diff --git a/doc/reference/01-process_definition.md b/docs/reference/01-process_definition.md similarity index 100% rename from doc/reference/01-process_definition.md rename to docs/reference/01-process_definition.md diff --git a/doc/reference/02-task_definition.md b/docs/reference/02-task_definition.md similarity index 100% rename from doc/reference/02-task_definition.md rename to docs/reference/02-task_definition.md diff --git a/doc/reference/03-generic_transformers_definition.md b/docs/reference/03-generic_transformers_definition.md similarity index 100% rename from doc/reference/03-generic_transformers_definition.md rename to docs/reference/03-generic_transformers_definition.md diff --git a/doc/reference/tasks/_template.md b/docs/reference/tasks/_template.md similarity index 100% rename from doc/reference/tasks/_template.md rename to docs/reference/tasks/_template.md diff --git a/doc/reference/tasks/aggregate_iterable_task.md b/docs/reference/tasks/aggregate_iterable_task.md similarity index 100% rename from doc/reference/tasks/aggregate_iterable_task.md rename to docs/reference/tasks/aggregate_iterable_task.md diff --git a/doc/reference/tasks/constant_iterable_output_task.md b/docs/reference/tasks/constant_iterable_output_task.md similarity index 100% rename from doc/reference/tasks/constant_iterable_output_task.md rename to docs/reference/tasks/constant_iterable_output_task.md diff --git a/doc/reference/tasks/constant_output_task.md b/docs/reference/tasks/constant_output_task.md similarity index 100% rename from doc/reference/tasks/constant_output_task.md rename to docs/reference/tasks/constant_output_task.md diff --git a/doc/reference/tasks/csv_reader_task.md b/docs/reference/tasks/csv_reader_task.md similarity index 100% rename from doc/reference/tasks/csv_reader_task.md rename to docs/reference/tasks/csv_reader_task.md diff --git a/doc/reference/tasks/csv_writer_task.md b/docs/reference/tasks/csv_writer_task.md similarity index 100% rename from doc/reference/tasks/csv_writer_task.md rename to docs/reference/tasks/csv_writer_task.md diff --git a/doc/reference/tasks/debug_task.md b/docs/reference/tasks/debug_task.md similarity index 100% rename from doc/reference/tasks/debug_task.md rename to docs/reference/tasks/debug_task.md diff --git a/doc/reference/tasks/denormalizer_task.md b/docs/reference/tasks/denormalizer_task.md similarity index 100% rename from doc/reference/tasks/denormalizer_task.md rename to docs/reference/tasks/denormalizer_task.md diff --git a/doc/reference/tasks/die_task.md b/docs/reference/tasks/die_task.md similarity index 100% rename from doc/reference/tasks/die_task.md rename to docs/reference/tasks/die_task.md diff --git a/doc/reference/tasks/dummy_task.md b/docs/reference/tasks/dummy_task.md similarity index 100% rename from doc/reference/tasks/dummy_task.md rename to docs/reference/tasks/dummy_task.md diff --git a/doc/reference/tasks/event_dispatcher_task.md b/docs/reference/tasks/event_dispatcher_task.md similarity index 100% rename from doc/reference/tasks/event_dispatcher_task.md rename to docs/reference/tasks/event_dispatcher_task.md diff --git a/doc/reference/tasks/input_aggregator_task.md b/docs/reference/tasks/input_aggregator_task.md similarity index 100% rename from doc/reference/tasks/input_aggregator_task.md rename to docs/reference/tasks/input_aggregator_task.md diff --git a/doc/reference/tasks/input_iterator_task.md b/docs/reference/tasks/input_iterator_task.md similarity index 100% rename from doc/reference/tasks/input_iterator_task.md rename to docs/reference/tasks/input_iterator_task.md diff --git a/doc/reference/tasks/iterable_batch_task.md b/docs/reference/tasks/iterable_batch_task.md similarity index 100% rename from doc/reference/tasks/iterable_batch_task.md rename to docs/reference/tasks/iterable_batch_task.md diff --git a/doc/reference/tasks/normalizer_task.md b/docs/reference/tasks/normalizer_task.md similarity index 100% rename from doc/reference/tasks/normalizer_task.md rename to docs/reference/tasks/normalizer_task.md diff --git a/doc/reference/tasks/property_getter_task.md b/docs/reference/tasks/property_getter_task.md similarity index 100% rename from doc/reference/tasks/property_getter_task.md rename to docs/reference/tasks/property_getter_task.md diff --git a/doc/reference/tasks/property_setter_task.md b/docs/reference/tasks/property_setter_task.md similarity index 100% rename from doc/reference/tasks/property_setter_task.md rename to docs/reference/tasks/property_setter_task.md diff --git a/doc/reference/tasks/transformer_task.md b/docs/reference/tasks/transformer_task.md similarity index 100% rename from doc/reference/tasks/transformer_task.md rename to docs/reference/tasks/transformer_task.md diff --git a/doc/reference/tasks/xml_reader_task.md b/docs/reference/tasks/xml_reader_task.md similarity index 100% rename from doc/reference/tasks/xml_reader_task.md rename to docs/reference/tasks/xml_reader_task.md diff --git a/doc/reference/tasks/xml_writer_task.md b/docs/reference/tasks/xml_writer_task.md similarity index 100% rename from doc/reference/tasks/xml_writer_task.md rename to docs/reference/tasks/xml_writer_task.md diff --git a/doc/reference/traits/condition_trait.md b/docs/reference/traits/condition_trait.md similarity index 100% rename from doc/reference/traits/condition_trait.md rename to docs/reference/traits/condition_trait.md diff --git a/doc/reference/traits/transformer_trait.md b/docs/reference/traits/transformer_trait.md similarity index 100% rename from doc/reference/traits/transformer_trait.md rename to docs/reference/traits/transformer_trait.md diff --git a/doc/reference/transformers/_template.md b/docs/reference/transformers/_template.md similarity index 100% rename from doc/reference/transformers/_template.md rename to docs/reference/transformers/_template.md diff --git a/doc/reference/transformers/array_filter_transformer.md b/docs/reference/transformers/array_filter_transformer.md similarity index 100% rename from doc/reference/transformers/array_filter_transformer.md rename to docs/reference/transformers/array_filter_transformer.md diff --git a/doc/reference/transformers/date_format.md b/docs/reference/transformers/date_format.md similarity index 100% rename from doc/reference/transformers/date_format.md rename to docs/reference/transformers/date_format.md diff --git a/doc/reference/transformers/date_parser.md b/docs/reference/transformers/date_parser.md similarity index 100% rename from doc/reference/transformers/date_parser.md rename to docs/reference/transformers/date_parser.md diff --git a/doc/reference/transformers/mapping_transformer.md b/docs/reference/transformers/mapping_transformer.md similarity index 100% rename from doc/reference/transformers/mapping_transformer.md rename to docs/reference/transformers/mapping_transformer.md diff --git a/doc/reference/transformers/rules_transformer.md b/docs/reference/transformers/rules_transformer.md similarity index 100% rename from doc/reference/transformers/rules_transformer.md rename to docs/reference/transformers/rules_transformer.md diff --git a/doc/reference/transformers/xpath_evaluator.md b/docs/reference/transformers/xpath_evaluator.md similarity index 100% rename from doc/reference/transformers/xpath_evaluator.md rename to docs/reference/transformers/xpath_evaluator.md diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 10838026..300158b5 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -16,7 +16,6 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; use CleverAge\ProcessBundle\Registry\TransformerRegistry; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -30,11 +29,14 @@ public function build(ContainerBuilder $container): void parent::build($container); $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer'), - PassConfig::TYPE_BEFORE_OPTIMIZATION, - 0 + new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') ); - $container->addCompilerPass(new CheckSerializerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 0); + $container->addCompilerPass(new CheckSerializerCompilerPass()); + } + + public function getPath(): string + { + return \dirname(__DIR__); } } diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index d6b650c5..5c8db1a2 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -25,16 +25,14 @@ /** * This is the class that loads and manages your bundle configuration. * - * @see http://symfony.com/doc/current/cookbook/bundles/extension.html + * @see https://symfony.com/doc/current/bundles/extension.html */ class CleverAgeProcessExtension extends Extension { public function load(array $configs, ContainerBuilder $container): void { // Get the path of the service folder wherever the bundle is installed - $reflection = new \ReflectionClass($this); - $serviceFolderPath = \dirname($reflection->getFileName(), 2).'/Resources/config/services'; - $this->findServices($container, $serviceFolderPath); + $this->findServices($container, __DIR__.'/../../config/services'); $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); From fff486ee89bf155d02262ae39ff685eaf9b209ed Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Mon, 21 Oct 2024 15:54:52 +0200 Subject: [PATCH 248/304] #148 Update documentation according to Symfony best practices --- CONTRIBUTING.md | 47 +++++- Makefile | 4 + README.md | 142 +----------------- docs/01-quick_start.md | 15 +- docs/02-task_types.md | 2 +- docs/03-custom_tasks.md | 8 +- docs/index.md | 140 +++++++++++++++++ .../03-generic_transformers_definition.md | 2 +- 8 files changed, 205 insertions(+), 155 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a4b6a92..b6e9caaa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,50 @@ Contributing ============ -Every contributions are welcomed. This bundle aims to provide a standalone set of generic component. -If a contribution is too specific or requires dependencies, it might be put in a separated sub-bundle. +First of all, **thank you** for contributing, **you are awesome**! -Ideally every PR should contain documentation and unit test updates. +Here are a few rules to follow in order to ease code reviews, and discussions before +maintainers accept and merge your work. + +You MUST run the quality & test suites. + +You SHOULD write (or update) unit tests. + +You SHOULD write documentation. + +Please, write [commit messages that make sense](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), +and [rebase your branch](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) before submitting your Pull Request. + +One may ask you to [squash your commits](https://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) +too. This is used to "clean" your Pull Request before merging it (we don't want +commits such as `fix tests`, `fix 2`, `fix 3`, etc.). + +Thank you! + +## Running the quality & test suites + +Tests suite uses Docker environments in order to be idempotent to OS's. More than this +PHP version is written inside the Dockerfile; this assures to test the bundle with +the same resources. No need to have PHP installed. + +You only need Docker set it up. + +To allow testing environments more smooth we implemented **Makefile**. +You have two commands available: + +```bash +make quality +``` + +```bash +make tests +``` + +which will execute all tests inside the docker. + +```bash +make test TEST="Tests/Util/FilenameUtilsTest.php" +``` ## Deprecations notices @@ -14,4 +54,5 @@ When a feature should be deprecated, or when you have a breaking change for a fu * Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v4.0', E_USER_DEPRECATED);` You can check which deprecation notice is triggered in tests +* `make bash` * `SYMFONY_DEPRECATIONS_HELPER=0 ./vendor/bin/phpunit` diff --git a/Makefile b/Makefile index 3461c159..0a58e32f 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,8 @@ bash: #[Docker] Connect to php container with current host user logs: #[Docker] Show logs $(DOCKER_COMPOSE) logs -f +quality: phpstan php-cs-fixer rector #[Quality] Run all quality checks + phpstan: #[Quality] Run PHPStan $(DOCKER_RUN_PHP) "vendor/bin/phpstan --no-progress --memory-limit=1G analyse" @@ -46,5 +48,7 @@ php-cs-fixer: #[Quality] Run PHP-CS-Fixer rector: #[Quality] Run Rector $(DOCKER_RUN_PHP) "vendor/bin/rector" +tests: phpunit #[Tests] Run all tests + phpunit: #[Tests] Run PHPUnit $(DOCKER_RUN_PHP) "vendor/bin/phpunit" diff --git a/README.md b/README.md index 5ad04ac2..d9ec2b9b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ CleverAge/ProcessBundle ======================= -## Introduction - This bundle allows to configure series of tasks to be performed on a certain order. Basically, it will greatly ease the configuration of import and exports but can do much more. @@ -12,144 +10,8 @@ Demo project can be found on [there](https://github.com/cleverage/process-bundle ## Documentation -- [Quick start](doc/01-quick_start.md) -- [Task types](doc/02-task_types.md) -- [Custom tasks and development](doc/03-custom_tasks.md) -- [Advanced workflow](doc/04-advanced_workflow.md) -- Cookbooks - - [Common Setup](doc/cookbooks/01-common_setup.md) - - [Transformations] - - [Flow manipulation] - - [Dummy tasks] - - [Debugging] - - [Logging] - - [Subprocess] - - [File manipulation] - - [Direct call (in controller)] - - [Performances monitoring](doc/cookbooks/performances_monitoring.md) - - [Memory usage analysis](doc/cookbooks/memory_usage_graph.md) -- Reference - - [Process definition](doc/reference/01-process_definition.md) - - [Task definition](doc/reference/02-task_definition.md) - - Basic and debug - - [ConstantOutputTask](doc/reference/tasks/constant_output_task.md) - - [ConstantIterableOutputTask](doc/reference/tasks/constant_iterable_output_task.md) - - [CounterTask] - - [DebugTask](doc/reference/tasks/debug_task.md) - - [DieTask](doc/reference/tasks/die_task.md) - - [DummyTask](doc/reference/tasks/dummy_task.md) - - [ErrorForwarderTask] - - [EventDispatcherTask](doc/reference/tasks/event_dispatcher_task.md) - - [MemInfoDumpTask] - - [StopwatchTask] - - Data manipulation and transformations - - [DenormalizerTask](doc/reference/tasks/denormalizer_task.md) - - [NormalizerTask](doc/reference/tasks/normalizer_task.md) - - [DeserializerTask] - - [SerializerTask] - - [PropertyGetterTask](doc/reference/tasks/property_getter_task.md) - - [PropertySetterTask](doc/reference/tasks/property_setter_task.md) - - [ObjectUpdaterTask] - - [SplitJoinLineTask] - - [TransformerTask](doc/reference/tasks/transformer_task.md) - - [ValidatorTask] - - File/CSV - - [CsvReaderTask](doc/reference/tasks/csv_reader_task.md) - - [CsvWriterTask](doc/reference/tasks/csv_writer_task.md) - - [CSVSplitterTask] - - [InputCsvReaderTask] - - File/JsonStream - - [JsonStreamReaderTask] - - File/XML - - [XmlReaderTask](doc/reference/tasks/xml_reader_task.md) - - [XmlWriterTask](doc/reference/tasks/xml_writer_task.md) - - File/Yaml - - [YamlReaderTask] - - [YamlWriterTask] - - File - - [FileMoverTask] - - [FileReaderTask] - - [FileRemoverTask] - - [FileWriterTask] - - [FolderBrowserTask] - - [InputFolderBrowserTask] - - Flow manipulation - - [AggregateIterableTask](doc/reference/tasks/aggregate_iterable_task.md) - - [InputAggregatorTask](doc/reference/tasks/input_aggregator_task.md) - - [InputIteratorTask](doc/reference/tasks/input_iterator_task.md) - - [ArrayMergeTask] - - [ColumnAggregatorTask] - - [RowAggregatorTask] - - [FilterTask] - - [GroupByAggregateIterableTask] - - [SimpleBatchTask] - - [IterableBatchTask] - - [SkipEmptyTask] - - [StopTask] - - Process - - [CommandRunnerTask] - - [ProcessExecutorTask] - - [ProcessLauncherTask] - - Reporting - - [AdvancedStatCounterTask] - - [LoggerTask] - - [StatCounterTask] - - Transformers - - Basic and debug - - [CachedTransformer] - - [CallbackTransformer] - - [CastTransformer] - - [ConstantTransformer] - - [ConvertValueTransformer] - - [DebugTransformer] - - [DefaultTransformer] - - [GenericTransformer] - - [EvaluatorTransformer] - - [ExpressionLanguageMapTransformer] - - [MappingTransformer](doc/reference/transformers/mapping_transformer.md) - - [MultiReplaceTransformer] - - [PregFilterTransformer] - - [RulesTransformer](doc/reference/transformers/rules_transformer.md) - - [TypeSetterTransformer] - - [UnsetTransformer] - - [WrapperTransformer] - - Array - - [ArrayElementTransformer] - - [ArrayFilterTransformer](doc/reference/transformers/array_filter_transformer.md) - - [ArrayFirstTransformer] - - [ArrayLastTransformer] - - [ArrayMapTransformer] - - [ArrayUnsetTransformer] - - Date - - [DateFormatTransformer](doc/reference/transformers/date_format.md) - - [DateParserTransformer](doc/reference/transformers/date_parser.md) - - Object - - [InstantiateTransformer] - - [PropertyAccessorTransformer] - - [RecursivePropertySetterTransformer] - - Serialization - - [DenormalizeTransformer] - - [NormalizeTransformer] - - String - - [ExplodeTransformer] - - [HashTransformer] - - [ImplodeTransformer] - - [SlugifyTransformer] - - [SprintfTransformer] - - [TrimTransformer] - - XML - - [XpathEvaluatorTransformer](doc/reference/transformers/xpath_evaluator.md) - - Other bridges - - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) - - [Eav](https://github.com/cleverage/eav-process-bundle) - - [Soap](https://github.com/cleverage/soap-process-bundle) - - [Another Soap](https://github.com/cleverage/process-soap-bundle) - - [Rest](https://github.com/cleverage/rest-process-bundle) - - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) - - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) - - [Cache](https://github.com/cleverage/cache-process-bundle) - - [Generic transformers definition](doc/reference/03-generic_transformers_definition.md) -- [UI](https://github.com/cleverage/processuibundle) +For usage documentation, see: +[docs/index.md](doc/index.md) ## Support & Contribution diff --git a/docs/01-quick_start.md b/docs/01-quick_start.md index 0bab2f4f..efcc83c7 100644 --- a/docs/01-quick_start.md +++ b/docs/01-quick_start.md @@ -20,13 +20,16 @@ The most common example is the ETL. It's a kind of application whose main purpos ## Installation -This bundle requires Symfony 6.3 minimum. You can install it using composer: +Make sure Composer is installed globally, as explained in the [installation chapter](https://getcomposer.org/doc/00-intro.md) +of the Composer documentation. + +Open a command console, enter your project directory and install it using composer: ```bash composer require cleverage/process-bundle ``` -Remember to add the following line to bundles.php (not required if Symfony Flex is used) +Remember to add the following line to config/bundles.php (not required if Symfony Flex is used) ```php CleverAge\ProcessBundle\CleverAgeProcessBundle::class => ['all' => true], @@ -97,11 +100,11 @@ Then you can add tasks in this array. They consist of a `service`, optionally co ``` Below you can see a minimal working ETL example. It consist of 3 tasks: -- the first *extract* some data (the [constant output task](./reference/tasks/constant_output_task.md) outputs... a constant value): it's an array with 3 +- the first *extract* some data (the [constant output task](reference/tasks/constant_output_task.md) outputs... a constant value): it's an array with 3 keys/values -- the second *transform* the given value (the [transformer task](./reference/tasks/transformer_task.md) is one of the most important!): the output is then an +- the second *transform* the given value (the [transformer task](reference/tasks/transformer_task.md) is one of the most important!): the output is then an array with 2 keys/values, created using the value from previous task -- finally, the last will just display the result (it's a cheap *load*, using the [debug task](./reference/tasks/debug_task.md), only for development +- finally, the last will just display the result (it's a cheap *load*, using the [debug task](reference/tasks/debug_task.md), only for development purpose!) ```yaml @@ -193,4 +196,4 @@ Once everything is working fine, you may want to automate your processes. The st To check if everything went fine, logs are stored in database: - `clever_process_history`: logs process started, with `process_code`, `start_date`, `end_date` and `statut` -- `clever_task_history`: logs custom tasks logs (see [logging]()), with `task_code`, `message`, `logged_at` date, `level`, a `reference` and `context` +- `clever_task_history`: logs custom tasks logs (see [logging]), with `task_code`, `message`, `logged_at` date, `level`, a `reference` and `context` diff --git a/docs/02-task_types.md b/docs/02-task_types.md index 9ebfd21e..6639f027 100644 --- a/docs/02-task_types.md +++ b/docs/02-task_types.md @@ -81,7 +81,7 @@ Transformers are a special subset of this bundle. They're not tasks strictly spe point for Transformers is the `CleverAge\ProcessBundle\Task\TransformerTask`, whose only purpose is to take some input, pass it to a transformer and transfer the output to next task. -The idea is to allow a great flexibility (especially using the [MappingTransformer]()), without using too much code. +The idea is to allow a great flexibility (especially using the [MappingTransformer]), without using too much code. They implement `CleverAge\ProcessBundle\Transformer\TransformerInterface` or `CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface`. diff --git a/docs/03-custom_tasks.md b/docs/03-custom_tasks.md index b6bc6372..607ac3b0 100644 --- a/docs/03-custom_tasks.md +++ b/docs/03-custom_tasks.md @@ -25,11 +25,11 @@ method will be called and the `$state` will contain a new input (`ProcessState:: may pass a new output to the next task (`ProcessState::setOutput`). The State also provide reporting tools: -* `ProcessState::log`: register a new log message (see[logging]()) +* `ProcessState::log`: register a new log message (see[logging]) * `ProcessState::getConsoleOutput`: direct link to Symfony's Console Output (deprecated, prefer log) Sometimes, when you execute a task, you need to change how the process may continue. It will be detailed in depth in -the [next chapter about error management]() but here are the main methods +the [next chapter about error management] but here are the main methods * `ProcessState::setSkipped`: process won't continue to next step * `ProcessState::setStopped`: process will fully stop * `ProcessState::setErrorOutput`: allow to direct an output to an error branch from your workflow @@ -50,14 +50,14 @@ Defining your tasks as Iterable or Blocking is as simple as implementing one of * `CleverAge\ProcessBundle\Model\IterableTaskInterface`: the `next` method should behave almost the same as PHP's native [next](https://secure.php.net/manual/en/function.next.php) function for arrays (except it only returns a boolean) * `CleverAge\ProcessBundle\Model\BlockingTaskInterface`: every `execute` method call should only accumulate data from -the input and once every previous task is _resolved_, the `proceed` method should provide an output (see [TODO]() for +the input and once every previous task is _resolved_, the `proceed` method should provide an output (see [TODO] for the exact definition of a resolved method) It's up to you to know when you should be using one of those, but basically: * When you loop over a collection of independent elements, you should use an Iterable task. It may help you reduce the memory footprint. * When you need to collect, upload, ... data as a whole, then you might need a Blocking task. Be sure to read [previous -chapter's notice]() about performance. +chapter's notice] about performance. Tasks cannot be both Iterable and Blocking. diff --git a/docs/index.md b/docs/index.md index e69de29b..7e268214 100644 --- a/docs/index.md +++ b/docs/index.md @@ -0,0 +1,140 @@ +## Documentation + +- [Quick start](01-quick_start.md) +- [Task types](02-task_types.md) +- [Custom tasks and development](03-custom_tasks.md) +- [Advanced workflow](04-advanced_workflow.md) +- Cookbooks + - [Common Setup](cookbooks/01-common_setup.md) + - [Transformations] + - [Flow manipulation] + - [Dummy tasks] + - [Debugging] + - [Logging] + - [Subprocess] + - [File manipulation] + - [Direct call (in controller)] + - [Performances monitoring](cookbooks/performances_monitoring.md) + - [Memory usage analysis](cookbooks/memory_usage_graph.md) +- Reference + - [Process definition](reference/01-process_definition.md) + - [Task definition](reference/02-task_definition.md) + - Basic and debug + - [ConstantOutputTask](reference/tasks/constant_output_task.md) + - [ConstantIterableOutputTask](reference/tasks/constant_iterable_output_task.md) + - [CounterTask] + - [DebugTask](reference/tasks/debug_task.md) + - [DieTask](reference/tasks/die_task.md) + - [DummyTask](reference/tasks/dummy_task.md) + - [ErrorForwarderTask] + - [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) + - [MemInfoDumpTask] + - [StopwatchTask] + - Data manipulation and transformations + - [DenormalizerTask](reference/tasks/denormalizer_task.md) + - [NormalizerTask](reference/tasks/normalizer_task.md) + - [DeserializerTask] + - [SerializerTask] + - [PropertyGetterTask](reference/tasks/property_getter_task.md) + - [PropertySetterTask](reference/tasks/property_setter_task.md) + - [ObjectUpdaterTask] + - [SplitJoinLineTask] + - [TransformerTask](reference/tasks/transformer_task.md) + - [ValidatorTask] + - File/CSV + - [CsvReaderTask](reference/tasks/csv_reader_task.md) + - [CsvWriterTask](reference/tasks/csv_writer_task.md) + - [CSVSplitterTask] + - [InputCsvReaderTask] + - File/JsonStream + - [JsonStreamReaderTask] + - File/XML + - [XmlReaderTask](reference/tasks/xml_reader_task.md) + - [XmlWriterTask](reference/tasks/xml_writer_task.md) + - File/Yaml + - [YamlReaderTask] + - [YamlWriterTask] + - File + - [FileMoverTask] + - [FileReaderTask] + - [FileRemoverTask] + - [FileWriterTask] + - [FolderBrowserTask] + - [InputFolderBrowserTask] + - Flow manipulation + - [AggregateIterableTask](reference/tasks/aggregate_iterable_task.md) + - [InputAggregatorTask](reference/tasks/input_aggregator_task.md) + - [InputIteratorTask](reference/tasks/input_iterator_task.md) + - [ArrayMergeTask] + - [ColumnAggregatorTask] + - [RowAggregatorTask] + - [FilterTask] + - [GroupByAggregateIterableTask] + - [SimpleBatchTask] + - [IterableBatchTask] + - [SkipEmptyTask] + - [StopTask] + - Process + - [CommandRunnerTask] + - [ProcessExecutorTask] + - [ProcessLauncherTask] + - Reporting + - [AdvancedStatCounterTask] + - [LoggerTask] + - [StatCounterTask] + - Transformers + - Basic and debug + - [CachedTransformer] + - [CallbackTransformer] + - [CastTransformer] + - [ConstantTransformer] + - [ConvertValueTransformer] + - [DebugTransformer] + - [DefaultTransformer] + - [GenericTransformer] + - [EvaluatorTransformer] + - [ExpressionLanguageMapTransformer] + - [MappingTransformer](reference/transformers/mapping_transformer.md) + - [MultiReplaceTransformer] + - [PregFilterTransformer] + - [RulesTransformer](reference/transformers/rules_transformer.md) + - [TypeSetterTransformer] + - [UnsetTransformer] + - [WrapperTransformer] + - Array + - [ArrayElementTransformer] + - [ArrayFilterTransformer](reference/transformers/array_filter_transformer.md) + - [ArrayFirstTransformer] + - [ArrayLastTransformer] + - [ArrayMapTransformer] + - [ArrayUnsetTransformer] + - Date + - [DateFormatTransformer](reference/transformers/date_format.md) + - [DateParserTransformer](reference/transformers/date_parser.md) + - Object + - [InstantiateTransformer] + - [PropertyAccessorTransformer] + - [RecursivePropertySetterTransformer] + - Serialization + - [DenormalizeTransformer] + - [NormalizeTransformer] + - String + - [ExplodeTransformer] + - [HashTransformer] + - [ImplodeTransformer] + - [SlugifyTransformer] + - [SprintfTransformer] + - [TrimTransformer] + - XML + - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) + - Other bridges + - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) + - [Eav](https://github.com/cleverage/eav-process-bundle) + - [Soap](https://github.com/cleverage/soap-process-bundle) + - [Another Soap](https://github.com/cleverage/process-soap-bundle) + - [Rest](https://github.com/cleverage/rest-process-bundle) + - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) + - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) + - [Cache](https://github.com/cleverage/cache-process-bundle) + - [Generic transformers definition](reference/03-generic_transformers_definition.md) +- [UI](https://github.com/cleverage/processuibundle) diff --git a/docs/reference/03-generic_transformers_definition.md b/docs/reference/03-generic_transformers_definition.md index 68b40ca1..9615761c 100644 --- a/docs/reference/03-generic_transformers_definition.md +++ b/docs/reference/03-generic_transformers_definition.md @@ -27,6 +27,6 @@ For each contextual option, you can define | `default` | `any` | | `null` | If not `null`, define the default value | | `default_is_null` | `bool` | | `false` | If you need `null` to be the default value, use this option | -The transformer options are the same than any other transformer using a sub-list of transformers (see [TransformerTrait](../traits/transformer_trait.md)). +The transformer options are the same than any other transformer using a sub-list of transformers (see [TransformerTrait](traits/transformer_trait.md)). You can use the syntax for contextual values (`{{ contextual_option_code }}`) to put placeholders that will be filled by those contextual options. From 719c9ee19522b71862b96af3d1876076ae55c47b Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 10:36:02 +0200 Subject: [PATCH 249/304] #148 Update services (step 1) according to Symfony best practices --- config/services/command.yaml | 32 +++++++++++++---- config/services/event.yaml | 3 +- config/services/expression_language.yaml | 7 ++-- config/services/logger.yaml | 35 +++++++++++++------ config/services/manager.yaml | 14 +++++--- config/services/registry.yaml | 7 ++-- config/services/task.yaml | 8 ++++- config/services/transformer.yaml | 11 +++--- .../CleverAgeProcessExtension.php | 2 +- 9 files changed, 87 insertions(+), 32 deletions(-) diff --git a/config/services/command.yaml b/config/services/command.yaml index 4c700e2f..58bd6e7c 100644 --- a/config/services/command.yaml +++ b/config/services/command.yaml @@ -1,7 +1,27 @@ services: - CleverAge\ProcessBundle\Command\: - resource: '../../../Command/*' - autowire: true - autoconfigure: true - bind: - $container: '@service_container' + cleverage_process.command.execute_process: + class: CleverAge\ProcessBundle\Command\ExecuteProcessCommand + public: false + tags: + - { name: console.command } + arguments: + - '@process_bundle.manager.process' + - '@event_dispatcher' + - '@process_bundle.registry.process_configuration' + + cleverage_process.command.list_process: + class: CleverAge\ProcessBundle\Command\ListProcessCommand + public: false + tags: + - { name: console.command } + arguments: + - '@process_bundle.registry.process_configuration' + + cleverage_process.command.process_help: + class: CleverAge\ProcessBundle\Command\ProcessHelpCommand + public: false + tags: + - { name: console.command } + arguments: + - '@process_bundle.registry.process_configuration' + - '@service_container' diff --git a/config/services/event.yaml b/config/services/event.yaml index f4a5bb70..8bb1ae18 100644 --- a/config/services/event.yaml +++ b/config/services/event.yaml @@ -1,5 +1,6 @@ services: - CleverAge\ProcessBundle\EventListener\DataQueueEventListener: + cleverage_process.event_listener.data_queue: + class: CleverAge\ProcessBundle\EventListener\DataQueueEventListener public: false tags: - { name: kernel.event_listener, event: cleverage_process.data_queue, method: pushData } diff --git a/config/services/expression_language.yaml b/config/services/expression_language.yaml index 63a47a74..125d3312 100644 --- a/config/services/expression_language.yaml +++ b/config/services/expression_language.yaml @@ -1,9 +1,12 @@ services: - CleverAge\ProcessBundle\ExpressionLanguage\PhpFunctionProvider: + cleverage_process.expression_language.php_function_provider: + class: CleverAge\ProcessBundle\ExpressionLanguage\PhpFunctionProvider + public: false arguments: - [ 'preg_match' ] cleverage_process.expression_language: class: Symfony\Component\ExpressionLanguage\ExpressionLanguage + public: false calls: - - ['registerProvider', ['@CleverAge\ProcessBundle\ExpressionLanguage\PhpFunctionProvider']] + - ['registerProvider', ['@cleverage_process.expression_language.php_function_provider']] diff --git a/config/services/logger.yaml b/config/services/logger.yaml index 1968bd79..b0ea1fbd 100644 --- a/config/services/logger.yaml +++ b/config/services/logger.yaml @@ -1,25 +1,40 @@ services: - CleverAge\ProcessBundle\Logger\ProcessProcessor: - autowire: true + cleverage_process.logger.process_processor: + class: CleverAge\ProcessBundle\Logger\ProcessProcessor + public: false tags: - { name: monolog.processor, channel: cleverage_process } + arguments: + - '@process_bundle.manager.process' - CleverAge\ProcessBundle\Logger\TaskProcessor: - autowire: true + cleverage_process.logger.task_processor: + class: CleverAge\ProcessBundle\Logger\TaskProcessor + public: false tags: - { name: monolog.processor, channel: cleverage_process_task } + arguments: + - '@process_bundle.manager.process' - CleverAge\ProcessBundle\Logger\TransformerProcessor: - autowire: true + cleverage_process.logger.transformer_processor: + class: CleverAge\ProcessBundle\Logger\TransformerProcessor + public: false tags: - { name: monolog.processor, channel: cleverage_process_transformer } + arguments: + - '@process_bundle.manager.process' - CleverAge\ProcessBundle\Logger\ProcessLogger: - autowire: true + cleverage_process.logger.process_logger: + class: CleverAge\ProcessBundle\Logger\ProcessLogger + public: false tags: - { name: monolog.logger, channel: cleverage_process } + arguments: + - '@monolog.logger' - CleverAge\ProcessBundle\Logger\TaskLogger: - autowire: true + cleverage_process.logger.task_logger: + class: CleverAge\ProcessBundle\Logger\TaskLogger + public: false tags: - { name: monolog.logger, channel: cleverage_process_task } + arguments: + - '@monolog.logger' diff --git a/config/services/manager.yaml b/config/services/manager.yaml index a4360642..ff8ee350 100644 --- a/config/services/manager.yaml +++ b/config/services/manager.yaml @@ -1,9 +1,15 @@ services: - CleverAge\ProcessBundle\Manager\ProcessManager: - autowire: true + process_bundle.manager.process: + class: CleverAge\ProcessBundle\Manager\ProcessManager public: false arguments: - $container: '@service_container' + - '@service_container' + - '@cleverage_process.logger.process_logger' + - '@cleverage_process.logger.task_logger' + - '@process_bundle.registry.process_configuration' + - '@process_bundle.context.contextual_option_resolver' + - '@event_dispatcher' - CleverAge\ProcessBundle\Context\ContextualOptionResolver: + process_bundle.context.contextual_option_resolver: + class: CleverAge\ProcessBundle\Context\ContextualOptionResolver public: false diff --git a/config/services/registry.yaml b/config/services/registry.yaml index 7e0ec1aa..852631f4 100644 --- a/config/services/registry.yaml +++ b/config/services/registry.yaml @@ -1,8 +1,11 @@ services: - CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry: + process_bundle.registry.process_configuration: + class: CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry + public: false arguments: - ~ - ~ - CleverAge\ProcessBundle\Registry\TransformerRegistry: + process_bundle.registry.transformer: + class: CleverAge\ProcessBundle\Registry\TransformerRegistry public: false diff --git a/config/services/task.yaml b/config/services/task.yaml index 61e64bf7..7c9ba30b 100644 --- a/config/services/task.yaml +++ b/config/services/task.yaml @@ -1,6 +1,12 @@ services: + _defaults: + bind: + $processManager: '@process_bundle.manager.process' + $processRegistry: '@process_bundle.registry.process_configuration' + $transformerRegistry: '@process_bundle.registry.transformer' + CleverAge\ProcessBundle\Task\: - resource: '../../../Task/*' + resource: '../../src/Task/*' autowire: true public: true shared: false diff --git a/config/services/transformer.yaml b/config/services/transformer.yaml index 63741e56..cd5cfeab 100644 --- a/config/services/transformer.yaml +++ b/config/services/transformer.yaml @@ -1,14 +1,15 @@ services: _defaults: - autowire: true - autoconfigure: true - public: true bind: $language: '@cleverage_process.expression_language' + $transformerRegistry: '@process_bundle.registry.transformer' CleverAge\ProcessBundle\Transformer\: - resource: '../../../Transformer/*' - exclude: '../../../Transformer/GenericTransformer.php' + resource: '../../src/Transformer/*' + exclude: '../../src/Transformer/GenericTransformer.php' + autowire: true + autoconfigure: true + public: true tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index 5c8db1a2..ceaf264c 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -37,7 +37,7 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $processConfigurationRegistry = $container->getDefinition(ProcessConfigurationRegistry::class); + $processConfigurationRegistry = $container->getDefinition('process_bundle.registry.process_configuration'); $processConfigurationRegistry->replaceArgument(0, $config['configurations']); $processConfigurationRegistry->replaceArgument(1, $config['default_error_strategy']); From f1d7670fc15bc211134076aaa4c712e8193212de Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 11:27:52 +0200 Subject: [PATCH 250/304] #147 Add missing dependency on "symfony/dotenv": "^6.4|^7.1" and symfony/runtime "^6.4|^7.1" --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3a00935f..7b1f9208 100644 --- a/composer.json +++ b/composer.json @@ -49,14 +49,15 @@ }, "require": { "php": ">=8.1", - "ext-json": "*", "ext-dom": "*", "ext-intl": "*", + "ext-json": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", "symfony/config": "^6.4|^7.1", "symfony/console": "^6.4|^7.1", "symfony/dependency-injection": "^6.4|^7.1", + "symfony/dotenv": "^6.4|^7.1", "symfony/event-dispatcher-contracts": "^3", "symfony/expression-language": "^6.4|^7.1", "symfony/form": "^6.4|^7.1", @@ -66,6 +67,7 @@ "symfony/options-resolver": "^6.4|^7.1", "symfony/process": "^6.4|^7.1", "symfony/property-access": "^6.4|^7.1", + "symfony/runtime": "^6.4|^7.1", "symfony/scheduler": "^6.4|^7.1", "symfony/serializer": "^6.4|^7.1", "symfony/stopwatch": "^6.4|^7.1", From dea1befded371a51de732638a938699d30aa6c85 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 17:09:51 +0200 Subject: [PATCH 251/304] #147 Replace `Symfony\Component\Form\Exception\InvalidConfigurationException` by `Symfony\Component\Config\Definition\Exception\InvalidConfigurationException` --- src/Task/Process/ProcessExecutorTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 12d3789b..6b27a171 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -18,7 +18,7 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use Psr\Log\LoggerInterface; -use Symfony\Component\Form\Exception\InvalidConfigurationException; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; From 45903b0e9578902533bec2caa0ccfe12b20c177c Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 17:10:18 +0200 Subject: [PATCH 252/304] #147 Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` --- CHANGELOG.md | 2 ++ composer.json | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc6049b3..7a0129f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v4.0 * [#142](https://github.com/cleverage/process-bundle/issues/142) DateFormatTransformer & DateParserTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Date` * [#142](https://github.com/cleverage/process-bundle/issues/142) ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` * [#142](https://github.com/cleverage/process-bundle/issues/142) InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` +* [#147](https://github.com/cleverage/process-bundle/issues/147) Replace `Symfony\Component\Form\Exception\InvalidConfigurationException` by `Symfony\Component\Config\Definition\Exception\InvalidConfigurationException` ### Changes @@ -17,6 +18,7 @@ v4.0 * [#139](https://github.com/cleverage/process-bundle/issues/139Update) Update rector, phpstan & php-cs-fixer configurations & apply it * [#141](https://github.com/cleverage/process-bundle/issues/141) `league/flysystem-bundle` is not required anymore * [#130](https://github.com/cleverage/process-bundle/issues/130) EventDispatcherInterface service declaration breaks dependency injection +* [#147](https://github.com/cleverage/process-bundle/issues/147) Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` ### Fixes diff --git a/composer.json b/composer.json index 7b1f9208..a7db03cb 100644 --- a/composer.json +++ b/composer.json @@ -60,15 +60,12 @@ "symfony/dotenv": "^6.4|^7.1", "symfony/event-dispatcher-contracts": "^3", "symfony/expression-language": "^6.4|^7.1", - "symfony/form": "^6.4|^7.1", "symfony/framework-bundle": "^6.4|^7.1", - "symfony/messenger": "^6.4|^7.1", "symfony/monolog-bundle": "~3.3", "symfony/options-resolver": "^6.4|^7.1", "symfony/process": "^6.4|^7.1", "symfony/property-access": "^6.4|^7.1", "symfony/runtime": "^6.4|^7.1", - "symfony/scheduler": "^6.4|^7.1", "symfony/serializer": "^6.4|^7.1", "symfony/stopwatch": "^6.4|^7.1", "symfony/validator": "^6.4|^7.1", From 7722734ce64d96c38569be1af31eed67431223bd Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 17:22:22 +0200 Subject: [PATCH 253/304] #148 Fix services prefix using cleverage_process instead of process_bundle --- CHANGELOG.md | 4 +++- config/services/command.yaml | 8 ++++---- config/services/logger.yaml | 6 +++--- config/services/manager.yaml | 8 ++++---- config/services/registry.yaml | 4 ++-- config/services/task.yaml | 6 +++--- config/services/transformer.yaml | 2 +- src/DependencyInjection/CleverAgeProcessExtension.php | 3 +-- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0129f9..86cb5d64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,15 @@ v4.0 * [#142](https://github.com/cleverage/process-bundle/issues/142) ExplodeTransformer, HashTransformer, ImplodeTransformer, SlugifyTransformer, SprintfTransformer & TrimTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\String` * [#142](https://github.com/cleverage/process-bundle/issues/142) InstantiateTransformer, PropertyAccessorTransformer RecursivePropertySetterTransformer namespaces changed to `CleverAge\ProcessBundle\Transformer\Object` * [#147](https://github.com/cleverage/process-bundle/issues/147) Replace `Symfony\Component\Form\Exception\InvalidConfigurationException` by `Symfony\Component\Config\Definition\Exception\InvalidConfigurationException` - +* [#148](https://github.com/cleverage/process-bundle/issues/148) Update services (step 1) according to Symfony best practices. Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. +Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_process` ### Changes * [#139](https://github.com/cleverage/process-bundle/issues/139Update) Makefile & .docker for local standalone usage * [#139](https://github.com/cleverage/process-bundle/issues/139Update) Update rector, phpstan & php-cs-fixer configurations & apply it * [#141](https://github.com/cleverage/process-bundle/issues/141) `league/flysystem-bundle` is not required anymore * [#130](https://github.com/cleverage/process-bundle/issues/130) EventDispatcherInterface service declaration breaks dependency injection +* [#147](https://github.com/cleverage/process-bundle/issues/147) Add missing dependencies on `symfony/dotenv` and `symfony/runtime` * [#147](https://github.com/cleverage/process-bundle/issues/147) Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` ### Fixes diff --git a/config/services/command.yaml b/config/services/command.yaml index 58bd6e7c..947bce64 100644 --- a/config/services/command.yaml +++ b/config/services/command.yaml @@ -5,9 +5,9 @@ services: tags: - { name: console.command } arguments: - - '@process_bundle.manager.process' + - '@cleverage_process.manager.process' - '@event_dispatcher' - - '@process_bundle.registry.process_configuration' + - '@cleverage_process.registry.process_configuration' cleverage_process.command.list_process: class: CleverAge\ProcessBundle\Command\ListProcessCommand @@ -15,7 +15,7 @@ services: tags: - { name: console.command } arguments: - - '@process_bundle.registry.process_configuration' + - '@cleverage_process.registry.process_configuration' cleverage_process.command.process_help: class: CleverAge\ProcessBundle\Command\ProcessHelpCommand @@ -23,5 +23,5 @@ services: tags: - { name: console.command } arguments: - - '@process_bundle.registry.process_configuration' + - '@cleverage_process.registry.process_configuration' - '@service_container' diff --git a/config/services/logger.yaml b/config/services/logger.yaml index b0ea1fbd..6925dd67 100644 --- a/config/services/logger.yaml +++ b/config/services/logger.yaml @@ -5,7 +5,7 @@ services: tags: - { name: monolog.processor, channel: cleverage_process } arguments: - - '@process_bundle.manager.process' + - '@cleverage_process.manager.process' cleverage_process.logger.task_processor: class: CleverAge\ProcessBundle\Logger\TaskProcessor @@ -13,7 +13,7 @@ services: tags: - { name: monolog.processor, channel: cleverage_process_task } arguments: - - '@process_bundle.manager.process' + - '@cleverage_process.manager.process' cleverage_process.logger.transformer_processor: class: CleverAge\ProcessBundle\Logger\TransformerProcessor @@ -21,7 +21,7 @@ services: tags: - { name: monolog.processor, channel: cleverage_process_transformer } arguments: - - '@process_bundle.manager.process' + - '@cleverage_process.manager.process' cleverage_process.logger.process_logger: class: CleverAge\ProcessBundle\Logger\ProcessLogger diff --git a/config/services/manager.yaml b/config/services/manager.yaml index ff8ee350..396d7d9f 100644 --- a/config/services/manager.yaml +++ b/config/services/manager.yaml @@ -1,15 +1,15 @@ services: - process_bundle.manager.process: + cleverage_process.manager.process: class: CleverAge\ProcessBundle\Manager\ProcessManager public: false arguments: - '@service_container' - '@cleverage_process.logger.process_logger' - '@cleverage_process.logger.task_logger' - - '@process_bundle.registry.process_configuration' - - '@process_bundle.context.contextual_option_resolver' + - '@cleverage_process.registry.process_configuration' + - '@cleverage_process.context.contextual_option_resolver' - '@event_dispatcher' - process_bundle.context.contextual_option_resolver: + cleverage_process.context.contextual_option_resolver: class: CleverAge\ProcessBundle\Context\ContextualOptionResolver public: false diff --git a/config/services/registry.yaml b/config/services/registry.yaml index 852631f4..48d5e469 100644 --- a/config/services/registry.yaml +++ b/config/services/registry.yaml @@ -1,11 +1,11 @@ services: - process_bundle.registry.process_configuration: + cleverage_process.registry.process_configuration: class: CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry public: false arguments: - ~ - ~ - process_bundle.registry.transformer: + cleverage_process.registry.transformer: class: CleverAge\ProcessBundle\Registry\TransformerRegistry public: false diff --git a/config/services/task.yaml b/config/services/task.yaml index 7c9ba30b..9fb96b4e 100644 --- a/config/services/task.yaml +++ b/config/services/task.yaml @@ -1,9 +1,9 @@ services: _defaults: bind: - $processManager: '@process_bundle.manager.process' - $processRegistry: '@process_bundle.registry.process_configuration' - $transformerRegistry: '@process_bundle.registry.transformer' + $processManager: '@cleverage_process.manager.process' + $processRegistry: '@cleverage_process.registry.process_configuration' + $transformerRegistry: '@cleverage_process.registry.transformer' CleverAge\ProcessBundle\Task\: resource: '../../src/Task/*' diff --git a/config/services/transformer.yaml b/config/services/transformer.yaml index cd5cfeab..6d2c40ee 100644 --- a/config/services/transformer.yaml +++ b/config/services/transformer.yaml @@ -2,7 +2,7 @@ services: _defaults: bind: $language: '@cleverage_process.expression_language' - $transformerRegistry: '@process_bundle.registry.transformer' + $transformerRegistry: '@cleverage_process.registry.transformer' CleverAge\ProcessBundle\Transformer\: resource: '../../src/Transformer/*' diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index ceaf264c..0dc1c6b8 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -13,7 +13,6 @@ namespace CleverAge\ProcessBundle\DependencyInjection; -use CleverAge\ProcessBundle\Registry\ProcessConfigurationRegistry; use CleverAge\ProcessBundle\Transformer\GenericTransformer; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -37,7 +36,7 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $processConfigurationRegistry = $container->getDefinition('process_bundle.registry.process_configuration'); + $processConfigurationRegistry = $container->getDefinition('cleverage_process.registry.process_configuration'); $processConfigurationRegistry->replaceArgument(0, $config['configurations']); $processConfigurationRegistry->replaceArgument(1, $config['default_error_strategy']); From 0b40728cbf09f4ce9aed02f3e3bc29b6726ad8e4 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 22 Oct 2024 17:42:02 +0200 Subject: [PATCH 254/304] #146 eav-process-bundle, enqueue-process-bundle, cache-process-bundle and process-soap-bundle were deprecated / archived. --- CHANGELOG.md | 3 ++- composer.json | 4 ---- docs/04-advanced_workflow.md | 1 - docs/index.md | 4 ---- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86cb5d64..6dc29371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,8 @@ Services must be prefixed with the bundle alias instead of using fully qualified * [#141](https://github.com/cleverage/process-bundle/issues/141) `league/flysystem-bundle` is not required anymore * [#130](https://github.com/cleverage/process-bundle/issues/130) EventDispatcherInterface service declaration breaks dependency injection * [#147](https://github.com/cleverage/process-bundle/issues/147) Add missing dependencies on `symfony/dotenv` and `symfony/runtime` -* [#147](https://github.com/cleverage/process-bundle/issues/147) Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` +* [#147](https://github.com/cleverage/process-bundle/issues/147) Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` +* [#146](https://github.com/cleverage/process-bundle/issues/146) eav-process-bundle, enqueue-process-bundle, cache-process-bundle and process-soap-bundle were deprecated / archived. ### Fixes diff --git a/composer.json b/composer.json index a7db03cb..bd93b8b0 100644 --- a/composer.json +++ b/composer.json @@ -83,13 +83,9 @@ }, "suggest": { "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", - "cleverage/eav-process-bundle": "Dedicated bundle for EAV dependencies for the process bundle", "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", - "cleverage/process-soap-bundle": "Another dedicated bundle for Soap dependencies for the process bundle", "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", - "cleverage/enqueue-process-bundle": "Manage asynchronous events within the process bundle", "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", - "cleverage/cache-process-bundle": "Dedicated bundle for cache handling for the process bundle", "cleverage/processuibundle": "A simple UX for cleverage/processbundle using EasyAdmin\n\n" }, "config": { diff --git a/docs/04-advanced_workflow.md b/docs/04-advanced_workflow.md index bef6e3f1..f31ce2a3 100644 --- a/docs/04-advanced_workflow.md +++ b/docs/04-advanced_workflow.md @@ -25,5 +25,4 @@ You can also use [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) _TODO_ * ProcessLauncherTask -* EnqueueBundle * pthread diff --git a/docs/index.md b/docs/index.md index 7e268214..1f21aa64 100644 --- a/docs/index.md +++ b/docs/index.md @@ -129,12 +129,8 @@ - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) - Other bridges - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) - - [Eav](https://github.com/cleverage/eav-process-bundle) - [Soap](https://github.com/cleverage/soap-process-bundle) - - [Another Soap](https://github.com/cleverage/process-soap-bundle) - [Rest](https://github.com/cleverage/rest-process-bundle) - - [Enqueue](https://github.com/cleverage/enqueue-process-bundle) - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) - - [Cache](https://github.com/cleverage/cache-process-bundle) - [Generic transformers definition](reference/03-generic_transformers_definition.md) - [UI](https://github.com/cleverage/processuibundle) From 249b716fea710748c8cec14cff4bf7b50b069778 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 23 Oct 2024 10:25:03 +0200 Subject: [PATCH 255/304] Fix CONTRIBUTING test rule --- CONTRIBUTING.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6e9caaa..d5f790d9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,12 +40,6 @@ make quality make tests ``` -which will execute all tests inside the docker. - -```bash -make test TEST="Tests/Util/FilenameUtilsTest.php" -``` - ## Deprecations notices When a feature should be deprecated, or when you have a breaking change for a future version, please : From 8961591f508d38013f58e59788fd34828b76273c Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 23 Oct 2024 11:15:51 +0200 Subject: [PATCH 256/304] Add missing project name on docker compose.yaml --- .docker/compose.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.docker/compose.yaml b/.docker/compose.yaml index 9c311377..bc72ae34 100644 --- a/.docker/compose.yaml +++ b/.docker/compose.yaml @@ -2,6 +2,8 @@ x-build-args: &build-args UID: "${UID:-1000}" GID: "${GID:-1000}" +name: cleverage-process-bundle + services: php: build: From daba33997008e0944d1ddf8f8dbbebb35bf6978a Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 23 Oct 2024 12:19:53 +0200 Subject: [PATCH 257/304] Minor fix on CHANGELOG --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc29371..8c1ac079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,8 @@ v4.0 Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_process` ### Changes -* [#139](https://github.com/cleverage/process-bundle/issues/139Update) Makefile & .docker for local standalone usage -* [#139](https://github.com/cleverage/process-bundle/issues/139Update) Update rector, phpstan & php-cs-fixer configurations & apply it +* [#139](https://github.com/cleverage/process-bundle/issues/139) Update Makefile & .docker for local standalone usage +* [#139](https://github.com/cleverage/process-bundle/issues/139) Update rector, phpstan & php-cs-fixer configurations & apply it * [#141](https://github.com/cleverage/process-bundle/issues/141) `league/flysystem-bundle` is not required anymore * [#130](https://github.com/cleverage/process-bundle/issues/130) EventDispatcherInterface service declaration breaks dependency injection * [#147](https://github.com/cleverage/process-bundle/issues/147) Add missing dependencies on `symfony/dotenv` and `symfony/runtime` From d14e426fbc173f080e7c2b011d309a2e87d3e272 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 16:05:57 +0200 Subject: [PATCH 258/304] Update doc due to new ui repository --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9ec2b9b..c31dc621 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Demo project can be found on [there](https://github.com/cleverage/process-bundle ## Documentation For usage documentation, see: -[docs/index.md](doc/index.md) +[docs/index.md](docs/index.md) ## Support & Contribution diff --git a/docs/index.md b/docs/index.md index 1f21aa64..10946b54 100644 --- a/docs/index.md +++ b/docs/index.md @@ -133,4 +133,4 @@ - [Rest](https://github.com/cleverage/rest-process-bundle) - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) - [Generic transformers definition](reference/03-generic_transformers_definition.md) -- [UI](https://github.com/cleverage/processuibundle) +- [UI](https://github.com/cleverage/ui-process-bundle) From d3fbee1d9f35a55f77d847024852c2a05095ee33 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 29 Oct 2024 10:37:36 +0100 Subject: [PATCH 259/304] #147 composer require symfony/monolog-bridge:"^6.4|^7.1" --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index bd93b8b0..d91bd22f 100644 --- a/composer.json +++ b/composer.json @@ -61,6 +61,7 @@ "symfony/event-dispatcher-contracts": "^3", "symfony/expression-language": "^6.4|^7.1", "symfony/framework-bundle": "^6.4|^7.1", + "symfony/monolog-bridge": "^6.4|^7.1", "symfony/monolog-bundle": "~3.3", "symfony/options-resolver": "^6.4|^7.1", "symfony/process": "^6.4|^7.1", From c0a352c8472f422d90c312f944eb57a0841d7036 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 29 Oct 2024 17:00:44 +0100 Subject: [PATCH 260/304] #139 Apply <10.0 restriction on phpunit/phpunit since configuration file is not compatible with 10.0+ --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d91bd22f..769eeb2c 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,7 @@ "phpstan/extension-installer": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", - "phpunit/phpunit": "*", + "phpunit/phpunit": "<10.0", "rector/rector": "*", "roave/security-advisories": "dev-latest", "symfony/test-pack": "^1.1" From 3901525ac111f668ab524ce6754891a013f85686 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 5 Nov 2024 14:40:09 +0100 Subject: [PATCH 261/304] #141 Add a default value to the node "default_error_strategy" --- src/DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index fee9cb58..a3f80a5a 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -40,7 +40,7 @@ public function getConfigTreeBuilder(): TreeBuilder // Default error strategy $definition->enumNode('default_error_strategy') ->values([TaskConfiguration::STRATEGY_SKIP, TaskConfiguration::STRATEGY_STOP]) - ->isRequired(); + ->defaultValue(TaskConfiguration::STRATEGY_STOP); $this->appendRootProcessConfigDefinition($definition); $this->appendRootTransformersConfigDefinition($definition); From 7c2329e5a9454d1f34c71c89261c2c47fd346d44 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 5 Nov 2024 15:05:38 +0100 Subject: [PATCH 262/304] #150 Remove CleverAge\ProcessBundle\Task\Debug\MemInfoDumpTask --- CHANGELOG.md | 1 + docs/index.md | 1 - src/Task/Debug/MemInfoDumpTask.php | 48 ------------------------------ 3 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 src/Task/Debug/MemInfoDumpTask.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c1ac079..32664c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ v4.0 * [#147](https://github.com/cleverage/process-bundle/issues/147) Replace `Symfony\Component\Form\Exception\InvalidConfigurationException` by `Symfony\Component\Config\Definition\Exception\InvalidConfigurationException` * [#148](https://github.com/cleverage/process-bundle/issues/148) Update services (step 1) according to Symfony best practices. Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_process` +* [#150](https://github.com/cleverage/process-bundle/issues/150) The class `\CleverAge\ProcessBundle\Task\Debug\MemInfoDumpTask` has been deleted without suggested replacement ### Changes * [#139](https://github.com/cleverage/process-bundle/issues/139) Update Makefile & .docker for local standalone usage diff --git a/docs/index.md b/docs/index.md index 10946b54..26b471b4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -28,7 +28,6 @@ - [DummyTask](reference/tasks/dummy_task.md) - [ErrorForwarderTask] - [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) - - [MemInfoDumpTask] - [StopwatchTask] - Data manipulation and transformations - [DenormalizerTask](reference/tasks/denormalizer_task.md) diff --git a/src/Task/Debug/MemInfoDumpTask.php b/src/Task/Debug/MemInfoDumpTask.php deleted file mode 100644 index 23d4c251..00000000 --- a/src/Task/Debug/MemInfoDumpTask.php +++ /dev/null @@ -1,48 +0,0 @@ -getOption($state, 'file_path'), 'w'); - meminfo_dump($handler); - fclose($handler); - } else { - $this->logger->critical('meminfo PHP extension is not loaded'); - } - } - - protected function configureOptions(OptionsResolver $resolver): void - { - $resolver->setRequired(['file_path']); - $resolver->setAllowedTypes('file_path', ['string']); - } -} From f2586cb35ddfb41265f069a0b9193373bfb81ebb Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 5 Nov 2024 15:35:08 +0100 Subject: [PATCH 263/304] #145 Add documentation/examples for Basic and debug tasks --- CHANGELOG.md | 1 + docs/index.md | 6 +- docs/reference/tasks/_template.md | 5 +- .../tasks/constant_iterable_output_task.md | 25 ++++++++- docs/reference/tasks/constant_output_task.md | 32 ++++++----- docs/reference/tasks/counter_task.md | 56 +++++++++++++++++++ docs/reference/tasks/debug_task.md | 17 +++++- docs/reference/tasks/die_task.md | 9 ++- docs/reference/tasks/dummy_task.md | 31 ++++++++++ docs/reference/tasks/error_forwarder_task.md | 42 ++++++++++++++ docs/reference/tasks/event_dispatcher_task.md | 24 ++++++-- docs/reference/tasks/stopwatch_task.md | 26 +++++++++ src/Task/Debug/DebugTask.php | 2 - src/Task/Debug/DieTask.php | 4 -- src/Task/Debug/StopwatchTask.php | 2 +- 15 files changed, 245 insertions(+), 37 deletions(-) create mode 100644 docs/reference/tasks/counter_task.md create mode 100644 docs/reference/tasks/error_forwarder_task.md create mode 100644 docs/reference/tasks/stopwatch_task.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 32664c97..ea673379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Services must be prefixed with the bundle alias instead of using fully qualified * [#147](https://github.com/cleverage/process-bundle/issues/147) Add missing dependencies on `symfony/dotenv` and `symfony/runtime` * [#147](https://github.com/cleverage/process-bundle/issues/147) Remove dependencies on `symfony/form`, `symfony/messenger` & `symfony/scheduler` * [#146](https://github.com/cleverage/process-bundle/issues/146) eav-process-bundle, enqueue-process-bundle, cache-process-bundle and process-soap-bundle were deprecated / archived. +* [#141](https://github.com/cleverage/process-bundle/issues/141) Add a default value to the node "default_error_strategy" ### Fixes diff --git a/docs/index.md b/docs/index.md index 26b471b4..76de1a95 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,13 +22,13 @@ - Basic and debug - [ConstantOutputTask](reference/tasks/constant_output_task.md) - [ConstantIterableOutputTask](reference/tasks/constant_iterable_output_task.md) - - [CounterTask] + - [CounterTask](reference/tasks/counter_task.md) - [DebugTask](reference/tasks/debug_task.md) - [DieTask](reference/tasks/die_task.md) - [DummyTask](reference/tasks/dummy_task.md) - - [ErrorForwarderTask] + - [ErrorForwarderTask](reference/tasks/error_forwarder_task.md) - [EventDispatcherTask](reference/tasks/event_dispatcher_task.md) - - [StopwatchTask] + - [StopwatchTask](reference/tasks/stopwatch_task.md) - Data manipulation and transformations - [DenormalizerTask](reference/tasks/denormalizer_task.md) - [NormalizerTask](reference/tasks/normalizer_task.md) diff --git a/docs/reference/tasks/_template.md b/docs/reference/tasks/_template.md index ed1d4a57..842c5f37 100644 --- a/docs/reference/tasks/_template.md +++ b/docs/reference/tasks/_template.md @@ -20,9 +20,8 @@ _Description of possible types_ Options ------- - -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | +| Code | Type | Required | Default | Description | +|--------|--------|--------------------|--------------------------------|---------------| | `code` | `type` | **X** _or nothing_ | `default value` _if available_ | _description_ | Examples diff --git a/docs/reference/tasks/constant_iterable_output_task.md b/docs/reference/tasks/constant_iterable_output_task.md index b5cbb2b1..ba3f6410 100644 --- a/docs/reference/tasks/constant_iterable_output_task.md +++ b/docs/reference/tasks/constant_iterable_output_task.md @@ -21,7 +21,26 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `output` | `array` | **X** | | Array of values to iterate onto | +| Code | Type | Required | Default | Description | +|----------|---------|:--------:|---------|---------------------------------| +| `output` | `array` | **X** | | Array of values to iterate onto | +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.constant_iterable_output_example: + tasks: + constant_iterable_output_example: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 + outputs: [debug] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/constant_output_task.md b/docs/reference/tasks/constant_output_task.md index 3fbff205..03fd41c3 100644 --- a/docs/reference/tasks/constant_output_task.md +++ b/docs/reference/tasks/constant_output_task.md @@ -21,24 +21,26 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `output` | `any` | **X** | | Value to output | +| Code | Type | Required | Default | Description | +|----------|-------|:---------|---------|-----------------| +| `output` | `any` | **X** | | Value to output | Example ------- ```yaml clever_age_process: - configurations: - project_prefix.process_name: - tasks: - constant_output_example: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: - id: 123 - firstname: Test1 - lastname: Test2 - outputs: [XXXX] -``` + configurations: + project_prefix.constant_output_example: + tasks: + constant_output_example: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 + outputs: [debug] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/counter_task.md b/docs/reference/tasks/counter_task.md new file mode 100644 index 00000000..997c8af7 --- /dev/null +++ b/docs/reference/tasks/counter_task.md @@ -0,0 +1,56 @@ +CounterTask +================== + +Count the number of times the task is processed and continue every N iteration (skip the rest of the time) + +Flush at the end with the actual count. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\CounterTask` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`int`: outputs the number of times the counter is called + +Options +------- + +| Code | Type | Required | Default | Description | +|---------------|-------|----------|----------|---------------------------------------------------| +| `flush_every` | `int` | **X** | | The period at which the task will produce outputs | + +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.counter_example: + tasks: + counter_example: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + options: + output: + test1: test1 + test2: test2 + test3: test3 + test4: test4 + test5: test5 + test6: test6 + outputs: [counter] + counter: + service: '@CleverAge\ProcessBundle\Task\CounterTask' + options: + flush_every: 2 + outputs: [ debug ] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/debug_task.md b/docs/reference/tasks/debug_task.md index 1a98b263..5a654089 100644 --- a/docs/reference/tasks/debug_task.md +++ b/docs/reference/tasks/debug_task.md @@ -23,4 +23,19 @@ Possible outputs Example ---------------- -https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.debug.yaml \ No newline at end of file +```yaml +clever_age_process: + configurations: + project_prefix.debug_example: + tasks: + debug_example: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 + outputs: [debug] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/die_task.md b/docs/reference/tasks/die_task.md index cdde437e..24008f4d 100644 --- a/docs/reference/tasks/die_task.md +++ b/docs/reference/tasks/die_task.md @@ -22,4 +22,11 @@ None Example ---------------- -https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.die.yaml \ No newline at end of file +```yaml +clever_age_process: + configurations: + project_prefix.die_example: + tasks: + die_example: + service: '@CleverAge\ProcessBundle\Task\Debug\DieTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/dummy_task.md b/docs/reference/tasks/dummy_task.md index fe8a5321..87fda52e 100644 --- a/docs/reference/tasks/dummy_task.md +++ b/docs/reference/tasks/dummy_task.md @@ -17,3 +17,34 @@ Possible outputs ---------------- `any`: re-output given input + +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.dummy_example: + tasks: + dummy_example: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + outputs: [output1, output2] + output1: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 + outputs: [debug] + output2: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 456 + firstname: Test3 + lastname: Test4 + outputs: [ debug ] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/error_forwarder_task.md b/docs/reference/tasks/error_forwarder_task.md new file mode 100644 index 00000000..df129aa3 --- /dev/null +++ b/docs/reference/tasks/error_forwarder_task.md @@ -0,0 +1,42 @@ +CounterTask +================== + +This is a dummy task mostly intended for testing purpose. + +Forward any input to the error output. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Debug\ErrorForwarderTask` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any`: directly error_output given `output` option + +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.error_forwarder_example: + tasks: + error_forwarder_example: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + options: + output: + error1: Error 1 + error2: Error 2 + error3: Error 3 + outputs: [error_forwarder] + error_forwarder: + service: '@CleverAge\ProcessBundle\Task\Debug\ErrorForwarderTask' + +``` \ No newline at end of file diff --git a/docs/reference/tasks/event_dispatcher_task.md b/docs/reference/tasks/event_dispatcher_task.md index 9b6862e2..1a2d17b7 100644 --- a/docs/reference/tasks/event_dispatcher_task.md +++ b/docs/reference/tasks/event_dispatcher_task.md @@ -22,8 +22,24 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `event_name` | `string` | **X** | | Format for normalization ("json", "xml", ... an empty string should also work) | -| `passive` | `bool` | | `true` | Pass input to output | +| Code | Type | Required | Default | Description | +|--------------|----------|:---------:|----------|----------------------| +| `event_name` | `string` | **X** | | | +| `passive` | `bool` | | `true` | Pass input to output | +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.event_dispatcher_example: + tasks: + event_dispatcher_example: + service: '@CleverAge\ProcessBundle\Task\Event\EventDispatcherTask' + options: + event_name: 'myapp.myevent' + outputs: [debug] + debug: + service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' +``` \ No newline at end of file diff --git a/docs/reference/tasks/stopwatch_task.md b/docs/reference/tasks/stopwatch_task.md new file mode 100644 index 00000000..f7ee724f --- /dev/null +++ b/docs/reference/tasks/stopwatch_task.md @@ -0,0 +1,26 @@ +StopwatchTask +============= + +Log all the __root__ events of the Stopwatch component. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Debug\StopwatchTask` + +Accepted inputs +--------------- + +`any` + +Example +------- + +```yaml +clever_age_process: + configurations: + project_prefix.stopwatch_example: + tasks: + stopwatch_example: + service: '@CleverAge\ProcessBundle\Task\Debug\StopwatchTask' +``` \ No newline at end of file diff --git a/src/Task/Debug/DebugTask.php b/src/Task/Debug/DebugTask.php index dfe1d284..9020262d 100644 --- a/src/Task/Debug/DebugTask.php +++ b/src/Task/Debug/DebugTask.php @@ -19,8 +19,6 @@ /** * Dump the content of the input. - * - * @example https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.debug.yaml */ class DebugTask implements TaskInterface { diff --git a/src/Task/Debug/DieTask.php b/src/Task/Debug/DieTask.php index cc307cd5..b8625914 100644 --- a/src/Task/Debug/DieTask.php +++ b/src/Task/Debug/DieTask.php @@ -15,20 +15,16 @@ use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\ProcessBundle\Model\TaskInterface; -use Symfony\Component\Console\Helper\Helper; /** * Class DieTask. * * Stops the process brutally - * - * @example https://github.com/cleverage/process-bundle-ui-demo/blob/main/config/packages/process/demo.die.yaml */ class DieTask implements TaskInterface { public function execute(ProcessState $state): never { - var_dump(Helper::formatMemory(memory_get_peak_usage(true))); exit; } } diff --git a/src/Task/Debug/StopwatchTask.php b/src/Task/Debug/StopwatchTask.php index ecf39e46..160db265 100644 --- a/src/Task/Debug/StopwatchTask.php +++ b/src/Task/Debug/StopwatchTask.php @@ -19,7 +19,7 @@ use Symfony\Component\Stopwatch\Stopwatch; /** - * Ouputs the stopwatch the content of the input. + * Log all the __root__ events of the Stopwatch component. */ class StopwatchTask implements TaskInterface { From 0f8042d634805a83b330ce4b488dad7a8f31ed81 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 21 Nov 2024 16:07:39 +0100 Subject: [PATCH 264/304] Fix Transformer configuration & add missing aliases on monolog handlers --- src/CleverAgeProcessBundle.php | 3 +-- src/DependencyInjection/CleverAgeProcessExtension.php | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 300158b5..7e94bede 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -15,7 +15,6 @@ use CleverAge\ProcessBundle\DependencyInjection\Compiler\CheckSerializerCompilerPass; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; -use CleverAge\ProcessBundle\Registry\TransformerRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -29,7 +28,7 @@ public function build(ContainerBuilder $container): void parent::build($container); $container->addCompilerPass( - new RegistryCompilerPass(TransformerRegistry::class, 'cleverage.transformer', 'addTransformer') + new RegistryCompilerPass('cleverage_process.registry.transformer', 'cleverage.transformer', 'addTransformer') ); $container->addCompilerPass(new CheckSerializerCompilerPass()); diff --git a/src/DependencyInjection/CleverAgeProcessExtension.php b/src/DependencyInjection/CleverAgeProcessExtension.php index 0dc1c6b8..cf7830bf 100644 --- a/src/DependencyInjection/CleverAgeProcessExtension.php +++ b/src/DependencyInjection/CleverAgeProcessExtension.php @@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Finder\Finder; /** @@ -45,6 +46,10 @@ public function load(array $configs, ContainerBuilder $container): void $transformerDefinition = new Definition(GenericTransformer::class); $transformerDefinition->setAutowired(true); $transformerDefinition->setPublic(false); + $transformerDefinition->setArguments([ + new Reference('cleverage_process.context.contextual_option_resolver'), + new Reference('cleverage_process.registry.transformer'), + ]); $transformerDefinition->addMethodCall('initialize', [$transformerCode, $transformerConfig]); $transformerDefinition->addTag('cleverage.transformer'); From eec6b0fdd00e5d41b6b288f7a2e4a4f1fe3e0668 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 22 Nov 2024 10:38:04 +0100 Subject: [PATCH 265/304] cleverage/process-bundle-demo#3 Rename process-bundle-ui-demo to process-bundle-demo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c31dc621..8c2b601b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Basically, it will greatly ease the configuration of import and exports but can Compatible with [Symfony stable version and latest Long-Term Support (LTS) release](https://symfony.com/releases). -Demo project can be found on [there](https://github.com/cleverage/process-bundle-ui-demo). +Demo project can be found on [there](https://github.com/cleverage/process-bundle-demo). ## Documentation From c2b07789f15b29c21cb43a2bfca9e56fa149dcac Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 22 Nov 2024 10:43:18 +0100 Subject: [PATCH 266/304] Update composer suggest to cleverage/ui-process-bundle --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 769eeb2c..5286b57a 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", "cleverage/flysystem-process-bundle": "Dedicated bundle for Flysystem dependencies for the process bundle", - "cleverage/processuibundle": "A simple UX for cleverage/processbundle using EasyAdmin\n\n" + "cleverage/ui-process-bundle": "UI for the process bundle" }, "config": { "allow-plugins": { From 653a5752fd2cd854fcc167857ed931e8464f3d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tonon=20Gr=C3=A9gory?= Date: Tue, 3 Dec 2024 14:02:20 +0100 Subject: [PATCH 267/304] [#151] Replace monolog.logger by logger on CleverAge\ProcessBundle\Logger\ProcessLogger && CleverAge\ProcessBundle\Logger\TaskLogger to use cleverage_process && cleverage_process_task channel instead of app channel. --- config/services/logger.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/services/logger.yaml b/config/services/logger.yaml index 6925dd67..96401ec9 100644 --- a/config/services/logger.yaml +++ b/config/services/logger.yaml @@ -29,7 +29,7 @@ services: tags: - { name: monolog.logger, channel: cleverage_process } arguments: - - '@monolog.logger' + - '@logger' cleverage_process.logger.task_logger: class: CleverAge\ProcessBundle\Logger\TaskLogger @@ -37,4 +37,4 @@ services: tags: - { name: monolog.logger, channel: cleverage_process_task } arguments: - - '@monolog.logger' + - '@logger' From dafe5b3cee3d06d3d5a15897ecb257a2659ffbfb Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Tue, 3 Dec 2024 20:47:22 +0100 Subject: [PATCH 268/304] #145 add TrimTransformer documentation --- docs/index.md | 2 +- .../transformers/trim_transformer.md | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 docs/reference/transformers/trim_transformer.md diff --git a/docs/index.md b/docs/index.md index 76de1a95..6e1a4a42 100644 --- a/docs/index.md +++ b/docs/index.md @@ -123,7 +123,7 @@ - [ImplodeTransformer] - [SlugifyTransformer] - [SprintfTransformer] - - [TrimTransformer] + - [TrimTransformer](reference/transformers/trim_transformer.md) - XML - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) - Other bridges diff --git a/docs/reference/transformers/trim_transformer.md b/docs/reference/transformers/trim_transformer.md new file mode 100644 index 00000000..85a09053 --- /dev/null +++ b/docs/reference/transformers/trim_transformer.md @@ -0,0 +1,32 @@ +TrimTransformer +========================= + +Strip whitespace (or other characters) from the beginning and end of a string + +This transformer uses the php internal function: https://www.php.net/manual/en/function.trim.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\TrimTransformer` +* **Transformer code**: `trim` + +Accepted inputs +--------------- + +Any value that can be cast to string and null. + +Possible outputs +---------------- + +Depending on the input : +- `null` if the input is null +- `string` if the input is not null + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: |-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `charlist` | `string` | | ***" \t\n\r\0\x0B"*** | List of characters to trim | + From debeec069013a8ea873f1178b6cf013cf2372caf Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 12 Dec 2024 09:43:44 +0100 Subject: [PATCH 269/304] #145 Add/Update docs --- docs/index.md | 8 +- .../tasks/constant_iterable_output_task.md | 24 +-- docs/reference/tasks/constant_output_task.md | 24 +-- docs/reference/tasks/counter_task.md | 31 +--- docs/reference/tasks/csv_reader_task.md | 32 +++- docs/reference/tasks/debug_task.md | 29 ++-- docs/reference/tasks/die_task.md | 16 +- docs/reference/tasks/dummy_task.md | 50 +++--- docs/reference/tasks/error_forwarder_task.md | 25 +-- docs/reference/tasks/event_dispatcher_task.md | 18 +- docs/reference/tasks/input_csv_reader_task.md | 46 +++++ docs/reference/tasks/logger_task.md | 41 +++++ docs/reference/tasks/stopwatch_task.md | 21 ++- docs/reference/tasks/transformer_task.md | 17 +- .../transformers/implode_transformer.md | 38 +++++ .../transformers/mapping_transformer.md | 157 ++++++++---------- .../transformers/rules_transformer.md | 64 +++---- .../transformers/slugify_transformer.md | 39 +++++ 18 files changed, 410 insertions(+), 270 deletions(-) create mode 100644 docs/reference/tasks/input_csv_reader_task.md create mode 100644 docs/reference/tasks/logger_task.md create mode 100644 docs/reference/transformers/implode_transformer.md create mode 100644 docs/reference/transformers/slugify_transformer.md diff --git a/docs/index.md b/docs/index.md index 6e1a4a42..96f54c07 100644 --- a/docs/index.md +++ b/docs/index.md @@ -44,7 +44,7 @@ - [CsvReaderTask](reference/tasks/csv_reader_task.md) - [CsvWriterTask](reference/tasks/csv_writer_task.md) - [CSVSplitterTask] - - [InputCsvReaderTask] + - [InputCsvReaderTask](reference/tasks/input_csv_reader_task.md) - File/JsonStream - [JsonStreamReaderTask] - File/XML @@ -79,7 +79,7 @@ - [ProcessLauncherTask] - Reporting - [AdvancedStatCounterTask] - - [LoggerTask] + - [LoggerTask](reference/tasks/logger_task.md) - [StatCounterTask] - Transformers - Basic and debug @@ -120,8 +120,8 @@ - String - [ExplodeTransformer] - [HashTransformer] - - [ImplodeTransformer] - - [SlugifyTransformer] + - [ImplodeTransformer](reference/transformers/implode_transformer.md) + - [SlugifyTransformer](reference/transformers/slugify_transformer.md) - [SprintfTransformer] - [TrimTransformer](reference/transformers/trim_transformer.md) - XML diff --git a/docs/reference/tasks/constant_iterable_output_task.md b/docs/reference/tasks/constant_iterable_output_task.md index ba3f6410..30b04829 100644 --- a/docs/reference/tasks/constant_iterable_output_task.md +++ b/docs/reference/tasks/constant_iterable_output_task.md @@ -29,18 +29,12 @@ Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.constant_iterable_output_example: - tasks: - constant_iterable_output_example: - service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' - options: - output: - id: 123 - firstname: Test1 - lastname: Test2 - outputs: [debug] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 +``` diff --git a/docs/reference/tasks/constant_output_task.md b/docs/reference/tasks/constant_output_task.md index 03fd41c3..ed2f042f 100644 --- a/docs/reference/tasks/constant_output_task.md +++ b/docs/reference/tasks/constant_output_task.md @@ -29,18 +29,12 @@ Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.constant_output_example: - tasks: - constant_output_example: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: - id: 123 - firstname: Test1 - lastname: Test2 - outputs: [debug] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 +``` diff --git a/docs/reference/tasks/counter_task.md b/docs/reference/tasks/counter_task.md index 997c8af7..455539e4 100644 --- a/docs/reference/tasks/counter_task.md +++ b/docs/reference/tasks/counter_task.md @@ -13,7 +13,7 @@ Task reference Accepted inputs --------------- -`any` +`any`, must implement IterableTaskInterface Possible outputs ---------------- @@ -31,26 +31,9 @@ Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.counter_example: - tasks: - counter_example: - service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' - options: - output: - test1: test1 - test2: test2 - test3: test3 - test4: test4 - test5: test5 - test6: test6 - outputs: [counter] - counter: - service: '@CleverAge\ProcessBundle\Task\CounterTask' - options: - flush_every: 2 - outputs: [ debug ] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\CounterTask' + options: + flush_every: 2 +``` diff --git a/docs/reference/tasks/csv_reader_task.md b/docs/reference/tasks/csv_reader_task.md index b5df5a40..0e7b4c3a 100644 --- a/docs/reference/tasks/csv_reader_task.md +++ b/docs/reference/tasks/csv_reader_task.md @@ -23,12 +23,26 @@ Underlying method is [fgetcsv](https://secure.php.net/manual/en/function.fgetcsv Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `file_path` | `string` | **X** | | Path of the file to read from (relative to symfony root or absolute) | -| `delimiter` | `string` | | `;` | CSV delimiter | -| `enclosure` | `string` | | `"` | CSV enclosure character | -| `escape` | `string` | | `\\` | CSV escape character | -| `headers` | `array` or `null` | | `null` | Static list of CSV headers, without the option, it will be dynamically read from first input | -| `mode` | `string` | | `rb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | -| `log_empty_lines` | `bool` | | `false` | Log when the output is empty | +| Code | Type | Required | Default | Description | +|-------------------|-------------------|:---------:|----------|--------------------------------------------------------------------------------------------------| +| `file_path` | `string` | **X** | | Path of the file to read from (relative to symfony root or absolute) | +| `delimiter` | `string` | | `;` | CSV delimiter | +| `enclosure` | `string` | | `"` | CSV enclosure character | +| `escape` | `string` | | `\\` | CSV escape character | +| `headers` | `array` or `null` | | `null` | Static list of CSV headers, without the option, it will be dynamically read from first input | +| `mode` | `string` | | `rb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | +| `log_empty_lines` | `bool` | | `false` | Log when the output is empty | + +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvReaderTask' + options: + file_path: 'path/to/file.csv' + delimiter: '{{ delimiter }}' ## delimiter is contextualized you must add -c delimiter:";" on console execute +``` + + diff --git a/docs/reference/tasks/debug_task.md b/docs/reference/tasks/debug_task.md index 5a654089..cfaf44d7 100644 --- a/docs/reference/tasks/debug_task.md +++ b/docs/reference/tasks/debug_task.md @@ -20,22 +20,21 @@ Possible outputs `any`: re-output given input +Options +------- + +None + Example ---------------- ```yaml -clever_age_process: - configurations: - project_prefix.debug_example: - tasks: - debug_example: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: - id: 123 - firstname: Test1 - lastname: Test2 - outputs: [debug] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 +``` diff --git a/docs/reference/tasks/die_task.md b/docs/reference/tasks/die_task.md index 24008f4d..741fdeed 100644 --- a/docs/reference/tasks/die_task.md +++ b/docs/reference/tasks/die_task.md @@ -19,14 +19,16 @@ Possible outputs None +Options +------- + +None + Example ---------------- ```yaml -clever_age_process: - configurations: - project_prefix.die_example: - tasks: - die_example: - service: '@CleverAge\ProcessBundle\Task\Debug\DieTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\Debug\DieTask' +``` diff --git a/docs/reference/tasks/dummy_task.md b/docs/reference/tasks/dummy_task.md index 87fda52e..323cafc5 100644 --- a/docs/reference/tasks/dummy_task.md +++ b/docs/reference/tasks/dummy_task.md @@ -18,33 +18,31 @@ Possible outputs `any`: re-output given input +Options +------- + +None + Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.dummy_example: - tasks: - dummy_example: - service: '@CleverAge\ProcessBundle\Task\DummyTask' - outputs: [output1, output2] - output1: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: - id: 123 - firstname: Test1 - lastname: Test2 - outputs: [debug] - output2: - service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' - options: - output: - id: 456 - firstname: Test3 - lastname: Test4 - outputs: [ debug ] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +dummy: + service: '@CleverAge\ProcessBundle\Task\DummyTask' + outputs: [output1, output2] +output1: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 123 + firstname: Test1 + lastname: Test2 +output2: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: + id: 456 + firstname: Test3 + lastname: Test4 +``` diff --git a/docs/reference/tasks/error_forwarder_task.md b/docs/reference/tasks/error_forwarder_task.md index df129aa3..592c9cb2 100644 --- a/docs/reference/tasks/error_forwarder_task.md +++ b/docs/reference/tasks/error_forwarder_task.md @@ -20,23 +20,16 @@ Possible outputs `any`: directly error_output given `output` option +Options +------- + +None + Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.error_forwarder_example: - tasks: - error_forwarder_example: - service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' - options: - output: - error1: Error 1 - error2: Error 2 - error3: Error 3 - outputs: [error_forwarder] - error_forwarder: - service: '@CleverAge\ProcessBundle\Task\Debug\ErrorForwarderTask' - -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\Debug\ErrorForwarderTask' +``` diff --git a/docs/reference/tasks/event_dispatcher_task.md b/docs/reference/tasks/event_dispatcher_task.md index 1a2d17b7..88c87e98 100644 --- a/docs/reference/tasks/event_dispatcher_task.md +++ b/docs/reference/tasks/event_dispatcher_task.md @@ -31,15 +31,9 @@ Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.event_dispatcher_example: - tasks: - event_dispatcher_example: - service: '@CleverAge\ProcessBundle\Task\Event\EventDispatcherTask' - options: - event_name: 'myapp.myevent' - outputs: [debug] - debug: - service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\Event\EventDispatcherTask' + options: + event_name: 'myapp.myevent' +``` diff --git a/docs/reference/tasks/input_csv_reader_task.md b/docs/reference/tasks/input_csv_reader_task.md new file mode 100644 index 00000000..59e67d2a --- /dev/null +++ b/docs/reference/tasks/input_csv_reader_task.md @@ -0,0 +1,46 @@ +InputCsvReaderTask +============= + +Reads a CSV file and iterate on each line, returning an array of key -> values. Skips empty lines. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\Csv\InputCsvReaderTask` +* **Iterable task** + +Accepted inputs +--------------- + +`string`: file path + +Possible outputs +---------------- + +`array`: foreach line, it will return a php array where key comes from headers and values are strings. +Underlying method is [fgetcsv](https://secure.php.net/manual/en/function.fgetcsv.php). + +Options +------- + +Same as [CsvReaderTask](reference/tasks/csv_reader_task.md) except following : + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|----------------------------| +| `file_path` | | | | Removed, use input instead | +| `base_path` | `string` | | `` | | + +Example +------- + +```yaml +clever_age_process: + configurations: + process.name: + entry_point: entrypoint # for upload_and_run process entry_point is required + tasks: + entrypoint: + service: '@CleverAge\ProcessBundle\Task\File\Csv\InputCsvReaderTask' + options: + delimiter: '{{ delimiter }}' ## delimiter is contextualized you must add -c delimiter:";" on console execute +``` diff --git a/docs/reference/tasks/logger_task.md b/docs/reference/tasks/logger_task.md new file mode 100644 index 00000000..ffcc51ac --- /dev/null +++ b/docs/reference/tasks/logger_task.md @@ -0,0 +1,41 @@ +LoggerTask +============= + +Log a specific message with context. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\Reporting\LoggerTask` + +Accepted inputs +--------------- + +`any` + +Possible outputs +---------------- + +`any` : forwarded input + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|--------------------|:---------:|-------------------|---------------------------------| +| `level` | `string` | **X** | `debug` | Use `Psr\Log\LogLevel` values | +| `message` | `string` | | `Log state input` | | +| `context` | `array` | | `['input']` | | +| `reference` | `string` or `null` | | `null` | Override `context['reference']` | + +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\Reporting\LoggerTask' + options: + level: warning + message: DEMO LOGGER +``` diff --git a/docs/reference/tasks/stopwatch_task.md b/docs/reference/tasks/stopwatch_task.md index f7ee724f..4953239b 100644 --- a/docs/reference/tasks/stopwatch_task.md +++ b/docs/reference/tasks/stopwatch_task.md @@ -13,14 +13,21 @@ Accepted inputs `any` +Possible outputs +---------------- + +None + +Options +------- + +None + Example ------- ```yaml -clever_age_process: - configurations: - project_prefix.stopwatch_example: - tasks: - stopwatch_example: - service: '@CleverAge\ProcessBundle\Task\Debug\StopwatchTask' -``` \ No newline at end of file +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\Debug\StopwatchTask' +``` diff --git a/docs/reference/tasks/transformer_task.md b/docs/reference/tasks/transformer_task.md index 4a8b5b21..efc98bcd 100644 --- a/docs/reference/tasks/transformer_task.md +++ b/docs/reference/tasks/transformer_task.md @@ -23,7 +23,18 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `transformers` | `array` | **X** | | List of transformers, see [TransformerTrait](../traits/transformer_trait.md) | +| Code | Type | Required | Default | Description | +|----------------|---------|:---------:|----------|------------------------------------------------------------------------------| +| `transformers` | `array` | **X** | | List of transformers, see [TransformerTrait](../traits/transformer_trait.md) | +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + slugify: ~ +``` diff --git a/docs/reference/transformers/implode_transformer.md b/docs/reference/transformers/implode_transformer.md new file mode 100644 index 00000000..dad93ac2 --- /dev/null +++ b/docs/reference/transformers/implode_transformer.md @@ -0,0 +1,38 @@ +ImplodeTransformer +========================= + +Join array elements with a string + +This transformer uses the php internal function: https://www.php.net/manual/en/function.implode.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\ImplodeTransformer` +* **Transformer code**: `implode` + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|-------------| +| `separator` | `string` | **X** | `|` | | + +Examples +-------- + +```yaml +# Transformer options level +implode: + separator: '-' +``` diff --git a/docs/reference/transformers/mapping_transformer.md b/docs/reference/transformers/mapping_transformer.md index 9830542d..4971f66b 100644 --- a/docs/reference/transformers/mapping_transformer.md +++ b/docs/reference/transformers/mapping_transformer.md @@ -29,23 +29,23 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `mapping` | `array` | **X** | | List of property => sub-mapping options. The property code can be a single string to be used as an array index, or a writable property path | -| `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for the whole mapping | -| `keep_input` | `bool` | | `false` | Use input as the mapping destination (takes precedence on `initial_value`). Keep in mind that due to PHP behavior, arrays are cloned while objects are passed by reference | -| `initial_value` | `any` | | `[]` | Set the mapping destination | -| `merge_callback` | `callable` or `null` | | `null` | Allow to change how a property can be set in the destination | +| Code | Type | Required | Default | Description | +|------------------|----------------------|:---------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `mapping` | `array` | **X** | | List of property => sub-mapping options. The property code can be a single string to be used as an array index, or a writable property path | +| `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for the whole mapping | +| `keep_input` | `bool` | | `false` | Use input as the mapping destination (takes precedence on `initial_value`). Keep in mind that due to PHP behavior, arrays are cloned while objects are passed by reference | +| `initial_value` | `any` | | `[]` | Set the mapping destination | +| `merge_callback` | `callable` or `null` | | `null` | Allow to change how a property can be set in the destination | Foreach property there is the following options. -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `code` | `string` or `array` or `null` | | `null` | A property path, or a list of property path. By default it would be the same as the destination property. Will be used as a source. The special value '.' access the whole object. | -| `constant` | `any` | | `null` | If not `null`, will be directly used as a source (takes precedence on `code`) | -| `set_null` | `bool` | | `false` | If `true`, `null` will be directly used as a source (takes precedence on `code`) | -| `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for this source | -| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | +| Code | Type | Required | Default | Description | +|------------------|-------------------------------|:---------:|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `code` | `string` or `array` or `null` | | `null` | A property path, or a list of property path. By default it would be the same as the destination property. Will be used as a source. The special value '.' access the whole object. | +| `constant` | `any` | | `null` | If not `null`, will be directly used as a source (takes precedence on `code`) | +| `set_null` | `bool` | | `false` | If `true`, `null` will be directly used as a source (takes precedence on `code`) | +| `ignore_missing` | `bool` | | `false` | Ignore property accessor errors for this source | +| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | Examples -------- @@ -55,43 +55,39 @@ Examples - output: an array with keys "code", "label", "type", "reference", "required" and "slug" ```yaml -transform_data: # Task level - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - mapping: - mapping: - code: # Simple mapping from "Code" to "code" - code: '[Code]' - "[label]": ~ # Value from "label" will be kept with the same name - type: # Get value from "type" and map values (with a default) - code: '[Type]' - transformers: - convert_value: - ignore_missing: true - map: - TEXTE: text - NUMERIQUE: number - LISTE_DEROULANTE: simpleselect - CHOIX_MULTIPLES: multiselect - DATE: date - default: - value: unknown - reference: # "null" column - set_null: true - required: # "true" column - constant: true - slug: # Get multiple sources, slugify them, and merge them - code: - name: '[Name]' - id: '[ID]' - transformers: - array_map: - transformers: - slugify: ~ - implode: - separator: '_' - outputs: [next_task] +# Transformer options level +mapping: + mapping: + code: # Simple mapping from "Code" to "code" + code: '[Code]' + "[label]": ~ # Value from "label" will be kept with the same name + type: # Get value from "type" and map values (with a default) + code: '[Type]' + transformers: + convert_value: + ignore_missing: true + map: + TEXTE: text + NUMERIQUE: number + LISTE_DEROULANTE: simpleselect + CHOIX_MULTIPLES: multiselect + DATE: date + default: + value: unknown + reference: # "null" column + set_null: true + required: # "true" column + constant: true + slug: # Get multiple sources, slugify them, and merge them + code: + name: '[Name]' + id: '[ID]' + transformers: + array_map: + transformers: + slugify: ~ + implode: + separator: '_' ``` * Mapping in depth, using objects @@ -99,23 +95,18 @@ transform_data: # T - output: an array with key "items", containing a list of array with key "name" ```yaml -transform_data: # Task level - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: # TransformerTask options - mapping: # Transformer code - mapping: # MappingTransformer options - items: # property code - code: 'productItems' # property options - transformers: # property options - array_map: # Transformer code - transformers: # ArrayMapTransformer options - mapping: # Transformer code - mapping: # MappingTransformer options - name: # property code - code: 'longName' # property options - - outputs: [next_task] +# Transformer options level +mapping: # Transformer code + mapping: # MappingTransformer options + items: # property code + code: 'productItems' # property options + transformers: + array_map: # Transformer code + transformers: # ArrayMapTransformer options + mapping: # Transformer code + mapping: # MappingTransformer options + name: # property code + code: 'longName' # property options ``` * Advanced property setter @@ -123,21 +114,17 @@ transform_data: # Ta - output: same object, with a modified "address.customer.hasFlag" ```yaml -transform_data: # Task level - service: '@CleverAge\ProcessBundle\Task\TransformerTask' - options: - transformers: - mapping: - keep_input: true - mapping: - address.customer.hasFlag: - code: address.postCode - transformers: - convert_value: - ignore_missing: true - map: - 69005: true - default: - value: false - outputs: [next_task] +# Transformer options level +mapping: + keep_input: true + mapping: + address.customer.hasFlag: + code: address.postCode + transformers: + convert_value: + ignore_missing: true + map: + 69005: true + default: + value: false ``` diff --git a/docs/reference/transformers/rules_transformer.md b/docs/reference/transformers/rules_transformer.md index fd65827a..71ecc40d 100644 --- a/docs/reference/transformers/rules_transformer.md +++ b/docs/reference/transformers/rules_transformer.md @@ -34,21 +34,21 @@ Without any matching rules, the value itself is returned. Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `rules_set` | `array` | **X** | | Ordered list of rules, see bellow for details | -| `use_value_as_variables` | `bool` | | `false` | Use given value as an array of variable to inject in expression | -| `expression_variables` | `array` or `null` | | `[value]` | Name of variables injected in the expression at initialization time | +| Code | Type | Required | Default | Description | +|--------------------------|-------------------|:--------:|-----------|---------------------------------------------------------------------| +| `rules_set` | `array` | **X** | | Ordered list of rules, see bellow for details | +| `use_value_as_variables` | `bool` | | `false` | Use given value as an array of variable to inject in expression | +| `expression_variables` | `array` or `null` | | `[value]` | Name of variables injected in the expression at initialization time | Foreach rule there is the following options. -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `condition` | `string` or `null` | | `null` | An expression used to match a value | -| `default` | `bool` | | `false` | Mark this rule as a default rule. The given rule must be the last, cannot have a condition, and there cannot have 2 default in the same time | -| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | -| `constant` | `any` | | `null` | If not `null`, given value will be directly output (takes precedence on `transformers`) | -| `set_null` | `bool` | | `false` | If `true`, `null` will be directly output (takes precedence on `constant`) | +| Code | Type | Required | Default | Description | +|----------------|--------------------|:---------:|---------|----------------------------------------------------------------------------------------------------------------------------------------------| +| `condition` | `string` or `null` | | `null` | An expression used to match a value | +| `default` | `bool` | | `false` | Mark this rule as a default rule. The given rule must be the last, cannot have a condition, and there cannot have 2 default in the same time | +| `transformers` | `array` | | `[]` | List of sub-transformers, see [TransformerTrait](../traits/transformer_trait.md) | +| `constant` | `any` | | `null` | If not `null`, given value will be directly output (takes precedence on `transformers`) | +| `set_null` | `bool` | | `false` | If `true`, `null` will be directly output (takes precedence on `constant`) | Examples -------- @@ -60,15 +60,15 @@ Examples ```yaml # Transformer options level rules: - rules_set: - - condition: 'value["order"].origin === "marketplace"' - transformers: - property_accessor: - property_path: '[customer].id' - - condition: 'value["order"].origin === "e-commerce"' - constant: 1234 - - default: true - set_null: true + rules_set: + - condition: 'value["order"].origin === "marketplace"' + transformers: + property_accessor: + property_path: '[customer].id' + - condition: 'value["order"].origin === "e-commerce"' + constant: 1234 + - default: true + set_null: true ``` * Use value as variables @@ -79,15 +79,15 @@ rules: ```yaml # Transformer options level rules: - use_value_as_variables: true - expression_variables: [order, customer] - rules_set: - - condition: 'order.origin === "marketplace"' - transformers: - property_accessor: - property_path: '[customer].id' - - condition: 'order.origin === "e-commerce"' - constant: 1234 - - default: true - set_null: true + use_value_as_variables: true + expression_variables: [order, customer] + rules_set: + - condition: 'order.origin === "marketplace"' + transformers: + property_accessor: + property_path: '[customer].id' + - condition: 'order.origin === "e-commerce"' + constant: 1234 + - default: true + set_null: true ``` diff --git a/docs/reference/transformers/slugify_transformer.md b/docs/reference/transformers/slugify_transformer.md new file mode 100644 index 00000000..cadab337 --- /dev/null +++ b/docs/reference/transformers/slugify_transformer.md @@ -0,0 +1,39 @@ +SlugifyTransformer +========================= + +Strip whitespace (or other characters) from the beginning and end of a string + +This transformer uses the php internal function: https://www.php.net/manual/en/class.transliterator.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\SlugifyTransformer` +* **Transformer code**: `slugify` + +Accepted inputs +--------------- + +Any value that can be cast to string. + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +|------------------|----------|:---------:|----------------------------------------|--------------------------------| +| `transliterator` | `string` | | `NFD; [:Nonspacing Mark:] Remove; NFC` | Used to create \Transliterator | +| `replace` | `string` | | `/[^a-z0-9]+/` | Used on preg_replace | +| `separator` | `string` | | `_` | Used on preg_replace | + +Examples +-------- + +```yaml +# Transformer options level +slugify: ~ +``` From c8ceda66c0a30d736ea95485f345a2a0b78a8455 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 13 Dec 2024 11:24:41 +0100 Subject: [PATCH 270/304] Replace deprecated phpstan option checkGenericClassInNonGenericObjectType by identifier: missingType.generics. Fix code. --- phpstan.neon | 2 +- src/Filesystem/CsvResource.php | 6 ------ src/Transformer/CachedTransformer.php | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index e374f1ba..f0560a73 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -14,7 +14,7 @@ parameters: - '#process\(\) has no return type specified#' - '#should return Iterator but returns Traversable#' - '#Negated boolean expression is always false#' - checkGenericClassInNonGenericObjectType: false + - identifier: missingType.generics reportUnmatchedIgnoredErrors: false inferPrivatePropertyTypeFromConstructor: true treatPhpDocTypesAsCertain: false diff --git a/src/Filesystem/CsvResource.php b/src/Filesystem/CsvResource.php index 97dc8b83..3c536dca 100644 --- a/src/Filesystem/CsvResource.php +++ b/src/Filesystem/CsvResource.php @@ -13,8 +13,6 @@ namespace CleverAge\ProcessBundle\Filesystem; -use function count; - /** * Read and write CSV resources through a simple API. */ @@ -303,10 +301,6 @@ protected function parseHeaders(?array $headers = null): array $this->manualHeaders = true; - if (!\is_array($headers)) { - throw new \UnexpectedValueException("Invalid headers for {$this->getResourceName()}, you need to pass the headers manually"); - } - if ([] === $headers) { throw new \UnexpectedValueException("Empty headers for {$this->getResourceName()}, you need to pass the headers manually"); } diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 53439e21..5fff4923 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -65,7 +65,7 @@ function (Options $options, $value) { public function transform(mixed $value, array $options = []): mixed { $cacheKey = $this->generateCacheKey($options['cache_key'], $value, $options); - if ($cacheKey && $this->cache instanceof CacheItemPoolInterface) { + if ($cacheKey) { try { $cacheItem = $this->cache->getItem($cacheKey); if ($cacheItem->isHit()) { From 0d2cc03be09915023ad5ee44375f2bfccd4bf254 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Mon, 16 Dec 2024 14:37:13 +0100 Subject: [PATCH 271/304] #115 Add BC break for new mandatory configuration `default_error_strategy` on `clever_age_process` level --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea673379..7ae40b24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ v4.0 * [#148](https://github.com/cleverage/process-bundle/issues/148) Update services (step 1) according to Symfony best practices. Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_process` * [#150](https://github.com/cleverage/process-bundle/issues/150) The class `\CleverAge\ProcessBundle\Task\Debug\MemInfoDumpTask` has been deleted without suggested replacement +* [#115](https://github.com/cleverage/process-bundle/issues/115) New mandatory configuration `default_error_strategy` on `clever_age_process` level. See [Quick Start/Global configuration](docs/01-quick_start.md#global-configuration) ### Changes * [#139](https://github.com/cleverage/process-bundle/issues/139) Update Makefile & .docker for local standalone usage From 7ddb637ef9cae6add724f3eebc789a4934eae36f Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 20 Dec 2024 18:29:02 +0100 Subject: [PATCH 272/304] #155 Implement InputFileReaderTask, InputLineReaderTask and LineReaderTask --- src/Task/File/InputFileReaderTask.php | 31 ++++++++++++++ src/Task/File/InputLineReaderTask.php | 32 ++++++++++++++ src/Task/File/LineReaderTask.php | 62 +++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 src/Task/File/InputFileReaderTask.php create mode 100644 src/Task/File/InputLineReaderTask.php create mode 100644 src/Task/File/LineReaderTask.php diff --git a/src/Task/File/InputFileReaderTask.php b/src/Task/File/InputFileReaderTask.php new file mode 100644 index 00000000..06c41812 --- /dev/null +++ b/src/Task/File/InputFileReaderTask.php @@ -0,0 +1,31 @@ +getInput()) { + $options['filename'] = $state->getInput(); + } + + return $options; + } + + protected function configureOptions(OptionsResolver $resolver): void + { + parent::configureOptions($resolver); + $resolver->remove('filename'); + } +} diff --git a/src/Task/File/InputLineReaderTask.php b/src/Task/File/InputLineReaderTask.php new file mode 100644 index 00000000..ce6c0feb --- /dev/null +++ b/src/Task/File/InputLineReaderTask.php @@ -0,0 +1,32 @@ +getInput()) { + $options['filename'] = $state->getInput(); + } + + return $options; + } + + protected function configureOptions(OptionsResolver $resolver): void + { + parent::configureOptions($resolver); + $resolver->remove('filename'); + } +} diff --git a/src/Task/File/LineReaderTask.php b/src/Task/File/LineReaderTask.php new file mode 100644 index 00000000..6942b9c3 --- /dev/null +++ b/src/Task/File/LineReaderTask.php @@ -0,0 +1,62 @@ +getOptions($state); + $filename = $options['filename']; + + if ($this->file instanceof \SplFileObject + && $this->file->getPathname() !== $filename) { + $this->file = null; + } + + if (!$this->file instanceof \SplFileObject) { + if (!file_exists($filename)) { + throw new \UnexpectedValueException("File does not exist: '{$filename}'"); + } + + if (!is_readable($filename)) { + throw new \UnexpectedValueException("File is not readable: '{$filename}'"); + } + + $this->file = new \SplFileObject($filename); + $this->file->setFlags(\SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); + $this->file->rewind(); + } + + $state->setOutput($this->file->current()); + $this->file->next(); + } + + public function next(ProcessState $state): bool + { + if (!$this->file instanceof \SplFileObject) { + throw new \LogicException('No File initialized'); + } + + return !$this->file->eof(); + } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired(['filename']); + $resolver->setAllowedTypes('filename', ['string']); + } +} From 52a3f31237d823e5c91100bf2ac7e155d1b63139 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 2 Jan 2025 15:51:14 +0100 Subject: [PATCH 273/304] #155 Add docs for [Input][FileReader|LineReader|FolderBrowser]Tasks --- docs/index.md | 9 ++-- docs/reference/tasks/file_reader_task.md | 40 ++++++++++++++++ docs/reference/tasks/folder_browser_task.md | 43 +++++++++++++++++ .../reference/tasks/input_file_reader_task.md | 41 ++++++++++++++++ .../tasks/input_folder_browser_task.md | 47 +++++++++++++++++++ .../reference/tasks/input_line_reader_task.md | 42 +++++++++++++++++ docs/reference/tasks/line_reader_task.md | 41 ++++++++++++++++ 7 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 docs/reference/tasks/file_reader_task.md create mode 100644 docs/reference/tasks/folder_browser_task.md create mode 100644 docs/reference/tasks/input_file_reader_task.md create mode 100644 docs/reference/tasks/input_folder_browser_task.md create mode 100644 docs/reference/tasks/input_line_reader_task.md create mode 100644 docs/reference/tasks/line_reader_task.md diff --git a/docs/index.md b/docs/index.md index 96f54c07..3a469759 100644 --- a/docs/index.md +++ b/docs/index.md @@ -55,11 +55,14 @@ - [YamlWriterTask] - File - [FileMoverTask] - - [FileReaderTask] + - [FileReaderTask](reference/tasks/file_reader_task.md) - [FileRemoverTask] - [FileWriterTask] - - [FolderBrowserTask] - - [InputFolderBrowserTask] + - [FolderBrowserTask](reference/tasks/folder_browser_task.md) + - [InputFileReaderTask](reference/tasks/input_file_reader_task.md) + - [InputFolderBrowserTask](reference/tasks/input_folder_browser_task.md) + - [InputLineReaderTask](reference/tasks/input_line_reader_task.md) + - [LineReaderTask](reference/tasks/line_reader_task.md) - Flow manipulation - [AggregateIterableTask](reference/tasks/aggregate_iterable_task.md) - [InputAggregatorTask](reference/tasks/input_aggregator_task.md) diff --git a/docs/reference/tasks/file_reader_task.md b/docs/reference/tasks/file_reader_task.md new file mode 100644 index 00000000..e0097a13 --- /dev/null +++ b/docs/reference/tasks/file_reader_task.md @@ -0,0 +1,40 @@ +FileReaderTask +============= + +Reads a file and return raw content as a string + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FileReaderTask` + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +`string`: raw content of the file. +Underlying method is [file_get_contents](https://www.php.net/manual/en/function.file-get-contents.php). + +Options +------- + +| Code | Type | Required | Default | Description | +|------------|----------|:---------:|----------|------------------------------------------| +| `filename` | `string` | **X** | | Path of the file to read from (absolute) | + +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\File\FileReaderTask' + options: + filename: 'path/to/file.txt' +``` + + diff --git a/docs/reference/tasks/folder_browser_task.md b/docs/reference/tasks/folder_browser_task.md new file mode 100644 index 00000000..003c3e7b --- /dev/null +++ b/docs/reference/tasks/folder_browser_task.md @@ -0,0 +1,43 @@ +FolderBrowserTask +============= + +Reads a folder and iterate on each file, returning absolute path as string. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FolderBrowserTask` +* **Iterable task** + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +`string`: absolute path of the file. +Underlying method is [Symfony Finder component](https://symfony.com/doc/current/components/finder.html). + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------|-------------------------------|:---------:|---------------------------|------------------------------------| +| `folder_path` | `string` | **X** | | Path of the directory to read from | +| `name_pattern` | `null` or `string` or `array` | | null | Restrict files using a pattern | +| `empty_log_level` | `string` | | Psr\Log\LogLevel::WARNING | From Psr\Log\LogLevel constants | + +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\File\FolderBrowserTask' + options: + folder_path: '%kernel.project_dir%/var/data' +``` + + diff --git a/docs/reference/tasks/input_file_reader_task.md b/docs/reference/tasks/input_file_reader_task.md new file mode 100644 index 00000000..d960ba21 --- /dev/null +++ b/docs/reference/tasks/input_file_reader_task.md @@ -0,0 +1,41 @@ +InputFileReaderTask +============= + +Reads a file and return raw content as a string + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\InputFileReaderTask` + +Accepted inputs +--------------- + +`string`: file path + +Possible outputs +---------------- + +`string`: raw content of the file. +Underlying method is [file_get_contents](https://www.php.net/manual/en/function.file-get-contents.php). + +Options +------- + +None + +Example +------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\File\FolderBrowserTask' + options: + folder_path: '%kernel.project_dir%/var/data' + outputs: read +read: + service: '@CleverAge\ProcessBundle\Task\File\InputFileReaderTask' +``` + + diff --git a/docs/reference/tasks/input_folder_browser_task.md b/docs/reference/tasks/input_folder_browser_task.md new file mode 100644 index 00000000..e95e2401 --- /dev/null +++ b/docs/reference/tasks/input_folder_browser_task.md @@ -0,0 +1,47 @@ +InputFolderBrowserTask +============= + +Reads a folder and iterate on each file, returning absolute path as string. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\InputFolderBrowserTask` +* **Iterable task** + +Accepted inputs +--------------- + +`string`: folder path + +Possible outputs +---------------- + +`string`: absolute path of the file. +Underlying method is [Symfony Finder component](https://symfony.com/doc/current/components/finder.html). + +Options +------- + +| Code | Type | Required | Default | Description | +|--------------------|----------|:---------:|---------|---------------------------------------| +| `base_folder_path` | `string` | | | Concatenated with input `folder_path` | + +Example +------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\ConstantOutputTask' + options: + output: '/var/data' + outputs: directory +directory: + service: '@CleverAge\ProcessBundle\Task\File\InputFolderBrowserTask' + options: + base_folder_path: '%kernel.project_dir%' + outputs: read +``` + + diff --git a/docs/reference/tasks/input_line_reader_task.md b/docs/reference/tasks/input_line_reader_task.md new file mode 100644 index 00000000..da185453 --- /dev/null +++ b/docs/reference/tasks/input_line_reader_task.md @@ -0,0 +1,42 @@ +InputLineReaderTask +============= + +Reads a file and iterate on each line, returning content as string. Skips empty lines. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\InputLineReaderTask` +* **Iterable task** + +Accepted inputs +--------------- + +`string`: file path + +Possible outputs +---------------- + +`string`: foreach line, it will return content as string. +Underlying method is [SplFileObject](https://www.php.net/manual/en/class.splfileobject.php). + +Options +------- + +None + +Example +------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\File\FolderBrowserTask' + options: + folder_path: '%kernel.project_dir%/var/data' + outputs: read +read: + service: '@CleverAge\ProcessBundle\Task\File\InputLineReaderTask' +``` + + diff --git a/docs/reference/tasks/line_reader_task.md b/docs/reference/tasks/line_reader_task.md new file mode 100644 index 00000000..8c5f2e4e --- /dev/null +++ b/docs/reference/tasks/line_reader_task.md @@ -0,0 +1,41 @@ +LineReaderTask +============= + +Reads a file and iterate on each line, returning content as string. Skips empty lines. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\LineReaderTask` +* **Iterable task** + +Accepted inputs +--------------- + +Input is ignored + +Possible outputs +---------------- + +`string`: foreach line, it will return content as string. +Underlying method is [SplFileObject](https://www.php.net/manual/en/class.splfileobject.php). + +Options +------- + +| Code | Type | Required | Default | Description | +|------------|----------|:---------:|----------|------------------------------------------| +| `filename` | `string` | **X** | | Path of the file to read from (absolute) | + +Example +------- + +```yaml +# Task configuration level +code: + service: '@CleverAge\ProcessBundle\Task\File\LineReaderTask' + options: + filename: 'path/to/file.txt' +``` + + From 10c27aa8f4b523b48b249c05fb612df3f579faaf Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 2 Jan 2025 15:58:16 +0100 Subject: [PATCH 274/304] #155 php-cs-fixer --- src/Task/File/InputFileReaderTask.php | 10 +++++++++- src/Task/File/InputLineReaderTask.php | 11 +++++++++-- src/Task/File/LineReaderTask.php | 10 +++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Task/File/InputFileReaderTask.php b/src/Task/File/InputFileReaderTask.php index 06c41812..5c638ff9 100644 --- a/src/Task/File/InputFileReaderTask.php +++ b/src/Task/File/InputFileReaderTask.php @@ -2,9 +2,17 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace CleverAge\ProcessBundle\Task\File; -use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/src/Task/File/InputLineReaderTask.php b/src/Task/File/InputLineReaderTask.php index ce6c0feb..6ae852b6 100644 --- a/src/Task/File/InputLineReaderTask.php +++ b/src/Task/File/InputLineReaderTask.php @@ -2,10 +2,17 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace CleverAge\ProcessBundle\Task\File; -use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; -use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/src/Task/File/LineReaderTask.php b/src/Task/File/LineReaderTask.php index 6942b9c3..da103ab0 100644 --- a/src/Task/File/LineReaderTask.php +++ b/src/Task/File/LineReaderTask.php @@ -2,9 +2,17 @@ declare(strict_types=1); +/* + * This file is part of the CleverAge/ProcessBundle package. + * + * Copyright (c) Clever-Age + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace CleverAge\ProcessBundle\Task\File; -use CleverAge\ProcessBundle\Filesystem\CsvFile; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; From bfb04af277e11f09df4439025ea64efd3e30043d Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 8 Jan 2025 15:54:27 +0100 Subject: [PATCH 275/304] #155 Update FolderBrowserTask doc for name_pattern --- docs/reference/tasks/folder_browser_task.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/reference/tasks/folder_browser_task.md b/docs/reference/tasks/folder_browser_task.md index 003c3e7b..3dcc44ef 100644 --- a/docs/reference/tasks/folder_browser_task.md +++ b/docs/reference/tasks/folder_browser_task.md @@ -23,11 +23,11 @@ Underlying method is [Symfony Finder component](https://symfony.com/doc/current/ Options ------- -| Code | Type | Required | Default | Description | -|-------------------|-------------------------------|:---------:|---------------------------|------------------------------------| -| `folder_path` | `string` | **X** | | Path of the directory to read from | -| `name_pattern` | `null` or `string` or `array` | | null | Restrict files using a pattern | -| `empty_log_level` | `string` | | Psr\Log\LogLevel::WARNING | From Psr\Log\LogLevel constants | +| Code | Type | Required | Default | Description | +|-------------------|-----------------------------|:---------:|---------------------------|----------------------------------------------------------------------------------------| +| `folder_path` | `string` | **X** | | Path of the directory to read from | +| `name_pattern` | `null`, `string` or `array` | | null | Restrict files using a pattern (a regexp, a glob, or a string) or an array of patterns | +| `empty_log_level` | `string` | | Psr\Log\LogLevel::WARNING | From Psr\Log\LogLevel constants | Example ------- From b520cdb07ff31aaeedbd6817ec96e4fce85d7c48 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Wed, 8 Jan 2025 16:16:49 +0100 Subject: [PATCH 276/304] Update changelog for 4.1.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae40b24..41ff4427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v4.1 +----- + +### Add +* [#155](https://github.com/cleverage/process-bundle/issues/155) Add InputFileReaderTask (Reads the whole input file and outputs its content), InputLineReaderTask (Reads an input file line by line and outputs each line.) and LineReaderTask (Reads a file line by line and outputs each line.) + v4.0 ------ From 45ec09f275ceae0f9e2e71a8055e5838b14a0390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tonon=20Gr=C3=A9gory?= Date: Fri, 21 Feb 2025 15:27:31 +0100 Subject: [PATCH 277/304] #158 Add dependency to symfony/service-contract --- composer.json | 3 ++- src/Model/AbstractConfigurableTask.php | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 5286b57a..37916dab 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,8 @@ "symfony/serializer": "^6.4|^7.1", "symfony/stopwatch": "^6.4|^7.1", "symfony/validator": "^6.4|^7.1", - "symfony/yaml": "^6.4|^7.1" + "symfony/yaml": "^6.4|^7.1", + "symfony/service-contracts": ">=1.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", diff --git a/src/Model/AbstractConfigurableTask.php b/src/Model/AbstractConfigurableTask.php index 149eae24..5228cec6 100644 --- a/src/Model/AbstractConfigurableTask.php +++ b/src/Model/AbstractConfigurableTask.php @@ -14,11 +14,12 @@ namespace CleverAge\ProcessBundle\Model; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\Service\ResetInterface; /** * Allow the task to configure it's options, set default basic options for errors handling. */ -abstract class AbstractConfigurableTask implements InitializableTaskInterface +abstract class AbstractConfigurableTask implements InitializableTaskInterface, ResetInterface { protected ?array $options = null; @@ -30,6 +31,11 @@ public function initialize(ProcessState $state): void $this->getOptions($state); } + public function reset(): void + { + $this->options = null; + } + protected function getOptions(ProcessState $state): ?array { if (null === $this->options) { From f513d6fbfb14454a2913b9f51502e3037c873133 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 27 Feb 2025 15:36:35 +0100 Subject: [PATCH 278/304] Prepare release v4.1.1 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41ff4427..89c70fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v4.1.1 +----- + +### Fixes + +* [#158](https://github.com/cleverage/process-bundle/issues/158) Add dependency to symfony/service-contract + v4.1 ----- From 24b12027a3e8585833c133d3a541ae8adb48c6b7 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 6 May 2025 15:18:58 +0200 Subject: [PATCH 279/304] cleverage/archive-process-bundle#1 Add new bridge ArchiveProcessBundle --- composer.json | 6 ++++++ docs/index.md | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 37916dab..c60d3300 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,11 @@ "email": "xmarchegay@clever-age.com", "homepage": "https://github.com/xaviermarchegay", "role": "Lead Developer" + }, + { + "name": "Nicolas Joubert", + "email": "njoubert@clever-age.com", + "role": "Lead Developer" } ], "autoload": { @@ -84,6 +89,7 @@ "symfony/test-pack": "^1.1" }, "suggest": { + "cleverage/archive-process-bundle": "Dedicated bundle for Archive dependencies for the Process Bundle", "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", diff --git a/docs/index.md b/docs/index.md index 3a469759..0157b55e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -130,9 +130,10 @@ - XML - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) - Other bridges + - [Archive](https://github.com/cleverage/archive-process-bundle) - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) - - [Soap](https://github.com/cleverage/soap-process-bundle) - - [Rest](https://github.com/cleverage/rest-process-bundle) - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) + - [Rest](https://github.com/cleverage/rest-process-bundle) + - [Soap](https://github.com/cleverage/soap-process-bundle) - [Generic transformers definition](reference/03-generic_transformers_definition.md) - [UI](https://github.com/cleverage/ui-process-bundle) From b4a80332b1a886475ff91fdfd19548b8550c6a02 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 18 Jun 2025 15:11:23 +0200 Subject: [PATCH 280/304] #162 Add timestamp placeholder on file_path parameter of CsvWriterTask. Improve documentation. --- docs/reference/tasks/csv_writer_task.md | 45 +++++++++++++++++++------ src/Task/File/Csv/CsvWriterTask.php | 1 + 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/docs/reference/tasks/csv_writer_task.md b/docs/reference/tasks/csv_writer_task.md index 96ac0f2b..0ff7e2ed 100644 --- a/docs/reference/tasks/csv_writer_task.md +++ b/docs/reference/tasks/csv_writer_task.md @@ -24,13 +24,38 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `file_path` | `string` | **X** | | Path of the file to write to (relative to symfony root or absolute). It can also take two placeholders (`{date}` and `{date_time}`) to insert timestamps into the filename | -| `delimiter` | `string` | | `;` | CSV delimiter | -| `enclosure` | `string` | | `"` | CSV enclosure character | -| `escape` | `string` | | `\\` | CSV escape character | -| `headers` | `array` or `null` | | `null` | Static list of CSV headers, without the option, it will be dynamically read from first line | -| `mode` | `string` | | `wb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | -| `split_character` | `string` | | `\|` | Used to implode array values | -| `write_headers` | `bool` | | `true` | Write the headers as a first line | +| Code | Type | Required | Default | Description | +|-------------------|-------------------|:--------:|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `file_path` | `string` | **X** | | Path of the file to write to (relative to symfony root or absolute).
    It can also take placeholders (`{date}`, `{date_time}`, `{timestamp}` `{unique_token}`) to insert data into the filename | +| `delimiter` | `string` | | `;` | CSV delimiter | +| `enclosure` | `string` | | `"` | CSV enclosure character | +| `escape` | `string` | | `\\` | CSV escape character | +| `headers` | `array` or `null` | | `null` | Static list of CSV headers, without the option, it will be dynamically read from first line | +| `mode` | `string` | | `wb` | File open mode (see [fopen mode parameter](https://secure.php.net/manual/en/function.fopen.php)) | +| `split_character` | `string` | | `\|` | Used to implode array values | +| `write_headers` | `bool` | | `true` | Write the headers as a first line | + +Example +---------------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + outputs: [ write ] + options: + output: + - column1: value1-1 + column2: value2-1 + column3: value3-1 + - column1: value1-2 + column2: value2-2 + column3: value3-2 + - column1: '' + column2: null + column3: value3-3 +write: + service: '@CleverAge\ProcessBundle\Task\File\Csv\CsvWriterTask' + options: + file_path: '%kernel.project_dir%/var/data/csv_writer_{date_time}.csv' +``` diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index d1145dec..e20532a6 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -59,6 +59,7 @@ protected function configureOptions(OptionsResolver $resolver): void [ '{date}' => date('Ymd'), '{date_time}' => date('Ymd_His'), + '{timestamp}' => time(), '{unique_token}' => uniqid('', true), ] ) From 393fca9037426818159762de5979564a45a463cd Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 19 Jun 2025 11:22:11 +0200 Subject: [PATCH 281/304] #164 Add cleverage/cache-process-bundle dependency --- composer.json | 1 + docs/index.md | 1 + 2 files changed, 2 insertions(+) diff --git a/composer.json b/composer.json index c60d3300..e6316520 100644 --- a/composer.json +++ b/composer.json @@ -90,6 +90,7 @@ }, "suggest": { "cleverage/archive-process-bundle": "Dedicated bundle for Archive dependencies for the Process Bundle", + "cleverage/cache-process-bundle": "Dedicated bundle for Cache dependencies for the Process Bundle", "cleverage/doctrine-process-bundle": "Dedicated bundle for Doctrine dependencies for the process bundle", "cleverage/soap-process-bundle": "Dedicated bundle for Soap dependencies for the process bundle", "cleverage/rest-process-bundle": "Dedicated bundle for Rest dependencies for the process bundle", diff --git a/docs/index.md b/docs/index.md index 0157b55e..47b626a0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -131,6 +131,7 @@ - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) - Other bridges - [Archive](https://github.com/cleverage/archive-process-bundle) + - [Cache](https://github.com/cleverage/cache-process-bundle) - [Doctrine](https://github.com/cleverage/doctrine-process-bundle) - [Flysystem](https://github.com/cleverage/flysystem-process-bundle) - [Rest](https://github.com/cleverage/rest-process-bundle) From d68c45bf9277b86f5af2f2031cdcb044c6963ccf Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 19 Jun 2025 17:30:59 +0200 Subject: [PATCH 282/304] Update CHANGELOG.md Prepare release v4.2 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c70fc3..26a44abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +v4.2 +----- + +### Add +* [#cleverage/archive-process-bundle#1](https://github.com/cleverage/archive-process-bundle/issues/1) Add new bridge ArchiveProcessBundle +* [#162](https://github.com/cleverage/process-bundle/issues/162) Add timestamp placeholder on file_path parameter of CsvWriterTask. Improve documentation. +* [#164](https://github.com/cleverage/process-bundle/issues/164) Add cleverage/cache-process-bundle dependency + v4.1.1 ----- From 90e2f7e936cbd8574302e253d3194a7b5e077332 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 20 Jun 2025 17:50:45 +0200 Subject: [PATCH 283/304] #166 Add PregMatchTransformer --- docs/index.md | 1 + .../transformers/preg_match_transformer.md | 53 +++++++++++++++++ .../String/PregMatchTransformer.php | 58 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 docs/reference/transformers/preg_match_transformer.md create mode 100644 src/Transformer/String/PregMatchTransformer.php diff --git a/docs/index.md b/docs/index.md index 47b626a0..de141792 100644 --- a/docs/index.md +++ b/docs/index.md @@ -124,6 +124,7 @@ - [ExplodeTransformer] - [HashTransformer] - [ImplodeTransformer](reference/transformers/implode_transformer.md) + - [PregMatchTransformer](reference/transformers/preg_match_transformer.md) - [SlugifyTransformer](reference/transformers/slugify_transformer.md) - [SprintfTransformer] - [TrimTransformer](reference/transformers/trim_transformer.md) diff --git a/docs/reference/transformers/preg_match_transformer.md b/docs/reference/transformers/preg_match_transformer.md new file mode 100644 index 00000000..83270645 --- /dev/null +++ b/docs/reference/transformers/preg_match_transformer.md @@ -0,0 +1,53 @@ +PregMatchTransformer +========================= + +Perform a regular expression match + +This transformer uses the php internal function: https://www.php.net/manual/en/function.preg-match.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\PregMatchTransformer` +* **Transformer code**: `preg_match` + +Accepted inputs +--------------- + +`string` + +Possible outputs +---------------- + +`array` or `null` + +Options +------- + +| Code | Type | Required | Default | Description | +|------------|-----------|:--------:|---------|------------------------------------------| +| `pattern` | `string` | **X** | | | +| `flags` | `int` | | 0 | | +| `offset` | `int` | | 0 | | +| `mode_all` | `boolean` | | false | Use preg_match_all instead of preg_match | + +Examples +-------- + +```yaml +# Transformer options level +entry: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + outputs: [ preg_match ] + options: + output: 'foobarbaz' +preg_match: + service: '@CleverAge\ProcessBundle\Task\TransformerTask' + options: + transformers: + preg_match: + pattern: '/(foo)(bar)(baz)/' + flags: !php/const PREG_OFFSET_CAPTURE + property_accessor: + property_path: '[2]' +``` diff --git a/src/Transformer/String/PregMatchTransformer.php b/src/Transformer/String/PregMatchTransformer.php new file mode 100644 index 00000000..143ba36b --- /dev/null +++ b/src/Transformer/String/PregMatchTransformer.php @@ -0,0 +1,58 @@ +setRequired(['pattern']); + $resolver->setAllowedTypes('pattern', ['string']); + $resolver->setDefault('flags', 0); + $resolver->setAllowedTypes('flags', ['int']); + $resolver->setDefault('offset', 0); + $resolver->setAllowedTypes('offset', ['int']); + $resolver->setDefault('mode_all', false); + $resolver->setAllowedTypes('mode_all', ['boolean']); + } +} From 1c97575ca30060a64a71eb36ebbac9590d1bb067 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 20 Jun 2025 17:57:00 +0200 Subject: [PATCH 284/304] Prepare release v4.3 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26a44abb..a395a717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v4.3 +----- + +### Add +* [#166](https://github.com/cleverage/process-bundle/issues/166) Add PregMatchTransformer + v4.2 ----- From b2fc5c1d83b0251cca1d5c75644738c0e5184fc9 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 8 Jul 2025 15:37:42 +0200 Subject: [PATCH 285/304] #168 Add JsonStreamWriterTask with related doc --- docs/index.md | 1 + .../tasks/json_stream_writer_task.md | 53 +++++++++++++++ .../File/JsonStream/JsonStreamWriterTask.php | 64 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 docs/reference/tasks/json_stream_writer_task.md create mode 100644 src/Task/File/JsonStream/JsonStreamWriterTask.php diff --git a/docs/index.md b/docs/index.md index de141792..aad5bbda 100644 --- a/docs/index.md +++ b/docs/index.md @@ -47,6 +47,7 @@ - [InputCsvReaderTask](reference/tasks/input_csv_reader_task.md) - File/JsonStream - [JsonStreamReaderTask] + - [JsonStreamWriterTask](reference/tasks/json_stream_writer_task.md) - File/XML - [XmlReaderTask](reference/tasks/xml_reader_task.md) - [XmlWriterTask](reference/tasks/xml_writer_task.md) diff --git a/docs/reference/tasks/json_stream_writer_task.md b/docs/reference/tasks/json_stream_writer_task.md new file mode 100644 index 00000000..79fd2e39 --- /dev/null +++ b/docs/reference/tasks/json_stream_writer_task.md @@ -0,0 +1,53 @@ +JsonStreamWriterTask +=============== + +Write given array to a json file, will wait until the end of the previous iteration (this is a blocking task) and outputs +the file path. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamWriterTask` +* **Blocking task** + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`string`: absolute path of the produced file + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------|----------|:--------:|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `file_path` | `string` | **X** | | Path of the file to write to (relative to symfony root or absolute).
    It can also take placeholders (`{date}`, `{date_time}`, `{timestamp}` `{unique_token}`) to insert data into the filename | + +Example +---------------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + outputs: [ write ] + options: + output: + - column1: value1-1 + column2: value2-1 + column3: value3-1 + - column1: value1-2 + column2: value2-2 + column3: value3-2 + - column1: '' + column2: null + column3: value3-3 +write: + service: '@CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamWriterTask' + options: + file_path: '%kernel.project_dir%/var/data/json_stream_writer_{date_time}.csv' +``` diff --git a/src/Task/File/JsonStream/JsonStreamWriterTask.php b/src/Task/File/JsonStream/JsonStreamWriterTask.php new file mode 100644 index 00000000..494cc0ed --- /dev/null +++ b/src/Task/File/JsonStream/JsonStreamWriterTask.php @@ -0,0 +1,64 @@ +getOptions($state); + if (!$this->file instanceof JsonStreamFile) { + $this->file = new JsonStreamFile($options['file_path'], 'wb'); + } + + $input = $state->getInput(); + if (!\is_array($input)) { + throw new \UnexpectedValueException('Input value is not an array'); + } + $this->file->writeLine($input); + } + + public function proceed(ProcessState $state): void + { + $options = $this->getOptions($state); + $state->setOutput($options['file_path']); + } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired(['file_path']); + $resolver->setAllowedTypes('file_path', ['string']); + $resolver->setNormalizer( + 'file_path', + static fn (Options $options, $value): string => strtr( + $value, + [ + '{date}' => date('Ymd'), + '{date_time}' => date('Ymd_His'), + '{timestamp}' => time(), + '{unique_token}' => uniqid('', true), + ] + ) + ); + } +} From dfbae4fa2a0b47179ea78dee30c546204414ed3a Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 8 Jul 2025 16:34:19 +0200 Subject: [PATCH 286/304] #169 Fix JsonStreamFile empty line at the end issue, even if SKIP_EMPTY is set. Add JsonStreamReaderTask doc. --- docs/index.md | 2 +- .../tasks/json_stream_reader_task.md | 43 +++++++++++++++++++ src/Filesystem/JsonStreamFile.php | 8 +++- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 docs/reference/tasks/json_stream_reader_task.md diff --git a/docs/index.md b/docs/index.md index aad5bbda..5e678dba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -46,7 +46,7 @@ - [CSVSplitterTask] - [InputCsvReaderTask](reference/tasks/input_csv_reader_task.md) - File/JsonStream - - [JsonStreamReaderTask] + - [JsonStreamReaderTask](reference/tasks/json_stream_reader_task.md) - [JsonStreamWriterTask](reference/tasks/json_stream_writer_task.md) - File/XML - [XmlReaderTask](reference/tasks/xml_reader_task.md) diff --git a/docs/reference/tasks/json_stream_reader_task.md b/docs/reference/tasks/json_stream_reader_task.md new file mode 100644 index 00000000..e48da640 --- /dev/null +++ b/docs/reference/tasks/json_stream_reader_task.md @@ -0,0 +1,43 @@ +JsonStreamReaderTask +============= + +Reads a json file and iterate on each line, returning decoded content as array. Skips empty lines. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamReaderTask` +* **Iterable task** + +Accepted inputs +--------------- + +`string`: Path of the file to read from (absolute) + +Possible outputs +---------------- + +`array`: foreach line, it will return content as array. +Underlying method are [SplFileObject::fgets](https://www.php.net/manual/fr/splfileobject.fgets.php) and [json_decode](https://www.php.net/manual/en/function.json-decode.php). + +Options +------- + +none + +Example +------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\ConstantIterableOutputTask' + outputs: read + options: + output: + file_path: '%kernel.project_dir%/var/data/json_stream_reader.json' +read: + service: '@CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamReaderTask' +``` + + diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index cd4359e0..6d4873b3 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -28,8 +28,8 @@ public function __construct(string $filename, string $mode = 'rb') { $this->file = new \SplFileObject($filename, $mode); - // Useful to skip empty trailing lines - $this->file->setFlags(\SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); + // Useful to skip empty trailing lines (doesn't work well on PHP 8, see readLine() code) + $this->file->setFlags(\SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); } /** @@ -72,6 +72,10 @@ public function readLine(?int $length = null): ?array } $rawLine = $this->file->fgets(); + // Fix issue on PHP 8 with empty line at the end, even if SKIP_EMPTY is set + if ('' === $rawLine) { + return null; + } ++$this->lineNumber; return json_decode($rawLine, true, 512, \JSON_THROW_ON_ERROR); From c0ec819d32847e05d1cc7377a22f836a59a8ba02 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 8 Jul 2025 18:16:03 +0200 Subject: [PATCH 287/304] #172 Add spl_file_object_flags and json_flags options on JsonStream*Tasks. Update docs. --- .../tasks/json_stream_reader_task.md | 10 +++++++- .../tasks/json_stream_writer_task.md | 12 +++++++--- src/Filesystem/JsonStreamFile.php | 24 +++++++++++++++---- .../File/JsonStream/JsonStreamReaderTask.php | 22 +++++++++++++++-- .../File/JsonStream/JsonStreamWriterTask.php | 15 ++++++++++-- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/docs/reference/tasks/json_stream_reader_task.md b/docs/reference/tasks/json_stream_reader_task.md index e48da640..77fc2329 100644 --- a/docs/reference/tasks/json_stream_reader_task.md +++ b/docs/reference/tasks/json_stream_reader_task.md @@ -23,7 +23,11 @@ Underlying method are [SplFileObject::fgets](https://www.php.net/manual/fr/splfi Options ------- -none +| Code | Type | Required | Default | Description | +|-------------------------|-----------------|:--------:|---------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `spl_file_object_flags` | `array`, `null` | | `\SplFileObject::DROP_NEW_LINE \SplFileObject::READ_AHEAD \SplFileObject::SKIP_EMPTY` | Flags to pass to `SplFileObject` constructor, can be empty.
    See [PHP documentation](https://www.php.net/manual/en/splfileobject.construct.php) for more information on available flags. | +| `json_flags` | `array`, `null` | | `\JSON_THROW_ON_ERROR` | Flags to pass to `json_encode` function, can be empty.
    See [PHP documentation](https://www.php.net/manual/en/function.json-encode.php) for more information on available flags. | + Example ------- @@ -38,6 +42,10 @@ entry: file_path: '%kernel.project_dir%/var/data/json_stream_reader.json' read: service: '@CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamReaderTask' + options: + spl_file_object_flags: [] + json_flags: + - !php/const JSON_ERROR_NONE ``` diff --git a/docs/reference/tasks/json_stream_writer_task.md b/docs/reference/tasks/json_stream_writer_task.md index 79fd2e39..9b4a2302 100644 --- a/docs/reference/tasks/json_stream_writer_task.md +++ b/docs/reference/tasks/json_stream_writer_task.md @@ -23,9 +23,11 @@ Possible outputs Options ------- -| Code | Type | Required | Default | Description | -|-------------|----------|:--------:|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `file_path` | `string` | **X** | | Path of the file to write to (relative to symfony root or absolute).
    It can also take placeholders (`{date}`, `{date_time}`, `{timestamp}` `{unique_token}`) to insert data into the filename | +| Code | Type | Required | Default | Description | +|-------------------------|-----------------|:--------:|---------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `file_path` | `string` | **X** | | Path of the file to write to (relative to symfony root or absolute).
    It can also take placeholders (`{date}`, `{date_time}`, `{timestamp}` `{unique_token}`) to insert data into the filename | +| `spl_file_object_flags` | `array`, `null` | | `\SplFileObject::DROP_NEW_LINE \SplFileObject::READ_AHEAD \SplFileObject::SKIP_EMPTY` | Flags to pass to `SplFileObject` constructor, can be empty.
    See [PHP documentation](https://www.php.net/manual/en/splfileobject.construct.php) for more information on available flags. | +| `json_flags` | `array`, `null` | | `\JSON_THROW_ON_ERROR` | Flags to pass to `json_encode` function, can be empty.
    See [PHP documentation](https://www.php.net/manual/en/function.json-encode.php) for more information on available flags. | Example ---------------- @@ -50,4 +52,8 @@ write: service: '@CleverAge\ProcessBundle\Task\File\JsonStream\JsonStreamWriterTask' options: file_path: '%kernel.project_dir%/var/data/json_stream_writer_{date_time}.csv' + spl_file_object_flags: [] + json_flags: + - !php/const JSON_PRETTY_PRINT + - !php/const JSON_UNESCAPED_SLASHES ``` diff --git a/src/Filesystem/JsonStreamFile.php b/src/Filesystem/JsonStreamFile.php index 6d4873b3..fc76dc62 100644 --- a/src/Filesystem/JsonStreamFile.php +++ b/src/Filesystem/JsonStreamFile.php @@ -20,16 +20,30 @@ class JsonStreamFile implements FileStreamInterface, WritableFileInterface { protected \SplFileObject $file; + private readonly int $jsonFlags; + protected ?int $lineCount = null; protected int $lineNumber = 1; - public function __construct(string $filename, string $mode = 'rb') - { + public function __construct( + string $filename, + string $mode = 'rb', + ?array $splFileObjectFlags = null, + ?array $jsonFlags = null, + ) { $this->file = new \SplFileObject($filename, $mode); // Useful to skip empty trailing lines (doesn't work well on PHP 8, see readLine() code) - $this->file->setFlags(\SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); + $this->file->setFlags(null !== $splFileObjectFlags + ? array_sum($splFileObjectFlags) + : \SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY + ); + + $this->jsonFlags = null !== $jsonFlags + ? array_sum($jsonFlags) + : \JSON_THROW_ON_ERROR + ; } /** @@ -78,12 +92,12 @@ public function readLine(?int $length = null): ?array } ++$this->lineNumber; - return json_decode($rawLine, true, 512, \JSON_THROW_ON_ERROR); + return json_decode($rawLine, true, 512, $this->jsonFlags); } public function writeLine(array $fields): int { - $this->file->fwrite(json_encode($fields, \JSON_THROW_ON_ERROR).\PHP_EOL); + $this->file->fwrite(json_encode($fields, $this->jsonFlags).\PHP_EOL); ++$this->lineNumber; return $this->lineNumber; diff --git a/src/Task/File/JsonStream/JsonStreamReaderTask.php b/src/Task/File/JsonStream/JsonStreamReaderTask.php index 8db6fc26..e1924b0f 100644 --- a/src/Task/File/JsonStream/JsonStreamReaderTask.php +++ b/src/Task/File/JsonStream/JsonStreamReaderTask.php @@ -14,17 +14,25 @@ namespace CleverAge\ProcessBundle\Task\File\JsonStream; use CleverAge\ProcessBundle\Filesystem\JsonStreamFile; +use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\IterableTaskInterface; use CleverAge\ProcessBundle\Model\ProcessState; +use Symfony\Component\OptionsResolver\OptionsResolver; -class JsonStreamReaderTask implements IterableTaskInterface +class JsonStreamReaderTask extends AbstractConfigurableTask implements IterableTaskInterface { protected ?JsonStreamFile $file = null; public function execute(ProcessState $state): void { if (!$this->file instanceof JsonStreamFile) { - $this->file = new JsonStreamFile($this->getFilePath($state), 'rb'); + $options = $this->getOptions($state); + $this->file = new JsonStreamFile( + $this->getFilePath($state), + 'rb', + $options['spl_file_object_flags'], + $options['json_flags'], + ); } $line = $this->file->readLine(); @@ -49,4 +57,14 @@ protected function getFilePath(ProcessState $state): string { return $state->getInput(); } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'spl_file_object_flags' => null, + 'json_flags' => null, + ]); + $resolver->setAllowedTypes('spl_file_object_flags', ['array', 'null']); + $resolver->setAllowedTypes('json_flags', ['array', 'null']); + } } diff --git a/src/Task/File/JsonStream/JsonStreamWriterTask.php b/src/Task/File/JsonStream/JsonStreamWriterTask.php index 494cc0ed..c57446b5 100644 --- a/src/Task/File/JsonStream/JsonStreamWriterTask.php +++ b/src/Task/File/JsonStream/JsonStreamWriterTask.php @@ -26,9 +26,14 @@ class JsonStreamWriterTask extends AbstractConfigurableTask implements BlockingT public function execute(ProcessState $state): void { - $options = $this->getOptions($state); if (!$this->file instanceof JsonStreamFile) { - $this->file = new JsonStreamFile($options['file_path'], 'wb'); + $options = $this->getOptions($state); + $this->file = new JsonStreamFile( + $options['file_path'], + 'wb', + $options['spl_file_object_flags'], + $options['json_flags'], + ); } $input = $state->getInput(); @@ -60,5 +65,11 @@ protected function configureOptions(OptionsResolver $resolver): void ] ) ); + $resolver->setDefaults([ + 'spl_file_object_flags' => null, + 'json_flags' => null, + ]); + $resolver->setAllowedTypes('spl_file_object_flags', ['array', 'null']); + $resolver->setAllowedTypes('json_flags', ['array', 'null']); } } From 97ac3807dc3cb413b87a333de2e76029941ca9d0 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 9 Jul 2025 17:44:38 +0200 Subject: [PATCH 288/304] #174 Add FileSplitterTask using Filesystem/SplFile. Add doc. --- docs/index.md | 1 + docs/reference/tasks/file_splitter_task.md | 42 ++++++++ src/Filesystem/SplFile.php | 106 ++++++++++++++++++++ src/Task/File/FileSplitterTask.php | 110 +++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 docs/reference/tasks/file_splitter_task.md create mode 100644 src/Filesystem/SplFile.php create mode 100644 src/Task/File/FileSplitterTask.php diff --git a/docs/index.md b/docs/index.md index 5e678dba..2d5b619c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -58,6 +58,7 @@ - [FileMoverTask] - [FileReaderTask](reference/tasks/file_reader_task.md) - [FileRemoverTask] + - [FileSplitterTask](reference/tasks/file_splitter_task.md) - [FileWriterTask] - [FolderBrowserTask](reference/tasks/folder_browser_task.md) - [InputFileReaderTask](reference/tasks/input_file_reader_task.md) diff --git a/docs/reference/tasks/file_splitter_task.md b/docs/reference/tasks/file_splitter_task.md new file mode 100644 index 00000000..a652eb4b --- /dev/null +++ b/docs/reference/tasks/file_splitter_task.md @@ -0,0 +1,42 @@ +FileSplitterTask +============= + +Split long file into smaller ones + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Task\File\FileSplitterTask` +* **Iterable task** + +Accepted inputs +--------------- + +`array`: inputs are merged with task defined options. + +Possible outputs +---------------- + +`string`: absolute path of the produced file + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------------|-----------------|:--------:|----------|------------------------------------------| +| `file_path` | `string` | **X** | | Path of the file to read from (absolute) | +| `max_lines` | `int` | **X** | 1000 | Max number of line on a produced file | + +Example +------- + +```yaml +# Task configuration level +entry: + service: '@CleverAge\ProcessBundle\Task\File\FileSplitterTask' + options: + file_path: '%kernel.project_dir%/var/data/json_stream_reader.json' + max_lines: 1 +``` + + diff --git a/src/Filesystem/SplFile.php b/src/Filesystem/SplFile.php new file mode 100644 index 00000000..14f38c40 --- /dev/null +++ b/src/Filesystem/SplFile.php @@ -0,0 +1,106 @@ +file = new \SplFileObject($filename, $mode); + + // Useful to skip empty trailing lines (doesn't work well on PHP 8, see readLine() code) + $this->file->setFlags(null !== $splFileObjectFlags + ? array_sum($splFileObjectFlags) + : \SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY + ); + } + + /** + * Warning! This method will rewind the file to the beginning before and after counting the lines! + */ + public function getLineCount(): int + { + if (null === $this->lineCount) { + $this->rewind(); + $line = 0; + while (!$this->isEndOfFile()) { + ++$line; + $this->file->next(); + } + $this->rewind(); + + $this->lineCount = $line; + } + + return $this->lineCount; + } + + public function getLineNumber(): int + { + return $this->lineNumber; + } + + public function isEndOfFile(): bool + { + return $this->file->eof(); + } + + /** + * Return an array containing current data and moving the file pointer. + */ + public function readLine(?int $length = null): ?string + { + if ($this->isEndOfFile()) { + return null; + } + + $rawLine = $this->file->fgets(); + // Fix issue on PHP 8 with empty line at the end, even if SKIP_EMPTY is set + if ('' === $rawLine) { + return null; + } + ++$this->lineNumber; + + return $rawLine; + } + + public function writeLine(string $data): int + { + $this->file->fwrite($data.\PHP_EOL); + ++$this->lineNumber; + + return $this->lineNumber; + } + + /** + * Rewind data to array. + */ + public function rewind(): void + { + $this->file->rewind(); + $this->lineNumber = 1; + } +} diff --git a/src/Task/File/FileSplitterTask.php b/src/Task/File/FileSplitterTask.php new file mode 100644 index 00000000..e87bc2e0 --- /dev/null +++ b/src/Task/File/FileSplitterTask.php @@ -0,0 +1,110 @@ +getMergedOptions($state); + $this->splFileObjectFlags = [\SplFileObject::READ_AHEAD, \SplFileObject::SKIP_EMPTY]; + if (!$this->file instanceof SplFile) { + $this->file = new SplFile($options['file_path'], 'rb', $this->splFileObjectFlags); + $this->lineCount = $this->file->getLineCount(); + } + + // Return a temporary file containing a limited number of lines + $splittedFilename = $this->splitFile($this->file, $options['max_lines']); + $state->setOutput($splittedFilename); + } + + /** + * Moves the internal pointer to the next element, + * return true if the task has a next element + * return false if the task has terminated it's iteration. + */ + public function next(ProcessState $state): bool + { + if (!$this->file instanceof SplFile) { + return false; + } + + // Fix issue on PHP 8 with empty line at the end, even if SKIP_EMPTY is set + $endOfFile = $this->file->isEndOfFile() || $this->file->getLineNumber() > $this->lineCount; + if ($endOfFile) { + $this->file = null; + } + + return !$endOfFile; + } + + protected function splitFile(SplFile $file, int $maxLines): string + { + $tmpFilePath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_'.uniqid('process', false).'.tmp'; + $splitFile = new SplFile($tmpFilePath, 'wb', $this->splFileObjectFlags); + + while ($splitFile->getLineNumber() <= $maxLines && !$file->isEndOfFile()) { + $line = $file->readLine(); + if ('' === $line || null === $line) { + continue; // This is probably an empty line, no harm to skip it + } + $splitFile->writeLine($line); + } + + return $tmpFilePath; + } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired(['file_path']); + $resolver->setAllowedTypes('file_path', ['string']); + $resolver->setDefaults([ + 'max_lines' => 1000, + ]); + $resolver->setAllowedTypes('max_lines', ['int']); + } + + /** + * @return array + */ + protected function getMergedOptions(ProcessState $state): array + { + /** @var array $options */ + $options = $this->getOptions($state); + + /** @var array|mixed $input */ + $input = $state->getInput() ?: []; + if (!\is_array($input)) { + $input = []; + } + // @var array $input + + return array_merge($options, $input); + } +} From dde5bd80ae56f8fb6e395644c1301d1940e8cd8d Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 9 Jul 2025 17:51:50 +0200 Subject: [PATCH 289/304] Prepare release v4.4 --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a395a717..ac53a6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +v4.4 +----- + +### Add +* [#168](https://github.com/cleverage/process-bundle/issues/168) Add JsonStreamWriterTask with related doc +* [#172](https://github.com/cleverage/process-bundle/issues/172) Add spl_file_object_flags and json_flags options on JsonStream*Tasks. Update docs. +* [#174](https://github.com/cleverage/process-bundle/issues/174) Add FileSplitterTask using Filesystem/SplFile. Add doc. + +### Fixes +* [#169](https://github.com/cleverage/process-bundle/issues/169) Fix JsonStreamFile empty line at the end issue, even if SKIP_EMPTY is set. Add JsonStreamReaderTask doc. + v4.3 ----- From 79ae79aea82f0e47de815cb77ba6f3fb4fb2b23e Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 19 Aug 2025 16:41:01 +0200 Subject: [PATCH 290/304] #176 Update rector configuration with minimal version PHP 8.1 --- rector.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/rector.php b/rector.php index 72a24086..b19c1121 100644 --- a/rector.php +++ b/rector.php @@ -8,23 +8,19 @@ use Rector\ValueObject\PhpVersion; return RectorConfig::configure() - ->withPhpVersion(PhpVersion::PHP_82) + ->withPhpVersion(PhpVersion::PHP_84) ->withPaths([ __DIR__.'/src', __DIR__.'/tests', ]) - ->withPhpSets(php82: true) + ->withPhpSets(php81: true) // here we can define, what prepared sets of rules will be applied - ->withPreparedSets( - deadCode: true, - codeQuality: true - ) + ->withPreparedSets(deadCode: true, codeQuality: true, symfonyCodeQuality: true) + ->withAttributesSets(symfony: true) ->withSets([ - LevelSetList::UP_TO_PHP_82, + LevelSetList::UP_TO_PHP_81, SymfonySetList::SYMFONY_64, - SymfonySetList::SYMFONY_71, SymfonySetList::SYMFONY_CODE_QUALITY, SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, - SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES, ]) ; From 03cb00f6b1287eb4b6d9e300a76ebee75d45510f Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 19 Aug 2025 16:44:04 +0200 Subject: [PATCH 291/304] #176 Update github workflows with PHP 8.1 to 8.4 for Symfony ^6.4 and PHP 8.2 to 8.4 for Symfony ^7.3 --- .github/workflows/quality.yml | 6 +++--- .github/workflows/test.yml | 24 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 9f1580fe..a07ce8b6 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -19,7 +19,7 @@ jobs: - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.2' + php-version: '8.4' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) @@ -36,7 +36,7 @@ jobs: - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.2' + php-version: '8.4' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) @@ -53,7 +53,7 @@ jobs: - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.2' + php-version: '8.4' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2d7e7a41..0e07db02 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,11 +22,17 @@ jobs: php-version: - '8.2' - '8.3' + - '8.4' dependencies: [highest] allowed-to-fail: [false] symfony-require: [''] variant: [normal] include: + - php-version: '8.1' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" - php-version: '8.2' dependencies: highest allowed-to-fail: false @@ -35,8 +41,8 @@ jobs: - php-version: '8.2' dependencies: highest allowed-to-fail: false - symfony-require: 7.1.* - variant: symfony/symfony:"7.1.*" + symfony-require: 7.3.* + variant: symfony/symfony:"7.3.*" - php-version: '8.3' dependencies: highest allowed-to-fail: false @@ -45,8 +51,18 @@ jobs: - php-version: '8.3' dependencies: highest allowed-to-fail: false - symfony-require: 7.1.* - variant: symfony/symfony:"7.1.*" + symfony-require: 7.3.* + variant: symfony/symfony:"7.3.*" + - php-version: '8.4' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.4' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.3.* + variant: symfony/symfony:"7.3.*" steps: - name: Checkout From 855571762a9a2e50d5acf82487ba7fa65371ed18 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 19 Aug 2025 16:44:53 +0200 Subject: [PATCH 292/304] #176 Update docker configuration with PHP 8.4 --- .docker/php/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile index f98c3ba0..33dd796b 100644 --- a/.docker/php/Dockerfile +++ b/.docker/php/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-fpm-alpine +FROM php:8.4-fpm-alpine ARG UID ARG GID From 07fa811998068fe2f083e66dc72b1fb79ff00964 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 19 Aug 2025 16:46:29 +0200 Subject: [PATCH 293/304] #176 Update composer dependencies for symfony ^6.4|^7.3 --- composer.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index e6316520..1293d7f6 100644 --- a/composer.json +++ b/composer.json @@ -59,23 +59,23 @@ "ext-json": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", - "symfony/config": "^6.4|^7.1", - "symfony/console": "^6.4|^7.1", - "symfony/dependency-injection": "^6.4|^7.1", - "symfony/dotenv": "^6.4|^7.1", + "symfony/config": "^6.4|^7.3", + "symfony/console": "^6.4|^7.3", + "symfony/dependency-injection": "^6.4|^7.3", + "symfony/dotenv": "^6.4|^7.3", "symfony/event-dispatcher-contracts": "^3", - "symfony/expression-language": "^6.4|^7.1", - "symfony/framework-bundle": "^6.4|^7.1", - "symfony/monolog-bridge": "^6.4|^7.1", + "symfony/expression-language": "^6.4|^7.3", + "symfony/framework-bundle": "^6.4|^7.3", + "symfony/monolog-bridge": "^6.4|^7.3", "symfony/monolog-bundle": "~3.3", - "symfony/options-resolver": "^6.4|^7.1", - "symfony/process": "^6.4|^7.1", - "symfony/property-access": "^6.4|^7.1", - "symfony/runtime": "^6.4|^7.1", - "symfony/serializer": "^6.4|^7.1", - "symfony/stopwatch": "^6.4|^7.1", - "symfony/validator": "^6.4|^7.1", - "symfony/yaml": "^6.4|^7.1", + "symfony/options-resolver": "^6.4|^7.3", + "symfony/process": "^6.4|^7.3", + "symfony/property-access": "^6.4|^7.3", + "symfony/runtime": "^6.4|^7.3", + "symfony/serializer": "^6.4|^7.3", + "symfony/stopwatch": "^6.4|^7.3", + "symfony/validator": "^6.4|^7.3", + "symfony/yaml": "^6.4|^7.3", "symfony/service-contracts": ">=1.0.0" }, "require-dev": { From 214d72da867bdca1145acd985f49b431940603aa Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 19 Aug 2025 16:56:54 +0200 Subject: [PATCH 294/304] Prepare v4.5 release --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac53a6b5..ee605191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v4.5 +----- + +## Changes + +* [#176](https://github.com/cleverage/process-bundle/issues/176) Upgrade to Symfony 7.3 & PHP 8.4 + v4.4 ----- From 08d261d18ac4b73c484ab0ca2398a710b0db4c7a Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 18 Nov 2025 17:08:37 +0100 Subject: [PATCH 295/304] doc: #145 Add array_map_transformer, multi_replace_transformer and sprintf_transformer documentations. Update implode_transformer ans slugify_transformer documentations Examples. --- CHANGELOG.md | 1 - docs/index.md | 6 +-- .../transformers/array_map_transformer.md | 47 ++++++++++++++++++ .../transformers/implode_transformer.md | 11 +++-- .../transformers/multi_replace_transformer.md | 44 +++++++++++++++++ .../transformers/slugify_transformer.md | 8 +++- .../transformers/sprintf_transformer.md | 48 +++++++++++++++++++ 7 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 docs/reference/transformers/array_map_transformer.md create mode 100644 docs/reference/transformers/multi_replace_transformer.md create mode 100644 docs/reference/transformers/sprintf_transformer.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ee605191..b08e1efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,6 @@ v4.5 ----- ## Changes - * [#176](https://github.com/cleverage/process-bundle/issues/176) Upgrade to Symfony 7.3 & PHP 8.4 v4.4 diff --git a/docs/index.md b/docs/index.md index 2d5b619c..26d38e0b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -99,7 +99,7 @@ - [EvaluatorTransformer] - [ExpressionLanguageMapTransformer] - [MappingTransformer](reference/transformers/mapping_transformer.md) - - [MultiReplaceTransformer] + - [MultiReplaceTransformer](reference/transformers/multi_replace_transformer.md) - [PregFilterTransformer] - [RulesTransformer](reference/transformers/rules_transformer.md) - [TypeSetterTransformer] @@ -110,7 +110,7 @@ - [ArrayFilterTransformer](reference/transformers/array_filter_transformer.md) - [ArrayFirstTransformer] - [ArrayLastTransformer] - - [ArrayMapTransformer] + - [ArrayMapTransformer](reference/transformers/array_map_transformer.md) - [ArrayUnsetTransformer] - Date - [DateFormatTransformer](reference/transformers/date_format.md) @@ -128,7 +128,7 @@ - [ImplodeTransformer](reference/transformers/implode_transformer.md) - [PregMatchTransformer](reference/transformers/preg_match_transformer.md) - [SlugifyTransformer](reference/transformers/slugify_transformer.md) - - [SprintfTransformer] + - [SprintfTransformer](reference/transformers/sprintf_transformer.md) - [TrimTransformer](reference/transformers/trim_transformer.md) - XML - [XpathEvaluatorTransformer](reference/transformers/xpath_evaluator.md) diff --git a/docs/reference/transformers/array_map_transformer.md b/docs/reference/transformers/array_map_transformer.md new file mode 100644 index 00000000..32f9bd01 --- /dev/null +++ b/docs/reference/transformers/array_map_transformer.md @@ -0,0 +1,47 @@ +ArrayMapTransformer +========================= + +Applies transformers to each element of an array. + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\Array\ArrayMapTransformer` +* **Transformer code**: `array_map` + +Accepted inputs +--------------- + +`array` + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +|----------------|---------|:--------:|---------|------------------------------------------------------------------------------| +| `transformers` | `array` | **X** | | List of transformers, see [TransformerTrait](../traits/transformer_trait.md) | +| `skip_null` | `bool` | | `false` | If true continue without applying other transformers on null values | + + +Examples +-------- + +```yaml +# Transformer mapping level +array_map: + code: + - '[id]' + - '[firstname]' + - '[lastname]' + transformers: + array_map: + transformers: + cast: + type: 'string' + uppercase: ~ +``` diff --git a/docs/reference/transformers/implode_transformer.md b/docs/reference/transformers/implode_transformer.md index dad93ac2..fb5d27c7 100644 --- a/docs/reference/transformers/implode_transformer.md +++ b/docs/reference/transformers/implode_transformer.md @@ -32,7 +32,12 @@ Examples -------- ```yaml -# Transformer options level -implode: - separator: '-' +# Transformer mapping level +sprintf_multiple: + code: + - '[firstname]' + - '[lastname]' + transformers: + implode: + separator: '-' ``` diff --git a/docs/reference/transformers/multi_replace_transformer.md b/docs/reference/transformers/multi_replace_transformer.md new file mode 100644 index 00000000..4a3f035e --- /dev/null +++ b/docs/reference/transformers/multi_replace_transformer.md @@ -0,0 +1,44 @@ +MultiReplaceTransformer +========================= + +Quickly replace a list of values in a string. + +This transformer uses the php internal function: https://www.php.net/manual/en/function.str-replace.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer` +* **Transformer code**: `multi_replace` + +Accepted inputs +--------------- + +Any value that can be cast to string. + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +|-------------------|---------|:--------:|---------|-----------------------------------| +| `replace_mapping` | `array` | **X** | | $search as key, $replace as value | + +Examples +-------- + +```yaml +# Transformer mapping level +multi_replace: + code: + - '[firstname]' + transformers: + multi_replace: + replace_mapping: + ' ': '!' + 'name': '' +``` diff --git a/docs/reference/transformers/slugify_transformer.md b/docs/reference/transformers/slugify_transformer.md index cadab337..3276f6de 100644 --- a/docs/reference/transformers/slugify_transformer.md +++ b/docs/reference/transformers/slugify_transformer.md @@ -34,6 +34,10 @@ Examples -------- ```yaml -# Transformer options level -slugify: ~ +# Transformer mapping level +slug: + code: + - '[firstname]' + transformers: + slugify: ~ ``` diff --git a/docs/reference/transformers/sprintf_transformer.md b/docs/reference/transformers/sprintf_transformer.md new file mode 100644 index 00000000..e8f15f00 --- /dev/null +++ b/docs/reference/transformers/sprintf_transformer.md @@ -0,0 +1,48 @@ +SprintfTransformer +========================= + +Return a formatted string. + +This transformer uses the php internal function: https://www.php.net/manual/en/function.vsprintf.php + +Task reference +-------------- + +* **Service**: `CleverAge\ProcessBundle\Transformer\String\SprintfTransformer` +* **Transformer code**: `sprintf` + +Accepted inputs +--------------- + +Any value that can be cast to `string` | `int` | `float` or `array` + +Possible outputs +---------------- + +`string` + +Options +------- + +| Code | Type | Required | Default | Description | +|----------|----------|:--------:|---------|----------------------------------------------------------------------------------------------------------------------| +| `format` | `string` | **X** | `%s` | The format string is composed of zero or more directives. Escape % with another %% due to ParameterBag restrictions. | + +Examples +-------- + +```yaml +# Transformer mapping level +sprintf_one: + code: '[firstname]' + transformers: + sprintf: + format: 'one/%%d' +sprintf_multiple: + code: + - '[firstname]' + - '[lastname]' + transformers: + sprintf: + format: 'multiple/%%s/%%s' +``` From c07583d68f52a6931e8e735d9838716c32fa1dd5 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 9 Dec 2025 08:53:55 +0100 Subject: [PATCH 296/304] #179 - Upgrade project dependencies and workflows: - **Bump PHP to 8.2+** and enable support for Symfony 6.4, 7.4, and 8.0 in `composer.json`. - Add PHP 8.5 support in GitHub workflows and Docker configuration. - Update PHPUnit dependencies and configuration to version 10+ with stricter coverage annotations. - Migrate from PHPDoc annotations to PHPUnit attributes in test classes. - Update `.github/workflows/test.yml` and `.github/workflows/quality.yml` to use `actions/checkout@v6`. - Adjust Rector configuration for PHP 8.5 compatibility. - Update Dockerfile to reflect changes in PHP version and simplifications. --- .docker/php/Dockerfile | 5 +-- .github/workflows/quality.yml | 12 +++--- .github/workflows/test.yml | 41 +++++++++++++------ .php-cs-fixer.dist.php | 1 - composer.json | 36 ++++++++-------- phpunit.xml.dist | 21 ++++------ rector.php | 8 ++-- .../MissingTransformerExceptionTest.php | 8 +--- .../Array/ArrayElementTransformerTest.php | 16 ++------ .../Array/ArrayFirstTransformerTest.php | 22 ++-------- tests/Transformer/CastTransformerTest.php | 28 ++----------- tests/Transformer/ConstantTransformerTest.php | 19 ++------- .../Date/DateFormatTransformerTest.php | 22 ++-------- .../Date/DateParserTransformerTest.php | 25 ++--------- tests/Transformer/DebugTransformerTest.php | 12 ++---- tests/Transformer/DefaultTransformerTest.php | 19 ++------- .../MultiReplaceTransformerTest.php | 22 ++-------- .../String/ExplodeTransformerTest.php | 22 ++-------- .../String/ImplodeTransformerTest.php | 22 ++-------- .../String/SprintfTransformerTest.php | 12 ++---- .../String/TrimTransformerTest.php | 22 ++-------- tests/Transformer/WrapperTransformerTest.php | 22 ++-------- .../Xml/XpathEvaluatorTransformerTest.php | 36 +++------------- 23 files changed, 128 insertions(+), 325 deletions(-) diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile index 33dd796b..82be215c 100644 --- a/.docker/php/Dockerfile +++ b/.docker/php/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.4-fpm-alpine +FROM php:8.5-fpm-alpine ARG UID ARG GID @@ -13,8 +13,7 @@ RUN apk update && apk add \ bash \ icu-dev \ && docker-php-ext-configure intl \ - && docker-php-ext-install intl opcache \ - && docker-php-ext-enable opcache + && docker-php-ext-install intl RUN ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \ && sed -i "s/^;date.timezone =.*/date.timezone = Europe\/Paris/" $PHP_INI_DIR/php.ini diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index a07ce8b6..f4e4f5b8 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.4' + php-version: '8.5' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) @@ -32,11 +32,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.4' + php-version: '8.5' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) @@ -49,11 +49,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: - php-version: '8.4' + php-version: '8.5' coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0e07db02..27a5a548 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,16 +23,12 @@ jobs: - '8.2' - '8.3' - '8.4' + - '8.5' dependencies: [highest] allowed-to-fail: [false] symfony-require: [''] variant: [normal] include: - - php-version: '8.1' - dependencies: highest - allowed-to-fail: false - symfony-require: 6.4.* - variant: symfony/symfony:"6.4.*" - php-version: '8.2' dependencies: highest allowed-to-fail: false @@ -41,8 +37,8 @@ jobs: - php-version: '8.2' dependencies: highest allowed-to-fail: false - symfony-require: 7.3.* - variant: symfony/symfony:"7.3.*" + symfony-require: 7.4.* + variant: symfony/symfony:"7.4.*" - php-version: '8.3' dependencies: highest allowed-to-fail: false @@ -51,8 +47,8 @@ jobs: - php-version: '8.3' dependencies: highest allowed-to-fail: false - symfony-require: 7.3.* - variant: symfony/symfony:"7.3.*" + symfony-require: 7.4.* + variant: symfony/symfony:"7.4.*" - php-version: '8.4' dependencies: highest allowed-to-fail: false @@ -61,12 +57,31 @@ jobs: - php-version: '8.4' dependencies: highest allowed-to-fail: false - symfony-require: 7.3.* - variant: symfony/symfony:"7.3.*" - + symfony-require: 7.4.* + variant: symfony/symfony:"7.4.*" + - php-version: '8.4' + dependencies: highest + allowed-to-fail: false + symfony-require: 8.* + variant: symfony/symfony:"8.*" + - php-version: '8.5' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.5' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.4.* + variant: symfony/symfony:"7.4.*" + - php-version: '8.5' + dependencies: highest + allowed-to-fail: false + symfony-require: 8.* + variant: symfony/symfony:"8.*" steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index b994793f..124bfa47 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -24,7 +24,6 @@ return (new PhpCsFixer\Config()) ->setRules([ - '@PHP71Migration' => true, '@PHP82Migration' => true, '@PHPUnit75Migration:risky' => true, '@Symfony' => true, diff --git a/composer.json b/composer.json index 1293d7f6..2609a9c4 100644 --- a/composer.json +++ b/composer.json @@ -53,29 +53,29 @@ } }, "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-dom": "*", "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", "psr/cache": "^1|^2|^3", - "symfony/config": "^6.4|^7.3", - "symfony/console": "^6.4|^7.3", - "symfony/dependency-injection": "^6.4|^7.3", - "symfony/dotenv": "^6.4|^7.3", + "symfony/config": "^6.4|^7.4|^8", + "symfony/console": "^6.4|^7.4|^8", + "symfony/dependency-injection": "^6.4|^7.4|^8", + "symfony/dotenv": "^6.4|^7.4|^8", "symfony/event-dispatcher-contracts": "^3", - "symfony/expression-language": "^6.4|^7.3", - "symfony/framework-bundle": "^6.4|^7.3", - "symfony/monolog-bridge": "^6.4|^7.3", - "symfony/monolog-bundle": "~3.3", - "symfony/options-resolver": "^6.4|^7.3", - "symfony/process": "^6.4|^7.3", - "symfony/property-access": "^6.4|^7.3", - "symfony/runtime": "^6.4|^7.3", - "symfony/serializer": "^6.4|^7.3", - "symfony/stopwatch": "^6.4|^7.3", - "symfony/validator": "^6.4|^7.3", - "symfony/yaml": "^6.4|^7.3", + "symfony/expression-language": "^6.4|^7.4|^8", + "symfony/framework-bundle": "^6.4|^7.4|^8", + "symfony/monolog-bridge":"^6.4|^7.4|^8", + "symfony/monolog-bundle": "^3.11|^4", + "symfony/options-resolver": "^6.4|^7.4|^8", + "symfony/process": "^6.4|^7.4|^8", + "symfony/property-access": "^6.4|^7.4|^8", + "symfony/runtime": "^6.4|^7.4|^8", + "symfony/serializer": "^6.4|^7.4|^8", + "symfony/stopwatch": "^6.4|^7.4|^8", + "symfony/validator": "^6.4|^7.4|^8", + "symfony/yaml": "^6.4|^7.4|^8", "symfony/service-contracts": ">=1.0.0" }, "require-dev": { @@ -83,7 +83,7 @@ "phpstan/extension-installer": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", - "phpunit/phpunit": "<10.0", + "phpunit/phpunit": "*", "rector/rector": "*", "roave/security-advisories": "dev-latest", "symfony/test-pack": "^1.1" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 766495c5..c3e7947d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,27 +1,22 @@ + failOnWarning="true"> tests - - + src - - + + \ No newline at end of file diff --git a/rector.php b/rector.php index b19c1121..a931fd42 100644 --- a/rector.php +++ b/rector.php @@ -3,24 +3,26 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; use Rector\Symfony\Set\SymfonySetList; use Rector\ValueObject\PhpVersion; return RectorConfig::configure() - ->withPhpVersion(PhpVersion::PHP_84) + ->withPhpVersion(PhpVersion::PHP_85) ->withPaths([ __DIR__.'/src', __DIR__.'/tests', ]) - ->withPhpSets(php81: true) + ->withPhpSets(php82: true) // here we can define, what prepared sets of rules will be applied ->withPreparedSets(deadCode: true, codeQuality: true, symfonyCodeQuality: true) ->withAttributesSets(symfony: true) ->withSets([ - LevelSetList::UP_TO_PHP_81, + LevelSetList::UP_TO_PHP_82, SymfonySetList::SYMFONY_64, SymfonySetList::SYMFONY_CODE_QUALITY, SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, + PHPUnitSetList::PHPUNIT_100, ]) ; diff --git a/tests/Exception/MissingTransformerExceptionTest.php b/tests/Exception/MissingTransformerExceptionTest.php index 6b30730b..41d3628b 100644 --- a/tests/Exception/MissingTransformerExceptionTest.php +++ b/tests/Exception/MissingTransformerExceptionTest.php @@ -16,14 +16,10 @@ use CleverAge\ProcessBundle\Exception\MissingTransformerException; use PHPUnit\Framework\TestCase; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Exception\MissingTransformerException - */ +#[\PHPUnit\Framework\Attributes\CoversClass(MissingTransformerException::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(MissingTransformerException::class, 'create')] class MissingTransformerExceptionTest extends TestCase { - /** - * @covers ::create - */ public function testCreate(): void { $exception = MissingTransformerException::create('my_transformer'); diff --git a/tests/Transformer/Array/ArrayElementTransformerTest.php b/tests/Transformer/Array/ArrayElementTransformerTest.php index fa98f00d..0d0cd18c 100644 --- a/tests/Transformer/Array/ArrayElementTransformerTest.php +++ b/tests/Transformer/Array/ArrayElementTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Array\ArrayElementTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(ArrayElementTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayElementTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayElementTransformer::class, 'configureOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayElementTransformer::class, 'getCode')] class ArrayElementTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformReturnsNthElementFromArray(): void { $transformer = new ArrayElementTransformer(); @@ -36,9 +34,6 @@ public function testTransformReturnsNthElementFromArray(): void $this->assertEquals('bar', $result); } - /** - * @covers ::configureOptions - */ public function testConfigureOptionsSetsRequiredOptions(): void { $resolver = new OptionsResolver(); @@ -52,9 +47,6 @@ public function testConfigureOptionsSetsRequiredOptions(): void $this->assertEquals(['index'], array_keys($resolvedOptions)); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new ArrayElementTransformer(); diff --git a/tests/Transformer/Array/ArrayFirstTransformerTest.php b/tests/Transformer/Array/ArrayFirstTransformerTest.php index 1b04a7fc..611d3923 100644 --- a/tests/Transformer/Array/ArrayFirstTransformerTest.php +++ b/tests/Transformer/Array/ArrayFirstTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Array\ArrayFirstTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(ArrayFirstTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayFirstTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayFirstTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ArrayFirstTransformer::class, 'configureOptions')] class ArrayFirstTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformReturnsFirstElementIfIterableAndAllowed(): void { $transformer = new ArrayFirstTransformer(); @@ -36,9 +34,6 @@ public function testTransformReturnsFirstElementIfIterableAndAllowed(): void $this->assertEquals(1, $result); } - /** - * @covers ::transform - */ public function testTransformReturnsValueIfNotIterableAndAllowed(): void { $this->expectException(\TypeError::class); @@ -52,9 +47,6 @@ public function testTransformReturnsValueIfNotIterableAndAllowed(): void $this->assertEquals('not_iterable_value', $result); } - /** - * @covers ::transform - */ public function testTransformThrowsExceptionIfNotIterableAndNotAllowed(): void { $transformer = new ArrayFirstTransformer(); @@ -66,9 +58,6 @@ public function testTransformThrowsExceptionIfNotIterableAndNotAllowed(): void $this->assertEquals($value, $result); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new ArrayFirstTransformer(); @@ -78,9 +67,6 @@ public function testGetCodeReturnsCorrectCode(): void $this->assertEquals('array_first', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptionsSetsDefaultOptions(): void { $resolver = new OptionsResolver(); diff --git a/tests/Transformer/CastTransformerTest.php b/tests/Transformer/CastTransformerTest.php index 215a6f47..7470a1d0 100644 --- a/tests/Transformer/CastTransformerTest.php +++ b/tests/Transformer/CastTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\CastTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(CastTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(CastTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(CastTransformer::class, 'configureOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(CastTransformer::class, 'getCode')] class CastTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testCastToInt(): void { $transformer = new CastTransformer(); @@ -37,9 +35,6 @@ public function testCastToInt(): void $this->assertEquals(123, $transformedValue); } - /** - * @covers ::transform - */ public function testCastToFloat(): void { $transformer = new CastTransformer(); @@ -52,9 +47,6 @@ public function testCastToFloat(): void $this->assertEquals(123.45, $transformedValue); } - /** - * @covers ::transform - */ public function testCastToString(): void { $transformer = new CastTransformer(); @@ -67,9 +59,6 @@ public function testCastToString(): void $this->assertEquals('123', $transformedValue); } - /** - * @covers ::transform - */ public function testCastToBool(): void { $transformer = new CastTransformer(); @@ -82,9 +71,6 @@ public function testCastToBool(): void $this->assertTrue($transformedValue); } - /** - * @covers ::transform - */ public function testCastToInvalidType(): void { $transformer = new CastTransformer(); @@ -96,9 +82,6 @@ public function testCastToInvalidType(): void $transformer->transform($value, $options); } - /** - * @covers ::configureOptions - */ public function testConfigureOptionsSetsRequiredOptions(): void { $resolver = new OptionsResolver(); @@ -112,9 +95,6 @@ public function testConfigureOptionsSetsRequiredOptions(): void $this->assertEquals(['type'], array_keys($resolvedOptions)); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new CastTransformer(); diff --git a/tests/Transformer/ConstantTransformerTest.php b/tests/Transformer/ConstantTransformerTest.php index 9a36ba94..edabdf33 100644 --- a/tests/Transformer/ConstantTransformerTest.php +++ b/tests/Transformer/ConstantTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\ConstantTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(ConstantTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(ConstantTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ConstantTransformer::class, 'configureOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ConstantTransformer::class, 'getCode')] class ConstantTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new ConstantTransformer(); @@ -36,9 +34,6 @@ public function testTransform(): void $this->assertEquals('default_value', $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithNullValue(): void { $transformer = new ConstantTransformer(); @@ -50,9 +45,6 @@ public function testTransformWithNullValue(): void $this->assertEquals('default_value', $transformedValue); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new ConstantTransformer(); @@ -63,9 +55,6 @@ public function testConfigureOptions(): void $this->assertTrue($resolver->isRequired('constant')); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new ConstantTransformer(); diff --git a/tests/Transformer/Date/DateFormatTransformerTest.php b/tests/Transformer/Date/DateFormatTransformerTest.php index 09ecf3ab..54bdfb4d 100644 --- a/tests/Transformer/Date/DateFormatTransformerTest.php +++ b/tests/Transformer/Date/DateFormatTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Date\DateFormatTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(DateFormatTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateFormatTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateFormatTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateFormatTransformer::class, 'configureOptions')] class DateFormatTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformValidDate(): void { $transformer = new DateFormatTransformer(); @@ -37,9 +35,6 @@ public function testTransformValidDate(): void $this->assertEquals('2023-09-28', $transformedValue); } - /** - * @covers ::transform - */ public function testTransformInvalidDate(): void { $transformer = new DateFormatTransformer(); @@ -51,9 +46,6 @@ public function testTransformInvalidDate(): void $transformer->transform($value, $options); } - /** - * @covers ::transform - */ public function testTransformNullValue(): void { // Arrange @@ -66,9 +58,6 @@ public function testTransformNullValue(): void $this->assertNull($transformedValue); } - /** - * @covers ::getCode - */ public function testGetCode(): void { $transformer = new DateFormatTransformer(); @@ -78,9 +67,6 @@ public function testGetCode(): void $this->assertEquals('date_format', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new DateFormatTransformer(); diff --git a/tests/Transformer/Date/DateParserTransformerTest.php b/tests/Transformer/Date/DateParserTransformerTest.php index 860d0487..5cb330f7 100644 --- a/tests/Transformer/Date/DateParserTransformerTest.php +++ b/tests/Transformer/Date/DateParserTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Date\DateParserTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(DateParserTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateParserTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateParserTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DateParserTransformer::class, 'configureOptions')] class DateParserTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformValidDate(): void { $transformer = new DateParserTransformer(); @@ -37,9 +35,6 @@ public function testTransformValidDate(): void $this->assertEquals('2023-09-28', $transformedValue->format('Y-m-d')); } - /** - * @covers ::transform - */ public function testTransformInvalidDate(): void { $transformer = new DateParserTransformer(); @@ -51,9 +46,6 @@ public function testTransformInvalidDate(): void $transformer->transform($value, $options); } - /** - * @covers ::transform - */ public function testTransformNullValue(): void { $transformer = new DateParserTransformer(); @@ -65,9 +57,6 @@ public function testTransformNullValue(): void $this->assertNull($transformedValue); } - /** - * @covers ::transform - */ public function testTransformDateTimeObject(): void { // Arrange @@ -80,9 +69,6 @@ public function testTransformDateTimeObject(): void $this->assertSame($value, $transformedValue); } - /** - * @covers ::getCode - */ public function testGetCode(): void { $transformer = new DateParserTransformer(); @@ -92,9 +78,6 @@ public function testGetCode(): void $this->assertEquals('date_parser', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new DateParserTransformer(); diff --git a/tests/Transformer/DebugTransformerTest.php b/tests/Transformer/DebugTransformerTest.php index 4dd9c5b2..b3802db5 100644 --- a/tests/Transformer/DebugTransformerTest.php +++ b/tests/Transformer/DebugTransformerTest.php @@ -17,14 +17,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\VarDumper; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DebugTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(DebugTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(DebugTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DebugTransformer::class, 'getCode')] class DebugTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new DebugTransformer(); @@ -39,9 +36,6 @@ public function testTransform(): void } } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new DebugTransformer(); diff --git a/tests/Transformer/DefaultTransformerTest.php b/tests/Transformer/DefaultTransformerTest.php index 7817b0df..f4579c9f 100644 --- a/tests/Transformer/DefaultTransformerTest.php +++ b/tests/Transformer/DefaultTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\DefaultTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(DefaultTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(DefaultTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DefaultTransformer::class, 'configureOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(DefaultTransformer::class, 'getCode')] class DefaultTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformWithNonNullValue(): void { $transformer = new DefaultTransformer(); @@ -36,9 +34,6 @@ public function testTransformWithNonNullValue(): void $this->assertSame($value, $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithNullValue(): void { $transformer = new DefaultTransformer(); @@ -50,9 +45,6 @@ public function testTransformWithNullValue(): void $this->assertEquals('default_value', $transformedValue); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $resolver = new OptionsResolver(); @@ -66,9 +58,6 @@ public function testConfigureOptions(): void $this->assertEquals(['value'], array_keys($resolvedOptions)); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new DefaultTransformer(); diff --git a/tests/Transformer/MultiReplaceTransformerTest.php b/tests/Transformer/MultiReplaceTransformerTest.php index 6eb2a852..158efe1f 100644 --- a/tests/Transformer/MultiReplaceTransformerTest.php +++ b/tests/Transformer/MultiReplaceTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\MultiReplaceTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(MultiReplaceTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(MultiReplaceTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(MultiReplaceTransformer::class, 'configureOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(MultiReplaceTransformer::class, 'getCode')] class MultiReplaceTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new MultiReplaceTransformer(); @@ -41,9 +39,6 @@ public function testTransform(): void $this->assertEquals('That is a test sentence.', $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithEmptyReplaceMapping(): void { $transformer = new MultiReplaceTransformer(); @@ -57,9 +52,6 @@ public function testTransformWithEmptyReplaceMapping(): void $this->assertEquals('This is a test string.', $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithNullValue(): void { $transformer = new MultiReplaceTransformer(); @@ -76,9 +68,6 @@ public function testTransformWithNullValue(): void $this->assertEquals('', $transformedValue); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new MultiReplaceTransformer(); @@ -93,9 +82,6 @@ public function testConfigureOptions(): void $this->assertEquals(['replace_mapping'], array_keys($resolvedOptions)); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new MultiReplaceTransformer(); diff --git a/tests/Transformer/String/ExplodeTransformerTest.php b/tests/Transformer/String/ExplodeTransformerTest.php index cb698dd8..41b4afd3 100644 --- a/tests/Transformer/String/ExplodeTransformerTest.php +++ b/tests/Transformer/String/ExplodeTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\ExplodeTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(ExplodeTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(ExplodeTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ExplodeTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ExplodeTransformer::class, 'configureOptions')] class ExplodeTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new ExplodeTransformer(); @@ -34,9 +32,6 @@ public function testTransform(): void $this->assertEquals(['1', '2', '3'], $result); } - /** - * @covers ::transform - */ public function testTransformWithEmptyString(): void { $transformer = new ExplodeTransformer(); @@ -46,9 +41,6 @@ public function testTransformWithEmptyString(): void $this->assertEquals([], $result); } - /** - * @covers ::transform - */ public function testTransformWithNullValue(): void { $transformer = new ExplodeTransformer(); @@ -58,9 +50,6 @@ public function testTransformWithNullValue(): void $this->assertEquals([], $result); } - /** - * @covers ::getCode - */ public function testGetCode(): void { $transformer = new ExplodeTransformer(); @@ -70,9 +59,6 @@ public function testGetCode(): void $this->assertEquals('explode', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new ExplodeTransformer(); diff --git a/tests/Transformer/String/ImplodeTransformerTest.php b/tests/Transformer/String/ImplodeTransformerTest.php index 5a1a72b7..d15c75e0 100644 --- a/tests/Transformer/String/ImplodeTransformerTest.php +++ b/tests/Transformer/String/ImplodeTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\ImplodeTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(ImplodeTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(ImplodeTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ImplodeTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(ImplodeTransformer::class, 'configureOptions')] class ImplodeTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new ImplodeTransformer(); @@ -34,9 +32,6 @@ public function testTransform(): void $this->assertEquals('1,2,3', $result); } - /** - * @covers ::transform - */ public function testTransformWithInvalidValue(): void { $this->expectException(\UnexpectedValueException::class); @@ -46,9 +41,6 @@ public function testTransformWithInvalidValue(): void $transformer->transform('invalid_value', ['separator' => ',']); } - /** - * @covers ::transform - */ public function testTransformWithDefaultSeparator(): void { $transformer = new ImplodeTransformer(); @@ -58,9 +50,6 @@ public function testTransformWithDefaultSeparator(): void $this->assertEquals('1|2|3', $result); } - /** - * @covers ::getCode - */ public function testGetCode(): void { $transformer = new ImplodeTransformer(); @@ -70,9 +59,6 @@ public function testGetCode(): void $this->assertEquals('implode', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptions(): void { $transformer = new ImplodeTransformer(); diff --git a/tests/Transformer/String/SprintfTransformerTest.php b/tests/Transformer/String/SprintfTransformerTest.php index 4648e893..af8100da 100644 --- a/tests/Transformer/String/SprintfTransformerTest.php +++ b/tests/Transformer/String/SprintfTransformerTest.php @@ -16,14 +16,11 @@ use CleverAge\ProcessBundle\Transformer\String\SprintfTransformer; use PHPUnit\Framework\TestCase; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\SprintfTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(SprintfTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(SprintfTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(SprintfTransformer::class, 'getCode')] class SprintfTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $sprintfTransformer = new SprintfTransformer(); @@ -34,9 +31,6 @@ public function testTransform(): void $this->assertEquals('foo bar', $result); } - /** - * @covers ::getCode - */ public function testCode(): void { $trimTransformer = new SprintfTransformer(); diff --git a/tests/Transformer/String/TrimTransformerTest.php b/tests/Transformer/String/TrimTransformerTest.php index 8bd4b6e0..962fdacf 100644 --- a/tests/Transformer/String/TrimTransformerTest.php +++ b/tests/Transformer/String/TrimTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\String\TrimTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(TrimTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(TrimTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(TrimTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(TrimTransformer::class, 'configureOptions')] class TrimTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransformTrimsStringWithDefaultCharlist(): void { $transformer = new TrimTransformer(); @@ -35,9 +33,6 @@ public function testTransformTrimsStringWithDefaultCharlist(): void $this->assertEquals('trim me', $result); } - /** - * @covers ::transform - */ public function testTransformTrimsStringWithCustomCharlist(): void { $transformer = new TrimTransformer(); @@ -49,9 +44,6 @@ public function testTransformTrimsStringWithCustomCharlist(): void $this->assertEquals('trim me', $result); } - /** - * @covers ::transform - */ public function testTransformReturnsNullForNullValue(): void { $transformer = new TrimTransformer(); @@ -62,9 +54,6 @@ public function testTransformReturnsNullForNullValue(): void $this->assertNull($result); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new TrimTransformer(); @@ -74,9 +63,6 @@ public function testGetCodeReturnsCorrectCode(): void $this->assertEquals('trim', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptionsSetsDefaultOptions(): void { $resolver = new OptionsResolver(); diff --git a/tests/Transformer/WrapperTransformerTest.php b/tests/Transformer/WrapperTransformerTest.php index 84cac9a2..a3bac458 100644 --- a/tests/Transformer/WrapperTransformerTest.php +++ b/tests/Transformer/WrapperTransformerTest.php @@ -17,14 +17,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\WrapperTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(WrapperTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(WrapperTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(WrapperTransformer::class, 'getCode')] +#[\PHPUnit\Framework\Attributes\CoversMethod(WrapperTransformer::class, 'configureOptions')] class WrapperTransformerTest extends TestCase { - /** - * @covers ::transform - */ public function testTransform(): void { $transformer = new WrapperTransformer(); @@ -38,9 +36,6 @@ public function testTransform(): void $this->assertEquals(['key' => 'my_value'], $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithIntegerWrapperKey(): void { $transformer = new WrapperTransformer(); @@ -54,9 +49,6 @@ public function testTransformWithIntegerWrapperKey(): void $this->assertEquals([1 => 'my_value'], $transformedValue); } - /** - * @covers ::transform - */ public function testTransformWithNullValue(): void { $transformer = new WrapperTransformer(); @@ -70,9 +62,6 @@ public function testTransformWithNullValue(): void $this->assertEquals(['key' => null], $transformedValue); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new WrapperTransformer(); @@ -82,9 +71,6 @@ public function testGetCodeReturnsCorrectCode(): void $this->assertEquals('wrapper', $code); } - /** - * @covers ::configureOptions - */ public function testConfigureOptionsSetsDefaultOptions(): void { $resolver = new OptionsResolver(); diff --git a/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php b/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php index baf16a5f..cb1eb488 100644 --- a/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php +++ b/tests/Transformer/Xml/XpathEvaluatorTransformerTest.php @@ -16,16 +16,13 @@ use CleverAge\ProcessBundle\Transformer\Xml\XpathEvaluatorTransformer; use PHPUnit\Framework\TestCase; -/** - * @coversDefaultClass \CleverAge\ProcessBundle\Transformer\Xml\XpathEvaluatorTransformer - */ +#[\PHPUnit\Framework\Attributes\CoversClass(XpathEvaluatorTransformer::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(XpathEvaluatorTransformer::class, 'buildXpath')] +#[\PHPUnit\Framework\Attributes\CoversMethod(XpathEvaluatorTransformer::class, 'query')] +#[\PHPUnit\Framework\Attributes\CoversMethod(XpathEvaluatorTransformer::class, 'transform')] +#[\PHPUnit\Framework\Attributes\CoversMethod(XpathEvaluatorTransformer::class, 'getCode')] class XpathEvaluatorTransformerTest extends TestCase { - /** - * @covers ::buildXpath - * @covers ::query - * @covers ::transform - */ public function testSimpleQuery(): void { $domDocument = new \DOMDocument(); @@ -45,11 +42,6 @@ public function testSimpleQuery(): void $this->assertEquals('ok', $result); } - /** - * @covers ::buildXpath - * @covers ::query - * @covers ::transform - */ public function testAttributeValueQuery(): void { $domDocument = new \DOMDocument(); @@ -62,11 +54,6 @@ public function testAttributeValueQuery(): void $this->assertEquals('ok', $result); } - /** - * @covers ::buildXpath - * @covers ::query - * @covers ::transform - */ public function testSubQuery(): void { $domDocument = new \DOMDocument(); @@ -80,11 +67,6 @@ public function testSubQuery(): void $this->assertEquals('ok', $result); } - /** - * @covers ::buildXpath - * @covers ::query - * @covers ::transform - */ public function testMultiResults(): void { $domDocument = new \DOMDocument(); @@ -99,11 +81,6 @@ public function testMultiResults(): void $this->assertEquals(['ok1', 'ok2', 'ok3'], $result); } - /** - * @covers ::buildXpath - * @covers ::query - * @covers ::transform - */ public function testMultiResultsAsNodeList(): void { $domDocument = new \DOMDocument(); @@ -122,9 +99,6 @@ public function testMultiResultsAsNodeList(): void self::assertEquals('ok3', $result[2]->textContent); } - /** - * @covers ::getCode - */ public function testGetCodeReturnsCorrectCode(): void { $transformer = new XpathEvaluatorTransformer(); From 00bacad364a7e39e1aa0e348f1b1b43da60639b4 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 9 Dec 2025 09:11:17 +0100 Subject: [PATCH 297/304] #179 - Update CHANGELOG for v5.0: include Symfony 8 and PHP 8.5 upgrade, remove PHP 8.1 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b08e1efd..bccbd449 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v5.0 +----- + +## Changes +* [#179](https://github.com/cleverage/process-bundle/issues/179) Upgrade to Symfony 8 & PHP 8.5 + +## BC breaks +* [#179](https://github.com/cleverage/process-bundle/issues/179) Remove PHP 8.1 + v4.5 ----- From ffe745a256a781bfd92e77ad533eb700562a4a17 Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Tue, 9 Dec 2025 11:07:12 +0100 Subject: [PATCH 298/304] #179 - Update CHANGELOG: refine PHP 8.5 and Symfony 8 support details, note removal of PHP 8.1 and Symfony 7.3 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bccbd449..286795e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,10 @@ v5.0 ----- ## Changes -* [#179](https://github.com/cleverage/process-bundle/issues/179) Upgrade to Symfony 8 & PHP 8.5 +* [#179](https://github.com/cleverage/process-bundle/issues/179) Add support for PHP 8.5 and Symfony 8.* Update phpunit/phpunit to version >10.0 ## BC breaks -* [#179](https://github.com/cleverage/process-bundle/issues/179) Remove PHP 8.1 +* [#179](https://github.com/cleverage/process-bundle/issues/179) Remove support for PHP 8.1 and Symfony 7.3 v4.5 ----- From 2be4cd5b9d1cd68f6cc855a8863f294bf91e4df6 Mon Sep 17 00:00:00 2001 From: xmarchegay Date: Tue, 9 Dec 2025 18:24:20 +0100 Subject: [PATCH 299/304] update PHP-CS-Fixer rules to match PHP 8.x migration --- .php-cs-fixer.dist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 124bfa47..54e1aead 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -24,8 +24,8 @@ return (new PhpCsFixer\Config()) ->setRules([ - '@PHP82Migration' => true, - '@PHPUnit75Migration:risky' => true, + '@PHP8x2Migration' => true, + '@PHPUnit7x5Migration:risky' => true, '@Symfony' => true, '@Symfony:risky' => true, 'protected_to_private' => false, From 3db3495e974b85b3a55cabdcf32bb92423eeb3de Mon Sep 17 00:00:00 2001 From: Xavier Marchegay Date: Mon, 22 Jun 2026 08:42:36 +0200 Subject: [PATCH 300/304] Add Dependabot configuration for GitHub Actions --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..89c38bf5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +# This keeps updated the GitHub actions used in .github/workflows/*.yaml +# See https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From 843bb220fe01817ab1c4822511556ccf0ac55ae8 Mon Sep 17 00:00:00 2001 From: xaviermarchegay Date: Mon, 22 Jun 2026 09:24:15 +0200 Subject: [PATCH 301/304] #185 - Run quality tools --- .php-cs-fixer.dist.php | 3 +++ src/DependencyInjection/Configuration.php | 2 +- src/Task/Process/ProcessLauncherTask.php | 2 +- src/Transformer/CachedTransformer.php | 2 +- src/Transformer/RulesTransformer.php | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 54e1aead..4c32dcd3 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,5 +1,7 @@ ['header' => $fileHeaderComment], 'modernize_strpos' => true, 'get_class_to_class_keyword' => true, + 'declare_strict_types' => true, ]) ->setRiskyAllowed(true) ->setFinder( diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index a3f80a5a..bdb9b8ef 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -175,7 +175,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition): void $definition->arrayNode($nodeName) ->beforeNormalization() ->ifString() - ->then(fn ($item): array => [$item])->end() + ->then(static fn ($item): array => [$item])->end() ->prototype('scalar'); } } diff --git a/src/Task/Process/ProcessLauncherTask.php b/src/Task/Process/ProcessLauncherTask.php index 8b3c4aad..30d5e6da 100644 --- a/src/Task/Process/ProcessLauncherTask.php +++ b/src/Task/Process/ProcessLauncherTask.php @@ -209,7 +209,7 @@ function (Options $options, $value) { $resolver->setAllowedTypes('sleep_interval', ['integer', 'double']); $resolver->setAllowedTypes('sleep_interval_after_launch', ['integer', 'double']); $resolver->setAllowedTypes('sleep_on_finalize_interval', ['integer', 'double']); - $microsecondNormalizer = fn (Options $options, $value): int => (int) ($value * 1_000_000); + $microsecondNormalizer = static fn (Options $options, $value): int => (int) ($value * 1_000_000); $resolver->setNormalizer('sleep_interval', $microsecondNormalizer); $resolver->setNormalizer('sleep_interval_after_launch', $microsecondNormalizer); $resolver->setNormalizer('sleep_on_finalize_interval', $microsecondNormalizer); diff --git a/src/Transformer/CachedTransformer.php b/src/Transformer/CachedTransformer.php index 5fff4923..bcdcb38e 100644 --- a/src/Transformer/CachedTransformer.php +++ b/src/Transformer/CachedTransformer.php @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('ttl', ['null', 'string', \DateTimeInterface::class]); $resolver->setNormalizer( 'ttl', - function (Options $options, $value) { + static function (Options $options, $value) { /* * Best use is a relative date string like "+1 hour". * diff --git a/src/Transformer/RulesTransformer.php b/src/Transformer/RulesTransformer.php index 22115368..7ef7d4e2 100644 --- a/src/Transformer/RulesTransformer.php +++ b/src/Transformer/RulesTransformer.php @@ -114,7 +114,7 @@ public function configureRuleOptions(OptionsResolver $resolver, ?array $expressi }; $resolver->setNormalizer('condition', $expressionNormalizer); - $resolver->setNormalizer('default', function (Options $options, $value) { + $resolver->setNormalizer('default', static function (Options $options, $value) { if ($value && $options['condition']) { throw new \InvalidArgumentException('A rule cannot have a condition and be the default in the same time'); } From 65cf83fc6fe2bfb91c25bfe90ec21ac598da223d Mon Sep 17 00:00:00 2001 From: xaviermarchegay Date: Mon, 22 Jun 2026 09:37:59 +0200 Subject: [PATCH 302/304] #185 - Run quality tools --- src/CleverAgeProcessBundle.php | 1 + src/Configuration/ProcessConfiguration.php | 9 +-------- src/Configuration/TaskConfiguration.php | 4 +--- src/Filesystem/CsvFile.php | 2 ++ src/Logger/TaskProcessor.php | 1 + src/Logger/TransformerProcessor.php | 1 + src/Task/File/Csv/AbstractCsvTask.php | 2 ++ src/Task/File/Csv/CsvReaderTask.php | 1 + src/Task/File/Csv/CsvSplitterTask.php | 4 ++++ src/Task/File/Csv/CsvWriterTask.php | 1 + src/Task/File/Csv/InputCsvReaderTask.php | 2 ++ src/Task/File/InputFileReaderTask.php | 2 ++ src/Task/File/InputFolderBrowserTask.php | 3 +++ src/Task/File/InputLineReaderTask.php | 2 ++ src/Task/FilterTask.php | 1 + src/Task/IterableBatchTask.php | 1 + src/Task/Process/ProcessExecutorTask.php | 1 + src/Task/SplitJoinLineTask.php | 1 + 18 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/CleverAgeProcessBundle.php b/src/CleverAgeProcessBundle.php index 7e94bede..cd704afa 100644 --- a/src/CleverAgeProcessBundle.php +++ b/src/CleverAgeProcessBundle.php @@ -34,6 +34,7 @@ public function build(ContainerBuilder $container): void $container->addCompilerPass(new CheckSerializerCompilerPass()); } + #[\Override] public function getPath(): string { return \dirname(__DIR__); diff --git a/src/Configuration/ProcessConfiguration.php b/src/Configuration/ProcessConfiguration.php index 37b06baf..48d9caa8 100644 --- a/src/Configuration/ProcessConfiguration.php +++ b/src/Configuration/ProcessConfiguration.php @@ -112,14 +112,7 @@ public function getDependencyGroups(): array if (null === $this->dependencyGroups) { $this->dependencyGroups = []; foreach ($this->getTaskConfigurations() as $taskConfiguration) { - $isInBranch = false; - foreach ($this->dependencyGroups as $branch) { - if (\in_array($taskConfiguration->getCode(), $branch, true)) { - $isInBranch = true; - break; - } - } - + $isInBranch = array_any($this->dependencyGroups, static fn ($branch) => \in_array($taskConfiguration->getCode(), $branch, true)); if (!$isInBranch) { $dependencies = $this->buildDependencies($taskConfiguration); $dependencies = $this->sortDependencies($dependencies); diff --git a/src/Configuration/TaskConfiguration.php b/src/Configuration/TaskConfiguration.php index feabfa7c..1645939e 100644 --- a/src/Configuration/TaskConfiguration.php +++ b/src/Configuration/TaskConfiguration.php @@ -112,9 +112,7 @@ public function getOutputs(): array return $this->outputs; } - /** - * @deprecated Use getErrorOutputs method instead - */ + #[\Deprecated(message: 'Use getErrorOutputs method instead')] public function getErrors(): array { @trigger_error('Deprecated method, use getErrorOutputs instead', \E_USER_DEPRECATED); diff --git a/src/Filesystem/CsvFile.php b/src/Filesystem/CsvFile.php index 1dc892ce..d8944e87 100644 --- a/src/Filesystem/CsvFile.php +++ b/src/Filesystem/CsvFile.php @@ -56,11 +56,13 @@ public function __construct( /** * Will return a resource if the file was created using a resource. */ + #[\Override] public function getFilePath(): string { return $this->filePath; } + #[\Override] protected function getResourceName(): string { return "CSV file '{$this->filePath}'"; diff --git a/src/Logger/TaskProcessor.php b/src/Logger/TaskProcessor.php index ac4a7d3b..374c5e46 100644 --- a/src/Logger/TaskProcessor.php +++ b/src/Logger/TaskProcessor.php @@ -17,6 +17,7 @@ class TaskProcessor extends AbstractProcessor { + #[\Override] public function __invoke(LogRecord $record): LogRecord { $record = parent::__invoke($record); diff --git a/src/Logger/TransformerProcessor.php b/src/Logger/TransformerProcessor.php index 8a61c301..b296b016 100644 --- a/src/Logger/TransformerProcessor.php +++ b/src/Logger/TransformerProcessor.php @@ -17,6 +17,7 @@ class TransformerProcessor extends AbstractProcessor { + #[\Override] public function __invoke(LogRecord $record): LogRecord { $record = parent::__invoke($record); diff --git a/src/Task/File/Csv/AbstractCsvTask.php b/src/Task/File/Csv/AbstractCsvTask.php index dd7d0cf9..2119dcb9 100644 --- a/src/Task/File/Csv/AbstractCsvTask.php +++ b/src/Task/File/Csv/AbstractCsvTask.php @@ -24,6 +24,7 @@ */ abstract class AbstractCsvTask extends AbstractCsvResourceTask { + #[\Override] protected function initFile(ProcessState $state): void { if ($this->csv instanceof CsvResource) { @@ -41,6 +42,7 @@ protected function initFile(ProcessState $state): void ); } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/Csv/CsvReaderTask.php b/src/Task/File/Csv/CsvReaderTask.php index afe16bd8..6168388e 100644 --- a/src/Task/File/Csv/CsvReaderTask.php +++ b/src/Task/File/Csv/CsvReaderTask.php @@ -82,6 +82,7 @@ protected function getHeaders(ProcessState $state, array $options): ?array return $options['headers']; } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/Csv/CsvSplitterTask.php b/src/Task/File/Csv/CsvSplitterTask.php index 234017a4..c11a0b9d 100644 --- a/src/Task/File/Csv/CsvSplitterTask.php +++ b/src/Task/File/Csv/CsvSplitterTask.php @@ -23,6 +23,7 @@ */ class CsvSplitterTask extends InputCsvReaderTask { + #[\Override] public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -49,6 +50,7 @@ public function execute(ProcessState $state): void * return true if the task has a next element * return false if the task has terminated it's iteration. */ + #[\Override] public function next(ProcessState $state): bool { if (!$this->csv instanceof CsvResource) { @@ -64,6 +66,7 @@ public function next(ProcessState $state): bool return !$endOfFile; } + #[\Override] public function finalize(ProcessState $state): void { if ($this->csv instanceof CsvResource) { @@ -100,6 +103,7 @@ protected function splitCsv(CsvResource $csv, int $maxLines): string return $tmpFilePath; } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/Csv/CsvWriterTask.php b/src/Task/File/Csv/CsvWriterTask.php index e20532a6..c4c70e55 100644 --- a/src/Task/File/Csv/CsvWriterTask.php +++ b/src/Task/File/Csv/CsvWriterTask.php @@ -43,6 +43,7 @@ public function proceed(ProcessState $state): void $state->setOutput($this->csv->getFilePath()); } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/Csv/InputCsvReaderTask.php b/src/Task/File/Csv/InputCsvReaderTask.php index 7afc735c..2234a263 100644 --- a/src/Task/File/Csv/InputCsvReaderTask.php +++ b/src/Task/File/Csv/InputCsvReaderTask.php @@ -21,6 +21,7 @@ */ class InputCsvReaderTask extends CsvReaderTask { + #[\Override] protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); @@ -31,6 +32,7 @@ protected function getOptions(ProcessState $state): array return $options; } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/InputFileReaderTask.php b/src/Task/File/InputFileReaderTask.php index 5c638ff9..d378a6dd 100644 --- a/src/Task/File/InputFileReaderTask.php +++ b/src/Task/File/InputFileReaderTask.php @@ -21,6 +21,7 @@ */ class InputFileReaderTask extends FileReaderTask { + #[\Override] protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); @@ -31,6 +32,7 @@ protected function getOptions(ProcessState $state): array return $options; } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/File/InputFolderBrowserTask.php b/src/Task/File/InputFolderBrowserTask.php index 2d6bb67b..a0151ae1 100644 --- a/src/Task/File/InputFolderBrowserTask.php +++ b/src/Task/File/InputFolderBrowserTask.php @@ -31,11 +31,13 @@ public function flush(ProcessState $state): void $state->setSkipped(true); } + #[\Override] public function initialize(ProcessState $state): void { parent::getOptions($state); } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -47,6 +49,7 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('base_folder_path', ['string']); } + #[\Override] protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); diff --git a/src/Task/File/InputLineReaderTask.php b/src/Task/File/InputLineReaderTask.php index 6ae852b6..73ac0ea2 100644 --- a/src/Task/File/InputLineReaderTask.php +++ b/src/Task/File/InputLineReaderTask.php @@ -21,6 +21,7 @@ */ class InputLineReaderTask extends LineReaderTask { + #[\Override] protected function getOptions(ProcessState $state): array { $options = parent::getOptions($state); @@ -31,6 +32,7 @@ protected function getOptions(ProcessState $state): array return $options; } + #[\Override] protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); diff --git a/src/Task/FilterTask.php b/src/Task/FilterTask.php index 8ea0abae..290ba13e 100644 --- a/src/Task/FilterTask.php +++ b/src/Task/FilterTask.php @@ -28,6 +28,7 @@ class FilterTask extends AbstractConfigurableTask { use ConditionTrait; + #[\Override] public function initialize(ProcessState $state): void { parent::initialize($state); diff --git a/src/Task/IterableBatchTask.php b/src/Task/IterableBatchTask.php index 9b751fba..b8840a74 100644 --- a/src/Task/IterableBatchTask.php +++ b/src/Task/IterableBatchTask.php @@ -35,6 +35,7 @@ public function __construct( ) { } + #[\Override] public function initialize(ProcessState $state): void { parent::initialize($state); diff --git a/src/Task/Process/ProcessExecutorTask.php b/src/Task/Process/ProcessExecutorTask.php index 6b27a171..6775e6c5 100644 --- a/src/Task/Process/ProcessExecutorTask.php +++ b/src/Task/Process/ProcessExecutorTask.php @@ -45,6 +45,7 @@ public function execute(ProcessState $state): void $state->setOutput($output); } + #[\Override] public function initialize(ProcessState $state): void { parent::initialize($state); diff --git a/src/Task/SplitJoinLineTask.php b/src/Task/SplitJoinLineTask.php index 6d695c5b..9b6a614a 100644 --- a/src/Task/SplitJoinLineTask.php +++ b/src/Task/SplitJoinLineTask.php @@ -21,6 +21,7 @@ */ class SplitJoinLineTask extends AbstractIterableOutputTask { + #[\Override] public function next(ProcessState $state): bool { $valid = parent::next($state); From 5240651bee85723d3795dc9739ba340a33ae6aed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 07:43:40 +0000 Subject: [PATCH 303/304] Bump ramsey/composer-install from 3 to 4 Bumps [ramsey/composer-install](https://github.com/ramsey/composer-install) from 3 to 4. - [Release notes](https://github.com/ramsey/composer-install/releases) - [Commits](https://github.com/ramsey/composer-install/compare/v3...v4) --- updated-dependencies: - dependency-name: ramsey/composer-install dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/quality.yml | 6 +++--- .github/workflows/test.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index f4e4f5b8..d6bd2968 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -23,7 +23,7 @@ jobs: coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@v4 - name: PHPStan run: vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github @@ -40,7 +40,7 @@ jobs: coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@v4 - name: PHP-CS-Fixer run: vendor/bin/php-cs-fixer fix --diff --dry-run --show-progress=none @@ -57,6 +57,6 @@ jobs: coverage: none tools: composer:v2 - name: Install Composer dependencies (locked) - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@v4 - name: Rector run: vendor/bin/rector --no-progress-bar --dry-run diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 27a5a548..3323bdf1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,7 +94,7 @@ jobs: if: matrix.variant != 'normal' && !startsWith(matrix.variant, 'symfony/symfony') run: composer require ${{ matrix.variant }} --no-update - name: Install Composer dependencies (${{ matrix.dependencies }}) - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@v4 with: dependency-versions: ${{ matrix.dependencies }} - name: Run Tests with coverage From f8201fee88b99949053370d50be347db1410e5e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 07:43:43 +0000 Subject: [PATCH 304/304] Bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/quality.yml | 6 +++--- .github/workflows/test.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index d6bd2968..1521e2c9 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3323bdf1..b49e0ce1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,7 +81,7 @@ jobs: variant: symfony/symfony:"8.*" steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install PHP with extensions uses: shivammathur/setup-php@v2 with: