Skip to content

Commit

Permalink
Merge pull request #71 from tienvx/add-subject-code-generator
Browse files Browse the repository at this point in the history
Add subject code generator
  • Loading branch information
tienvx committed Oct 23, 2018
2 parents b173a40 + d9a5e07 commit 3822e51
Show file tree
Hide file tree
Showing 22 changed files with 197 additions and 39 deletions.
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"pnz/messenger-filesystem-transport": "^0.1.2",
"guzzlehttp/guzzle": "~6.0",
"symfony/security-bundle": "^4.1",
"symfony/monolog-bundle": "^3.3"
"symfony/monolog-bundle": "^3.3",
"symfony/maker-bundle": "^1.8"
},
"autoload": {
"psr-4": {
Expand All @@ -49,7 +50,8 @@
},
"autoload-dev": {
"psr-4": {
"Tienvx\\Bundle\\MbtBundle\\Tests\\": ["tests", "tests/app/src"]
"Tienvx\\Bundle\\MbtBundle\\Tests\\": "tests/",
"App\\": "tests/app/src/"
}
},
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<phpunit bootstrap="./tests/app/bootstrap.php" colors="true">
<php>
<server name="KERNEL_CLASS" value="Tienvx\Bundle\MbtBundle\Tests\AppKernel" />
<server name="KERNEL_CLASS" value="App\AppKernel" />
<env name="APP_ENV" value="test" />
<env name="APP_DEBUG" value="false" />
</php>
Expand All @@ -18,6 +18,7 @@
<directory>./src</directory>
<exclude>
<directory>./src/Resources</directory>
<directory>./src/Maker</directory>
</exclude>
</whitelist>
</filter>
Expand Down
2 changes: 1 addition & 1 deletion src/Command/ExecuteTaskCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

$this->setAnonymousToken();

$subject = $this->subjectManager->createSubjectForModel($task->getModel());
$subject = $this->subjectManager->createSubject($task->getModel());
$subject->setUp();
$generator = $this->generatorManager->getGenerator($task->getGenerator());
$workflow = $this->workflowRegistry->get($subject, $task->getModel());
Expand Down
2 changes: 1 addition & 1 deletion src/Command/GeneratePathCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$model = $input->getArgument('model');
$generatorName = $input->getOption('generator');
$generator = $this->generatorManager->getGenerator($generatorName);
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
$subject->setTesting(true);
$subject->setUp();
$workflow = $this->workflowRegistry->get($subject, $model);
Expand Down
6 changes: 6 additions & 0 deletions src/DependencyInjection/Compiler/WorkflowRegistryPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Symfony\Component\DependencyInjection\Reference;
use Tienvx\Bundle\MbtBundle\Command\ExecuteTaskCommand;
use Tienvx\Bundle\MbtBundle\Command\GeneratePathCommand;
use Tienvx\Bundle\MbtBundle\Maker\MakeSubject;
use Tienvx\Bundle\MbtBundle\Validator\Constraints\ModelValidator;

class WorkflowRegistryPass implements CompilerPassInterface
Expand Down Expand Up @@ -45,6 +46,11 @@ public function process(ContainerBuilder $container)

$modelValidatorDefinition = $container->getDefinition(ModelValidator::class);
$modelValidatorDefinition->addMethodCall('setWorkflowRegistry', [$workflowRegistry]);

if ($container->hasDefinition(MakeSubject::class)) {
$makeSubjectDefinition = $container->getDefinition(MakeSubject::class);
$makeSubjectDefinition->addMethodCall('setWorkflowRegistry', [$workflowRegistry]);
}
}
}
}
121 changes: 121 additions & 0 deletions src/Maker/MakeSubject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace Tienvx\Bundle\MbtBundle\Maker;

use Doctrine\Common\Annotations\Annotation;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Workflow\Registry;
use Tienvx\Bundle\MbtBundle\Subject\Subject;
use Tienvx\Bundle\MbtBundle\Subject\SubjectManager;

