cerbero90/Workflow

View on GitHub
src/Wrappers/MarshalDispatcher.php

Summary

Maintainability
A
0 mins
Test Coverage
<?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}]");
    }

}