Files
iTop/sources/Forms/FormBuilder/DependencyMap.php
Benjamin Dalsass 4c1ad0f4f2 N°8772 - Form dependencies manager implementation
- Form SDK implementation
- Basic Forms
- Dynamics Forms
- Basic Blocks + Data Model Block
- Form Compilation
- Turbo integration
2025-12-30 11:42:55 +01:00

241 lines
5.7 KiB
PHP

<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\FormBuilder;
use Combodo\iTop\Forms\Block\AbstractFormBlock;
use Combodo\iTop\Forms\Block\Expression\AbstractExpressionFormBlock;
use Combodo\iTop\Forms\Block\FormBlock;
use Combodo\iTop\Forms\IO\FormBinding;
use Combodo\iTop\Forms\IO\FormInput;
use Combodo\iTop\Forms\IO\FormOutput;
/**
* Map containing information of form block dependencies.
*
* @package Combodo\iTop\Forms\FormBuilder
* @since 3.3.0
*/
class DependencyMap
{
/** @var array array of blocks impacted by dependence */
private array $aBlocksImpactedBy = [];
/** @var array array of binding */
private array $aBindings = [];
/** @var array array of binding (OUT > 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;
}
}