| 
<?php
 /*
 * This file is part of Chevere.
 *
 * (c) Rodolfo Berrios <rodolfo@chevere.org>
 *
 * 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\Interfaces\VectorInterface;
 use Chevere\DataStructure\Map;
 use Chevere\DataStructure\Traits\MapTrait;
 use Chevere\DataStructure\Vector;
 use Chevere\Message\Interfaces\MessageInterface;
 use Chevere\Parameter\Arguments;
 use Chevere\Parameter\Interfaces\ArgumentsInterface;
 use Chevere\Parameter\Interfaces\CastInterface;
 use Chevere\Workflow\Interfaces\RunInterface;
 use Chevere\Workflow\Interfaces\WorkflowInterface;
 use OverflowException;
 use function Chevere\Message\message;
 use function Chevere\Parameter\cast;
 
 final class Run implements RunInterface
 {
 /**
 * @template-use MapTrait<CastInterface>
 */
 use MapTrait;
 
 private string $uuid;
 
 private ArgumentsInterface $arguments;
 
 /**
 * Skipped jobs.
 *
 * @var VectorInterface<string>
 */
 private VectorInterface $skip;
 
 /**
 * @param mixed ...$variable Variables matching workflow parameters
 */
 public function __construct(
 private WorkflowInterface $workflow,
 mixed ...$variable
 ) {
 $this->uuid = uuidv4();
 $this->arguments = new Arguments(
 $workflow->parameters(),
 $variable
 );
 $this->map = new Map();
 $this->skip = new Vector();
 }
 
 public function uuid(): string
 {
 return $this->uuid;
 }
 
 public function workflow(): WorkflowInterface
 {
 return $this->workflow;
 }
 
 public function arguments(): ArgumentsInterface
 {
 return $this->arguments;
 }
 
 public function skip(): VectorInterface
 {
 return $this->skip;
 }
 
 public function withResponse(string $job, CastInterface $response): RunInterface
 {
 $this->assertNoSkipOverflow($job, message('Job %job% is skipped'));
 $new = clone $this;
 $new->workflow->jobs()->get($job);
 $new->workflow->getJobResponseParameter($job)->__invoke($response->mixed());
 $new->map = $new->map->withPut($job, $response);
 
 return $new;
 }
 
 public function withSkip(string ...$job): RunInterface
 {
 $new = clone $this;
 foreach ($job as $item) {
 $new->workflow->jobs()->get($item);
 $new->assertNoSkipOverflow($item, message('Job %job% already skipped'));
 $new->skip = $new->skip->withPush($item);
 }
 
 return $new;
 }
 
 public function response(string $job, string|int ...$key): CastInterface
 {
 return cast($this->map->get($job)->mixed(), ...$key);
 }
 
 /**
 * @codeCoverageIgnore
 */
 public function getReturn(string $job): CastInterface
 {
 return $this->response($job);
 }
 
 private function assertNoSkipOverflow(string $job, MessageInterface $message): void
 {
 if ($this->skip->contains($job)) {
 throw new OverflowException(
 strtr($message->__toString(), [
 '%job%' => $job,
 ])
 );
 }
 }
 }
 
 |