N°7063 - Forms SDK - Add Symfony forms component

error forms issue
This commit is contained in:
Benjamin Dalsass
2024-01-11 10:10:08 +01:00
parent a50f579793
commit e55f1f1d66
8 changed files with 103 additions and 118 deletions

View File

@@ -170,7 +170,6 @@ class FormHelper
// interval - duration
$oFormFactory->AddDurationField('interval', [
'label' => 'Fréquence',
'input' => 'array',
'with_minutes' => true,
'with_seconds' => true,
'with_weeks' => true,

View File

@@ -60,7 +60,7 @@ enum FormFieldTypeEnumeration
['widget']
),
FormFieldTypeEnumeration::DURATION => array_merge($aOptions,
['input', 'with_minutes', 'with_seconds', 'with_weeks', 'with_days']
['with_minutes', 'with_seconds', 'with_weeks', 'with_days']
),
FormFieldTypeEnumeration::FIELDSET => array_merge($aOptions,
['fields', 'layout']

View File

@@ -71,10 +71,10 @@ final class FormFactory
*/
public function GetFieldsDescriptions() : array
{
// prepare data
// prepare fields descriptions
$aResult = $this->aFieldsDescriptions;
// merge each adapter data...
// merge each adapter fields descriptions...
foreach ($this->GetAllAdapters() as $oAdapter){
$aResult = array_merge($aResult, $oAdapter->GetFieldsDescriptions());
}
@@ -101,8 +101,10 @@ final class FormFactory
*/
public function GetData() : mixed
{
// prepare fields data
$aData = $this->oFieldsData;
// merge each adapter fields data...
foreach ($this->GetAllAdapters() as $adapter){
$aData = array_merge($aData, $adapter->GetFieldsData());
}

View File

@@ -25,7 +25,6 @@ use Combodo\iTop\FormSDK\Symfony\Type\Compound\CollectionType;
use Combodo\iTop\FormSDK\Symfony\Type\Compound\FieldsetType;
use Combodo\iTop\FormSDK\Symfony\Type\Layout\ColumnType;
use Combodo\iTop\FormSDK\Symfony\Type\Layout\RowType;
use LogAPI;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateIntervalType;
@@ -38,8 +37,6 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
/**
* Symfony implementation bridge.
@@ -69,123 +66,108 @@ class SymfonyBridge
*/
public function ToSymfonyFormType(FormFieldDescription $oFormDescription) : ?array
{
switch($oFormDescription->GetType()){
case FormFieldTypeEnumeration::TEXT:
return [
'name' => $oFormDescription->GetName(),
'type' => TextType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::AREA:
return [
'name' => $oFormDescription->GetName(),
'type' => TextareaType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::DATE:
return [
'name' => $oFormDescription->GetName(),
'type' => DateType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::SELECT:
return [
'name' => $oFormDescription->GetName(),
'type' => ChoiceType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::SWITCH:
return [
'name' => $oFormDescription->GetName(),
'type' => CheckboxType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::FIELDSET:
$aOptions = $oFormDescription->GetOptions();
$this->TransformFieldsetOptions($aOptions);
return [
'name' => $oFormDescription->GetName(),
'type' => FieldsetType::class,
'options' => $aOptions
];
case FormFieldTypeEnumeration::NUMBER:
return [
'name' => $oFormDescription->GetName(),
'type' => NumberType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::DURATION:
return [
'name' => $oFormDescription->GetName(),
'type' => DateIntervalType::class,
'options' => $oFormDescription->GetOptions()
];
case FormFieldTypeEnumeration::COLLECTION:
$aOptions = $oFormDescription->GetOptions();
$this->TransformCollectionOptions($aOptions);
return [
'name' => $oFormDescription->GetName(),
'type' => CollectionType::class,
'options' => $aOptions
];
case FormFieldTypeEnumeration::FILE:
$aOptions = $oFormDescription->GetOptions();
return [
'name' => $oFormDescription->GetName(),
'type' => FileType::class,
'options' => $aOptions
];
default:
return null;
}
return [
'name' => $oFormDescription->GetName(),
'type' => $this->ToSymfonyFormTypeClass($oFormDescription->GetType()),
'options' => $this->ToSymfonyFormTypeOptions($oFormDescription->GetType(), $oFormDescription->GetOptions())
];
}
/**
* Transform fieldset options.
* Transform type to Symfony form type class.
*
* @param \Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration $oType
*
* @return string|null
*/
public function ToSymfonyFormTypeClass(FormFieldTypeEnumeration $oType) : ?string
{
return match ($oType) {
FormFieldTypeEnumeration::TEXT => TextType::class,
FormFieldTypeEnumeration::AREA => TextareaType::class,
FormFieldTypeEnumeration::DATE => DateType::class,
FormFieldTypeEnumeration::SELECT => ChoiceType::class,
FormFieldTypeEnumeration::SWITCH => CheckboxType::class,
FormFieldTypeEnumeration::FIELDSET => FieldsetType::class,
FormFieldTypeEnumeration::NUMBER => NumberType::class,
FormFieldTypeEnumeration::DURATION => DateIntervalType::class,
FormFieldTypeEnumeration::COLLECTION => CollectionType::class,
FormFieldTypeEnumeration::FILE => FileType::class,
default => null,
};
}
/**
*
* @param \Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration $oType
* @param array $aOptions
*
* @return array
*/
public function ToSymfonyFormTypeOptions(FormFieldTypeEnumeration $oType, array $aOptions) : array
{
return match ($oType) {
FormFieldTypeEnumeration::DURATION => $this->TransformDurationOptions($aOptions),
FormFieldTypeEnumeration::FIELDSET => $this->TransformFieldsetOptions($aOptions),
FormFieldTypeEnumeration::COLLECTION => $this->TransformCollectionOptions($aOptions),
default => $aOptions,
};
}
/**
* Transform duration field options.
*
* @param array $aOptions
*
* @return void
* @return array
*/
private function TransformFieldsetOptions(array &$aOptions) : void
private function TransformDurationOptions(array $aOptions) : array
{
$aOptions['input'] = 'array';
$aFields = [];
return $aOptions;
}
/**
* Transform fieldset field options.
*
* @param array $aOptions
*
* @return array
*/
private function TransformFieldsetOptions(array $aOptions) : array
{
$aOptions['types_declarations'] = [];
foreach ($aOptions['fields'] as $oChildFormDescription){
$aSymfony = $this->ToSymfonyFormType($oChildFormDescription);
$aFields[$oChildFormDescription->GetName()] = $aSymfony;
$aOptions['types_declarations'][$oChildFormDescription->GetName()] = $aSymfony;
}
$aOptions['fields'] = $aFields;
unset($aOptions['fields']);
return $aOptions;
}
/**
* Transform collection options.
* Transform collection field options.
*
* @param array $aOptions
*
* @return void
* @return array
*/
private function TransformCollectionOptions(array &$aOptions) : void
private function TransformCollectionOptions(array &$aOptions) : array
{
$aOptions['entry_type'] = $this->ToSymfonyFormTypeClass($aOptions['element_type']);
$aOptions['entry_type'] = FieldsetType::class;
$aOptions['entry_options'] = $this->ToSymfonyFormTypeOptions($aOptions['element_type'], $aOptions['element_options']);
$this->TransformFieldsetOptions($aOptions['element_options']);
$aOptions['entry_options'] = $aOptions['element_options'];
$aOptions['types_labels'] = $aOptions['fields_labels'];
unset($aOptions['element_options']);
unset($aOptions['element_type']);
unset($aOptions['element_options']);
unset($aOptions['fields_labels']);
return $aOptions;
}
/**
@@ -214,18 +196,18 @@ class SymfonyBridge
$aSymfonyTypesDeclaration[$sKey] = $this->ToSymfonyFormType($oFormFieldDescription);
}
// prepare fieldset types layouts...
// handle fieldset types layouts...
foreach ($aSymfonyTypesDeclaration as &$aSymfonyTypeDeclaration){
if($aSymfonyTypeDeclaration['type'] === FieldsetType::class
&& isset($aSymfonyTypeDeclaration['options']['layout'])){
['types' => $aItems] = $this->CreateLayoutTypes($aSymfonyTypeDeclaration['options']['layout'], $oFormBuilder, $aSymfonyTypeDeclaration['options']['fields']);
$aSymfonyTypeDeclaration['options']['fields'] = array_merge($aItems, $aSymfonyTypeDeclaration['options']['fields']);
['types_declarations' => $aLayoutSymfonyTypesDeclarations] = $this->CreateLayoutTypes($aSymfonyTypeDeclaration['options']['layout'], $oFormBuilder, $aSymfonyTypeDeclaration['options']['types_declarations']);
$aSymfonyTypeDeclaration['options']['types_declarations'] = array_merge($aLayoutSymfonyTypesDeclarations, $aSymfonyTypeDeclaration['options']['types_declarations']);
}
}
// prepare global layout types
['types' => $aItems] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aSymfonyTypesDeclaration);
$aSymfonyTypesDeclaration = array_merge($aItems, $aSymfonyTypesDeclaration);
// handle global layout types
['types_declarations' => $aLayoutSymfonyTypesDeclaration] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aSymfonyTypesDeclaration);
$aSymfonyTypesDeclaration = array_merge($aLayoutSymfonyTypesDeclaration, $aSymfonyTypesDeclaration);
// add Symfony types to builder...
foreach ($aSymfonyTypesDeclaration as $oSymfonyTypeDeclaration){
@@ -297,7 +279,7 @@ class SymfonyBridge
}
return [
'types' => $aResult,
'types_declarations' => $aResult,
'label' => $sLabel,
'css_classes' => $sClasses
];
@@ -316,14 +298,14 @@ class SymfonyBridge
*/
private function CreateLayoutContainerType(array $aLayout, FormBuilderInterface $oFormBuilder, string $sKey, string $sTypeClassName, array &$aDescriptions) : array
{
['types' => $aItems, 'label' => $sLabel, 'css_classes' => $sCssClasses] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aDescriptions);
['types_declarations' => $aTypesDeclarations, 'label' => $sLabel, 'css_classes' => $sCssClasses] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aDescriptions);
return [
'name' => $sKey,
'type' => $sTypeClassName,
'options' => [
'label' => $sLabel !== null ? $sLabel : false,
'fields' => $aItems,
'types_declarations' => $aTypesDeclarations,
'attr' => [
'class' => $sCssClasses
],

View File

@@ -41,7 +41,7 @@ class CollectionType extends AbstractType
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'fields_labels' => [],
'types_labels' => [],
]);
}
@@ -55,7 +55,7 @@ class CollectionType extends AbstractType
public function buildView(FormView $view, FormInterface $form, array $options): void
{
// pass the form type option directly to the template
$view->vars['fields_labels'] = $options['fields_labels'];
$view->vars['types_labels'] = $options['types_labels'];
}
/** @inheritdoc */

View File

@@ -37,8 +37,9 @@ class FieldsetType extends AbstractType
/** @inheritdoc */
public function buildForm(FormBuilderInterface $builder, array $options) : void
{
foreach ($options['fields'] as $oField){
$builder->add($oField['name'], $oField['type'], $oField['options']);
// add each types to form...
foreach ($options['types_declarations'] as $aTypeDeclaration){
$builder->add($aTypeDeclaration['name'], $aTypeDeclaration['type'], $aTypeDeclaration['options']);
}
}
@@ -46,7 +47,7 @@ class FieldsetType extends AbstractType
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'fields' => [],
'types_declarations' => [],
'layout' => []
]);
}

View File

@@ -37,8 +37,9 @@ class LayoutType extends AbstractType
/** @inheritdoc */
public function buildForm(FormBuilderInterface $builder, array $options) : void
{
foreach ($options['fields'] as $oField){
$builder->add($oField['name'], $oField['type'], $oField['options']);
// add each types
foreach ($options['types_declarations'] as $oTypeDeclaration){
$builder->add($oTypeDeclaration['name'], $oTypeDeclaration['type'], $oTypeDeclaration['options']);
}
}
@@ -46,7 +47,7 @@ class LayoutType extends AbstractType
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'fields' => [],
'types_declarations' => [],
'inherit_data' => true // this type is abstract and used for logical grouping
]);
}

View File

@@ -49,7 +49,7 @@
<table class="table table-striped">
<thead>
<tr>
{% for label in form.vars.fields_labels %}
{% for label in form.vars.types_labels %}
<td>{{ label }}</td>
{% endfor %}
</tr>