Skip to content

Commit

Permalink
Add CLI command gmorel:state-engine:generate-workflow-specifications
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Guillaume MOREL committed May 3, 2015
1 parent d7ad14c commit c913ed0
Show file tree
Hide file tree
Showing 41 changed files with 2,137 additions and 19 deletions.
12 changes: 12 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
# need to install vendors, for example via composer.
before_commands:
- composer install --dev
checks:
php:
code_rating: true
duplication: true
build:
tests:
override:
-
command: 'phpunit --coverage-clover=some-file'
coverage:
file: 'some-file'
format: 'php-clover'
tools:
php_cs_fixer:
extensions:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\App\Command;

/**
* @author Guillaume MOREL <github.com/gmorel>
* @see Command Design Pattern
* SpecificationGeneration Bounded Context available behaviour
*/
class RenderWorkflowSpecificationFromWorkflowServiceCommand
{
/** @var string */
private $workFlowServiceId;

/** @var string */
private $outputFileName;

/**
* @param string $workFlowServiceId
* @param string $outputFileName
*/
public function __construct($workFlowServiceId, $outputFileName)
{
$this->workFlowServiceId = $workFlowServiceId;
$this->outputFileName = $outputFileName;
}

/**
* @return string
*/
public function getWorkFlowServiceId()
{
return $this->workFlowServiceId;
}

/**
* @return string
*/
public function getOutputFileName()
{
return $this->outputFileName;
}
}
27 changes: 27 additions & 0 deletions App/Resources/config/services.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<!-- Bounded Context entry point -->
<service id="spec_gen.state_workflow.service" class="SpecGen\StateWorkflowSpecGenBundle\App\SpecificationService" public="true">
<argument type="service" id="spec_gen.state_workflow.workflow.container" />
<argument type="service" id="spec_gen.state_workflow.cytoscape_specification_representation.generator" />
<argument type="service" id="spec_gen.state_workflow.file_system.writer" />
</service>

<!-- CLI -->
<service id="spec_gen.state_workflow.workflow.generate_workflow_specifications.cli" class="SpecGen\StateWorkflowSpecGenBundle\UI\Cli\GenerateWorkflowSpecificationsCommand" public="true">
<argument type="service" id="spec_gen.state_workflow.service" />
<tag name="console.command" />
</service>

<service id="spec_gen.state_workflow.cytoscape_specification_representation.generator" class="SpecGen\StateWorkflowSpecGenBundle\Infra\CytoscapeSpecificationRepresentationGenerator" public="false"/>
<service id="spec_gen.state_workflow.file_system.writer" class="SpecGen\StateWorkflowSpecGenBundle\Infra\FileSystemSpecificationWriter" public="false"/>

<service id="spec_gen.state_workflow.workflow.container" class="SpecGen\StateWorkflowSpecGenBundle\Domain\WorkflowContainer" public="false">
</service>
</services>
</container>
78 changes: 78 additions & 0 deletions App/SpecificationService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\App;

use SpecGen\StateWorkflowSpecGenBundle\App\Command\RenderWorkflowSpecificationFromWorkflowServiceCommand;
use SpecGen\StateWorkflowSpecGenBundle\Domain\Exception\WorkflowServiceNotFoundException;
use SpecGen\StateWorkflowSpecGenBundle\Domain\SpecificationRepresentationGeneratorInterface;
use SpecGen\StateWorkflowSpecGenBundle\Domain\SpecificationWriterInterface;
use SpecGen\StateWorkflowSpecGenBundle\Domain\WorkflowContainer;

