<?php
/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chevere\Workflow;
use Chevere\DataStructure\Map;
use Chevere\Parameter\Interfaces\ParameterInterface;
use Chevere\Parameter\Interfaces\ParametersInterface;
use Chevere\Parameter\Parameters;
use Chevere\Workflow\Interfaces\JobInterface;
use Chevere\Workflow\Interfaces\JobsInterface;
use Chevere\Workflow\Interfaces\ResponseReferenceInterface;
use Chevere\Workflow\Interfaces\VariableInterface;
use Chevere\Workflow\Interfaces\WorkflowInterface;
use OutOfBoundsException;
use function Chevere\Action\getParameters;
use function Chevere\Parameter\bool;
final class Workflow implements WorkflowInterface
{
private ParametersInterface $parameters;
/**
* @var Map<string[]>
*/
private Map $expected;
/**
* @var Map<ParameterInterface>
*/
private Map $provided;
public function __construct(
private JobsInterface $jobs
) {
$this->parameters = new Parameters();
$this->expected = new Map();
$this->provided = new Map();
$this->putAdded(
...iterator_to_array(
$jobs->getIterator()
)
);
}
public function jobs(): JobsInterface
{
return $this->jobs;
}
public function count(): int
{
return $this->jobs->count();
}
public function withAddedJob(JobInterface ...$job): WorkflowInterface
{
$new = clone $this;
$new->jobs = $new->jobs->withAdded(...$job);
$new->putAdded(...$job);
return $new;
}
public function parameters(): ParametersInterface
{
return $this->parameters;
}
/**
* @throws OutOfBoundsException
*/
public function getJobResponseParameter(string $job): ParameterInterface
{
/** @var ParameterInterface */
return $this->provided->get($job);
}
private function putParameters(string $name, JobInterface $job): void
{
$action = $job->action();
$parameters = getParameters($action::class);
$this->provided = $this->provided->withPut($name, $action::return());
foreach ($job->arguments() as $name => $value) {
if ($parameters->isVariadic()) {
$lastKey = array_key_last($parameters->keys());
$name = $parameters->keys()[$lastKey];
}
$parameter = $parameters->get($name);
$this->putVariableReference($value, $parameter);
}
}
private function putVariable(
VariableInterface $variable,
ParameterInterface $parameter
): void {
if ($this->parameters->has($variable->__toString())) {
return;
}
$this->parameters = $this->parameters
->withRequired(
$variable->__toString(),
$parameter,
);
}
private function putAdded(JobInterface ...$job): void
{
foreach ($job as $name => $item) {
$name = strval($name);
$this->putJobConditions($item);
$this->putParameters($name, $item);
}
}
private function putJobConditions(JobInterface $job): void
{
$parameter = bool();
foreach ($job->runIf() as $value) {
$this->putVariableReference($value, $parameter);
}
}
private function putVariableReference(
mixed $value,
ParameterInterface $parameter
): void {
$isVariable = $value instanceof VariableInterface;
$isResponse = $value instanceof ResponseReferenceInterface;
if (! ($isVariable || $isResponse)) {
return;
}
if ($isVariable) {
/** @var VariableInterface $value */
$this->putVariable($value, $parameter);
return;
}
/** @var ResponseReferenceInterface $value */
try {
/** @var array<string> $expected */
$expected = $this->expected->get($value->job());
} catch (OutOfBoundsException) {
$expected = [];
}
$expected[] = $value->key()
?? $value->job();
$this->expected = $this->expected
->withPut($value->job(), $expected);
}
}
|