Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@
# Workflow
/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @lyrixx
/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/WorkflowGuardListenerPass.php @lyrixx
/src/Symfony/Component/Workflow/ @lyrixx
# Yaml
/src/Symfony/Component/Yaml/ @xabbuh
1 change: 1 addition & 0 deletions UPGRADE-7.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ FrameworkBundle
---------------

* Deprecate `Symfony\Bundle\FrameworkBundle\Console\Application::add()` in favor of `addCommand()`
* Deprecate `Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand` in favor of `Symfony\Component\Workflow\Command\WorkflowDumpCommand`

HtmlSanitizer
-------------
Expand Down
116 changes: 5 additions & 111 deletions src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,120 +12,14 @@
namespace Symfony\Bundle\FrameworkBundle\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\Workflow\Debug\TraceableWorkflow;
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
use Symfony\Component\Workflow\Dumper\MermaidDumper;
use Symfony\Component\Workflow\Dumper\PlantUmlDumper;
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\StateMachine;
use Symfony\Component\Workflow\Command\WorkflowDumpCommand as BaseWorkflowDumpCommand;

trigger_deprecation('symfony/framework-bundle', '7.4', 'The "%s" class is deprecated, use "%s" instead.', WorkflowDumpCommand::class, BaseWorkflowDumpCommand::class);

/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*
* @final
* @deprecated since Symfony 7.4, use {@see \Symfony\Component\Workflow\Command\WorkflowDumpCommand} instead.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggested code style change looks legit to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too late, I've fixed it after the merge.

*/
#[AsCommand(name: 'workflow:dump', description: 'Dump a workflow')]
class WorkflowDumpCommand extends Command
class WorkflowDumpCommand extends BaseWorkflowDumpCommand

Check failure on line 23 in src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidExtendClass

