src/Wrappers/MarshalDispatcher.php
<?php
namespace Cerbero\Workflow\Wrappers;
use Exception;
use ArrayAccess;
use ReflectionClass;
use ReflectionParameter;
use Illuminate\Contracts\Bus\Dispatcher;
/**
* Wrapper to marshal commands before dispatching them.
*
* @author Andrea Marco Sartori
*/
class MarshalDispatcher implements DispatcherInterface
{
/**
* @author Andrea Marco Sartori
* @var Illuminate\Contracts\Bus\Dispatcher $dispatcher Bus dispatcher.
*/
protected $dispatcher;
/**
* @author Andrea Marco Sartori
* @var string $command Command to dispatch
*/
protected $command;
/**
* @author Andrea Marco Sartori
* @var \ArrayAccess $values Parameters values
*/
protected $values;
/**
* Set the dependencies.
*
* @author Andrea Marco Sartori
* @param Illuminate\Contracts\Bus\Dispatcher $dispatcher
* @return void
*/
public function __construct(Dispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Set the pipes commands should be piped through before dispatching.
*
* @author Andrea Marco Sartori
* @param array $pipes
* @return $this
*/
public function pipeThrough(array $pipes)
{
$this->dispatcher->pipeThrough($pipes);
return $this;
}
/**
* Marshal a command and dispatch it.
*
* @author Andrea Marco Sartori
* @param mixed $command
* @param \ArrayAccess $source
* @param array $extras
* @return mixed
*/
public function dispatchFrom($command, ArrayAccess $source, array $extras = [])
{
$this->command = $command;
$this->values = array_merge((array) $source, $extras);
return $this->dispatcher->dispatch($this->marshal());
}
/**
* Marshal the command to dispatch.
*
* @author Andrea Marco Sartori
* @return mixed
*/
protected function marshal()
{
$reflection = new ReflectionClass($this->command);
$constructor = $reflection->getConstructor();
$params = $this->getParamsToInject($constructor->getParameters());
return $reflection->newInstanceArgs($params);
}
/**
* Retrieve the arguments to inject into the command constructor.
*
* @author Andrea Marco Sartori
* @param array $parameters
* @return array
*/
protected function getParamsToInject(array $parameters)
{
return array_map(function ($parameter)
{
return $this->grabParameter($parameter);
}, $parameters);
}
/**
* Get a parameter value for a marshaled command.
*
* @author Andrea Marco Sartori
* @param \ReflectionParameter $parameter
* @return mixed
*/
protected function grabParameter(ReflectionParameter $parameter)
{
if (isset($this->values[$parameter->name]))
{
return $this->values[$parameter->name];
}
if ($parameter->isDefaultValueAvailable())
{
return $parameter->getDefaultValue();
}
throw new Exception("Unable to map parameter [{$parameter->name}] to command [{$this->command}]");
}
}