/**
* @author Guillaume MOREL <github.com/gmorel>
* SpecificationGeneration Bounded Context entry point
*/
class SpecificationService
{
/** @var WorkflowContainer */
private $workflowContainer;

/** @var SpecificationRepresentationGeneratorInterface */
private $specificationRepresentationGenerator;

/** @var SpecificationWriterInterface */
private $specificationWriter;

/**
* @param WorkflowContainer $workflowContainer
* @param SpecificationRepresentationGeneratorInterface $specificationRepresentationGenerator
* @param SpecificationWriterInterface $specificationWriter
*/
public function __construct(WorkflowContainer $workflowContainer, SpecificationRepresentationGeneratorInterface $specificationRepresentationGenerator, SpecificationWriterInterface $specificationWriter)
{
$this->workflowContainer = $workflowContainer;
$this->specificationRepresentationGenerator = $specificationRepresentationGenerator;
$this->specificationWriter = $specificationWriter;
}

/**
* Render specification for the given StateWorkflow
* @api
* @param RenderWorkflowSpecificationFromWorkflowServiceCommand $command
*
* @throws WorkflowServiceNotFoundException
*/
public function renderSpecification(RenderWorkflowSpecificationFromWorkflowServiceCommand $command)
{
$stateWorkflow = $this->workflowContainer->get(
$command->getWorkFlowServiceId()
);

$htmlSpecificationRepresentation = $this->specificationRepresentationGenerator->createSpecification(
$stateWorkflow
);

$this->specificationWriter->write(
$htmlSpecificationRepresentation,
$command->getOutputFileName()
);
}

/**
* Get all available StateWorkflow service
* @api
*
* @return string[]
*/
public function getAvailableWorkflowIds()
{
$availableWorkflows = $this->workflowContainer->all();

$availableWorkflowsIds = array();
foreach ($availableWorkflows as $availableWorkflow) {
$availableWorkflowsIds[] = $availableWorkflow->getServiceId();
}

return $availableWorkflowsIds;
}
}
33 changes: 33 additions & 0 deletions DependencyInjection/RegisterStateWorkflowCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Form\Exception\InvalidConfigurationException;

/**
* Register all State Workflow entity
* @author Guillaume MOREL <github.com/gmorel>
*/
class RegisterStateWorkflowCompilerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('spec_gen.state_workflow.workflow.container')) {
throw new InvalidConfigurationException('Cant find "spec_gen.state_workflow.workflow.container" service');
}

$definition = $container->getDefinition('spec_gen.state_workflow.workflow.container');

$services = $container->findTaggedServiceIds('gmorel.state_workflow_bundle.workflow');

foreach ($services as $id => $attributes) {
$definition->addMethodCall('addWorkflow', array(new Reference($id)));
}
}
}
31 changes: 31 additions & 0 deletions DependencyInjection/SpecGenStateWorkflowSpecGenBundleExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Config\FileLocator;

/**
* @author Guillaume MOREL <github.com/gmorel>
*/
class SpecGenStateWorkflowSpecGenBundleExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../App/Resources/config'));
$loader->load('services.xml');
}

/**
* {@inheritdoc}
*/
public function getAlias()
{
return 'spec_gen_state_workflow';
}
}
11 changes: 11 additions & 0 deletions Domain/Exception/UnableToWriteSpecificationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace SpecificationGeneration\Domain\Exception;

/**
* @author Guillaume MOREL <github.com/gmorel>
*/
class UnableToWriteSpecificationException extends \Exception
{

}
11 changes: 11 additions & 0 deletions Domain/Exception/WorkflowServiceNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\Domain\Exception;

/**
* @author Guillaume MOREL <github.com/gmorel>
*/
class WorkflowServiceNotFoundException extends \DomainException
{

}
91 changes: 91 additions & 0 deletions Domain/IntrospectedState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace SpecGen\StateWorkflowSpecGenBundle\Domain;

/**
* @author Guillaume MOREL <github.com/gmorel>
*/
class IntrospectedState
{
const IS_ROOT = true;
const IS_NOT_ROOT = false;

const IS_LEAF = true;
const IS_NOT_LEAF = false;

/** @var string */
private $key;

/** @var string */
private $name;

/** @var bool */
private $isRoot;

/** @var bool */
private $isLeaf;

/**
* @param string $stateKey
* @param string $stateName
*/
public function __construct($stateKey, $stateName)
{
$this->key = $stateKey;
$this->name = $stateName;
$this->isRoot = self::IS_NOT_ROOT;
$this->isLeaf = self::IS_NOT_LEAF;
}

/**
* @return string
*/
public function getKey()
{
return $this->key;
}

/**
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* @return boolean
*/
public function isRoot()
{
return $this->isRoot;
}

/**
* @return boolean
*/
public function isLeaf()
{
return $this->isLeaf;
}

/**
* @return $this
*/
public function setIsRoot()
{
$this->isRoot = true;

return $this;
}

/**
* @return $this
*/
public function setIsLeaf()
{
$this->isLeaf = true;

return $this;
}
}
Loading

0 comments on commit c913ed0

Please sign in to comment.