Skip to content

Commit 327e0cc

Browse files
committed
WIP
1 parent 976cc82 commit 327e0cc

11 files changed

Lines changed: 108 additions & 114 deletions

composer.json

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,28 @@
4747
"doctrine/doctrine-bundle": "^2.0",
4848
"monolog/monolog": "^2.0||^3.0",
4949
"psr/log": "^1.1||^2.0||^3.0",
50-
"symfony/config": "^7.0",
51-
"symfony/console": "^7.0",
52-
"symfony/dependency-injection": "^7.0",
53-
"symfony/event-dispatcher": "^7.0",
54-
"symfony/http-kernel": "^7.0",
55-
"symfony/lock": "^7.0",
56-
"symfony/monolog-bridge": "^7.0",
57-
"symfony/options-resolver": "^7.0",
58-
"symfony/validator": "^7.0",
59-
"symfony/yaml": "^7.0"
50+
"symfony/config": "^7.3",
51+
"symfony/console": "^7.3",
52+
"symfony/dependency-injection": "^7.3",
53+
"symfony/event-dispatcher": "^7.3",
54+
"symfony/http-kernel": "^7.3",
55+
"symfony/lock": "^7.3",
56+
"symfony/monolog-bridge": "^7.3",
57+
"symfony/options-resolver": "^7.3",
58+
"symfony/validator": "^7.3",
59+
"symfony/yaml": "^7.3"
6060
},
6161
"require-dev": {
6262
"amphp/amp": "^2.5",
6363
"friendsofphp/php-cs-fixer": "^3.75",
6464
"phpunit/phpunit": "^11",
6565
"portphp/portphp": "^1.9",
6666
"rector/rector": "^2.0",
67-
"symfony/messenger": "^7.0"
67+
"symfony/messenger": "^7.3"
6868
},
6969
"suggest": {
7070
"amphp/amp": "Provide asynchronous steps for your dataflows",
71+
"league/flysystem": "Allows Dataflow file exception mode, i.e. saving job exceptions outside the database",
7172
"portphp/portphp": "Provides generic readers, steps and writers for your dataflows.",
7273
"symfony/messenger": "Allows messenger mode, i.e. letting workers run jobs"
7374
},

rector.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
declare(strict_types=1);
44

5-
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
65
use Rector\Config\RectorConfig;
76
use Rector\Set\ValueObject\LevelSetList;
87
use Rector\Symfony\Set\SymfonySetList;
@@ -12,11 +11,11 @@
1211
__DIR__.'/src',
1312
__DIR__.'/Tests',
1413
])
15-
->withComposerBased(symfony: true)
16-
->withRules([InlineConstructorDefaultToPropertyRector::class])
14+
->withComposerBased(doctrine: true, symfony: true)
1715
->withSets([
1816
SymfonySetList::SYMFONY_CODE_QUALITY,
1917
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
18+
SymfonySetList::SYMFONY_73,
2019
LevelSetList::UP_TO_PHP_82,
2120
])
2221
;

src/Command/AddScheduledDataflowCommand.php

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@
99
use CodeRhapsodie\DataflowBundle\Registry\DataflowTypeRegistryInterface;
1010
use CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository;
1111
use Symfony\Component\Console\Attribute\AsCommand;
12-
use Symfony\Component\Console\Command\Command;
13-
use Symfony\Component\Console\Input\InputInterface;
14-
use Symfony\Component\Console\Input\InputOption;
15-
use Symfony\Component\Console\Output\OutputInterface;
12+
use Symfony\Component\Console\Attribute\Option;
1613
use Symfony\Component\Console\Style\SymfonyStyle;
1714
use Symfony\Component\Validator\Validator\ValidatorInterface;
1815

