Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Workflow] Add colors to workflow dumps #29538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
13 changes: 13 additions & 0 deletions src/Symfony/Component/Workflow/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ CHANGELOG

* Trigger `entered` event for subject entering in the Workflow for the first time
* Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature.
* Add style to transitions by declaring metadata:
```
$places = range('a', 'b');
$transition = new Transition('t1', 'a', 'b');
$transitions[] = $transition;
$transitionsMetadata = new \SplObjectStorage();
$transitionsMetadata[$transition] = [
'color' => 'Red',
'arrow_color' => '#00ff00',
];
$inMemoryMetadataStore = new InMemoryMetadataStore([], [], $transitionsMetadata);
return new Definition($places, $transitions, null, $inMemoryMetadataStore);
```

4.1.0
-----
Expand Down
49 changes: 41 additions & 8 deletions src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
*/
protected function findPlaces(Definition $definition, Marking $marking = null)
{
$workflowMetadata = $definition->getMetadataStore();

$places = [];

foreach ($definition->getPlaces() as $place) {
Expand All @@ -74,6 +76,15 @@ protected function findPlaces(Definition $definition, Marking $marking = null)
$attributes['color'] = '#FF0000';
$attributes['shape'] = 'doublecircle';
}
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
if (null !== $backgroundColor) {
$attributes['style'] = 'filled';
$attributes['fillcolor'] = $backgroundColor;
}
$label = $workflowMetadata->getMetadata('label', $place);
if (null !== $label) {
$attributes['name'] = $label;
}
$places[$place] = [
'attributes' => $attributes,
];
Expand All @@ -87,12 +98,23 @@ protected function findPlaces(Definition $definition, Marking $marking = null)
*/
protected function findTransitions(Definition $definition)
{
$workflowMetadata = $definition->getMetadataStore();

$transitions = [];

foreach ($definition->getTransitions() as $transition) {
$attributes = ['shape' => 'box', 'regular' => true];

$backgroundColor = $workflowMetadata->getMetadata('bg_color', $transition);
if (null !== $backgroundColor) {
$attributes['style'] = 'filled';
$attributes['fillcolor'] = $backgroundColor;
}
$name = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();

$transitions[] = [
'attributes' => ['shape' => 'box', 'regular' => true],
'name' => $transition->getName(),
'attributes' => $attributes,
'name' => $name,
];
}

Expand All @@ -107,7 +129,14 @@ protected function addPlaces(array $places)
$code = '';

foreach ($places as $id => $place) {
$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($id), $this->addAttributes($place['attributes']));
if (isset($place['attributes']['name'])) {
$placeName = $place['attributes']['name'];
unset($place['attributes']['name']);
} else {
$placeName = $id;
}

$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($placeName), $this->addAttributes($place['attributes']));
}

return $code;
Expand All @@ -121,7 +150,7 @@ protected function addTransitions(array $transitions)
$code = '';