src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php:23:35: InvalidExtendClass: Class Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand may not inherit from final class Symfony\Component\Workflow\Command\WorkflowDumpCommand (see https://psalm.dev/232)

Check failure on line 23 in src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidExtendClass

src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php:23:35: InvalidExtendClass: Class Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand may not inherit from final class Symfony\Component\Workflow\Command\WorkflowDumpCommand (see https://psalm.dev/232)
{
private const DUMP_FORMAT_OPTIONS = [
'puml',
'mermaid',
'dot',
];

public function __construct(
private ServiceLocator $workflows,
) {
parent::__construct();
}

protected function configure(): void
{
$this
->setDefinition([
new InputArgument('name', InputArgument::REQUIRED, 'A workflow name'),
new InputArgument('marking', InputArgument::IS_ARRAY, 'A marking (a list of places)'),
new InputOption('label', 'l', InputOption::VALUE_REQUIRED, 'Label a graph'),
new InputOption('with-metadata', null, InputOption::VALUE_NONE, 'Include the workflow\'s metadata in the dumped graph', null),
new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'),
])
->setHelp(<<<'EOF'
The <info>%command.name%</info> command dumps the graphical representation of a
workflow in different formats
<info>DOT</info>: %command.full_name% <workflow name> | dot -Tpng > workflow.png
<info>PUML</info>: %command.full_name% <workflow name> --dump-format=puml | java -jar plantuml.jar -p > workflow.png
<info>MERMAID</info>: %command.full_name% <workflow name> --dump-format=mermaid | mmdc -o workflow.svg
EOF
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$workflowName = $input->getArgument('name');

if (!$this->workflows->has($workflowName)) {
throw new InvalidArgumentException(\sprintf('The workflow named "%s" cannot be found.', $workflowName));
}
$workflow = $this->workflows->get($workflowName);
if ($workflow instanceof TraceableWorkflow) {
$workflow = $workflow->getInner();
}
$type = $workflow instanceof StateMachine ? 'state_machine' : 'workflow';
$definition = $workflow->getDefinition();

switch ($input->getOption('dump-format')) {
case 'puml':
$transitionType = 'workflow' === $type ? PlantUmlDumper::WORKFLOW_TRANSITION : PlantUmlDumper::STATEMACHINE_TRANSITION;
$dumper = new PlantUmlDumper($transitionType);
break;

case 'mermaid':
$transitionType = 'workflow' === $type ? MermaidDumper::TRANSITION_TYPE_WORKFLOW : MermaidDumper::TRANSITION_TYPE_STATEMACHINE;
$dumper = new MermaidDumper($transitionType);
break;

case 'dot':
default:
$dumper = ('workflow' === $type) ? new GraphvizDumper() : new StateMachineGraphvizDumper();
}

$marking = new Marking();

foreach ($input->getArgument('marking') as $place) {
$marking->mark($place);
}

$options = [
'name' => $workflowName,
'with-metadata' => $input->getOption('with-metadata'),
'nofooter' => true,
'label' => $input->getOption('label'),
];
$output->writeln($dumper->dump($definition, $marking, $options));

return 0;
}

public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('name')) {
$suggestions->suggestValues(array_keys($this->workflows->getProvidedServices()));
}

if ($input->mustSuggestOptionValuesFor('dump-format')) {
$suggestions->suggestValues(self::DUMP_FORMAT_OPTIONS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
use Symfony\Bundle\FrameworkBundle\Command\SecretsSetCommand;
use Symfony\Bundle\FrameworkBundle\Command\TranslationDebugCommand;
use Symfony\Bundle\FrameworkBundle\Command\TranslationExtractCommand;
use Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand;
use Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\EventListener\SuggestMissingPackageSubscriber;
Expand All @@ -61,6 +60,7 @@
use Symfony\Component\Translation\Command\TranslationPushCommand;
use Symfony\Component\Translation\Command\XliffLintCommand;
use Symfony\Component\Validator\Command\DebugCommand as ValidatorDebugCommand;
use Symfony\Component\Workflow\Command\WorkflowDumpCommand;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;

return static function (ContainerConfigurator $container) {
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Workflow/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* Add support for `BackedEnum` in `MethodMarkingStore`
* Add support for weighted transitions
* Add a command to dump a workflow definition in different formats (dot, plantuml, mermaid)

7.3
---
Expand Down
131 changes: 131 additions & 0 deletions src/Symfony/Component/Workflow/Command/WorkflowDumpCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Workflow\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Workflow\Debug\TraceableWorkflow;
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
use Symfony\Component\Workflow\Dumper\MermaidDumper;
use Symfony\Component\Workflow\Dumper\PlantUmlDumper;
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\StateMachine;
use Symfony\Contracts\Service\ServiceProviderInterface;

/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*
* @final
*/
#[AsCommand(name: 'workflow:dump', description: 'Dump a workflow')]
class WorkflowDumpCommand extends Command
{
private const DUMP_FORMAT_OPTIONS = [
'puml',
'mermaid',
'dot',
];

public function __construct(
private ServiceProviderInterface $workflows,
) {
parent::__construct();
}

protected function configure(): void
{
$this
->setDefinition([
new InputArgument('name', InputArgument::REQUIRED, 'A workflow name'),
new InputArgument('marking', InputArgument::IS_ARRAY, 'A marking (a list of places)'),
new InputOption('label', 'l', InputOption::VALUE_REQUIRED, 'Label a graph'),
new InputOption('with-metadata', null, InputOption::VALUE_NONE, 'Include the workflow\'s metadata in the dumped graph', null),
new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'),
])
->setHelp(<<<'EOF'
The <info>%command.name%</info> command dumps the graphical representation of a
workflow in different formats

<info>DOT</info>: %command.full_name% <workflow name> | dot -Tpng > workflow.png
<info>PUML</info>: %command.full_name% <workflow name> --dump-format=puml | java -jar plantuml.jar -p > workflow.png
<info>MERMAID</info>: %command.full_name% <workflow name> --dump-format=mermaid | mmdc -o workflow.svg
EOF
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$workflowName = $input->getArgument('name');

if (!$this->workflows->has($workflowName)) {
throw new InvalidArgumentException(\sprintf('The workflow named "%s" cannot be found.', $workflowName));
}
$workflow = $this->workflows->get($workflowName);
if ($workflow instanceof TraceableWorkflow) {
$workflow = $workflow->getInner();
}
$type = $workflow instanceof StateMachine ? 'state_machine' : 'workflow';
$definition = $workflow->getDefinition();

switch ($input->getOption('dump-format')) {
case 'puml':
$transitionType = 'workflow' === $type ? PlantUmlDumper::WORKFLOW_TRANSITION : PlantUmlDumper::STATEMACHINE_TRANSITION;
$dumper = new PlantUmlDumper($transitionType);
break;

case 'mermaid':
$transitionType = 'workflow' === $type ? MermaidDumper::TRANSITION_TYPE_WORKFLOW : MermaidDumper::TRANSITION_TYPE_STATEMACHINE;
$dumper = new MermaidDumper($transitionType);
break;

case 'dot':
default:
$dumper = ('workflow' === $type) ? new GraphvizDumper() : new StateMachineGraphvizDumper();
}

$marking = new Marking();

foreach ($input->getArgument('marking') as $place) {
$marking->mark($place);
}

$options = [
'name' => $workflowName,
'with-metadata' => $input->getOption('with-metadata'),
'nofooter' => true,
'label' => $input->getOption('label'),
];
$output->writeln($dumper->dump($definition, $marking, $options));

return 0;
}

public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('name')) {
$suggestions->suggestValues(array_keys($this->workflows->getProvidedServices()));
}

if ($input->mustSuggestOptionValuesFor('dump-format')) {
$suggestions->suggestValues(self::DUMP_FORMAT_OPTIONS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
namespace Symfony\Component\Workflow\Tests\Command;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\Workflow\Command\WorkflowDumpCommand;

class WorkflowDumpCommandTest extends TestCase
{
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Workflow/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^6.4|^7.0|^8.0",
"symfony/console": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
"symfony/error-handler": "^6.4|^7.0|^8.0",
"symfony/event-dispatcher": "^6.4|^7.0|^8.0",
Expand Down
Loading