final class MakeSubject extends AbstractMaker
{
/**
* @var Registry
*/
private $workflowRegistry;

/**
* @var SubjectManager
*/
private $subjectManager;

public function __construct(SubjectManager $subjectManager)
{
$this->subjectManager = $subjectManager;
}

public function setWorkflowRegistry(Registry $workflowRegistry)
{
$this->workflowRegistry = $workflowRegistry;
}

public static function getCommandName(): string
{
return 'make:subject';
}

public function configureCommand(Command $command, InputConfiguration $inputConf)
{
$command
->setDescription('Creates a new subject class for a model')
->addArgument('model', InputArgument::OPTIONAL, 'The model to generate subject.')
->addArgument('subject-class', InputArgument::OPTIONAL, sprintf('Choose a name for your subject class (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeSubject.txt'))
;
}

/**
* @param InputInterface $input
* @param ConsoleStyle $io
* @param Generator $generator
* @throws \Exception
*/
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
{
$model = $input->getArgument('model');
$subject = new class extends Subject {
};
$workflow = $this->workflowRegistry->get($subject, $model);

if ($this->subjectManager->hasSubject($model)) {
$subject = $this->subjectManager->getSubject($model);
if (class_exists($subject)) {
$io->text(sprintf('The subject for model %s has been already defined: %s!', $model, $subject));
return;
}
} else {
$subject = $input->getArgument('subject-class');
}

$subjectClassNameDetails = $generator->createClassNameDetails(
$subject,
'Subject\\'
);

$methods = [];
foreach ($workflow->getDefinition()->getPlaces() as $place => $status) {
if ($status) {
$methods[] = $place;
}
}
foreach ($workflow->getDefinition()->getTransitions() as $transition) {
$methods[] = $transition->getName();
}

$generator->generateClass(
$subjectClassNameDetails->getFullName(),
__DIR__.'/../Resources/skeleton/subject/Subject.tpl.php',
[
'methods' => array_unique($methods),
]
);

$generator->writeChanges();

$this->writeSuccessMessage($io);
$io->text([
'Next: Update configuration file at tienvx_mbt.subjects, add this line:',
sprintf('%s: %s', $model, $subjectClassNameDetails->getFullName()),
'Then: Open your new subject class and implement places and transitions!'
]);
}

public function configureDependencies(DependencyBuilder $dependencies)
{
$dependencies->addClassDependency(
// we only need doctrine/annotations, which contains
// the recipe that loads annotation data providers
Annotation::class,
'annotations'
);
}
}
6 changes: 4 additions & 2 deletions src/PathReducer/BinaryPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Tienvx\Bundle\MbtBundle\Helper\GraphBuilder;
use Tienvx\Bundle\MbtBundle\Helper\PathBuilder;
use Tienvx\Bundle\MbtBundle\Helper\PathRunner;
use Tienvx\Bundle\MbtBundle\Subject\Subject;