foreach ($transitions as $place) {
$code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes']));
$code .= sprintf(" transition_%s [label=\"%s\",%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes']));
}

return $code;
Expand All @@ -132,19 +161,23 @@ protected function addTransitions(array $transitions)
*/
protected function findEdges(Definition $definition)
{
$workflowMetadata = $definition->getMetadataStore();

$dotEdges = [];

foreach ($definition->getTransitions() as $transition) {
$transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();

foreach ($transition->getFroms() as $from) {
$dotEdges[] = [
'from' => $from,
'to' => $transition->getName(),
'to' => $transitionName,
'direction' => 'from',
];
}
foreach ($transition->getTos() as $to) {
$dotEdges[] = [
'from' => $transition->getName(),
'from' => $transitionName,
'to' => $to,
'direction' => 'to',
];
Expand Down Expand Up @@ -209,15 +242,15 @@ protected function escape($value): string
return \is_bool($value) ? ($value ? '1' : '0') : \addslashes($value);
}

private function addAttributes(array $attributes): string
protected function addAttributes(array $attributes): string
{
$code = [];

foreach ($attributes as $k => $v) {
$code[] = sprintf('%s="%s"', $k, $this->escape($v));
}

return $code ? ', '.implode(', ', $code) : '';
return $code ? ' '.implode(' ', $code) : '';
}

private function addOptions(array $options): string
Expand Down
109 changes: 99 additions & 10 deletions src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use InvalidArgumentException;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
use Symfony\Component\Workflow\Transition;

/**
* PlantUmlDumper dumps a workflow as a PlantUML file.
Expand Down Expand Up @@ -63,13 +65,13 @@ public function __construct(string $transitionType = null)
public function dump(Definition $definition, Marking $marking = null, array $options = []): string
{
$options = array_replace_recursive(self::DEFAULT_OPTIONS, $options);
$code = $this->initialize($options);

$workflowMetadata = $definition->getMetadataStore();

$code = $this->initialize($options, $definition);

foreach ($definition->getPlaces() as $place) {
$placeEscaped = $this->escape($place);
$code[] =
"state $placeEscaped".
($definition->getInitialPlace() === $place ? ' '.self::INITIAL : '').
($marking && $marking->has($place) ? ' '.self::MARKED : '');
$code[] = $this->getState($place, $definition, $marking);
}
if ($this->isWorkflowTransitionType()) {
foreach ($definition->getTransitions() as $transition) {
Expand All @@ -83,18 +85,34 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
$fromEscaped = $this->escape($from);
foreach ($transition->getTos() as $to) {
$toEscaped = $this->escape($to);

$transitionEscapedWithStyle = $this->getTransitionEscapedWithStyle($workflowMetadata, $transition, $transitionEscaped);

$arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition);

$transitionColor = '';
if (null !== $arrowColor) {
$transitionColor = $this->getTransitionColor($arrowColor) ?? '';
}

if ($this->isWorkflowTransitionType()) {
$transitionLabel = '';
// Add label only if it has a style
if ($transitionEscapedWithStyle != $transitionEscaped) {
$transitionLabel = ": $transitionEscapedWithStyle";
}

$lines = [
"$fromEscaped --> $transitionEscaped",
"$transitionEscaped --> $toEscaped",
"$fromEscaped -${transitionColor}-> ${transitionEscaped}${transitionLabel}",
"$transitionEscaped -${transitionColor}-> ${toEscaped}${transitionLabel}",
];
foreach ($lines as $line) {
if (!\in_array($line, $code)) {
$code[] = $line;
}
}
} else {
$code[] = "$fromEscaped --> $toEscaped: $transitionEscaped";
$code[] = "$fromEscaped -${transitionColor}-> $toEscaped: $transitionEscapedWithStyle";
}
}
}
Expand Down Expand Up @@ -126,15 +144,28 @@ private function getLines(array $code): string
return implode(PHP_EOL, $code);
}

private function initialize(array $options): array
private function initialize(array $options, Definition $definition): array
{
$workflowMetadata = $definition->getMetadataStore();

$code = [];
if (isset($options['title'])) {
$code[] = "title {$options['title']}";
}
if (isset($options['name'])) {
$code[] = "title {$options['name']}";
}

// Add style from nodes
foreach ($definition->getPlaces() as $place) {
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
if (null !== $backgroundColor) {
$key = 'BackgroundColor<<'.$this->getColorId($backgroundColor).'>>';

$options['skinparams']['state'][$key] = $backgroundColor;
}
}

if (isset($options['skinparams']) && \is_array($options['skinparams'])) {
foreach ($options['skinparams'] as $skinparamKey => $skinparamValue) {
if (!$this->isWorkflowTransitionType() && 'agent' === $skinparamKey) {
Expand All @@ -160,4 +191,62 @@ private function escape(string $string): string
// It's not possible to escape property double quote, so let's remove it
return '"'.str_replace('"', '', $string).'"';
}

private function getState(string $place, Definition $definition, Marking $marking = null): string
{
$workflowMetadata = $definition->getMetadataStore();

$placeEscaped = $this->escape($place);

$output = "state $placeEscaped".
($definition->getInitialPlace() === $place ? ' '.self::INITIAL : '').
($marking && $marking->has($place) ? ' '.self::MARKED : '');

$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
if (null !== $backgroundColor) {
$output .= ' <<'.$this->getColorId($backgroundColor).'>>';
}

$description = $workflowMetadata->getMetadata('description', $place);
if (null !== $description) {
$output .= ' as '.$place.
PHP_EOL.
$place.' : '.$description;
}

return $output;
}

private function getTransitionEscapedWithStyle(MetadataStoreInterface $workflowMetadata, Transition $transition, string $to): string
{
$to = $workflowMetadata->getMetadata('label', $transition) ?? $to;

$color = $workflowMetadata->getMetadata('color', $transition) ?? null;

if (null !== $color) {
$to = sprintf(
'<font color=%1$s>%2$s</font>',
$color,
$to
);
}

return $this->escape($to);
}

private function getTransitionColor(string $color): string
{
// PUML format requires that color in transition have to be prefixed with “#”.
if ('#' !== substr($color, 0, 1)) {
$color = '#'.$color;
}

return sprintf('[%s]', $color);
}

private function getColorId(string $color): string
{
// Remove “#“ from start of the color name so it can be used as an identifier.
return ltrim($color, '#');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,32 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
*/
protected function findEdges(Definition $definition)
{
$workflowMetadata = $definition->getMetadataStore();

$edges = [];

foreach ($definition->getTransitions() as $transition) {
$attributes = [];

$transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();

$labelColor = $workflowMetadata->getMetadata('color', $transition);
if (null !== $labelColor) {
$attributes['fontcolor'] = $labelColor;
}
$arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition);
if (null !== $arrowColor) {
$attributes['color'] = $arrowColor;
}

foreach ($transition->getFroms() as $from) {
foreach ($transition->getTos() as $to) {
$edges[$from][] = [
'name' => $transition->getName(),
$edge = [
'name' => $transitionName,
'to' => $to,
'attributes' => $attributes,
];
$edges[$from][] = $edge;
}
}
}
Expand All @@ -71,7 +88,14 @@ protected function addEdges(array $edges)

foreach ($edges as $id => $edges) {
foreach ($edges as $edge) {
$code .= sprintf(" place_%s -> place_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $this->escape($edge['name']), 'solid');
$code .= sprintf(
" place_%s -> place_%s [label=\"%s\" style=\"%s\"%s];\n",
$this->dotize($id),
$this->dotize($edge['to']),
$this->escape($edge['name']),
'solid',
$this->addAttributes($edge['attributes'])
);
}
}

Expand Down
Loading