Skip to content

Commit c913ed0

Browse files
author
Guillaume MOREL
committed
Add CLI command gmorel:state-engine:generate-workflow-specifications
Allow generating workflow specifications as simple html file Aim is to ease workflow visualization And to have a rendered workflow always ISO to the one written in the code base And this generated automatically and regularly The code base is always up to date and reflects the specs No forgotten - No human error
1 parent d7ad14c commit c913ed0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2137
-19
lines changed

.scrutinizer.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22
# need to install vendors, for example via composer.
33
before_commands:
44
- composer install --dev
5+
checks:
6+
php:
7+
code_rating: true
8+
duplication: true
9+
build:
10+
tests:
11+
override:
12+
-
13+
command: 'phpunit --coverage-clover=some-file'
14+
coverage:
15+
file: 'some-file'
16+
format: 'php-clover'
517
tools:
618
php_cs_fixer:
719
extensions:
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\App\Command;
4+
5+
/**
6+
* @author Guillaume MOREL <github.com/gmorel>
7+
* @see Command Design Pattern
8+
* SpecificationGeneration Bounded Context available behaviour
9+
*/
10+
class RenderWorkflowSpecificationFromWorkflowServiceCommand
11+
{
12+
/** @var string */
13+
private $workFlowServiceId;
14+
15+
/** @var string */
16+
private $outputFileName;
17+
18+
/**
19+
* @param string $workFlowServiceId
20+
* @param string $outputFileName
21+
*/
22+
public function __construct($workFlowServiceId, $outputFileName)
23+
{
24+
$this->workFlowServiceId = $workFlowServiceId;
25+
$this->outputFileName = $outputFileName;
26+
}
27+
28+
/**
29+
* @return string
30+
*/
31+
public function getWorkFlowServiceId()
32+
{
33+
return $this->workFlowServiceId;
34+
}
35+
36+
/**
37+
* @return string
38+
*/
39+
public function getOutputFileName()
40+
{
41+
return $this->outputFileName;
42+
}
43+
}

App/Resources/config/services.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<!-- Bounded Context entry point -->
9+
<service id="spec_gen.state_workflow.service" class="SpecGen\StateWorkflowSpecGenBundle\App\SpecificationService" public="true">
10+
<argument type="service" id="spec_gen.state_workflow.workflow.container" />
11+
<argument type="service" id="spec_gen.state_workflow.cytoscape_specification_representation.generator" />
12+
<argument type="service" id="spec_gen.state_workflow.file_system.writer" />
13+
</service>
14+
15+
<!-- CLI -->
16+
<service id="spec_gen.state_workflow.workflow.generate_workflow_specifications.cli" class="SpecGen\StateWorkflowSpecGenBundle\UI\Cli\GenerateWorkflowSpecificationsCommand" public="true">
17+
<argument type="service" id="spec_gen.state_workflow.service" />
18+
<tag name="console.command" />
19+
</service>
20+
21+
<service id="spec_gen.state_workflow.cytoscape_specification_representation.generator" class="SpecGen\StateWorkflowSpecGenBundle\Infra\CytoscapeSpecificationRepresentationGenerator" public="false"/>
22+
<service id="spec_gen.state_workflow.file_system.writer" class="SpecGen\StateWorkflowSpecGenBundle\Infra\FileSystemSpecificationWriter" public="false"/>
23+
24+
<service id="spec_gen.state_workflow.workflow.container" class="SpecGen\StateWorkflowSpecGenBundle\Domain\WorkflowContainer" public="false">
25+
</service>
26+
</services>
27+
</container>

