<?php
namespace Crea\ProcessBundle\Provider;
use Crea\ProcessBundle\Model\AbstractProcessStep;
use Crea\ProcessBundle\Model\ProcessStepInterface;
use Crea\ProcessBundle\ProcessConfiguration\ProcessConfigurationSpecificValuesTrait;
use RuntimeException;
class ProcessStepProvider implements ProcessStepProviderInterface
{
use ProcessConfigurationSpecificValuesTrait;
/** @var ProcessStepInterface[] */
private array $processStepServices;
/** @var ProcessStepInterface[] */
private array $processSteps = [];
public function __construct(iterable $processSteps,
iterable $processConfigurationSpecificProviders)
{
$this->processStepServices = $processSteps instanceof \Traversable ? iterator_to_array($processSteps) : $processSteps;
$this->processConfigurationSpecificProviders = $processConfigurationSpecificProviders instanceof \Traversable ? iterator_to_array($processConfigurationSpecificProviders) : $processConfigurationSpecificProviders;
}
public function getStep(string $index, string $processType, string $specificValue): ?ProcessStepInterface
{
$this->buildProcessSteps($this->processStepServices);
if (array_key_exists($index, $this->processSteps)) {
//process type and specific value are defined
foreach ($this->processSteps[$index] as $processStep) {
if ($processType === $processStep->getProcessType() && $specificValue === $processStep->getSpecificValue()) {
return $processStep;
}
}
//only process type is defined
foreach ($this->processSteps[$index] as $processStep) {
if ($processType === $processStep->getProcessType() && null === $processStep->getSpecificValue()) {
return $processStep;
}
}
//only specific value is defined
foreach ($this->processSteps[$index] as $processStep) {
if (null === $processStep->getProcessType() && $specificValue === $processStep->getSpecificValue()) {
return $processStep;
}
}
//process type and specific value are not defined
foreach ($this->processSteps[$index] as $processStep) {
if (null === $processStep->getProcessType() && null === $processStep->getSpecificValue()) {
return $processStep;
}
}
}
return null;
}
public function getSteps(string $processType, string $specificValue): array
{
$this->buildProcessSteps($this->processStepServices);
$steps = [];
foreach ($this->processSteps as $index => $processSteps) {
//process type and specific value are defined
foreach ($processSteps as $processStep) {
if ($processType === $processStep->getProcessType() && $specificValue === $processStep->getSpecificValue()) {
$steps[$index] = $processStep;
break;
}
}
//only process type is defined
foreach ($processSteps as $processStep) {
if ($processType === $processStep->getProcessType() && null === $processStep->getSpecificValue()) {
$steps[$index] = $processStep;
break;
}
}
//only specific value is defined
foreach ($processSteps as $processStep) {
if (null === $processStep->getProcessType() && $specificValue === $processStep->getSpecificValue()) {
$steps[$index] = $processStep;
break;
}
}
//process type and specific value are not defined
foreach ($processSteps as $processStep) {
if (null === $processStep->getProcessType() && null === $processStep->getSpecificValue()) {
$steps[$index] = $processStep;
break;
}
}
}
return $steps;
}
public function getStepsIndexes(): array
{
$this->buildProcessSteps($this->processStepServices);
$processStepsIndexes = [];
foreach ($this->processSteps as $index => $processStep) {
if (!in_array($index, $processStepsIndexes)) {
$processStepsIndexes[] = $index;
}
}
return $processStepsIndexes;
}
private function buildProcessSteps(array $processSteps): void
{
if (count($this->processSteps) === 0) {
//hydrate with AbstractProcessStep class
foreach ($processSteps as $processStep) {
if (!$processStep instanceof AbstractProcessStep) {
throw new RuntimeException(get_Class($processStep).' must implement abstract class "AbstractProcessStep"');
}
if (!array_key_exists($processStep->getIndex(), $this->processSteps)) {
$this->processSteps[$processStep->getIndex()] = [];
}
$this->processSteps[$processStep->getIndex()][] = $processStep;
}
//check
$combinations = [];
$specificValues = $this->getProcessConfigurationSpecificValues();
foreach ($this->processSteps as $processSteps) {
foreach ($processSteps as $processStep) {
//check specific values in process steps
if ($processStep->getSpecificValue() !== null && !in_array($processStep->getSpecificValue(), $specificValues)) {
throw new RuntimeException('Specific value "'.$processStep->getSpecificValue().'" does not exist in step class "'.get_class($processStep).'". Available values are : '.implode(", ", $specificValues).'.');
}
//check duplicate combination of index, process type and specific value
$combination = $processStep->getIndex()."-".($processStep->getProcessType() !== null ? $processStep->getProcessType() : "")."-".($processStep->getSpecificValue() !== null ? $processStep->getSpecificValue() : "");
if (!in_array($combination, $combinations)) {
$combinations[] = $combination;
}
else {
throw new RuntimeException('Duplicate combination of index "'.$processStep->getIndex().'", process type "'.$processStep->getProcessType().'" and specific value "'.$processStep->getSpecificValue().'" in step class.');
}
}
}
}
}
}