Skip to content

Commit

Permalink
Merge branch 'workflow-actions'
Browse files Browse the repository at this point in the history
* workflow-actions:
  adopt documentation to new action system
  tiny codestyle fixes
  split ActionReference class into 2 separate classes for service method and static method references and the base interface
  add usage of ExpressionListener in func tests
  fix compilation of action calls in expressions
  fix traverse through actions inside ActionExpressionLanguage
  implement action concept
  • Loading branch information
fduch committed Nov 2, 2016
2 parents aa4ff36 + 345d072 commit 5266c0c
Show file tree
Hide file tree
Showing 50 changed files with 3,022 additions and 1,307 deletions.
77 changes: 77 additions & 0 deletions Action/Executor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* This file is part of the Global Trading Technologies Ltd workflow-extension-bundle package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* (c) fduch <alex.medwedew@gmail.com>
*
* Date: 23.09.16
*/

namespace Gtt\Bundle\WorkflowExtensionsBundle\Action;

use Gtt\Bundle\WorkflowExtensionsBundle\Action\Reference\ActionReferenceInterface;
use Gtt\Bundle\WorkflowExtensionsBundle\WorkflowContext;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Action executor
*
* @author fduch <alex.medwedew@gmail.com>
*/
class Executor
{
/**
* Action registry
*
* @var Registry
*/
private $registry;

/**
* Container DI
*
* @var ContainerInterface
*/
private $container;

/**
* Executor constructor.
*
* @param Registry $registry action registry
* @param ContainerInterface $container container DI
*/
public function __construct(Registry $registry, ContainerInterface $container)
{
$this->registry = $registry;
$this->container = $container;
}

/**
* Executes action
*
* @param WorkflowContext $workflowContext workflow context
* @param string $actionName action name
* @param array $args action arguments
*
* @return mixed
*/
public function execute(WorkflowContext $workflowContext, $actionName, array $args = [])
{
$actionReference = $this->registry->get($actionName);

if ($actionReference->getType() == ActionReferenceInterface::TYPE_WORKFLOW) {
array_unshift($args, $workflowContext);
}

if ($actionReference instanceof ContainerAwareInterface) {
// container should be injected to allow action to use service as an method owner
$actionReference->setContainer($this->container);
}

return $actionReference->invoke($args);
}
}
64 changes: 64 additions & 0 deletions Action/ExpressionLanguage/ActionExpressionLanguage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/**
* This file is part of the Global Trading Technologies Ltd workflow-extension-bundle package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* (c) fduch <alex.medwedew@gmail.com>
*
* Date: 01.09.16
*/

namespace Gtt\Bundle\WorkflowExtensionsBundle\Action\ExpressionLanguage;

use Gtt\Bundle\WorkflowExtensionsBundle\Action\Registry;
use Gtt\Bundle\WorkflowExtensionsBundle\Action\Executor;
use Gtt\Bundle\WorkflowExtensionsBundle\ExpressionLanguage\ContainerAwareExpressionLanguage;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;

/**
* Expression language allows to use actions inside expressions
*
* @author fduch <alex.medwedew@gmail.com>
*/
class ActionExpressionLanguage extends ContainerAwareExpressionLanguage
{
/**
* {@inheritdoc}
*/
public function __construct(
Registry $actionRegistry,
Executor $actionExecutor,
ContainerInterface $container,
ParserCacheInterface $cache = null,
array $providers = array())
{
parent::__construct($container, $cache, $providers);

foreach ($actionRegistry as $actionName => $action) {
$this->register(
$actionName,
function () use ($actionName, $actionExecutor)
{
$rawArgs = func_get_args();
$compiledArgsArray = "array(". implode(", ", $rawArgs) . ")";

return sprintf(
'$container->get("gtt.workflow.action.executor")->execute($workflowContext, "%s", %s)',
$actionName,
$compiledArgsArray
);
},
function () use ($actionName, $actionExecutor)
{
$args = func_get_args();
$variables = array_shift($args);

return $actionExecutor->execute($variables['workflowContext'], $actionName, $args);
}
);
}
}
}
54 changes: 54 additions & 0 deletions Action/Reference/ActionReferenceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* This file is part of the Global Trading Technologies Ltd workflow-extension-bundle package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* (c) fduch <alex.medwedew@gmail.com>
*
* Date: 14.09.16
*/

namespace Gtt\Bundle\WorkflowExtensionsBundle\Action\Reference;

use Gtt\Bundle\WorkflowExtensionsBundle\Exception\ActionException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use ReflectionMethod;

/**
* Reference to some method can be treated as an action
*
* @author fduch <alex.medwedew@gmail.com>
*/
interface ActionReferenceInterface
{
/**
* Base default action type
*/
const TYPE_REGULAR = "regular";

/**
* Action type requires WorkflowContext instance as first argument in arguments list
*/
const TYPE_WORKFLOW = "workflow";

/**
* Returns action type
*
* For now can be regular or workflow
*
* @return string
*/
public function getType();

/**
* Invokes action
*
* @param array $args action args
*
* @return mixed
*/
public function invoke(array $args);
}
145 changes: 145 additions & 0 deletions Action/Reference/ServiceMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<?php
/**
* This file is part of the Global Trading Technologies Ltd workflow-extension-bundle package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* (c) fduch <alex.medwedew@gmail.com>
*
* Date: 14.09.16
*/

namespace Gtt\Bundle\WorkflowExtensionsBundle\Action\Reference;

use Gtt\Bundle\WorkflowExtensionsBundle\Exception\ActionException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use ReflectionMethod;

/**
* Reference to service method
*
* @author fduch <alex.medwedew@gmail.com>
*/
class ServiceMethod implements ActionReferenceInterface, ContainerAwareInterface
{
/**
* Service id of the object which method is used as an action
*
* @var string
*/
private $serviceId;

/**
* Method name used as action
*
* @var string
*/
private $methodName;

/**
* Action type
*
* @var string
*/
private $type;

/**
* Action method reflection
*
* @var ReflectionMethod
*/
private $reflectionMethod;

/**
* Target object object which method is used as an action
* Used internally to invoke action
*
* @var object
*/
private $object;

/**
* DI Container instance
*
* @var ContainerInterface
*/
private $container;

/**
* ActionReference constructor.
*
* @param string $methodName method name
* @param int $serviceId service id which method is used as an action
* @param string $type action reference type
*/
public function __construct($methodName, $serviceId, $type = self::TYPE_REGULAR)
{
$this->methodName = $methodName;
$this->serviceId = $serviceId;
$this->type = $type;
}

/**
* Returns action type
*
* @return string
*/
public function getType()
{
return $this->type;
}

/**
* {@inheritdoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}

/**
* Invokes action
*
* @param array $args action args
*
* @return mixed
*/
public function invoke(array $args)
{
return $this->getReflectionMethod()->invokeArgs($this->getObject(), $args);
}

/**
* Returns reflection method
*
* @return ReflectionMethod
*/
private function getReflectionMethod()
{
if (!$this->reflectionMethod) {
$this->reflectionMethod = new ReflectionMethod($this->getObject(), $this->methodName);
}

return $this->reflectionMethod;
}

/**
* Returns service object
*
* @return object
*/
private function getObject()
{
if (!$this->object) {
if (!$this->container) {
throw ActionException::containerUnavailableForServiceMethodReference($this->serviceId);
}

$this->object = $this->container->get($this->serviceId);
}

return $this->object;
}
}

0 comments on commit 5266c0c

Please sign in to comment.