App/SpecificationService.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\App;
4+
5+
use SpecGen\StateWorkflowSpecGenBundle\App\Command\RenderWorkflowSpecificationFromWorkflowServiceCommand;
6+
use SpecGen\StateWorkflowSpecGenBundle\Domain\Exception\WorkflowServiceNotFoundException;
7+
use SpecGen\StateWorkflowSpecGenBundle\Domain\SpecificationRepresentationGeneratorInterface;
8+
use SpecGen\StateWorkflowSpecGenBundle\Domain\SpecificationWriterInterface;
9+
use SpecGen\StateWorkflowSpecGenBundle\Domain\WorkflowContainer;
10+
11+
/**
12+
* @author Guillaume MOREL <github.com/gmorel>
13+
* SpecificationGeneration Bounded Context entry point
14+
*/
15+
class SpecificationService
16+
{
17+
/** @var WorkflowContainer */
18+
private $workflowContainer;
19+
20+
/** @var SpecificationRepresentationGeneratorInterface */
21+
private $specificationRepresentationGenerator;
22+
23+
/** @var SpecificationWriterInterface */
24+
private $specificationWriter;
25+
26+
/**
27+
* @param WorkflowContainer $workflowContainer
28+
* @param SpecificationRepresentationGeneratorInterface $specificationRepresentationGenerator
29+
* @param SpecificationWriterInterface $specificationWriter
30+
*/
31+
public function __construct(WorkflowContainer $workflowContainer, SpecificationRepresentationGeneratorInterface $specificationRepresentationGenerator, SpecificationWriterInterface $specificationWriter)
32+
{
33+
$this->workflowContainer = $workflowContainer;
34+
$this->specificationRepresentationGenerator = $specificationRepresentationGenerator;
35+
$this->specificationWriter = $specificationWriter;
36+
}
37+
38+
/**
39+
* Render specification for the given StateWorkflow
40+
* @api
41+
* @param RenderWorkflowSpecificationFromWorkflowServiceCommand $command
42+
*
43+
* @throws WorkflowServiceNotFoundException
44+
*/
45+
public function renderSpecification(RenderWorkflowSpecificationFromWorkflowServiceCommand $command)
46+
{
47+
$stateWorkflow = $this->workflowContainer->get(
48+
$command->getWorkFlowServiceId()
49+
);
50+
51+
$htmlSpecificationRepresentation = $this->specificationRepresentationGenerator->createSpecification(
52+
$stateWorkflow
53+
);
54+
55+
$this->specificationWriter->write(
56+
$htmlSpecificationRepresentation,
57+
$command->getOutputFileName()
58+
);
59+
}
60+
61+
/**
62+
* Get all available StateWorkflow service
63+
* @api
64+
*
65+
* @return string[]
66+
*/
67+
public function getAvailableWorkflowIds()
68+
{
69+
$availableWorkflows = $this->workflowContainer->all();
70+
71+
$availableWorkflowsIds = array();
72+
foreach ($availableWorkflows as $availableWorkflow) {
73+
$availableWorkflowsIds[] = $availableWorkflow->getServiceId();
74+
}
75+
76+
return $availableWorkflowsIds;
77+
}
78+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\DependencyInjection;
4+
5+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
6+
use Symfony\Component\DependencyInjection\ContainerBuilder;
7+
use Symfony\Component\DependencyInjection\Reference;
8+
use Symfony\Component\Form\Exception\InvalidConfigurationException;
9+
10+
/**
11+
* Register all State Workflow entity
12+
* @author Guillaume MOREL <github.com/gmorel>
13+
*/
14+
class RegisterStateWorkflowCompilerPass implements CompilerPassInterface
15+
{
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
public function process(ContainerBuilder $container)
20+
{
21+
if (false === $container->hasDefinition('spec_gen.state_workflow.workflow.container')) {
22+
throw new InvalidConfigurationException('Cant find "spec_gen.state_workflow.workflow.container" service');
23+
}
24+
25+
$definition = $container->getDefinition('spec_gen.state_workflow.workflow.container');
26+
27+
$services = $container->findTaggedServiceIds('gmorel.state_workflow_bundle.workflow');
28+
29+
foreach ($services as $id => $attributes) {
30+
$definition->addMethodCall('addWorkflow', array(new Reference($id)));
31+
}
32+
}
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\DependencyInjection;
4+
5+
use Symfony\Component\DependencyInjection\ContainerBuilder;
6+
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
7+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
8+
use Symfony\Component\Config\FileLocator;
9+
10+
/**
11+
* @author Guillaume MOREL <github.com/gmorel>
12+
*/
13+
class SpecGenStateWorkflowSpecGenBundleExtension extends Extension
14+
{
15+
/**
16+
* {@inheritdoc}
17+
*/
18+
public function load(array $configs, ContainerBuilder $container)
19+
{
20+
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../App/Resources/config'));
21+
$loader->load('services.xml');
22+
}
23+
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function getAlias()
28+
{
29+
return 'spec_gen_state_workflow';
30+
}
31+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace SpecificationGeneration\Domain\Exception;
4+
5+
/**
6+
* @author Guillaume MOREL <github.com/gmorel>
7+
*/
8+
class UnableToWriteSpecificationException extends \Exception
9+
{
10+
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\Domain\Exception;
4+
5+
/**
6+
* @author Guillaume MOREL <github.com/gmorel>
7+
*/
8+
class WorkflowServiceNotFoundException extends \DomainException
9+
{
10+
11+
}

Domain/IntrospectedState.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace SpecGen\StateWorkflowSpecGenBundle\Domain;
4+
5+
/**
6+
* @author Guillaume MOREL <github.com/gmorel>
7+
*/
8+
class IntrospectedState
9+
{
10+
const IS_ROOT = true;
11+
const IS_NOT_ROOT = false;
12+
13+
const IS_LEAF = true;
14+
const IS_NOT_LEAF = false;
15+
16+
/** @var string */
17+
private $key;
18+
19+
/** @var string */
20+
private $name;
21+
22+
/** @var bool */
23+
private $isRoot;
24+
25+
/** @var bool */
26+
private $isLeaf;
27+
28+
/**
29+
* @param string $stateKey
30+
* @param string $stateName
31+
*/
32+
public function __construct($stateKey, $stateName)
33+
{
34+
$this->key = $stateKey;
35+
$this->name = $stateName;
36+
$this->isRoot = self::IS_NOT_ROOT;
37+
$this->isLeaf = self::IS_NOT_LEAF;
38+
}
39+
40+
/**
41+
* @return string
42+
*/
43+
public function getKey()
44+
{
45+
return $this->key;
46+
}
47+
48+
/**
49+
* @return string
50+
*/
51+
public function getName()
52+
{
53+
return $this->name;
54+
}
55+
56+
/**
57+
* @return boolean
58+
*/
59+
public function isRoot()
60+
{
61+
return $this->isRoot;
62+
}
63+
64+
/**
65+
* @return boolean
66+
*/
67+
public function isLeaf()
68+
{
69+
return $this->isLeaf;
70+
}
71+
72+
/**
73+
* @return $this
74+
*/
75+
public function setIsRoot()
76+
{
77+
$this->isRoot = true;
78+
79+
return $this;
80+
}
81+
82+
/**
83+
* @return $this
84+
*/
85+
public function setIsLeaf()
86+
{
87+
$this->isLeaf = true;
88+
89+
return $this;
90+
}
91+
}

0 commit comments

Comments
 (0)