diff --git a/css/form-sdk/form.css b/css/form-sdk/form.css index 0955bbdd9..983c3a6a1 100644 --- a/css/form-sdk/form.css +++ b/css/form-sdk/form.css @@ -1,7 +1,11 @@ -html{ - font-family: "Montserrat"; -} +/** + * Widgets Factory. + * + * @package FormSDK + * @since 3.2.0 + */ +/* debug purpose */ .form-type-pictograms{ display: inline-block; margin-left: 5px; @@ -11,56 +15,31 @@ html{ padding: 0px 5px; border-radius: 8px; } - .form-type-pictograms i{ width: 15px; } - -.form-object legend{ - font-weight: bold; - color: grey; -} - -.form-object{ - border: 1px lightgrey dashed; - padding: 8px 12px; - border-radius: 8px; -} - -.complete .pattern:after{ +.complete .form-type-pictograms .pattern:after{ content: '\f00c'; font-family: "Font Awesome 6 Free"; font-weight: 900; background-color: #20b220; border-radius: 50%; - font-size: 9px; + font-size: 7px; color: white; position: relative; top: -10px; padding: 2px; } -.ajax-query-type{ - font-size: .8rem; +/* form object row */ +.form-object-row{ + border: 1px lightgrey dashed; + padding: 8px 12px; + border-radius: 8px; +} +.form-object-row legend{ + font-weight: bold; + color: grey; } -.theme_viewer{ - display: flex; -} - -.theme{ - width: 100%; - padding: 20px; -} - -.theme1 h4{ - color: #cc8d17; - border-bottom: 1px #cc8d17 solid; - margin-bottom: 20px; -} -.theme2 h4{ - color: #c7306e; - border-bottom: 1px #c7306e solid; - margin-bottom: 20px; -} \ No newline at end of file diff --git a/js/form-sdk/widget-factory.js b/js/form-sdk/widget-factory.js index c17bf8776..0d09fe355 100644 --- a/js/form-sdk/widget-factory.js +++ b/js/form-sdk/widget-factory.js @@ -1,4 +1,9 @@ - +/** + * Widgets Factory. + * + * @package FormSDK + * @since 3.2.0 + */ const iTopFormWidgetFactory = new function(){ /** @@ -6,42 +11,63 @@ const iTopFormWidgetFactory = new function(){ * * @constructor */ - const AutoInstall = function() - { + const AutoInstall = function() { console.log('AutoInstall'); - // SELECT widget implementation - $('[data-widget="SelectWidget"]').each(function(e){ - const oElement = $(this); - if(!oElement.data('widget-state-initialized')){ - const sId = oElement.attr('id'); - const aOptions = oElement.data('widget-options'); - iTopFormWidgetFactory.CreateSelectWidget(sId, aOptions); - oElement.data('widget-state-initialized', true); - } - }); + // widgets catalog + const WIDGETS = { + SELECT: {name: 'SelectWidget', builder: CreateSelectWidget}, + TEXT: {name: 'TextWidget', builder: CreateTextWidget}, + AREA: {name: 'AreaWidget', builder: CreateAreaWidget} + } - $('[data-widget="TextWidget"]').each(function(e){ - const oElement = $(this); - if(!oElement.data('widget-state-initialized')){ - const sId = oElement.attr('id'); - const aOptions = oElement.data('widget-options'); - iTopFormWidgetFactory.CreateTextWidget(sId, aOptions); - oElement.data('widget-state-initialized', true); - } - }); + // instanciate widgets... + for (const widgetsKey in WIDGETS) { + + // widget configuration + const aWidgetConfiguration = WIDGETS[widgetsKey]; + + // instanciate widget + $(`[data-widget="${aWidgetConfiguration.name}"]`).each(function (e) { + const oElement = $(this); + if (!oElement.data('widget-state-initialized')) { + const sId = oElement.attr('id'); + const aOptions = oElement.data('widget-options'); + aWidgetConfiguration.builder(sId, aOptions); + console.log(aWidgetConfiguration.name, sId, aOptions); + oElement.data('widget-state-initialized', true); + } + }); + } - $('[data-widget="AreaWidget"]').each(function(e){ - const oElement = $(this); - if(!oElement.data('widget-state-initialized')){ - const sId = oElement.attr('id'); - const aOptions = oElement.data('widget-options'); - iTopFormWidgetFactory.CreateAreaWidget(sId, aOptions); - oElement.data('widget-state-initialized', true); - } - }); } + /** + * CreateTextWidget. + * + * @param {string} sId + * @param {array} aOptions + * @constructor + */ + const CreateTextWidget = function(sId, aOptions){ + + if(aOptions['pattern'] !== undefined){ + + const oElement = $(`#${sId}`); + const oMask = IMask(oElement[0], + { + mask: aOptions['pattern'], + lazy: false, + } + ); + oMask.on('accept', () => { + masked = oMask.masked; + oElement.closest('div').toggleClass('complete', masked.isComplete) + }); + } + + }; + /** * CreateAreaWidget. * @@ -51,9 +77,6 @@ const iTopFormWidgetFactory = new function(){ */ const CreateAreaWidget = function(sId, aOptions){ - console.log('CreateAreaWidget', sId, aOptions); - - editor = CKEDITOR.replace(sId, { language: 'fr', stylesSet: 'my_styles', @@ -72,34 +95,6 @@ const iTopFormWidgetFactory = new function(){ }; - /** - * CreateTextWidget. - * - * @param {string} sId - * @param {array} aOptions - * @constructor - */ - const CreateTextWidget = function(sId, aOptions){ - - console.log('CreateTextWidget', sId, aOptions); - - if(aOptions['pattern'] !== undefined){ - - const oElement = $(`#${sId}`); - const oMask = IMask(oElement[0], - { - mask: aOptions['pattern'], - lazy: false, - } - ); - oMask.on('accept', () => { - masked = oMask.masked; - oElement.closest('div').toggleClass('complete', masked.isComplete) - }); - } - - }; - /** * CreateSelectAjaxWidget. * @@ -107,10 +102,8 @@ const iTopFormWidgetFactory = new function(){ * @param {array} aOptions * @constructor */ - const CreateSelectWidget = function(sId, aOptions){ - - console.log('CreateSelectAjaxWidget', sId, aOptions); - + const CreateSelectWidget = function(sId, aOptions) + { const aPlugins = {}; if(aOptions['max_items'] != '1'){ @@ -144,10 +137,7 @@ const iTopFormWidgetFactory = new function(){ }; return { - AutoInstall, - CreateTextWidget, - CreateAreaWidget, - CreateSelectWidget, + AutoInstall } }; diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 393af0402..aefabc474 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -399,16 +399,17 @@ return array( 'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => $baseDir . '/sources/Core/MetaModel/HierarchicalKey.php', 'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php', - 'Combodo\\iTop\\FormSDK\\Controller\\TestController' => $baseDir . '/sources/FormSDK/Controller/TestController.php', - 'Combodo\\iTop\\FormSDK\\Dto\\ObjectSearchDto' => $baseDir . '/sources/FormSDK/Dto/ObjectSearchDto.php', - 'Combodo\\iTop\\FormSDK\\Field\\Description\\FormFieldDescription' => $baseDir . '/sources/FormSDK/Field/Description/FormFieldDescription.php', - 'Combodo\\iTop\\FormSDK\\Field\\Description\\FormFieldTypeEnumeration' => $baseDir . '/sources/FormSDK/Field/Description/FormFieldTypeEnumeration.php', - 'Combodo\\iTop\\FormSDK\\Helper\\FormHelper' => $baseDir . '/sources/FormSDK/Helper/FormHelper.php', - 'Combodo\\iTop\\FormSDK\\Helper\\SelectHelper' => $baseDir . '/sources/FormSDK/Helper/SelectDataProvider.php', - 'Combodo\\iTop\\FormSDK\\Helper\\TwigHelper' => $baseDir . '/sources/FormSDK/Helper/TwigHelper.php', - 'Combodo\\iTop\\FormSDK\\Service\\FactoryAddon\\FormFactoryAddonInterface' => $baseDir . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php', - 'Combodo\\iTop\\FormSDK\\Service\\FactoryAddon\\FormFactoryObjectAddon' => $baseDir . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php', + 'Combodo\\iTop\\FormImplementation\\Controller\\TestController' => $baseDir . '/sources/FormImplementation/Controller/TestController.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', + 'Combodo\\iTop\\FormImplementation\\Helper\\TwigHelper' => $baseDir . '/sources/FormImplementation/Helper/TwigHelper.php', + 'Combodo\\iTop\\FormSDK\\Field\\FormFieldDescription' => $baseDir . '/sources/FormSDK/Field/FormFieldDescription.php', + 'Combodo\\iTop\\FormSDK\\Field\\FormFieldTypeEnumeration' => $baseDir . '/sources/FormSDK/Field/FormFieldTypeEnumeration.php', + 'Combodo\\iTop\\FormSDK\\Service\\FactoryAdapter\\FormFactoryAdapterInterface' => $baseDir . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php', + 'Combodo\\iTop\\FormSDK\\Service\\FactoryAdapter\\FormFactoryObjectAdapter' => $baseDir . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php', 'Combodo\\iTop\\FormSDK\\Service\\FormFactory' => $baseDir . '/sources/FormSDK/Service/FormFactory.php', + '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\\FormObjectType' => $baseDir . '/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 23af377ce..fba35ca9d 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -808,16 +808,17 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => __DIR__ . '/../..' . '/sources/Core/MetaModel/HierarchicalKey.php', 'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', - 'Combodo\\iTop\\FormSDK\\Controller\\TestController' => __DIR__ . '/../..' . '/sources/FormSDK/Controller/TestController.php', - 'Combodo\\iTop\\FormSDK\\Dto\\ObjectSearchDto' => __DIR__ . '/../..' . '/sources/FormSDK/Dto/ObjectSearchDto.php', - 'Combodo\\iTop\\FormSDK\\Field\\Description\\FormFieldDescription' => __DIR__ . '/../..' . '/sources/FormSDK/Field/Description/FormFieldDescription.php', - 'Combodo\\iTop\\FormSDK\\Field\\Description\\FormFieldTypeEnumeration' => __DIR__ . '/../..' . '/sources/FormSDK/Field/Description/FormFieldTypeEnumeration.php', - 'Combodo\\iTop\\FormSDK\\Helper\\FormHelper' => __DIR__ . '/../..' . '/sources/FormSDK/Helper/FormHelper.php', - 'Combodo\\iTop\\FormSDK\\Helper\\SelectHelper' => __DIR__ . '/../..' . '/sources/FormSDK/Helper/SelectDataProvider.php', - 'Combodo\\iTop\\FormSDK\\Helper\\TwigHelper' => __DIR__ . '/../..' . '/sources/FormSDK/Helper/TwigHelper.php', - 'Combodo\\iTop\\FormSDK\\Service\\FactoryAddon\\FormFactoryAddonInterface' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php', - 'Combodo\\iTop\\FormSDK\\Service\\FactoryAddon\\FormFactoryObjectAddon' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php', + 'Combodo\\iTop\\FormImplementation\\Controller\\TestController' => __DIR__ . '/../..' . '/sources/FormImplementation/Controller/TestController.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', + 'Combodo\\iTop\\FormImplementation\\Helper\\TwigHelper' => __DIR__ . '/../..' . '/sources/FormImplementation/Helper/TwigHelper.php', + 'Combodo\\iTop\\FormSDK\\Field\\FormFieldDescription' => __DIR__ . '/../..' . '/sources/FormSDK/Field/FormFieldDescription.php', + 'Combodo\\iTop\\FormSDK\\Field\\FormFieldTypeEnumeration' => __DIR__ . '/../..' . '/sources/FormSDK/Field/FormFieldTypeEnumeration.php', + 'Combodo\\iTop\\FormSDK\\Service\\FactoryAdapter\\FormFactoryAdapterInterface' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php', + 'Combodo\\iTop\\FormSDK\\Service\\FactoryAdapter\\FormFactoryObjectAdapter' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php', 'Combodo\\iTop\\FormSDK\\Service\\FormFactory' => __DIR__ . '/../..' . '/sources/FormSDK/Service/FormFactory.php', + '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\\FormObjectType' => __DIR__ . '/../..' . '/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php', diff --git a/lib/composer/installed.php b/lib/composer/installed.php index bb53dda80..33c1cdb4c 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' => '47aeb0cbd303fc27c06bae27b6447b1bef4d8e35', + 'reference' => '20949605c30bc7a83d0b554f4af23b6cf802c292', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -22,7 +22,7 @@ 'combodo/itop' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '47aeb0cbd303fc27c06bae27b6447b1bef4d8e35', + 'reference' => '20949605c30bc7a83d0b554f4af23b6cf802c292', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/sources/FormSDK/Controller/TestController.php b/sources/FormImplementation/Controller/TestController.php similarity index 91% rename from sources/FormSDK/Controller/TestController.php rename to sources/FormImplementation/Controller/TestController.php index cc9bb544d..2cc558b7d 100644 --- a/sources/FormSDK/Controller/TestController.php +++ b/sources/FormImplementation/Controller/TestController.php @@ -1,11 +1,11 @@ handleRequest($oRequest); return $this->render('formSDK/theme.html.twig', [ - 'name1' => 'Portal', + 'name1' => 'Portail', 'name2' => 'Console', 'form1' => $oForm1->createView(), 'form2' => $oForm2->createView(), diff --git a/sources/FormSDK/Dto/ObjectSearchDto.php b/sources/FormImplementation/Dto/ObjectSearchDto.php similarity index 86% rename from sources/FormSDK/Dto/ObjectSearchDto.php rename to sources/FormImplementation/Dto/ObjectSearchDto.php index 09bb200e8..16c256ff1 100644 --- a/sources/FormSDK/Dto/ObjectSearchDto.php +++ b/sources/FormImplementation/Dto/ObjectSearchDto.php @@ -1,6 +1,6 @@ CreateFactory(); - // add 2 person forms... + // add X person forms... for($i = 0 ; $i < 2 ; $i++){ // retrieve person @@ -61,6 +61,11 @@ class FormHelper 'required' => false ], new DateTime('1979/06/27')); + // ready + $oFormFactory->AddSwitchField('notify', [ + 'label' => 'Veuillez m\'avertir en cas de changement', + ], true); + // blog - date $oFormFactory->AddAreaField('blog', [ 'label' => 'Blog', @@ -81,7 +86,7 @@ class FormHelper ], [ 'url' => 'http://localhost' . $oRouter->generate('formSDK_ajax_select'), - 'ajax_query_parameter' => 'query', + 'query_parameter' => 'query', 'value_field' => 'breed', 'label_field' => 'breed', 'search_field' => 'breed', @@ -95,21 +100,33 @@ class FormHelper 'required' => false ], 'Person', 'SELECT Person', [], '', 20); + // requests - select with OQL + $oFormFactory->AddSelectOqlField('requests', [ + 'label' => 'Tickets', + 'required' => false + ], 'UserRequest', 'SELECT UserRequest', [], '', 20); + // mode - select with static data $oFormFactory->AddSelectField('mode', [ 'label' => 'Mon mode', 'choices' => SelectDataProvider::GetModes(), 'expanded' => true, - 'multiple' => false - ], ''); + 'multiple' => false, + 'label_attr' => [ + 'class' => 'radio-inline' + ] + ], '1'); // options - select with static data $oFormFactory->AddSelectField('option', [ 'label' => 'Mes options', 'choices' => SelectDataProvider::GetOptions(), 'expanded' => true, - 'multiple' => true - ], null); + 'multiple' => true, + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ], ['0', '2','4']); return $oFormFactory; } diff --git a/sources/FormSDK/Helper/SelectDataProvider.php b/sources/FormImplementation/Helper/SelectDataProvider.php similarity index 97% rename from sources/FormSDK/Helper/SelectDataProvider.php rename to sources/FormImplementation/Helper/SelectDataProvider.php index e0ecbb094..c4ff0a2fb 100644 --- a/sources/FormSDK/Helper/SelectDataProvider.php +++ b/sources/FormImplementation/Helper/SelectDataProvider.php @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License */ -namespace Combodo\iTop\FormSDK\Helper; +namespace Combodo\iTop\FormImplementation\Helper; use Dict; diff --git a/sources/FormSDK/Helper/TwigHelper.php b/sources/FormImplementation/Helper/TwigHelper.php similarity index 96% rename from sources/FormSDK/Helper/TwigHelper.php rename to sources/FormImplementation/Helper/TwigHelper.php index 594f99784..fa53bf0c3 100644 --- a/sources/FormSDK/Helper/TwigHelper.php +++ b/sources/FormImplementation/Helper/TwigHelper.php @@ -1,6 +1,6 @@ sPath; + return $this->sName; } } \ No newline at end of file diff --git a/sources/FormSDK/Field/Description/FormFieldTypeEnumeration.php b/sources/FormSDK/Field/FormFieldTypeEnumeration.php similarity index 86% rename from sources/FormSDK/Field/Description/FormFieldTypeEnumeration.php rename to sources/FormSDK/Field/FormFieldTypeEnumeration.php index c19b87c73..630f1df6e 100644 --- a/sources/FormSDK/Field/Description/FormFieldTypeEnumeration.php +++ b/sources/FormSDK/Field/FormFieldTypeEnumeration.php @@ -17,10 +17,10 @@ * You should have received a copy of the GNU Affero General Public License */ -namespace Combodo\iTop\FormSDK\Field\Description; +namespace Combodo\iTop\FormSDK\Field; /** - * Form types. + * Types of fields. * * @package FormSDK * @since 3.2.0 @@ -31,6 +31,7 @@ enum FormFieldTypeEnumeration : string case AREA = 'AREA'; case DATE = 'DATE'; case SELECT = 'SELECT'; + case SWITCH = 'SWITCH'; case DB_OBJECT = 'DB_OBJECT'; /** @@ -40,10 +41,10 @@ enum FormFieldTypeEnumeration : string */ public function GetAvailableOptions() : array { - $aOptions = ['label', 'required', 'disabled']; + $aOptions = ['required', 'disabled', 'attr', 'label', 'label_attr']; return match ($this->value) { - FormFieldTypeEnumeration::SELECT => array_merge($aOptions, ['']), + FormFieldTypeEnumeration::SELECT => array_merge($aOptions, ['placeholder']), default => $aOptions, }; } diff --git a/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php b/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php index 5977e6ab9..eea0dccc2 100644 --- a/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php +++ b/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php @@ -37,7 +37,7 @@ interface FormFactoryAdapterInterface /** * Return description the form. * - * @return \Combodo\iTop\FormSDK\Field\Description\FormFieldDescription[] + * @return \Combodo\iTop\FormSDK\Field\FormFieldDescription[] */ public function GetFormDescriptions() : array; diff --git a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php index 780ca70d6..cfb58bcfd 100644 --- a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php +++ b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php @@ -21,8 +21,8 @@ namespace Combodo\iTop\FormSDK\Service\FactoryAdapter; use AttributeDefinition; use AttributeString; -use Combodo\iTop\FormSDK\Field\Description\FormFieldDescription; -use Combodo\iTop\FormSDK\Field\Description\FormFieldTypeEnumeration; +use Combodo\iTop\FormSDK\Field\FormFieldDescription; +use Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration; use DBObject; use Exception; use ExceptionLog; @@ -89,8 +89,14 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface { $aOptions = []; + $sLabel = $oAttributeDefinition->GetLabel(); + if(!$this->bGroup){ + $sLabel = $this->GetLabel() . ' ••• ' . $sLabel; + } + if($oAttributeDefinition instanceof AttributeString) { $aOptions['required'] = !$oAttributeDefinition->IsNullAllowed(); + $aOptions['label'] = $sLabel; } return $aOptions; @@ -101,7 +107,7 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface * * @param string $sAttributeCode * - * @return \Combodo\iTop\FormSDK\Field\Description\FormFieldDescription|null + * @return \Combodo\iTop\FormSDK\Field\FormFieldDescription|null * @throws \Exception */ private function GetAttributeDescription(string $sAttributeCode) : ?FormFieldDescription @@ -110,7 +116,7 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface if($oAttributeDefinition instanceof AttributeString) { return new FormFieldDescription( - $this->GetAttributePath($sAttributeCode), + $this->GetAttributeName($sAttributeCode), FormFieldTypeEnumeration::TEXT, array_merge( $this->GetAttributeOptions($oAttributeDefinition), @@ -122,16 +128,15 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface } /** - * Return attribute path. + * Return attribute name. * * @param string $sAttributeCode * * @return string */ - private function GetAttributePath(string $sAttributeCode) : string + private function GetAttributeName(string $sAttributeCode) : string { return $this->bGroup ? $sAttributeCode : $this->GetIdentifier() . '-' . $sAttributeCode; -// return $this->GetIdentifier() . '-' . $sAttributeCode; } /** @inheritdoc */ @@ -140,10 +145,10 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface $aData = []; foreach ($this->aAttributes as $sAttributeCode => $oValue){ try { - $aData[$this->GetAttributePath($sAttributeCode)] = $this->GetAttributeData($sAttributeCode); + $aData[$this->GetAttributeName($sAttributeCode)] = $this->GetAttributeData($sAttributeCode); } catch (Exception $e) { - $aData[$this->GetAttributePath($sAttributeCode)] = null; + $aData[$this->GetAttributeName($sAttributeCode)] = null; ExceptionLog::LogException($e); } } @@ -163,9 +168,9 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface { $aDescriptions = []; - foreach ($this->aAttributes as $sKey => $oValue){ + foreach ($this->aAttributes as $sAttCode => $oValue){ try { - $aDescriptions[$this->GetIdentifier() .'_' .$sKey] = $this->GetAttributeDescription($sKey); + $aDescriptions[$this->GetAttributeName($sAttCode)] = $this->GetAttributeDescription($sAttCode); } catch (Exception $e) { ExceptionLog::LogException($e); @@ -174,15 +179,21 @@ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface if($this->bGroup){ $oGroupDescriptions = new FormFieldDescription($this->GetIdentifier(), FormFieldTypeEnumeration::DB_OBJECT, [ - 'descriptions' => $aDescriptions + 'descriptions' => $aDescriptions, + 'label' => $this->GetLabel() ]); - return [$oGroupDescriptions]; + return [$this->GetIdentifier() => $oGroupDescriptions]; } else{ return $aDescriptions; } } + public function GetLabel(): string + { + return get_class($this->oDBObject) . ' ' . $this->oDBObject->GetKey(); + } + /** @inheritdoc */ public function GetIdentifier(): string { diff --git a/sources/FormSDK/Service/FormFactory.php b/sources/FormSDK/Service/FormFactory.php index 658200174..4c8112e5f 100644 --- a/sources/FormSDK/Service/FormFactory.php +++ b/sources/FormSDK/Service/FormFactory.php @@ -20,11 +20,12 @@ namespace Combodo\iTop\FormSDK\Service; use Combodo\iTop\FormSDK\Helper\SelectDataProvider; +use Combodo\iTop\FormSDK\Service\FormFactoryBuilderTrait; use Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryObjectAdapter; use Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface; use Combodo\iTop\FormSDK\Symfony\SymfonyBridge; -use Combodo\iTop\FormSDK\Field\Description\FormFieldDescription; -use Combodo\iTop\FormSDK\Field\Description\FormFieldTypeEnumeration; +use Combodo\iTop\FormSDK\Field\FormFieldDescription; +use Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration; use DBObject; use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\FormInterface; @@ -52,6 +53,9 @@ class FormFactory /** @var array $aData form data */ private array $aData = []; + /** builder */ + use FormFactoryBuilderTrait; + /** * Constructor. * @@ -67,6 +71,8 @@ class FormFactory } /** + * Return descriptions and data arrays. + * * @return array{descriptions:array, data:array} */ public function GetFormDescriptionsAndData() : array @@ -129,188 +135,12 @@ class FormFactory * Get form. * * @param string|null $sName - * - * @return \Symfony\Component\Form\FormInterface + * @return mixed */ - public function GetForm(?string $sName): FormInterface + public function GetForm(?string $sName = null) : mixed { ['descriptions' => $aDescriptions, 'data' => $aData] = $this->GetFormDescriptionsAndData(); return $this->oSymfonyBridge->GetForm($aDescriptions, $aData, $sName); } - /** - * Add text field. - * - * @param string $sKey - * @param array $aOptions - * @param mixed $oData - * - * @return $this - */ - public function AddTextField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory - { - // test widget for regex constraint - if(array_key_exists('constraints', $aOptions)){ - $oConstraint = $aOptions['constraints']; - if($oConstraint instanceof Regex){ - $aWidgetOptions = [ - 'pattern' => $oConstraint->pattern, - ]; - $aOptions = array_merge([ - 'attr' => [ - 'data-widget' => 'TextWidget', - 'data-pattern' => $oConstraint->pattern, - 'data-widget-options' => json_encode($aWidgetOptions) - ] - ], $aOptions); - } - } - - $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::TEXT, $aOptions); - $this->aData[$sKey] = $oData; - - return $this; - } - - /** - * Add area field. - * - * @param string $sKey - * @param array $aOptions - * @param mixed $oData - * - * @return $this - */ - public function AddAreaField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory - { - $aOptions = array_merge([ - 'attr' => [ - 'data-widget' => 'AreaWidget', - 'data-widget-options' => json_encode([]) - ] - ], $aOptions); - - $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::AREA, $aOptions); - $this->aData[$sKey] = $oData; - - return $this; - } - - /** - * Add date field. - * - * @param string $sKey - * @param array $aOptions - * @param mixed $oData - * - * @return $this - */ - public function AddDateField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory - { - $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::DATE, $aOptions); - $this->aData[$sKey] = $oData; - - return $this; - } - - - /** - * Add select field. - * - * @param string $sKey - * @param array $aOptions - * @param mixed $oData - * - * @return $this - */ - public function AddSelectField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory - { - $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::SELECT, $aOptions); - $this->aData[$sKey] = $oData; - - return $this; - } - - /** - * Add dynamic ajax select field. - * - * @param string $sKey - * @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 - { - // merge ajax options - $aAjaxOptions = array_merge([ - 'url' => '', - 'query_parameter' => 'query', - 'value_field' => 'value', - 'label_field' => 'label', - 'search_field' => 'search', - 'preload' => false, - 'threshold' => -1, - 'configuration' => 'AJAX' - ], $aAjaxOptions); - - // merge options - $aOptions = array_merge([ - 'placeholder' => 'Select...', - 'attr' => [ - 'data-widget' => 'SelectWidget', - 'data-ajax-query-type' => $aAjaxOptions['configuration'], - 'data-widget-options' => json_encode($aAjaxOptions) - ], -// 'choice_loader' => new CallbackChoiceLoader(function() use ($aAjaxOptions, $aAjaxData): array { -// $curl_data = utils::DoPostRequest($aAjaxOptions['url'], []); -// $response_data = json_decode($curl_data); -// if(count($response_data->items) > $aAjaxOptions['threshold']) return []; -// $result = []; -// foreach ($response_data->items as $e) { -// $result[$e->breed] = $e->breed; -// } -// return $result; -// }), - ], $aOptions); - - return $this->AddSelectField($sKey, $aOptions, $oData); - } - - - /** - * Add dynamic OQL select field. - * - * @param string $sKey - * @param array $aOptions - * @param string $sObjectClass - * @param string $sOql - * @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 - { - $aAjaxData = [ - 'class' => $sObjectClass, - 'oql' => $sOql, - 'fields' => '{'.implode($aFieldsToLoad).'}', - ]; - $sUrl = 'http://localhost' . $this->oRouter->generate('formSDK_object_search') . '?' . http_build_query($aAjaxData); - $aAjaxOptions = [ - 'url' => $sUrl, - 'query_parameter' => 'search', - 'value_field' => 'key', - 'label_field' => 'friendlyname', - 'search_field' => 'friendlyname', - 'threshold' => $iAjaxThershold, - 'configuration' => 'OQL' - ]; - return $this->AddSelectAjaxField($sKey, $aOptions, $aAjaxOptions, $aAjaxData, $oData); - } } \ No newline at end of file diff --git a/sources/FormSDK/Service/FormFactoryBuilderTrait.php b/sources/FormSDK/Service/FormFactoryBuilderTrait.php new file mode 100644 index 000000000..5c66cf482 --- /dev/null +++ b/sources/FormSDK/Service/FormFactoryBuilderTrait.php @@ -0,0 +1,210 @@ + $oConstraint->pattern, + ]; + $aOptions = array_merge([ + 'attr' => [ + 'data-widget' => 'TextWidget', + 'data-pattern' => $oConstraint->pattern, + 'data-widget-options' => json_encode($aWidgetOptions) + ] + ], $aOptions); + } + } + + $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::TEXT, $aOptions); + $this->aData[$sKey] = $oData; + + return $this; + } + + /** + * Add area field. + * + * @param string $sKey + * @param array $aOptions + * @param mixed $oData + * + * @return $this + */ + public function AddAreaField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + { + $aOptions = array_merge([ + 'attr' => [ + 'data-widget' => 'AreaWidget', + 'data-widget-options' => json_encode([]) + ] + ], $aOptions); + + $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::AREA, $aOptions); + $this->aData[$sKey] = $oData; + + return $this; + } + + /** + * Add date field. + * + * @param string $sKey + * @param array $aOptions + * @param mixed $oData + * + * @return $this + */ + public function AddDateField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + { + $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::DATE, $aOptions); + $this->aData[$sKey] = $oData; + + return $this; + } + + + /** + * Add select field. + * + * @param string $sKey + * @param array $aOptions + * @param mixed $oData + * + * @return $this + */ + public function AddSelectField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + { + $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::SELECT, $aOptions); + $this->aData[$sKey] = $oData; + + return $this; + } + + /** + * Add dynamic ajax select field. + * + * @param string $sKey + * @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 + { + // merge ajax options + $aAjaxOptions = array_merge([ + 'url' => '', + 'query_parameter' => 'query', + 'value_field' => 'value', + 'label_field' => 'label', + 'search_field' => 'search', + 'preload' => false, + 'threshold' => -1, + 'configuration' => 'AJAX' + ], $aAjaxOptions); + + // merge options + $aOptions = array_merge([ + 'placeholder' => 'Select...', + 'attr' => [ + 'data-widget' => 'SelectWidget', + 'data-ajax-query-type' => $aAjaxOptions['configuration'], + 'data-widget-options' => json_encode($aAjaxOptions) + ], + // 'choice_loader' => new CallbackChoiceLoader(function() use ($aAjaxOptions, $aAjaxData): array { + // $curl_data = utils::DoPostRequest($aAjaxOptions['url'], []); + // $response_data = json_decode($curl_data); + // if(count($response_data->items) > $aAjaxOptions['threshold']) return []; + // $result = []; + // foreach ($response_data->items as $e) { + // $result[$e->breed] = $e->breed; + // } + // return $result; + // }), + ], $aOptions); + + return $this->AddSelectField($sKey, $aOptions, $oData); + } + + + /** + * Add dynamic OQL select field. + * + * @param string $sKey + * @param array $aOptions + * @param string $sObjectClass + * @param string $sOql + * @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 + { + $aAjaxData = [ + 'class' => $sObjectClass, + 'oql' => $sOql, + 'fields' => '{'.implode($aFieldsToLoad).'}', + ]; + $sUrl = 'http://localhost' . $this->oRouter->generate('formSDK_object_search') . '?' . http_build_query($aAjaxData); + $aAjaxOptions = [ + 'url' => $sUrl, + 'query_parameter' => 'search', + 'value_field' => 'key', + 'label_field' => 'friendlyname', + 'search_field' => 'friendlyname', + 'threshold' => $iAjaxThershold, + 'configuration' => 'OQL' + ]; + return $this->AddSelectAjaxField($sKey, $aOptions, $aAjaxOptions, $aAjaxData, $oData); + } + + /** + * Add switch field. + * + * @param string $sKey + * @param array $aOptions + * @param mixed $oData + * + * @return $this + */ + public function AddSwitchField(string $sKey, array $aOptions, mixed $oData = null) : FormFactory + { + $aOptions = array_merge([ + 'label_attr' => ['class' => 'checkbox-switch'], + ], $aOptions); + + $this->aDescriptions[$sKey] = new FormFieldDescription($sKey, FormFieldTypeEnumeration::SWITCH, $aOptions); + $this->aData[$sKey] = $oData; + + return $this; + } +} \ No newline at end of file diff --git a/sources/FormSDK/Service/FormManager.php b/sources/FormSDK/Service/FormManager.php index 190df5870..fd414547a 100644 --- a/sources/FormSDK/Service/FormManager.php +++ b/sources/FormSDK/Service/FormManager.php @@ -30,7 +30,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; * @package FormSDK * @since 3.2.0 */ -class FormManager +final class FormManager { /** diff --git a/sources/FormSDK/Symfony/SymfonyBridge.php b/sources/FormSDK/Symfony/SymfonyBridge.php index ffc5831dd..221d2f868 100644 --- a/sources/FormSDK/Symfony/SymfonyBridge.php +++ b/sources/FormSDK/Symfony/SymfonyBridge.php @@ -20,9 +20,10 @@ namespace Combodo\iTop\FormSDK\Symfony; use Combodo\iTop\FormSDK\Symfony\Type\Compound\FormObjectType; -use Combodo\iTop\FormSDK\Field\Description\FormFieldDescription; -use Combodo\iTop\FormSDK\Field\Description\FormFieldTypeEnumeration; +use Combodo\iTop\FormSDK\Field\FormFieldDescription; +use Combodo\iTop\FormSDK\Field\FormFieldTypeEnumeration; 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\DateType; use Symfony\Component\Form\Extension\Core\Type\FormType; @@ -54,7 +55,7 @@ class SymfonyBridge /** * Transform description to Symfony description. * - * @param \Combodo\iTop\FormSDK\Field\Description\FormFieldDescription $oFormDescription + * @param \Combodo\iTop\FormSDK\Field\FormFieldDescription $oFormDescription * * @return array|null */ @@ -64,32 +65,39 @@ class SymfonyBridge case FormFieldTypeEnumeration::TEXT: return [ - 'path' => $oFormDescription->GetPath(), + 'name' => $oFormDescription->GetName(), 'type' => TextType::class, 'options' => $oFormDescription->GetOptions() ]; case FormFieldTypeEnumeration::AREA: return [ - 'path' => $oFormDescription->GetPath(), + 'name' => $oFormDescription->GetName(), 'type' => TextareaType::class, 'options' => $oFormDescription->GetOptions() ]; case FormFieldTypeEnumeration::DATE: return [ - 'path' => $oFormDescription->GetPath(), + 'name' => $oFormDescription->GetName(), 'type' => DateType::class, 'options' => $oFormDescription->GetOptions() ]; case FormFieldTypeEnumeration::SELECT: return [ - 'path' => $oFormDescription->GetPath(), + 'name' => $oFormDescription->GetName(), 'type' => ChoiceType::class, 'options' => $oFormDescription->GetOptions() ]; + case FormFieldTypeEnumeration::SWITCH: + return [ + 'name' => $oFormDescription->GetName(), + 'type' => CheckboxType::class, + 'options' => $oFormDescription->GetOptions() + ]; + case FormFieldTypeEnumeration::DB_OBJECT: $aOptions = $oFormDescription->GetOptions(); $aItems = []; @@ -99,7 +107,7 @@ class SymfonyBridge } $aOptions['descriptions'] = $aItems; return [ - 'path' => $oFormDescription->GetPath(), + 'name' => $oFormDescription->GetName(), 'type' => FormObjectType::class, 'options' => $aOptions ]; @@ -131,10 +139,12 @@ class SymfonyBridge // iterate throw descriptions... foreach ($aDescriptions as $oFormDescription){ + // symfony form type description $aSymfony = $this->ToSymfonyFormType($oFormDescription); + // add type to form $oFormBuilder->add( - $aSymfony['path'], + $aSymfony['name'], $aSymfony['type'], $aSymfony['options'] ); @@ -147,7 +157,7 @@ class SymfonyBridge * @see https://itecnote.com/tecnote/php-disable-backend-validation-for-choice-field-in-symfony-2-type/ */ if($aSymfony['type'] === ChoiceType::class){ - $oFormBuilder->get($aSymfony['path'])->resetViewTransformers(); + $oFormBuilder->get($aSymfony['name'])->resetViewTransformers(); } } diff --git a/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php b/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php index 35cfca288..4013121f0 100644 --- a/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php +++ b/sources/FormSDK/Symfony/Type/Compound/FormObjectType.php @@ -19,7 +19,7 @@ namespace Combodo\iTop\FormSDK\Symfony\Type\Compound; -use Combodo\iTop\FormSDK\Field\Description\FormFieldDescription; +use Combodo\iTop\FormSDK\Field\FormFieldDescription; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormBuilderInterface; @@ -39,7 +39,7 @@ class FormObjectType extends AbstractType { /** @var FormFieldDescription $oDescription */ foreach ($options['descriptions'] as $oDescription){ - $builder->add($oDescription['path'], $oDescription['type'], $oDescription['options']); + $builder->add($oDescription['name'], $oDescription['type'], $oDescription['options']); } } diff --git a/symfony/config/routes.yaml b/symfony/config/routes.yaml index d93ae3a39..700b8ece6 100644 --- a/symfony/config/routes.yaml +++ b/symfony/config/routes.yaml @@ -1,5 +1,5 @@ controllers: resource: - path: ../../sources/FormSDK/Controller/ - namespace: Combodo\iTop\FormSDK\Controller + path: ../../sources/FormImplementation/Controller/ + namespace: Combodo\iTop\FormImplementation\Controller type: attribute diff --git a/symfony/config/services.yaml b/symfony/config/services.yaml index 65f23cfb5..db6435366 100644 --- a/symfony/config/services.yaml +++ b/symfony/config/services.yaml @@ -17,7 +17,7 @@ services: resource: '../../sources' exclude: - '../../sources/alias.php' - - '../../sources/FormSDK/Symfony/Type' + - '../../sources/FormImplementation/Symfony/Type' - '../../sources/Application/WebPage' # add more service definitions when explicit configuration is needed diff --git a/templates/formSDK/form.html.twig b/templates/formSDK/form.html.twig index d2a6af77c..a2fd3fa7e 100644 --- a/templates/formSDK/form.html.twig +++ b/templates/formSDK/form.html.twig @@ -3,7 +3,9 @@ {% block body %} -
+
+ +

Form SDK : Components

{# specific form theme #} {% if theme is defined %} diff --git a/templates/formSDK/theme.html.twig b/templates/formSDK/theme.html.twig index 04d67f81d..3420e2c8a 100644 --- a/templates/formSDK/theme.html.twig +++ b/templates/formSDK/theme.html.twig @@ -1,9 +1,35 @@ {% extends 'base.html.twig' %} +{% block stylesheets %} + + + +{% endblock %} + {% block body %} -
+
{# specific form theme #} {% if theme1 is defined %} diff --git a/templates/formSDK/themes/portal.html.twig b/templates/formSDK/themes/portal.html.twig index 4db83756f..62c74ce33 100644 --- a/templates/formSDK/themes/portal.html.twig +++ b/templates/formSDK/themes/portal.html.twig @@ -32,7 +32,7 @@ {%- endblock form_label -%} {%- block form_object_row -%} - {%- set row_attr = row_attr|merge({class: 'mb-3 form-object'}) -%} + {%- set row_attr = row_attr|merge({class: 'mb-3 form-object-row'}) -%} {{ form_row(form, {'row_attr': row_attr}) }} {%- endblock form_object_row -%}