diff --git a/css/form-sdk/form.css b/css/form-sdk/form.css index 8717a8dae..0de671705 100644 --- a/css/form-sdk/form.css +++ b/css/form-sdk/form.css @@ -55,3 +55,25 @@ .form_interval_horizontal > div{ margin-right: 8px; } + +.form-compound-fieldset{ + padding: 8px; + border-radius: 10px; + border: 1px dashed lightgrey; +} + + +.form-layout-row{ + display: flex; + flex-direction: row; +} +.form-layout-column{ + margin: 10px; +} +.form-layout-column:first-child{ + margin-left: 0px; +} +.form-layout-column:last-child{ + margin-right: 0px; +} + diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index da3924076..76538d12b 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -400,6 +400,7 @@ return array( 'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\FormImplementation\\Controller\\TestController' => $baseDir . '/sources/FormImplementation/Controller/TestController.php', + 'Combodo\\iTop\\FormImplementation\\Dto\\CountDto' => $baseDir . '/sources/FormImplementation/Dto/CountDto.php', 'Combodo\\iTop\\FormImplementation\\Dto\\ObjectSearchDto' => $baseDir . '/sources/FormImplementation/Dto/ObjectSearchDto.php', 'Combodo\\iTop\\FormImplementation\\Helper\\FormHelper' => $baseDir . '/sources/FormImplementation/Helper/FormHelper.php', 'Combodo\\iTop\\FormImplementation\\Helper\\SelectDataProvider' => $baseDir . '/sources/FormImplementation/Helper/SelectDataProvider.php', @@ -412,9 +413,10 @@ return array( 'Combodo\\iTop\\FormSDK\\Service\\FormFactoryBuilderTrait' => $baseDir . '/sources/FormSDK/Service/FormFactoryBuilderTrait.php', 'Combodo\\iTop\\FormSDK\\Service\\FormManager' => $baseDir . '/sources/FormSDK/Service/FormManager.php', 'Combodo\\iTop\\FormSDK\\Symfony\\SymfonyBridge' => $baseDir . '/sources/FormSDK/Symfony/SymfonyBridge.php', + 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Compound\\FieldsetType' => $baseDir . '/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Compound\\FormObjectType' => $baseDir . '/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php', + 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\AbstractLayoutType' => $baseDir . '/sources/FormSDK/Symfony/Type/Layout/LayoutType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\ColumnType' => $baseDir . '/sources/FormSDK/Symfony/Type/Layout/ColumnType.php', - 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\FieldsetType' => $baseDir . '/sources/FormSDK/Symfony/Type/Layout/FieldsetType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\RowType' => $baseDir . '/sources/FormSDK/Symfony/Type/Layout/RowType.php', 'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => $baseDir . '/sources/Form/Field/AbstractSimpleField.php', 'Combodo\\iTop\\Form\\Field\\BlobField' => $baseDir . '/sources/Form/Field/BlobField.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 3fe907901..4024b5051 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -809,6 +809,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\FormImplementation\\Controller\\TestController' => __DIR__ . '/../..' . '/sources/FormImplementation/Controller/TestController.php', + 'Combodo\\iTop\\FormImplementation\\Dto\\CountDto' => __DIR__ . '/../..' . '/sources/FormImplementation/Dto/CountDto.php', 'Combodo\\iTop\\FormImplementation\\Dto\\ObjectSearchDto' => __DIR__ . '/../..' . '/sources/FormImplementation/Dto/ObjectSearchDto.php', 'Combodo\\iTop\\FormImplementation\\Helper\\FormHelper' => __DIR__ . '/../..' . '/sources/FormImplementation/Helper/FormHelper.php', 'Combodo\\iTop\\FormImplementation\\Helper\\SelectDataProvider' => __DIR__ . '/../..' . '/sources/FormImplementation/Helper/SelectDataProvider.php', @@ -821,9 +822,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Combodo\\iTop\\FormSDK\\Service\\FormFactoryBuilderTrait' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FormFactoryBuilderTrait.php', 'Combodo\\iTop\\FormSDK\\Service\\FormManager' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FormManager.php', 'Combodo\\iTop\\FormSDK\\Symfony\\SymfonyBridge' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/SymfonyBridge.php', + 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Compound\\FieldsetType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Compound\\FormObjectType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php', + 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\AbstractLayoutType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Layout/LayoutType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\ColumnType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Layout/ColumnType.php', - 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\FieldsetType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Layout/FieldsetType.php', 'Combodo\\iTop\\FormSDK\\Symfony\\Type\\Layout\\RowType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Layout/RowType.php', 'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => __DIR__ . '/../..' . '/sources/Form/Field/AbstractSimpleField.php', 'Combodo\\iTop\\Form\\Field\\BlobField' => __DIR__ . '/../..' . '/sources/Form/Field/BlobField.php', diff --git a/lib/composer/installed.php b/lib/composer/installed.php index 2392d0ca3..7b5c6f143 100644 --- a/lib/composer/installed.php +++ b/lib/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'combodo/itop', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '75fde4c9a3fb4b46ae8765e961d0f590bdad199b', + 'reference' => '00f241e4cf314d4190bedeba80de9ec12461b958', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -22,7 +22,7 @@ 'combodo/itop' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '75fde4c9a3fb4b46ae8765e961d0f590bdad199b', + 'reference' => '00f241e4cf314d4190bedeba80de9ec12461b958', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/sources/FormImplementation/Dto/CountDto.php b/sources/FormImplementation/Dto/CountDto.php new file mode 100644 index 000000000..b98292ccf --- /dev/null +++ b/sources/FormImplementation/Dto/CountDto.php @@ -0,0 +1,34 @@ +$offset; + } + public function offsetSet($offset, $value) : void + { + $this->$offset = $value; + } + + public function offsetUnset($offset) : void + { + unset($this->$offset); + } +} diff --git a/sources/FormImplementation/Helper/FormHelper.php b/sources/FormImplementation/Helper/FormHelper.php index 3dd8486c6..eed12474f 100644 --- a/sources/FormImplementation/Helper/FormHelper.php +++ b/sources/FormImplementation/Helper/FormHelper.php @@ -3,6 +3,9 @@ namespace Combodo\iTop\FormImplementation\Helper; use Combodo\iTop\Controller\AbstractAppController; +use Combodo\iTop\FormImplementation\Dto\CountDto; +use Combodo\iTop\FormSDK\Field\FormFieldDescription; +use Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration; use Combodo\iTop\FormSDK\Service\FormManager; use DateInterval; use DateTime; @@ -30,6 +33,23 @@ class FormHelper // create a factory $oFormFactory = $oFormManager->CreateFactory(); + // form data + $aData = [ + 'city' => 'Autun', + 'tel' => '+33(6) 35 57 48 77', + 'birthday' => new DateTime('1979/06/27'), + 'count' => 10, + 'counts' => ['count1' => 10, 'count2' => 20, 'count3' => 30], + 'counts2' => new CountDto(), + 'interval' => ['days' => '12', 'hours' => '13', 'years' => '10', 'months' => '6', 'minutes' => '0', 'seconds' => '0', 'weeks' => '3'], + 'blog' => 'Your story', + 'notify' => true, + 'language' => 'FR FR', + 'mode' => '1', + 'options' => ['0', '2','4'] + ]; + $oFormFactory->SetData($aData); + // add X person forms... for($i = 0 ; $i < self::$PERSON_COUNT ; $i++){ @@ -37,7 +57,7 @@ class FormHelper $oPerson = MetaModel::GetObject('Person', $i+1); // create object adapter - $oObjectPlugin = $oFormFactory->CreateObjectAdapter($oPerson, true); + $oObjectPlugin = $oFormFactory->CreateObjectAdapter($oPerson, false); $oObjectPlugin->AddAttribute('name'); $oObjectPlugin->AddAttribute('mobile_phone'); } @@ -47,27 +67,51 @@ class FormHelper 'label' => 'Ma ville', 'help' => 'This is where you live', 'constraints' => new Length(['min' => 3]) - ], 'Autun'); + ]); // tel - text with pattern $oFormFactory->AddTextField('tel', [ 'label' => 'Tel', 'constraints' => new Regex(['pattern' => '/\+33\(\d\) \d\d \d\d \d\d \d\d/'], null, '+{33}(0) 00 00 00 00'), 'required' => false - ], '+33(6) 35 57 48 77'); + ]); // birthday - date $oFormFactory->AddDateField('birthday', [ 'label' => 'Anniversaire', 'widget' => 'single_text', 'required' => false - ], new DateTime('1979/06/27')); + ]); // count - number $oFormFactory->AddNumberField('count', [ 'label' => 'Compteur', 'required' => false - ], 10); + ]); + + // counts - fieldset + $oCount1 = new FormFieldDescription('count1', FormFieldTypeEnumeration::NUMBER, []); + $oCount2 = new FormFieldDescription('count2', FormFieldTypeEnumeration::NUMBER, []); + $oCount3 = new FormFieldDescription('count3', FormFieldTypeEnumeration::NUMBER, []); + $oFormFactory->AddFieldSet('counts', [ + 'label' => 'Compteurs', + 'required' => false, + 'fields' => [ + $oCount1, $oCount2, $oCount3 + ] + ]); + + // counts - fieldset alternative + $oCount1 = new FormFieldDescription('count1', FormFieldTypeEnumeration::NUMBER, []); + $oCount2 = new FormFieldDescription('count2', FormFieldTypeEnumeration::NUMBER, []); + $oCount3 = new FormFieldDescription('count3', FormFieldTypeEnumeration::NUMBER, []); + $oFormFactory->AddFieldSet('counts2', [ + 'label' => 'Compteurs', + 'required' => false, + 'fields' => [ + $oCount1, $oCount2, $oCount3 // OR $oData + ] + ]); // interval - duration $oFormFactory->AddDurationField('interval', [ @@ -80,24 +124,24 @@ class FormHelper 'attr' => [ 'class' => 'form_interval_horizontal' ] - ], ['days' => '12', 'hours' => '13', 'years' => '10', 'months' => '6', 'minutes' => '0', 'seconds' => '0', 'weeks' => '3']); + ]); // ready $oFormFactory->AddSwitchField('notify', [ 'label' => 'Veuillez m\'avertir en cas de changement', - ], true); + ]); // blog - date $oFormFactory->AddAreaField('blog', [ 'label' => 'Blog', 'required' => false - ], 'Your story'); + ]); // language - select with static data $oFormFactory->AddSelectField('language', [ 'label' => 'Ma langue', 'choices' => SelectDataProvider::GetApplicationLanguages() - ], 'FR FR'); + ]); // dog - select with ajax API $oFormFactory->AddSelectAjaxField('dog', [ @@ -136,10 +180,10 @@ class FormHelper 'label_attr' => [ 'class' => 'radio-inline' ] - ], '1'); + ]); // options - select with static data - $oFormFactory->AddSelectField('option', [ + $oFormFactory->AddSelectField('options', [ 'label' => 'Mes options', 'choices' => SelectDataProvider::GetOptions(), 'expanded' => true, @@ -147,7 +191,7 @@ class FormHelper 'label_attr' => [ 'class' => 'checkbox-inline' ] - ], ['0', '2','4']); + ]); // layout description $oFormFactory->SetLayoutDescription([ diff --git a/sources/FormSDK/Field/FormFieldTypeEnumeration.php b/sources/FormSDK/Field/FormFieldTypeEnumeration.php index 5ccc86fbf..8a2818872 100644 --- a/sources/FormSDK/Field/FormFieldTypeEnumeration.php +++ b/sources/FormSDK/Field/FormFieldTypeEnumeration.php @@ -33,8 +33,8 @@ enum FormFieldTypeEnumeration : string case DATE = 'DATE'; case SELECT = 'SELECT'; case SWITCH = 'SWITCH'; - case DB_OBJECT = 'DB_OBJECT'; case DURATION = 'DURATION'; + case FIELDSET = 'FIELDSET'; /** * Return available options. @@ -44,7 +44,7 @@ enum FormFieldTypeEnumeration : string public function GetAvailableOptions() : array { // global options - $aOptions = ['required', 'disabled', 'attr', 'label', 'label_attr', 'help']; + $aOptions = ['required', 'disabled', 'attr', 'label', 'label_attr', 'help', 'inherit_data']; // specific options $test = match ($this) { @@ -60,7 +60,7 @@ enum FormFieldTypeEnumeration : string FormFieldTypeEnumeration::DURATION => array_merge($aOptions, ['input', 'with_minutes', 'with_seconds', 'with_weeks', 'with_days'] ), - FormFieldTypeEnumeration::DB_OBJECT => array_merge($aOptions, + FormFieldTypeEnumeration::FIELDSET => array_merge($aOptions, ['fields'] ), default => $aOptions, diff --git a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php index b86f95a56..6cbe7f870 100644 --- a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php +++ b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php @@ -192,9 +192,9 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface } if($this->bGroup){ - $oGroupDescriptions = new FormFieldDescription($this->GetIdentifier(), FormFieldTypeEnumeration::DB_OBJECT, [ + $oGroupDescriptions = new FormFieldDescription($this->GetIdentifier(), FormFieldTypeEnumeration::FIELDSET, [ 'fields' => $aFieldsDescriptions, - 'label' => $this->GetLabel() + 'label' => $this->GetLabel(), ]); return [$this->GetIdentifier() => $oGroupDescriptions]; } diff --git a/sources/FormSDK/Service/FormFactory.php b/sources/FormSDK/Service/FormFactory.php index b5b07dc48..d0440c1cf 100644 --- a/sources/FormSDK/Service/FormFactory.php +++ b/sources/FormSDK/Service/FormFactory.php @@ -49,8 +49,11 @@ class FormFactory /** @var array $aFieldsDescriptions form types descriptions */ private array $aFieldsDescriptions = []; - /** @var array $aFieldsData form data */ - private array $aFieldsData = []; + /** @var mixed $oFieldsData form data */ + private mixed $oFieldsData = []; + + /** @var array $aLayoutDecription description of the layout */ + private array $aLayoutDecription; /** builder */ use FormFactoryBuilderTrait; @@ -70,27 +73,34 @@ class FormFactory } /** - * Return fields descriptions and data arrays. + * Return fields descriptions. * - * @return array{descriptions:array, data:array} + * @return array{fields_descriptions:array, layout_description:array} */ - public function GetFieldsDescriptionsAndData() : array + public function GetFieldsDescriptions() : array { // prepare data - $aResult = [ - 'descriptions' => $this->aFieldsDescriptions, - 'data' => $this->aFieldsData, - ]; + $aResult = $this->aFieldsDescriptions; + // merge each adapter data... foreach ($this->GetAllAdapters() as $oAdapter){ - $aResult['descriptions'] = array_merge($aResult['descriptions'], $oAdapter->GetFieldsDescriptions()); - $aResult['data'] = array_merge($aResult['data'], $oAdapter->GetFieldsData()); + $aResult = array_merge($aResult, $oAdapter->GetFieldsDescriptions()); } return $aResult; } + /** + * Return layout description. + * + * @return array + */ + public function GetLayoutDescription() : array + { + return $this->aLayoutDecription; + } + /** * Create an object adapter. * @@ -130,6 +140,43 @@ class FormFactory return $this->aAdapters; } + /** + * Set layout description. + * + * @param array $aLayoutDescription + * + * @return $this + */ + public function SetLayoutDescription(array $aLayoutDescription) + { + $this->aLayoutDecription = $aLayoutDescription; + return $this; + } + + /** + * @param mixed $oData + * + * @return void + */ + public function SetData(mixed $oData) : void + { + $this->oFieldsData = $oData; + } + + /*** + * @return array + */ + public function GetData() : mixed + { + $aData = $this->oFieldsData; + + foreach ($this->GetAllAdapters() as $adapter){ + $aData = array_merge($aData, $adapter->GetFieldsData()); + } + + return $aData; + } + /** * Create form. * @@ -138,8 +185,8 @@ class FormFactory */ public function CreateForm(?string $sName = null) : mixed { - ['descriptions' => $aDescriptions, 'data' => $aData] = $this->GetFieldsDescriptionsAndData(); - return $this->oSymfonyBridge->CreateForm($aDescriptions, $aData, $sName); + $aFieldsDescriptions = $this->GetFieldsDescriptions(); + return $this->oSymfonyBridge->CreateForm($aFieldsDescriptions, $this->GetData(), $sName, $this->GetLayoutDescription()); } } \ No newline at end of file diff --git a/sources/FormSDK/Service/FormFactoryBuilderTrait.php b/sources/FormSDK/Service/FormFactoryBuilderTrait.php index cc621be25..e0779fa23 100644 --- a/sources/FormSDK/Service/FormFactoryBuilderTrait.php +++ b/sources/FormSDK/Service/FormFactoryBuilderTrait.php @@ -16,11 +16,10 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddTextField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddTextField(string $sKey, array $aOptions) : FormFactory { // test widget for regex constraint if(array_key_exists('constraints', $aOptions)){ @@ -40,7 +39,6 @@ trait FormFactoryBuilderTrait } $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::TEXT, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -50,16 +48,12 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddNumberField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddNumberField(string $sKey, array $aOptions) : FormFactory { -// $aOptions['property_path'] = $sKey; - $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::NUMBER, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -69,11 +63,10 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddAreaField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddAreaField(string $sKey, array $aOptions) : FormFactory { $aOptions = array_merge([ 'attr' => [ @@ -83,7 +76,6 @@ trait FormFactoryBuilderTrait ], $aOptions); $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::AREA, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -93,14 +85,12 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddDateField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddDateField(string $sKey, array $aOptions) : FormFactory { $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::DATE, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -110,14 +100,12 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddDurationField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddDurationField(string $sKey, array $aOptions) : FormFactory { $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::DURATION, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -127,14 +115,12 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddSelectField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddSelectField(string $sKey, array $aOptions) : FormFactory { $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::SELECT, $aOptions); - $this->aFieldsData[$sKey] = $oData; return $this; } @@ -146,11 +132,10 @@ trait FormFactoryBuilderTrait * @param array $aOptions * @param array $aAjaxOptions * @param array $aAjaxData - * @param mixed $oData * * @return \Combodo\iTop\FormSDK\Service\FormFactory */ - public function AddSelectAjaxField(string $sKey, array $aOptions, array $aAjaxOptions, array $aAjaxData = [], mixed $oData = null) : FormFactory + public function AddSelectAjaxField(string $sKey, array $aOptions, array $aAjaxOptions, array $aAjaxData = []) : FormFactory { // merge ajax options $aAjaxOptions = array_merge([ @@ -184,7 +169,7 @@ trait FormFactoryBuilderTrait // }), ], $aOptions); - return $this->AddSelectField($sKey, $aOptions, $oData); + return $this->AddSelectField($sKey, $aOptions); } @@ -198,11 +183,10 @@ trait FormFactoryBuilderTrait * @param array $aFieldsToLoad * @param string $sSearch * @param int $iAjaxThershold - * @param mixed $oData * * @return \Combodo\iTop\FormSDK\Service\FormFactory */ - public function AddSelectOqlField(string $sKey, array $aOptions, string $sObjectClass, string $sOql, array $aFieldsToLoad, string $sSearch, int $iAjaxThershold, mixed $oData = null) : FormFactory + public function AddSelectOqlField(string $sKey, array $aOptions, string $sObjectClass, string $sOql, array $aFieldsToLoad, string $sSearch, int $iAjaxThershold) : FormFactory { $aAjaxData = [ 'class' => $sObjectClass, @@ -219,7 +203,7 @@ trait FormFactoryBuilderTrait 'threshold' => $iAjaxThershold, 'configuration' => 'OQL' ]; - return $this->AddSelectAjaxField($sKey, $aOptions, $aAjaxOptions, $aAjaxData, $oData); + return $this->AddSelectAjaxField($sKey, $aOptions, $aAjaxOptions, $aAjaxData); } /** @@ -227,18 +211,32 @@ trait FormFactoryBuilderTrait * * @param string $sKey * @param array $aOptions - * @param mixed $oData * * @return $this */ - public function AddSwitchField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + public function AddSwitchField(string $sKey, array $aOptions) : FormFactory { $aOptions = array_merge([ 'label_attr' => ['class' => 'checkbox-switch'], ], $aOptions); $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::SWITCH, $aOptions); - $this->aFieldsData[$sKey] = $oData; + + return $this; + } + + + /** + * Add fieldset. + * + * @param string $sKey + * @param array $aOptions + * + * @return $this + */ + public function AddFieldSet(string $sKey, array $aOptions) : FormFactory + { + $this->aFieldsDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::FIELDSET, $aOptions); return $this; } diff --git a/sources/FormSDK/Symfony/SymfonyBridge.php b/sources/FormSDK/Symfony/SymfonyBridge.php index 0a19f0e0a..aa739cd69 100644 --- a/sources/FormSDK/Symfony/SymfonyBridge.php +++ b/sources/FormSDK/Symfony/SymfonyBridge.php @@ -19,9 +19,12 @@ namespace Combodo\iTop\FormSDK\Symfony; -use Combodo\iTop\FormSDK\Symfony\Type\Compound\FormObjectType; use Combodo\iTop\FormSDK\Field\FormFieldDescription; use Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration; +use Combodo\iTop\FormSDK\Symfony\Type\Compound\FieldsetType; +use Combodo\iTop\FormSDK\Symfony\Type\Compound\FormObjectType; +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; @@ -100,7 +103,7 @@ class SymfonyBridge 'options' => $oFormDescription->GetOptions() ]; - case FormFieldTypeEnumeration::DB_OBJECT: + case FormFieldTypeEnumeration::FIELDSET: $aOptions = $oFormDescription->GetOptions(); $aFields = []; foreach ($aOptions['fields'] as $oChildFormDescription){ @@ -110,7 +113,7 @@ class SymfonyBridge $aOptions['fields'] = $aFields; return [ 'name' => $oFormDescription->GetName(), - 'type' => FormObjectType::class, + 'type' => FieldsetType::class, 'options' => $aOptions ]; @@ -137,43 +140,51 @@ class SymfonyBridge * Create Symfony form. * * @param array $aDescriptions - * @param array $aData + * @param mixed $oData * @param string|null $sName + * @param array|null $aLayout * * @return \Symfony\Component\Form\FormInterface */ - public function CreateForm(array $aDescriptions, array $aData, ?string $sName = null): FormInterface + public function CreateForm(array $aDescriptions, mixed $oData, ?string $sName = null, array $aLayout = []): FormInterface { // create Symfony form builder if($sName !== null){ - $oFormBuilder = $this->oFormFactory->createNamedBuilder($sName, FormType::class, $aData); + $oFormBuilder = $this->oFormFactory->createNamedBuilder($sName, FormType::class, $oData); } else{ - $oFormBuilder = $this->oFormFactory->createBuilder(FormType::class, $aData); + $oFormBuilder = $this->oFormFactory->createBuilder(FormType::class, $oData); } - // iterate throw descriptions... - foreach ($aDescriptions as $oFormDescription){ + // transform fields descriptions... + $aSymfonyTypesDeclaration = []; + foreach ($aDescriptions as $sKey => $oFormDescription){ + $aSymfonyTypesDeclaration[$sKey] = $this->ToSymfonyFormType($oFormDescription); + } - // symfony form type description - $aSymfony = $this->ToSymfonyFormType($oFormDescription); + // create layout types + ['types' => $aItems] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aSymfonyTypesDeclaration); + $oTest = array_merge($aItems, $aSymfonyTypesDeclaration); + + // add symfony types to builder... + foreach ($oTest as $oSymfonyTypeDeclaration){ // add type to form $oFormBuilder->add( - $aSymfony['name'], - $aSymfony['type'], - $aSymfony['options'] + $oSymfonyTypeDeclaration['name'], + $oSymfonyTypeDeclaration['type'], + $oSymfonyTypeDeclaration['options'] ); /** * Allow choices to be loaded client side via ajax. - * without this, field value needs to be part of initial choices that may be empty. - * Need reflexion because, value can be hacked with invalid value without extra validation. + * without this, field value needs to be part of initial choices that may be empty. + * Need reflexion because, value can be hacked with invalid value without validation. * @see https://symfony.com/doc/current/reference/forms/types/choice.html#choice-loader * @see https://itecnote.com/tecnote/php-disable-backend-validation-for-choice-field-in-symfony-2-type/ - */ - if($aSymfony['type'] === ChoiceType::class){ - $oFormBuilder->get($aSymfony['name'])->resetViewTransformers(); + */ + if($oSymfonyTypeDeclaration['type'] === ChoiceType::class){ + $oFormBuilder->get($oSymfonyTypeDeclaration['name'])->resetViewTransformers(); } } @@ -181,4 +192,62 @@ class SymfonyBridge return $oFormBuilder->getForm(); } + /** + * @param $aLayout + * @param $oFormBuilder + * @param array $aDescriptions + * + * @return array + */ + private function CreateLayoutTypes($aLayout, $oFormBuilder, array &$aDescriptions){ + + $aResult = []; + $sClasses = ''; + + foreach ($aLayout as $sKey => $oLayoutElement) + { + if($sKey === 'css_classes'){ + $sClasses = $oLayoutElement; + } + else if(str_starts_with($sKey, 'row__')){ + $aResult[$sKey] = $this->CreateLayoutContainerType($oLayoutElement, $oFormBuilder, $sKey, RowType::class, $aDescriptions); + } + else if(str_starts_with($sKey, 'column__')){ + $aResult[$sKey] = $this->CreateLayoutContainerType($oLayoutElement, $oFormBuilder, $sKey, ColumnType::class, $aDescriptions); + } + else if(str_starts_with($sKey, 'fieldset__')){ + $aResult[$sKey] = $this->CreateLayoutContainerType($oLayoutElement, $oFormBuilder, $sKey, FieldsetType::class, $aDescriptions); + } + else { + if (array_key_exists($oLayoutElement, $aDescriptions)) { + $aResult[$oLayoutElement] = $aDescriptions[$oLayoutElement]; + unset($aDescriptions[$oLayoutElement]); + } + } + } + + return [ + 'types' => $aResult, + 'css_classes' => $sClasses + ]; + } + + private function CreateLayoutContainerType($oLayoutElement, $oFormBuilder, $sKey, $oType, &$aDescriptions) + { + ['types' => $aItems, 'css_classes' => $sCssClasses] = $this->CreateLayoutTypes($oLayoutElement, $oFormBuilder, $aDescriptions); + + return [ + 'name' => $sKey, + 'type' => $oType, + 'options' => [ + 'fields' => $aItems, + 'attr' => [ + 'class' => $sCssClasses + ], + 'inherit_data' => true + ], + ]; + } + + } \ No newline at end of file diff --git a/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php b/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php new file mode 100644 index 000000000..bfc52c6d6 --- /dev/null +++ b/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php @@ -0,0 +1,72 @@ +add($oField['name'], $oField['type'], $oField['options']); + } + } + + private function handleRow(FormBuilderInterface $builder, array $aData){ + + } + + private function handleColumn(FormBuilderInterface $builder, array $aData){ + + } + + /** @inheritdoc */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'fields' => [], + 'view' => [], + ]); + } + + /** @inheritdoc */ + public function getParent(): string + { + return FormType::class; + } + +} \ No newline at end of file diff --git a/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php b/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php index 4f6c207d6..8da495ed0 100644 --- a/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php +++ b/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php @@ -34,41 +34,12 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class FormObjectType extends AbstractType { - /* - * View Definition. - * - * [ - * 'row' => [ - * 'col' => [ - * 'description' => [ - * 'label' => '', - * 'css_classes' => '' - * ], - * 'items' => ['name', 'birthday'] - * 'fieldset' => ['address', 'city', 'country'] - * ] - * ] - * ] - * - * - */ + /** @inheritdoc */ public function buildForm(FormBuilderInterface $builder, array $options) : void { - foreach ($options['view'] as $oItem) { - if($oItem === 'row'){ - $this->handleRow(); - } - else if($oItem === 'col'){ - $this->handleColumn(); - } - else{ - - } - - } foreach ($options['fields'] as $oField){ $builder->add($oField['name'], $oField['type'], $oField['options']); @@ -90,7 +61,7 @@ class FormObjectType extends AbstractType 'fields' => [], 'view' => [], 'attr' => [ - 'class' => '' + 'class' => 'form-object-row' ] ]); } diff --git a/sources/FormSDK/Symfony/Type/Layout/ColumnType.php b/sources/FormSDK/Symfony/Type/Layout/ColumnType.php new file mode 100644 index 000000000..dd44e9408 --- /dev/null +++ b/sources/FormSDK/Symfony/Type/Layout/ColumnType.php @@ -0,0 +1,43 @@ +add($oField['name'], $oField['type'], $oField['options']); + } + } + + /** @inheritdoc */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'fields' => [], + 'view' => [], + 'inherit_data' => true // this type is abstract and used for grouping + ]); + } + + /** @inheritdoc */ + public function getParent(): string + { + return FormType::class; + } + +} \ No newline at end of file diff --git a/sources/FormSDK/Symfony/Type/Layout/RowType.php b/sources/FormSDK/Symfony/Type/Layout/RowType.php new file mode 100644 index 000000000..79c985fd5 --- /dev/null +++ b/sources/FormSDK/Symfony/Type/Layout/RowType.php @@ -0,0 +1,43 @@ +