OUT) grouped by block and output name */ private array $aBindingsOutputToInput = []; /** @var array array of binding (IN > IN) grouped by block and output name */ private array $aBindingsInputToInput = []; /** @var array array of binding (OUT > OUT) grouped by block and output name */ private array $aBindingsOutputToOutputs = []; /** * Constructor. * * @param array $aBlocksWithDependencies */ public function __construct(private readonly array $aBlocksWithDependencies) { // Initialization $this->Init(); } /** * Initialize. * * @return void */ private function Init(): void { /** Iterate throw blocks with dependencies... @var AbstractFormBlock $oDependentBlock */ foreach ($this->aBlocksWithDependencies as $oDependentBlock) { /** Iterate throw the block inputs bindings... @var FormBinding $oBinding**/ foreach ($oDependentBlock->GetBoundInputsBindings() as $oBinding) { // OUT > IN if ($oBinding->oSourceIO instanceof FormOutput && $oBinding->oDestinationIO instanceof FormInput) { $this->AddBindingToMap($this->aBindingsOutputToInput, $oBinding); $this->AddToBlockImpactedBy($oBinding->oSourceIO->GetOwnerBlock()->GetName(), $oDependentBlock); } // IN > IN if ($oBinding->oSourceIO instanceof FormInput && $oBinding->oDestinationIO instanceof FormInput) { $this->AddBindingToMap($this->aBindingsInputToInput, $oBinding); } } /** Iterate throw the block inputs connections... @var FormBinding $oBinding**/ foreach ($oDependentBlock->GetBoundOutputBindings() as $oBinding) { // OUT > OUT if ($oBinding->oSourceIO instanceof FormOutput && $oBinding->oDestinationIO instanceof FormOutput) { $this->AddBindingToMap($this->aBindingsOutputToOutputs, $oBinding); } } } } /** * Add a binding to a map. * * @param array $map * @param FormBinding $oBinding * * @return void */ private function AddBindingToMap(array &$map, FormBinding $oBinding): void { // Binding information $sBlockName = $oBinding->oSourceIO->GetOwnerBlock()->GetName(); $sIOName = $oBinding->oSourceIO->GetName(); // initialize map if (!isset($map[$sBlockName])) { $map[$sBlockName] = []; } if (!isset($map[$sBlockName][$sIOName])) { $map[$sBlockName][$sIOName] = []; } // add to map $map[$sBlockName][$sIOName][] = $oBinding; $this->aBindings[] = $oBinding; } /** * @param string $sDependsOnName * @param AbstractFormBlock $oImpactedBlock * * @return void */ private function AddToBlockImpactedBy(string $sDependsOnName, AbstractFormBlock $oImpactedBlock): void { // Initialize array for this dependence if (!array_key_exists($sDependsOnName, $this->aBlocksImpactedBy)) { $this->aBlocksImpactedBy[$sDependsOnName] = []; } // Add the block $this->aBlocksImpactedBy[$sDependsOnName][$oImpactedBlock->GetName()] = $oImpactedBlock; // TODO if ($oImpactedBlock instanceof AbstractExpressionFormBlock) { foreach ($oImpactedBlock->GetOutputs() as $oOutput) { foreach ($oOutput->GetBindings() as $oBinding) { $this->AddToBlockImpactedBy($sDependsOnName, $oBinding->oDestinationIO->GetOwnerBlock()); } } } } /** * @return array */ public function GetImpactingBlocksWithoutDependencies(): array { $aResult = []; // Iterate throw binding OUT > IN foreach (array_keys($this->aBindingsOutputToInput) as $sOutputBlockName) { // Exclude block containing dependencies if (!array_key_exists($sOutputBlockName, $this->aBlocksWithDependencies)) { $aResult[] = $sOutputBlockName; } } return $aResult; } /** * Get block impacted by a given block. * The blocks can be filtered using a callable. * * @param string $sBlockName * @param callable|null $oFilter * * @return array|null */ public function GetBlocksImpactedBy(string $sBlockName, callable $oFilter = null): ?array { if (!array_key_exists($sBlockName, $this->aBlocksImpactedBy)) { return null; } $aBlocks = $this->aBlocksImpactedBy[$sBlockName]; // Filtering if ($oFilter !== null) { $aBlocks = array_filter($aBlocks, $oFilter); } return $aBlocks; } /** * Check if a block impacts other blocks. * * @param string $sBlockName * * @return bool */ public function HasBlocksImpactedBy(string $sBlockName): bool { return $this->GetBlocksImpactedBy($sBlockName) !== null; } /** * Get bindings OUT > IN. * * @return array */ public function GetOutputToInputs(): array { return $this->aBindingsOutputToInput; } /** * Get bindings IN > IN. * * @return array */ public function GetInputToInputs(): array { return $this->aBindingsInputToInput; } /** * Get bindings OUT > OUT. * * @return array */ public function GetOutputToOutputs(): array { return $this->aBindingsOutputToOutputs; } /** * Get all bindings. * * @return array */ public function GetAllBindings() { return $this->aBindings; } }