N°8772 - dynamic form

This commit is contained in:
Benjamin Dalsass
2025-11-07 11:00:15 +01:00
parent b6ec29c6ec
commit a448f668bc
11 changed files with 177 additions and 38 deletions

View File

@@ -485,6 +485,7 @@ return array(
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => $baseDir . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => $baseDir . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
@@ -508,6 +509,7 @@ return array(
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\AttributeIOFormat' => $baseDir . '/sources/Forms/Block/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\BooleanIOFormat' => $baseDir . '/sources/Forms/Block/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\ClassIOFormat' => $baseDir . '/sources/Forms/Block/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\NumberIOFormat' => $baseDir . '/sources/Forms/Block/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\RawFormat' => $baseDir . '/sources/Forms/Block/IO/Format/RawFormat.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => $baseDir . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => $baseDir . '/sources/Forms/FormBuilder/DependencyMap.php',

View File

@@ -866,6 +866,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
@@ -889,6 +890,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\AttributeIOFormat' => __DIR__ . '/../..' . '/sources/Forms/Block/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\BooleanIOFormat' => __DIR__ . '/../..' . '/sources/Forms/Block/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\ClassIOFormat' => __DIR__ . '/../..' . '/sources/Forms/Block/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\NumberIOFormat' => __DIR__ . '/../..' . '/sources/Forms/Block/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\Block\\IO\\Format\\RawFormat' => __DIR__ . '/../..' . '/sources/Forms/Block/IO/Format/RawFormat.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyMap.php',

View File

@@ -146,7 +146,7 @@ abstract class AbstractFormBlock implements IFormBlock
public function GetOptionsMergedWithDynamic(string $sEventType = null): array
{
return array_merge($this->aDynamicOptions, $this->aOptions);
return array_merge($this->GetDynamicOptions(), $this->GetOptions());
}
public function GetDynamicOptions(string $sEventType = null): array

View File

@@ -43,27 +43,40 @@ class CollectionBlock extends AbstractTypeFormBlock
$this->AddInput(self::INPUT_CLASS_NAME, ClassIOFormat::class);
}
/** @inheritdoc */
public function InitBlockOptions(array &$aUserOptions): void
protected $oBlock;
public function GetOptions(): array
{
parent::InitBlockOptions($aUserOptions);
$aOptions = parent::GetOptions();
// Convert block information in type information
if(isset($aUserOptions['block_entry_type'])) {
$sBlockEntryType = $aUserOptions['block_entry_type'];
$sBlockEntryOptions = $this->aUserOptions['block_entry_options'];
$oBlock = new ($sBlockEntryType)('prototype', $sBlockEntryOptions);
unset($aUserOptions['block_entry_type']);
unset($aUserOptions['block_entry_options']);
$aUserOptions['entry_type'] = $oBlock->GetFormType();
$aUserOptions['entry_options'] = $oBlock->GetOptions();
$aUserOptions['prototype'] = true;
$aUserOptions['allow_add'] = true;
$aUserOptions['prototype_options'] = [
if(isset($aOptions['block_entry_type'])) {
$aOptions['prototype'] = true;
$aOptions['allow_add'] = true;
$aOptions['prototype_options'] = [
'label' => false
];
}
$sBlockEntryType = $aOptions['block_entry_type'];
$sBlockEntryOptions = $aOptions['block_entry_options'];
$this->oBlock = new ($sBlockEntryType)('prototype', $sBlockEntryOptions);
// $this->HandleBlockDependencies();
// $this->oBlock->SetParent($this->GetParent());
// $oBlock->DependsOn('company', 'company', AbstractFormBlock::OUTPUT_VALUE);
unset($aOptions['block_entry_type']);
unset($aOptions['block_entry_options']);
$aOptions['entry_type'] = $this->oBlock->GetFormType();
$aOptions['entry_options'] = $this->oBlock->GetOptions();
return $aOptions;
}
public function HandleBlockDependencies(): void
{
}
}

View File

@@ -0,0 +1,24 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\Block\Base;
use Combodo\iTop\Forms\Block\AbstractTypeFormBlock;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
/**
* Form block for string.
*
*/
class IntegerFormBlock extends AbstractTypeFormBlock
{
/** @inheritdoc */
public function GetFormType(): string
{
return IntegerType::class;
}
}

View File

@@ -33,14 +33,14 @@ class FormType extends AbstractType
$aData[] = [
'name' => $oChild->GetName(),
'added' => $oChild->IsAdded(),
'id' => FormTypeHelper::buildFormTypeFullPath($form) . '_' . $oChild->GetName()
'id' => FormTypeHelper::GetFormId($form) . '_' . $oChild->GetName()
];
}
else{
$aData[] = [
'name' => $oChild->GetName(),
'added' => $oChild->IsAdded(),
'id' => FormTypeHelper::buildFormTypeFullPath($form) . '_' . $oChild->GetName()
'id' => FormTypeHelper::GetFormId($form) . '_' . $oChild->GetName()
];
}

View File

@@ -2,18 +2,86 @@
namespace Combodo\iTop\Forms\Block\FormType;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use Symfony\Component\Form\FormInterface;
class FormTypeHelper
{
public static function buildFormTypeFullPath(FormInterface $form): string
/**
* @param FormInterface $oForm
*
* @return string
*/
public static function GetFormId(FormInterface $oForm): string
{
$names = [];
$current = $form;
while ($current !== null) {
$names[] = $current->getName();
$current = $current->getParent();
if (is_null($oForm->getParent())) {
return $oForm->getName();
}
return implode('_', array_reverse($names));
return self::GetFormId($oForm->getParent()).'_'.$oForm->getName();
}
/**
* Compute the blocks to redraw based on a turbo trigger.
*
* @param FormBlock $oFormBlock
* @param FormInterface $oForm
* @param string $sBlockTurboTriggerName
*
* @return array
*/
public static function ComputeBlocksToRedraw(FormBlock $oFormBlock, FormInterface $oForm, string $sBlockTurboTriggerName): array
{
// Result
$aBlocksToRedraw = [];
// Get the form corresponding to the turbo trigger
$oFormTurboTrigger = self::GetFormAt($oForm, $sBlockTurboTriggerName);
$sBlockTurboTriggerId = self::GetFormId($oFormTurboTrigger);
// Get the parent form
$oParent = $oFormTurboTrigger->getParent();
$sParentName = self::GetFormId($oParent);
// Get the block corresponding to the turbo trigger form
$oBlockTurboTrigger = $oFormTurboTrigger->getConfig()->getOption('form_block');
$oMap = $oBlockTurboTrigger->GetParent()->GetDependenciesMap();
// Add itself
$aBlocksToRedraw[$sBlockTurboTriggerId] = $oFormTurboTrigger->createView();
// Add impacted blocks
$aImpacted = $oMap->GetImpacted($oBlockTurboTrigger->GetName());
foreach ($aImpacted as $oImpactedBlock) {
$sName = $sParentName.'_'.$oImpactedBlock->GetName();
if($oParent->has($oImpactedBlock->GetName())){
$aBlocksToRedraw[$sName] = $oParent->get($oImpactedBlock->GetName())->createView();
}
else{
$aBlocksToRedraw[$sName] = null;
}
}
return $aBlocksToRedraw;
}
/**
* @param FormInterface $oForm
* @param string $sBlockTurboTriggerName
*
* @return FormInterface|null
*/
public static function GetFormAt(FormInterface $oForm, string $sBlockTurboTriggerName): ?FormInterface
{
if (preg_match_all('/\[(?<level>[^\[]+)\]/', $sBlockTurboTriggerName, $aMatches)) {
foreach ($aMatches['level'] as $level) {
$oForm = $oForm->Get($level);
}
}
return $oForm;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Combodo\iTop\Forms\Block\IO\Format;
class NumberIOFormat
{
public mixed $oValue;
public function __construct(string $oValue)
{
$this->oValue = $oValue;
// validation du format sinon exception
}
public function __toString(): string
{
return $this->oValue;
}
}

View File

@@ -157,17 +157,17 @@ class DependencyHandler
*/
private function CheckDependencies(FormInterface|FormBuilderInterface $oForm, string $sOutputBlock = null, string $sEventType = null): void
{
// $aImpactedBlocks = $this->aDependentBlocks;
// if($sOutputBlock !== null){
// $aImpactedBlocks = $this->oDependenciesMap->GetBlocksDependingOn($sOutputBlock);
// }
//
// if($aImpactedBlocks === null){
// return;
// }
$aImpactedBlocks = $this->aDependentBlocks;
if($sOutputBlock !== null){
$aImpactedBlocks = $this->oDependenciesMap->GetBlocksDependingOn($sOutputBlock);
}
if($aImpactedBlocks === null){
return;
}
/** Iterate throw dependencies... @var AbstractFormBlock $oDependentBlock */
foreach ($this->aDependentBlocks as $oDependentBlock) {
foreach ($aImpactedBlocks as $oDependentBlock) {
if (!$oDependentBlock instanceof AbstractTypeFormBlock) {
continue;
}

View File

@@ -12,6 +12,7 @@ use Combodo\iTop\Forms\Block\FormBlock;
use Combodo\iTop\Forms\Block\IO\FormBinding;
use Combodo\iTop\Forms\Block\IO\FormInput;
use Combodo\iTop\Forms\Block\IO\FormOutput;
use Combodo\iTop\ItopSdkFormDemonstrator\Form\Block\ExpressionFormBlock;
/**
* Dependencies handler.
@@ -99,6 +100,15 @@ class DependencyMap
// Add the block
$this->aBlocksWithDependenciesGroupByDependence[$sDependenceBlockName][$oBlockWithDependencies->GetName()] = $oBlockWithDependencies;
// TODO
if($oBlockWithDependencies instanceof ExpressionFormBlock){
foreach($oBlockWithDependencies->GetOutputs() as $oOutput){
foreach($oOutput->GetBindings() as $oBinding){
$this->AddToBlockWithDependenciesMap($sDependenceBlockName, $oBinding->oDestinationIO->GetOwnerBlock());
}
}
}
}
/**

View File

@@ -90,10 +90,11 @@ class FormBuilder implements FormBuilderInterface, IteratorAggregate
if (count($aBlocksWithDependencies) > 0) {
$this->oDependencyHandler = new DependencyHandler($this->builder->getName(), $oFormBlock, $this, $this->aChildren, $aBlocksWithDependencies);
$oFormBlock->oDependencyMap = $this->oDependencyHandler->GetMap();
if (is_null($oFormBlock->GetParent())) {
// Insert a hidden type to save the place
$this->builder->add('_turbo_trigger', HiddenType::class, ['prevent_form_build' => true]);
}
}
if (is_null($oFormBlock->GetParent())) {
// Insert a hidden type to save the place
$this->builder->add('_turbo_trigger', HiddenType::class, ['prevent_form_build' => true]);
}
}