@@ -22,34 +19,24 @@
2219
#[AsCommand('code-rhapsodie:dataflow:schedule:add', 'Create a scheduled dataflow', help: <<<'TXT'
2320
The <info>%command.name%</info> allows you to create a new scheduled dataflow.
2421
TXT)]
25-
class AddScheduledDataflowCommand extends Command
22+
final readonly class AddScheduledDataflowCommand
2623
{
27-
public function __construct(private readonly DataflowTypeRegistryInterface $registry, private readonly ScheduledDataflowRepository $scheduledDataflowRepository, private readonly ValidatorInterface $validator, private readonly ConnectionFactory $connectionFactory)
24+
public function __construct(private DataflowTypeRegistryInterface $registry, private ScheduledDataflowRepository $scheduledDataflowRepository, private ValidatorInterface $validator, private ConnectionFactory $connectionFactory)
2825
{
29-
parent::__construct();
3026
}
3127

32-
protected function configure(): void
33-
{
34-
$this
35-
->addOption('label', null, InputOption::VALUE_REQUIRED, 'Label of the scheduled dataflow')
36-
->addOption('type', null, InputOption::VALUE_REQUIRED, 'Type of the scheduled dataflow (FQCN)')
37-
->addOption(
38-
'options',
39-
null,
40-
InputOption::VALUE_OPTIONAL,
41-
'Options of the scheduled dataflow (ex: {"option1": "value1", "option2": "value2"})'
42-
)
43-
->addOption('frequency', null, InputOption::VALUE_REQUIRED, 'Frequency of the scheduled dataflow')
44-
->addOption('first_run', null, InputOption::VALUE_REQUIRED, 'Date for the first run of the scheduled dataflow (Y-m-d H:i:s)')
45-
->addOption('enabled', null, InputOption::VALUE_REQUIRED, 'State of the scheduled dataflow')
46-
->addOption('connection', null, InputOption::VALUE_REQUIRED, 'Define the DBAL connection to use');
47-
}
48-
49-
protected function execute(InputInterface $input, OutputInterface $output): int
50-
{
51-
if ($input->getOption('connection') !== null) {
52-
$this->connectionFactory->setConnectionName($input->getOption('connection'));
28+
public function __invoke(
29+
SymfonyStyle $io,
30+
#[Option('Label of the scheduled dataflow')] ?string $label = null,
31+
#[Option('Type of the scheduled dataflow (FQCN)')] ?string $type = null,
32+
#[Option('Options of the scheduled dataflow (ex: {"option1": "value1", "option2": "value2"})')] ?string $options = null,
33+
#[Option('Frequency of the scheduled dataflow')] ?string $frequency = null,
34+
#[Option('Date for the first run of the scheduled dataflow (Y-m-d H:i:s)')] ?string $firstRun = null,
35+
#[Option('State of the scheduled dataflow')] ?bool $enabled = null,
36+
#[Option('Define the DBAL connection to use')] ?string $connection = null,
37+
): int {
38+
if ($connection !== null) {
39+
$this->connectionFactory->setConnectionName($connection);
5340
}
5441
$choices = [];
5542
$typeMapping = [];
@@ -58,36 +45,29 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5845
$typeMapping[$dataflowType->getLabel()] = $fqcn;
5946
}
6047

61-
$io = new SymfonyStyle($input, $output);
62-
$label = $input->getOption('label');
6348
if (!$label) {
6449
$label = $io->ask('What is the scheduled dataflow label?');
6550
}
66-
$type = $input->getOption('type');
6751
if (!$type) {
6852
$selectedType = $io->choice('What is the scheduled dataflow type?', $choices);
6953
$type = $typeMapping[$selectedType];
7054
}
71-
$options = $input->getOption('options');
7255
if (!$options) {
7356
$options = $io->ask(
7457
'What are the launch options for the scheduled dataflow? (ex: {"option1": "value1", "option2": "value2"})',
7558
json_encode([])
7659
);
7760
}
78-
$frequency = $input->getOption('frequency');
7961
if (!$frequency) {
8062
$frequency = $io->choice(
8163
'What is the frequency for the scheduled dataflow?',
8264
ScheduledDataflow::AVAILABLE_FREQUENCIES
8365
);
8466
}
85-
$firstRun = $input->getOption('first_run');
8667
if (!$firstRun) {
8768
$firstRun = $io->ask('When is the first execution of the scheduled dataflow (format: Y-m-d H:i:s)?');
8869
}
89-
$enabled = $input->getOption('enabled');
90-
if (!$enabled) {
70+
if ($enabled === null) {
9171
$enabled = $io->confirm('Enable the scheduled dataflow?');
9272
}
9373

src/Command/ChangeScheduleStatusCommand.php

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@
77
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
88
use CodeRhapsodie\DataflowBundle\Factory\ConnectionFactory;
99
use CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository;
10+
use Symfony\Component\Console\Attribute\Argument;
1011
use Symfony\Component\Console\Attribute\AsCommand;
11-
use Symfony\Component\Console\Command\Command;
12-
use Symfony\Component\Console\Input\InputArgument;
13-
use Symfony\Component\Console\Input\InputInterface;
14-
use Symfony\Component\Console\Input\InputOption;
15-
use Symfony\Component\Console\Output\OutputInterface;
12+
use Symfony\Component\Console\Attribute\Option;
1613
use Symfony\Component\Console\Style\SymfonyStyle;
1714

1815
/**
@@ -21,50 +18,47 @@
2118
#[AsCommand('code-rhapsodie:dataflow:schedule:change-status', 'Change schedule status', help: <<<'TXT'
2219
The <info>%command.name%</info> command able you to change schedule status.
2320
TXT)]
24-
class ChangeScheduleStatusCommand extends Command
21+
final readonly class ChangeScheduleStatusCommand
2522
{
26-
public function __construct(private readonly ScheduledDataflowRepository $scheduledDataflowRepository, private readonly ConnectionFactory $connectionFactory)
23+
public function __construct(private ScheduledDataflowRepository $scheduledDataflowRepository, private ConnectionFactory $connectionFactory)
2724
{
28-
parent::__construct();
2925
}
3026

31-
protected function configure(): void
32-
{
33-
$this
34-
->addArgument('schedule-id', InputArgument::REQUIRED, 'Id of the schedule')
35-
->addOption('enable', null, InputOption::VALUE_NONE, 'Enable the schedule')
36-
->addOption('disable', null, InputOption::VALUE_NONE, 'Disable the schedule')
37-
->addOption('connection', null, InputOption::VALUE_REQUIRED, 'Define the DBAL connection to use');
38-
}
39-
40-
protected function execute(InputInterface $input, OutputInterface $output): int
41-
{
42-
if ($input->getOption('connection') !== null) {
43-
$this->connectionFactory->setConnectionName($input->getOption('connection'));
27+
public function __invoke(
28+
SymfonyStyle $io,
29+
#[Argument('Id of the schedule')] int $scheduleId,
30+
#[Option('Enable the schedule')] ?bool $enable = null,
31+
#[Option('Disable the schedule')] ?bool $disable = null,
32+
#[Option('Define the DBAL connection to use')] ?string $connection = null,
33+
): int {
34+
if ($connection !== null) {
35+
$this->connectionFactory->setConnectionName($connection);
4436
}
45-
$io = new SymfonyStyle($input, $output);
37+
4638
/** @var ScheduledDataflow|null $schedule */
47-
$schedule = $this->scheduledDataflowRepository->find((int) $input->getArgument('schedule-id'));
39+
$schedule = $this->scheduledDataflowRepository->find($scheduleId);
4840

4941
if (!$schedule) {
50-
$io->error(\sprintf('Cannot find scheduled dataflow with id "%d".', $input->getArgument('schedule-id')));
42+
$io->error(\sprintf('Cannot find scheduled dataflow with id "%d".', $scheduleId));
5143

5244
return 1;
5345
}
5446

55-
if ($input->getOption('enable') && $input->getOption('disable')) {
47+
if ($enable !== null && $disable !== null) {
5648
$io->error('You cannot pass enable and disable options in the same time.');
5749

5850
return 2;
5951
}
60-
if (!$input->getOption('enable') && !$input->getOption('disable')) {
52+
if ($enable === null && $disable === null) {
6153
$io->error('You must pass enable or disable option.');
6254

6355
return 3;
6456
}
6557

58+
$enable = $enable ?? !$disable;
59+
6660
try {
67-
$schedule->setEnabled($input->getOption('enable'));
61+
$schedule->setEnabled($enable);
6862
$this->scheduledDataflowRepository->save($schedule);
6963
$io->success(\sprintf('Schedule with id "%s" has been successfully updated.', $schedule->getId()));
7064
} catch (\Exception $e) {

src/Command/DatabaseSchemaCommand.php

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,28 @@
1212
use Doctrine\DBAL\Schema\Schema;
1313
use Doctrine\DBAL\Schema\Table;
1414
use Symfony\Component\Console\Attribute\AsCommand;
15+
use Symfony\Component\Console\Attribute\Option;
1516
use Symfony\Component\Console\Command\Command;
16-
use Symfony\Component\Console\Input\InputInterface;
17-
use Symfony\Component\Console\Input\InputOption;
18-
use Symfony\Component\Console\Output\OutputInterface;
1917
use Symfony\Component\Console\Question\ConfirmationQuestion;
2018
use Symfony\Component\Console\Style\SymfonyStyle;
2119

2220
#[AsCommand(name: 'code-rhapsodie:dataflow:database-schema', description: 'Generates schema create / update SQL queries', help: <<<'TXT'
2321
The <info>%command.name%</info> help you to generate SQL Query to create or update your database schema for this bundle
2422
TXT)]
25-
class DatabaseSchemaCommand extends Command
23+
final readonly class DatabaseSchemaCommand
2624
{
27-
public function __construct(private readonly ConnectionFactory $connectionFactory)
25+
public function __construct(private ConnectionFactory $connectionFactory)
2826
{
29-
parent::__construct();
3027
}
3128

32-
protected function configure(): void
33-
{
34-
$this
35-
->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Dump only the update SQL queries.')
36-
->addOption('update', null, InputOption::VALUE_NONE, 'Dump/execute only the update SQL queries.')
37-
->addOption('connection', null, InputOption::VALUE_REQUIRED, 'Define the DBAL connection to use');
38-
}
39-
40-
protected function execute(InputInterface $input, OutputInterface $output): int
41-
{
42-
$io = new SymfonyStyle($input, $output);
43-
44-
if ($input->getOption('connection') !== null) {
45-
$this->connectionFactory->setConnectionName($input->getOption('connection'));
29+
public function __invoke(
30+
SymfonyStyle $io,
31+
#[Option('Dump only the update SQL queries.')] bool $dump = false,
32+
#[Option('Dump/execute only the update SQL queries.')] bool $update = false,
33+
#[Option('Define the DBAL connection to use')] ?string $connection = null,
34+
): int {
35+
if ($connection !== null) {
36+
$this->connectionFactory->setConnectionName($connection);
4637
}
4738

4839
$connection = $this->connectionFactory->getConnection();
@@ -52,7 +43,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5243

5344
$sqls = $schema->toSql($connection->getDatabasePlatform());
5445

55-
if ($input->getOption('update')) {
46+
if ($update) {
5647
$sm = $connection->createSchemaManager();
5748

5849
$tableArray = [JobRepository::TABLE_NAME, ScheduledDataflowRepository::TABLE_NAME];
@@ -85,7 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8576
}
8677
}
8778

88-
if ($input->getOption('dump-sql')) {
79+
if ($dump) {
8980
$io->text('Execute these SQL Queries on your database:');
9081
foreach ($sqls as $sql) {
9182
$io->text($sql.';');
@@ -106,6 +97,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
10697

10798
$io->success(\sprintf('%d queries executed.', \count($sqls)));
10899

109-
return parent::SUCCESS;
100+
return Command::SUCCESS;
110101
}
111102
}

src/Command/JobCleanupCommand.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44

55
namespace CodeRhapsodie\DataflowBundle\Command;
66

7+
use CodeRhapsodie\DataflowBundle\ExceptionsHandler\ExceptionHandlerInterface;
78
use CodeRhapsodie\DataflowBundle\Repository\JobRepository;
89
use Symfony\Component\Console\Attribute\AsCommand;
910
use Symfony\Component\Console\Command\Command;
10-
use Symfony\Component\Console\Input\InputInterface;
11-
use Symfony\Component\Console\Output\OutputInterface;
1211

1312
#[AsCommand(name: 'code-rhapsodie:dataflow:job:cleanup', description: 'Cleanup job history.', help: <<<'TXT'
1413
Job retention can be configured with the "job_history.retention" configuration.
1514
TXT)]
16-
class JobCleanupCommand extends Command
15+
final readonly class JobCleanupCommand
1716
{
18-
public function __construct(private readonly JobRepository $jobRepository, private readonly int $retention)
19-
{
20-
parent::__construct();
21-
}
22-
23-
protected function configure()
24-
{
17+
public function __construct(
18+
private JobRepository $jobRepository,
19+
private ExceptionHandlerInterface $exceptionHandler,
20+
private int $retention,
21+
) {
2522
}
2623

27-
protected function execute(InputInterface $input, OutputInterface $output): int
24+
public function __invoke(): int
2825
{
29-
$this->jobRepository->deleteOld($this->retention);
26+
$removedIds = $this->jobRepository->deleteOld($this->retention);
27+
foreach ($removedIds as $jobId) {
28+
$this->exceptionHandler->delete($jobId);
29+
}
3030

3131
return Command::SUCCESS;
3232
}

src/ExceptionsHandler/ExceptionHandlerInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ interface ExceptionHandlerInterface
99
public function save(?int $jobId, ?array $exceptions): void;
1010

1111
public function find(int $jobId): ?array;
12+
13+
public function delete(int $jobId): void;
1214
}

src/ExceptionsHandler/FilesystemExceptionHandler.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ public function find(int $jobId): ?array
3434
return [];
3535
}
3636
}
37+
38+
public function delete(int $jobId): void
39+
{
40+
$this->filesystem->delete(\sprintf('dataflow-job-%s.log', $jobId));
41+
}
3742
}

src/ExceptionsHandler/NullExceptionHandler.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ class NullExceptionHandler implements ExceptionHandlerInterface
88
{
99
public function save(?int $jobId, ?array $exceptions): void
1010
{
11+
// Nothing to do
1112
}
1213

1314
public function find(int $jobId): ?array
1415
{
1516
return null;
1617
}
18+
19+
public function delete(int $jobId): void
20+
{
21+
// Nothing to do
22+
}
1723
}

0 commit comments

Comments
 (0)