class BinaryPathReducer extends AbstractPathReducer
{
Expand All @@ -21,7 +22,8 @@ public function reduce(Bug $bug)
parent::reduce($bug);

$model = $bug->getTask()->getModel();
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = new class extends Subject {
};
$workflow = $this->workflowRegistry->get($subject, $model);

if (!$workflow instanceof StateMachine) {
Expand All @@ -47,7 +49,7 @@ public function reduce(Bug $bug)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
if ($newThrowable->getMessage() === $bug->getBugMessage()) {
Expand Down
6 changes: 4 additions & 2 deletions src/PathReducer/GreedyPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Tienvx\Bundle\MbtBundle\Helper\GraphBuilder;
use Tienvx\Bundle\MbtBundle\Helper\PathBuilder;
use Tienvx\Bundle\MbtBundle\Helper\PathRunner;
use Tienvx\Bundle\MbtBundle\Subject\Subject;

class GreedyPathReducer extends AbstractPathReducer
{
Expand All @@ -21,7 +22,8 @@ public function reduce(Bug $bug)
parent::reduce($bug);

$model = $bug->getTask()->getModel();
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = new class extends Subject {
};
$workflow = $this->workflowRegistry->get($subject, $model);

if (!$workflow instanceof StateMachine) {
Expand All @@ -47,7 +49,7 @@ public function reduce(Bug $bug)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
if ($newThrowable->getMessage() === $bug->getBugMessage()) {
Expand Down
2 changes: 1 addition & 1 deletion src/PathReducer/LoopPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function reduce(Bug $bug)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
$workflow = $this->workflowRegistry->get($subject, $model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
Expand Down
2 changes: 1 addition & 1 deletion src/PathReducer/QueuedLoopPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function handle(string $message)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
$workflow = $this->workflowRegistry->get($subject, $model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
Expand Down
6 changes: 4 additions & 2 deletions src/PathReducer/RandomPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Tienvx\Bundle\MbtBundle\Helper\PathBuilder;
use Tienvx\Bundle\MbtBundle\Helper\Randomizer;
use Tienvx\Bundle\MbtBundle\Helper\PathRunner;
use Tienvx\Bundle\MbtBundle\Subject\Subject;

class RandomPathReducer extends AbstractPathReducer
{
Expand All @@ -22,7 +23,8 @@ public function reduce(Bug $bug)
parent::reduce($bug);

$model = $bug->getTask()->getModel();
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = new class extends Subject {
};
$workflow = $this->workflowRegistry->get($subject, $model);

if (!$workflow instanceof StateMachine) {
Expand All @@ -41,7 +43,7 @@ public function reduce(Bug $bug)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
if ($newThrowable->getMessage() === $bug->getBugMessage()) {
Expand Down
6 changes: 4 additions & 2 deletions src/PathReducer/WeightedRandomPathReducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Tienvx\Bundle\MbtBundle\Helper\PathBuilder;
use Tienvx\Bundle\MbtBundle\Helper\Randomizer;
use Tienvx\Bundle\MbtBundle\Helper\PathRunner;
use Tienvx\Bundle\MbtBundle\Subject\Subject;

class WeightedRandomPathReducer extends AbstractPathReducer
{
Expand All @@ -23,7 +24,8 @@ public function reduce(Bug $bug)
parent::reduce($bug);

$model = $bug->getTask()->getModel();
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = new class extends Subject {
};
$workflow = $this->workflowRegistry->get($subject, $model);

if (!$workflow instanceof StateMachine) {
Expand All @@ -46,7 +48,7 @@ public function reduce(Bug $bug)
// Make sure new path shorter than old path.
if ($newPath->countPlaces() < $path->countPlaces()) {
try {
$subject = $this->subjectManager->createSubjectForModel($model);
$subject = $this->subjectManager->createSubject($model);
PathRunner::run($newPath, $workflow, $subject);
} catch (Throwable $newThrowable) {
if ($newThrowable->getMessage() === $bug->getBugMessage()) {
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/help/MakeSubject.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The <info>%command.name%</info> command generates a new subject class for a model.

<info>php %command.full_name% model-name CoolStuffSubject</info>

If the argument is missing, the command will ask for the model name and subject class name interactively.
15 changes: 15 additions & 0 deletions src/Resources/skeleton/subject/Subject.tpl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?= "<?php\n" ?>

namespace <?= $namespace; ?>;

use Tienvx\Bundle\MbtBundle\Subject\Subject;

class <?= $class_name; ?> extends Subject
{
<?php foreach ($methods as $index => $method): ?>
public function <?= $method; ?>()
{
}
<?= $index < (count($methods) - 1) ? "\n" : ''; ?>
<?php endforeach; ?>
}
9 changes: 7 additions & 2 deletions src/Subject/SubjectManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,22 @@ public function addSubjects(array $subjects)
}
}

public function hasSubjectForModel(string $model)
public function hasSubject(string $model)
{
return isset($this->subjects[$model]);
}

public function getSubject(string $model)
{
return $this->subjects[$model];
}

/**
* @param string $model
* @return Subject
* @throws Exception
*/
public function createSubjectForModel(string $model): Subject
public function createSubject(string $model): Subject
{
if (!isset($this->subjects[$model])) {
throw new Exception(sprintf('Subject for model %s is not specified.', $model));
Expand Down
Loading

0 comments on commit 3822e51

Please sign in to comment.