mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 11:08:45 +02:00
N°8772 - Form dependencies manager implementation - WIP
This commit is contained in:
@@ -477,6 +477,7 @@ return array(
|
|||||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\Base\\StringFormBlock' => $baseDir . '/sources/Forms/Block/Base/StringFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\Base\\StringFormBlock' => $baseDir . '/sources/Forms/Block/Base/StringFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
||||||
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\FormBlock' => $baseDir . '/sources/Forms/Block/FormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\FormBlock' => $baseDir . '/sources/Forms/Block/FormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\FormInput' => $baseDir . '/sources/Forms/Block/FormInput.php',
|
'Combodo\\iTop\\Forms\\Block\\FormInput' => $baseDir . '/sources/Forms/Block/FormInput.php',
|
||||||
|
|||||||
@@ -858,6 +858,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
|||||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\Base\\StringFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/StringFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\Base\\StringFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/StringFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
||||||
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\FormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlock.php',
|
'Combodo\\iTop\\Forms\\Block\\FormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlock.php',
|
||||||
'Combodo\\iTop\\Forms\\Block\\FormInput' => __DIR__ . '/../..' . '/sources/Forms/Block/FormInput.php',
|
'Combodo\\iTop\\Forms\\Block\\FormInput' => __DIR__ . '/../..' . '/sources/Forms/Block/FormInput.php',
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ abstract class AbstractFormBlock
|
|||||||
return $this->aOptions;
|
return $this->aOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function AddSubFormBlock(AbstractFormBlock $oSubFormBlock): void
|
public function AddSubFormBlock(AbstractFormBlock $oSubFormBlock): AbstractFormBlock
|
||||||
{
|
{
|
||||||
$this->aSubFormBlocks[] = $oSubFormBlock;
|
$this->aSubFormBlocks[] = $oSubFormBlock;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetSubFormBlocks(): array
|
public function GetSubFormBlocks(): array
|
||||||
@@ -57,11 +58,40 @@ abstract class AbstractFormBlock
|
|||||||
$this->aFormOutputs[$oFormOutput->GetName()] = $oFormOutput;
|
$this->aFormOutputs[$oFormOutput->GetName()] = $oFormOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetOutput(string $sName): FormOutput
|
public function GetOutput(string $sName): ?FormOutput
|
||||||
{
|
{
|
||||||
return $this->aFormOutputs[$sName];
|
return $this->aFormOutputs[$sName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sInputName
|
||||||
|
* @param string $sOutputBlockName
|
||||||
|
* @param string $sOutputName
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
* @throws \Combodo\iTop\Forms\Block\FormsBlockException
|
||||||
|
*/
|
||||||
|
public function DependsOn(string $sInputName, string $sOutputBlockName, string $sOutputName): AbstractFormBlock
|
||||||
|
{
|
||||||
|
$oFormInput = $this->GetInput($sInputName);
|
||||||
|
if (is_null($oFormInput)) {
|
||||||
|
throw new FormsBlockException('Missing input ' . $sInputName . ' for ' . $this->sName);
|
||||||
|
}
|
||||||
|
$oFormInput->Connect($sOutputBlockName, $sOutputName);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function HasConnections(): bool
|
||||||
|
{
|
||||||
|
foreach ($this->aFormInputs as $oFormInput) {
|
||||||
|
if ($oFormInput->HasConnections()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
abstract public function GetFormType(): string;
|
abstract public function GetFormType(): string;
|
||||||
|
|
||||||
abstract public function InitInputs(): void;
|
abstract public function InitInputs(): void;
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ use Combodo\iTop\Forms\Block\FormInput;
|
|||||||
|
|
||||||
class AttributeChoiceFormBlock extends ChoiceFormBlock
|
class AttributeChoiceFormBlock extends ChoiceFormBlock
|
||||||
{
|
{
|
||||||
|
public const INPUT_CLASS_NAME = 'class_name';
|
||||||
|
|
||||||
public function InitInputs(): void
|
public function InitInputs(): void
|
||||||
{
|
{
|
||||||
$this->AddInput(new FormInput('class_name', 'string'));
|
$this->AddInput(new FormInput(self::INPUT_CLASS_NAME, 'string'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Combodo\iTop\Forms\Block\DataModel;
|
||||||
|
|
||||||
|
use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock;
|
||||||
|
use Combodo\iTop\Forms\Block\FormInput;
|
||||||
|
|
||||||
|
class AttributeValueChoiceFormBlock extends ChoiceFormBlock
|
||||||
|
{
|
||||||
|
|
||||||
|
public const INPUT_CLASS_NAME = 'class_name';
|
||||||
|
public const INPUT_ATTRIBUTE = 'attribute';
|
||||||
|
|
||||||
|
public function __construct(string $sName, array $aOptions = [])
|
||||||
|
{
|
||||||
|
$aOptions['multiple'] = true;
|
||||||
|
parent::__construct($sName, $aOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function InitInputs(): void
|
||||||
|
{
|
||||||
|
$this->AddInput(new FormInput(self::INPUT_CLASS_NAME, 'string'));
|
||||||
|
$this->AddInput(new FormInput(self::INPUT_ATTRIBUTE, 'string'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,9 +8,12 @@ use Combodo\iTop\Forms\Block\FormOutput;
|
|||||||
class OqlFormBlock extends StringFormBlock
|
class OqlFormBlock extends StringFormBlock
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public const OUTPUT_SELECTED_CLASS = 'selected_class';
|
||||||
|
|
||||||
public function InitOutputs(): void
|
public function InitOutputs(): void
|
||||||
{
|
{
|
||||||
$this->AddOutput(new FormOutput('selected_class', 'string'));
|
parent::InitOutputs();
|
||||||
|
$this->AddOutput(new FormOutput(self::OUTPUT_SELECTED_CLASS, 'string'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,17 +3,17 @@
|
|||||||
namespace Combodo\iTop\Forms\Block;
|
namespace Combodo\iTop\Forms\Block;
|
||||||
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
|
||||||
use Symfony\Component\Form\FormInterface;
|
|
||||||
|
|
||||||
class FormBlock extends AbstractFormBlock
|
class FormBlock extends AbstractFormBlock
|
||||||
{
|
{
|
||||||
|
public const OUTPUT_VALUE = 'value';
|
||||||
|
|
||||||
public function __construct(string $sName, array $aOptions = [])
|
public function __construct(string $sName, array $aOptions = [])
|
||||||
{
|
{
|
||||||
|
$aOptions['form_block'] = $this;
|
||||||
parent::__construct($sName, $aOptions);
|
parent::__construct($sName, $aOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function GetFormType(): string
|
public function GetFormType(): string
|
||||||
{
|
{
|
||||||
return FormType::class;
|
return FormType::class;
|
||||||
@@ -25,14 +25,6 @@ class FormBlock extends AbstractFormBlock
|
|||||||
|
|
||||||
public function InitOutputs(): void
|
public function InitOutputs(): void
|
||||||
{
|
{
|
||||||
}
|
$this->AddOutput(new FormOutput(self::OUTPUT_VALUE, 'string'));
|
||||||
|
|
||||||
public function Build(FormBuilderInterface $oBuilder): FormInterface
|
|
||||||
{
|
|
||||||
foreach ($this->GetSubFormBlocks() as $oSubForm) {
|
|
||||||
$oBuilder->add($oSubForm->GetName(), $oSubForm->GetFormType(), $oSubForm->GetOptions());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $oBuilder->getForm();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ class FormInput
|
|||||||
|
|
||||||
private string $sType;
|
private string $sType;
|
||||||
|
|
||||||
|
private array $aConnections = [];
|
||||||
|
|
||||||
public function __construct(string $sName, string $sType)
|
public function __construct(string $sName, string $sType)
|
||||||
{
|
{
|
||||||
$this->sName = $sName;
|
$this->sName = $sName;
|
||||||
@@ -33,4 +35,19 @@ class FormInput
|
|||||||
{
|
{
|
||||||
$this->sType = $sType;
|
$this->sType = $sType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function Connect(string $sOutputBlockName, string $sOutputName)
|
||||||
|
{
|
||||||
|
$this->aConnections[] = ['block' => $sOutputBlockName, 'output' => $sOutputName];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetConnections(): array
|
||||||
|
{
|
||||||
|
return $this->aConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function HasConnections(): bool
|
||||||
|
{
|
||||||
|
return count($this->aConnections) > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ class FormOutput
|
|||||||
|
|
||||||
private string $sType;
|
private string $sType;
|
||||||
|
|
||||||
private AbstractConverter $oConverter;
|
private null|AbstractConverter $oConverter;
|
||||||
|
|
||||||
public function __construct(string $sName, string $sType, AbstractConverter $oConverter = null)
|
public function __construct(string $sName, string $sType, AbstractConverter $oConverter = null)
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ class FormOutput
|
|||||||
|
|
||||||
public function GetOutputValue(mixed $oData): mixed
|
public function GetOutputValue(mixed $oData): mixed
|
||||||
{
|
{
|
||||||
$this->oConverter->Convert($oData);
|
return $this->oConverter->Convert($oData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
14
sources/Forms/Block/FormsBlockException.php
Normal file
14
sources/Forms/Block/FormsBlockException.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||||
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Combodo\iTop\Forms\Block;
|
||||||
|
|
||||||
|
use Combodo\iTop\Forms\FormsException;
|
||||||
|
|
||||||
|
class FormsBlockException extends FormsException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace Combodo\iTop\Forms\FormBuilder;
|
namespace Combodo\iTop\Forms\FormBuilder;
|
||||||
|
|
||||||
use Combodo\iTop\Forms\Dependency\DependencyDescription;
|
|
||||||
use Combodo\iTop\Forms\Dependency\DependencyHandler;
|
use Combodo\iTop\Forms\Dependency\DependencyHandler;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
@@ -30,44 +29,30 @@ class FormBuilder implements FormBuilderInterface, \IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function __construct(private FormBuilderInterface $builder)
|
public function __construct(private FormBuilderInterface $builder)
|
||||||
{
|
{
|
||||||
|
$this->InitFormBlocks();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a dependency description to the form builder.
|
|
||||||
* The associate form will be created as a hidden field and added later when all its dependencies were met.
|
|
||||||
*
|
|
||||||
* @param DependencyDescription $oDependencyDescription the dependency description
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function AddDependency(DependencyDescription $oDependencyDescription): void
|
|
||||||
{
|
|
||||||
if($this->dependencyHandler === null){
|
|
||||||
\IssueLog::Error('create dependency handler ' . $this->builder->getName());
|
|
||||||
$this->dependencyHandler = new DependencyHandler($this->builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->dependencyHandler->AddDependencyDescription($oDependencyDescription);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(string|FormBuilderInterface $child, ?string $type = null, array $options = []): static
|
public function add(string|FormBuilderInterface $child, ?string $type = null, array $options = []): static
|
||||||
{
|
{
|
||||||
if(!empty($options['bindings'])) {
|
$this->builder->add($child, $type, $options);
|
||||||
$this->builder->add($child, HiddenType::class);
|
|
||||||
$this->AddDependency(new DependencyDescription($options['bindings'], $child, $type, $options));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$this->builder->add($child, $type, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addExpression(string $name, string $expression): static
|
private function InitFormBlocks()
|
||||||
{
|
{
|
||||||
$options['bindings'] = [$expression];
|
$oFormBlock = $this->builder->getOption('form_block');
|
||||||
return $this->add($name, null, $options);
|
if (is_null($oFormBlock)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \Combodo\iTop\Forms\Block\FormBlock $oSubFormBlock */
|
||||||
|
foreach ($oFormBlock->GetSubFormBlocks() as $oSubFormBlock) {
|
||||||
|
if ($oSubFormBlock->HasConnections()) {
|
||||||
|
$this->builder->add($oSubFormBlock->GetName(), HiddenType::class);
|
||||||
|
} else {
|
||||||
|
$this->add($oSubFormBlock->GetName(), $oSubFormBlock->GetFormType(), $oSubFormBlock->getOptions());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pure decoration of FormBuilderInterface
|
// pure decoration of FormBuilderInterface
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ use Symfony\Component\Form\AbstractTypeExtension;
|
|||||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Form\FormEvents;
|
use Symfony\Component\Form\FormEvents;
|
||||||
use Symfony\Component\Form\FormInterface;
|
|
||||||
use Symfony\Component\Form\FormView;
|
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class FormTypeExtension extends AbstractTypeExtension
|
class FormTypeExtension extends AbstractTypeExtension
|
||||||
@@ -23,9 +21,7 @@ class FormTypeExtension extends AbstractTypeExtension
|
|||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$resolver->setDefined([
|
$resolver->setDefined([
|
||||||
'inputs',
|
'form_block',
|
||||||
'outputs',
|
|
||||||
'bindings',
|
|
||||||
'listener_callback',
|
'listener_callback',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
12
sources/Forms/FormsException.php
Normal file
12
sources/Forms/FormsException.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||||
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Combodo\iTop\Forms;
|
||||||
|
|
||||||
|
class FormsException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user