diff --git a/css/form-sdk/form.css b/css/form-sdk/form.css index 08151b6e4..d47a12c02 100644 --- a/css/form-sdk/form.css +++ b/css/form-sdk/form.css @@ -14,6 +14,7 @@ cursor: pointer; padding: 0px 5px; border-radius: 8px; + font-size: 0.9rem; } .form-type-pictograms i{ width: 15px; @@ -31,6 +32,13 @@ padding: 2px; } +/* form label */ +.form-label.required:after{ + content: '*'; + color: #e63535; + margin-left: 3px; +} + /* form object row */ .form-object-row{ border: 1px lightgrey dashed; diff --git a/js/form-sdk/widget-factory.js b/js/form-sdk/widget-factory.js index 0d09fe355..5851da666 100644 --- a/js/form-sdk/widget-factory.js +++ b/js/form-sdk/widget-factory.js @@ -21,13 +21,13 @@ const iTopFormWidgetFactory = new function(){ AREA: {name: 'AreaWidget', builder: CreateAreaWidget} } - // instanciate widgets... + // instantiate widgets... for (const widgetsKey in WIDGETS) { // widget configuration const aWidgetConfiguration = WIDGETS[widgetsKey]; - // instanciate widget + // instantiate widget $(`[data-widget="${aWidgetConfiguration.name}"]`).each(function (e) { const oElement = $(this); if (!oElement.data('widget-state-initialized')) { @@ -119,6 +119,7 @@ const iTopFormWidgetFactory = new function(){ maxItems: aOptions['max_items'], preload: aOptions['preload'], plugins: aPlugins, + loadThrottle: 200, load: function(query, callback) { let sUrl = aOptions['url']; if(!sUrl.includes('?')){ diff --git a/sources/FormImplementation/Controller/TestController.php b/sources/FormImplementation/Controller/TestController.php index c7a689056..cc46f1023 100644 --- a/sources/FormImplementation/Controller/TestController.php +++ b/sources/FormImplementation/Controller/TestController.php @@ -18,16 +18,15 @@ use Symfony\Component\Routing\RouterInterface; class TestController extends AbstractAppController { + /** + * @throws \ArchivedObjectException + * @throws \CoreException + */ #[Route('/formSDK/test_form/{mode}', name: 'formSDK_test_form')] public function form(Request $oRequest, FormManager $oFormManager, RouterInterface $oRouter, int $mode): Response { // create factory - try{ - $oFactory = FormHelper::CreateSampleFormFactory($oFormManager, $oRouter, $mode); - } - catch (Exception $e) { - throw $this->createNotFoundException('unable to create sample form factory', $e); - } + $oFactory = FormHelper::CreateSampleFormFactory($oFormManager, $oRouter, $mode); // get the form $oForm = $oFactory->CreateForm(); @@ -46,9 +45,7 @@ class TestController extends AbstractAppController $oAdapter->UpdateFieldsData($data); } -// dump($data); - -// return $this->redirectToRoute('app_success'); + return $this->redirectToRoute('app_success'); } // render view @@ -59,16 +56,15 @@ class TestController extends AbstractAppController } - #[Route('/formSDK/test_theme', name: 'formSDK_test_theme')] - public function theme(Request $oRequest, FormManager $oFormManager, RouterInterface $oRouter): Response + /** + * @throws \ArchivedObjectException + * @throws \CoreException + */ + #[Route('/formSDK/test_theme/{mode}', name: 'formSDK_test_theme')] + public function theme(Request $oRequest, FormManager $oFormManager, RouterInterface $oRouter, int $mode): Response { // create factory - try{ - $oFactory = FormHelper::CreateSampleFormFactory($oFormManager, $oRouter); - } - catch (Exception $e) { - throw $this->createNotFoundException('unable to create sample form factory'); - } + $oFactory = FormHelper::CreateSampleFormFactory($oFormManager, $oRouter, $mode); // get the forms (named instances) $oForm1 = $oFactory->CreateForm('form1'); diff --git a/sources/FormSDK/Field/FormFieldDescription.php b/sources/FormSDK/Field/FormFieldDescription.php index 131d53b6f..36c71ecc9 100644 --- a/sources/FormSDK/Field/FormFieldDescription.php +++ b/sources/FormSDK/Field/FormFieldDescription.php @@ -25,7 +25,7 @@ use Exception; * Description of a form field. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class FormFieldDescription { @@ -37,7 +37,7 @@ class FormFieldDescription * @param FormFieldTypeEnumeration $oType * @param array $aOptions * - * @throws \Exception + * @throws \Exception throw an exception when invalid options are provided */ public function __construct( private readonly string $sName, @@ -45,8 +45,8 @@ class FormFieldDescription private readonly array $aOptions ) { + // check options $oCheckStatus = $this->oType->CheckOptions($this->aOptions); - if(!$oCheckStatus['valid']){ $sInvalidOptions = implode(', ', $oCheckStatus['invalid_options']); throw new Exception("Invalid option(s) $sInvalidOptions provided for field $sName"); diff --git a/sources/FormSDK/Field/FormFieldTypeEnumeration.php b/sources/FormSDK/Field/FormFieldTypeEnumeration.php index a009bbe5d..bd8b400fc 100644 --- a/sources/FormSDK/Field/FormFieldTypeEnumeration.php +++ b/sources/FormSDK/Field/FormFieldTypeEnumeration.php @@ -23,16 +23,16 @@ namespace Combodo\iTop\FormSDK\Field; * Types of fields. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ enum FormFieldTypeEnumeration { case TEXT; - case NUMBER; case AREA; + case SWITCH; + case NUMBER; case DATE; case SELECT; - case SWITCH; case DURATION; case FIELDSET; case COLLECTION; @@ -45,7 +45,7 @@ enum FormFieldTypeEnumeration public function GetAvailableOptions() : array { // global options - $aOptions = ['required', 'disabled', 'attr', 'label', 'label_attr', 'help', 'inherit_data']; + $aOptions = ['required', 'disabled', 'attr', 'label', 'label_attr', 'help']; // specific options return match ($this) { diff --git a/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php b/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php index 27b63e8fe..f1d051617 100644 --- a/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php +++ b/sources/FormSDK/Service/FactoryAdapter/FormFactoryAdapterInterface.php @@ -23,10 +23,11 @@ namespace Combodo\iTop\FormSDK\Service\FactoryAdapter; * Form factory adapter interface. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ interface FormFactoryAdapterInterface { + /** * Return adapter identifier. * @@ -57,5 +58,4 @@ interface FormFactoryAdapterInterface */ public function UpdateFieldsData(array $aFormData) : bool; - } \ No newline at end of file diff --git a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php index 75fc684b7..db5c1c4b7 100644 --- a/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php +++ b/sources/FormSDK/Service/FactoryAdapter/FormFactoryObjectAdapter.php @@ -32,7 +32,7 @@ use MetaModel; * Form manipulation for DBObject. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ final class FormFactoryObjectAdapter implements FormFactoryAdapterInterface { diff --git a/sources/FormSDK/Service/FormFactory.php b/sources/FormSDK/Service/FormFactory.php index 9c334554e..86fd4d3aa 100644 --- a/sources/FormSDK/Service/FormFactory.php +++ b/sources/FormSDK/Service/FormFactory.php @@ -31,13 +31,10 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; * Build and manipulate forms. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ -class FormFactory +final class FormFactory { - /** @var \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface[] $aAdapters */ - private array $aAdapters = []; - /** @var array $aFieldsDescriptions form types descriptions */ private array $aFieldsDescriptions = []; @@ -47,7 +44,10 @@ class FormFactory /** @var array $aLayoutDescription description of the layout */ private array $aLayoutDescription = []; - /** builder */ + /** @var \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface[] $aAdapters list of adapters */ + private array $aAdapters = []; + + /** description builder */ use FormFactoryBuilderTrait; /** @@ -76,79 +76,12 @@ class FormFactory // merge each adapter data... foreach ($this->GetAllAdapters() as $oAdapter){ - try{ - $aResult = array_merge($aResult, $oAdapter->GetFieldsDescriptions()); - } - catch(Exception $e){ - ExceptionLog::LogException($e); - } + $aResult = array_merge($aResult, $oAdapter->GetFieldsDescriptions()); } return $aResult; } - /** - * Return layout description. - * - * @return array - */ - public function GetLayoutDescription() : array - { - return $this->aLayoutDescription; - } - - /** - * Create an object adapter. - * - * @param \DBObject $oDBObject - * @param bool $bGroup - * - * @return \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryObjectAdapter - */ - public function CreateObjectAdapter(DBObject $oDBObject, bool $bGroup = true) : FormFactoryObjectAdapter - { - $oObjectBuilder = new FormFactoryObjectAdapter($oDBObject, $bGroup); - $this->AddAdapter(get_class($oDBObject) . '_' . $oDBObject->GetKey(), $oObjectBuilder); - return $oObjectBuilder; - } - - /** - * Add an adapter. - * - * @param string $sKey - * @param \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface $oAdapter - * - * @return $this - */ - public function AddAdapter(string $sKey, FormFactoryAdapterInterface $oAdapter) : FormFactory - { - $this->aAdapters[$sKey] = $oAdapter; - return $this; - } - - /** - * Get all adapters. - * - * @return \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface[] - */ - public function GetAllAdapters() : array - { - return $this->aAdapters; - } - - /** - * Set layout description. - * - * @param array $aLayoutDescription - * - * @return $this - */ - public function SetLayoutDescription(array $aLayoutDescription) : FormFactory - { - $this->aLayoutDescription = $aLayoutDescription; - return $this; - } - /** * Set form data. * @@ -177,6 +110,68 @@ class FormFactory return $aData; } + /** + * Set layout description. + * + * @param array $aLayoutDescription + * + * @return $this + */ + public function SetLayoutDescription(array $aLayoutDescription) : FormFactory + { + $this->aLayoutDescription = $aLayoutDescription; + return $this; + } + + /** + * Return layout description. + * + * @return array + */ + public function GetLayoutDescription() : array + { + return $this->aLayoutDescription; + } + + /** + * Add an adapter. + * + * @param string $sKey + * @param \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface $oAdapter + * + * @return $this + */ + public function AddAdapter(string $sKey, FormFactoryAdapterInterface $oAdapter) : FormFactory + { + $this->aAdapters[$sKey] = $oAdapter; + return $this; + } + + /** + * Get all adapters. + * + * @return \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryAdapterInterface[] + */ + public function GetAllAdapters() : array + { + return $this->aAdapters; + } + + /** + * Create an object adapter. + * + * @param \DBObject $oDBObject + * @param bool $bGroup + * + * @return \Combodo\iTop\FormSDK\Service\FactoryAdapter\FormFactoryObjectAdapter + */ + public function CreateObjectAdapter(DBObject $oDBObject, bool $bGroup = true) : FormFactoryObjectAdapter + { + $oObjectBuilder = new FormFactoryObjectAdapter($oDBObject, $bGroup); + $this->AddAdapter(get_class($oDBObject) . '_' . $oDBObject->GetKey(), $oObjectBuilder); + return $oObjectBuilder; + } + /** * Create form. * diff --git a/sources/FormSDK/Service/FormFactoryBuilderTrait.php b/sources/FormSDK/Service/FormFactoryBuilderTrait.php index 63f4f3626..241ca5b44 100644 --- a/sources/FormSDK/Service/FormFactoryBuilderTrait.php +++ b/sources/FormSDK/Service/FormFactoryBuilderTrait.php @@ -1,4 +1,21 @@ $sObjectClass, 'oql' => $sOql, - 'fields' => '{'.implode($aFieldsToLoad).'}', + 'fields' => '{'.implode($aAttributesToLoad).'}', ]; $sUrl = 'http://localhost' . $this->oRouter->generate('formSDK_object_search') . '?' . http_build_query($aAjaxData); $aAjaxOptions = [ @@ -204,7 +229,7 @@ trait FormFactoryBuilderTrait 'value_field' => 'key', 'label_field' => 'friendlyname', 'search_field' => 'friendlyname', - 'threshold' => $iAjaxThershold, + 'threshold' => $iAjaxThreshold, 'configuration' => 'OQL' ]; return $this->AddSelectAjaxField($sKey, $aOptions, $aAjaxOptions, $aAjaxData); diff --git a/sources/FormSDK/Service/FormManager.php b/sources/FormSDK/Service/FormManager.php index fd414547a..cdd4b15f1 100644 --- a/sources/FormSDK/Service/FormManager.php +++ b/sources/FormSDK/Service/FormManager.php @@ -28,7 +28,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; * This service allow you to manage forms. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ final class FormManager { diff --git a/sources/FormSDK/Symfony/SymfonyBridge.php b/sources/FormSDK/Symfony/SymfonyBridge.php index 3d822c8bd..f93e3efcd 100644 --- a/sources/FormSDK/Symfony/SymfonyBridge.php +++ b/sources/FormSDK/Symfony/SymfonyBridge.php @@ -34,6 +34,7 @@ use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; @@ -41,7 +42,7 @@ use Symfony\Component\Form\FormInterface; * Symfony implementation bridge. * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class SymfonyBridge { @@ -139,6 +140,13 @@ class SymfonyBridge } } + /** + * Transform fieldset options. + * + * @param array $aOptions + * + * @return void + */ private function TransformFieldsetOptions(array &$aOptions){ $aFields = []; @@ -149,6 +157,13 @@ class SymfonyBridge $aOptions['fields'] = $aFields; } + /** + * Transform collection options. + * + * @param array $aOptions + * + * @return void + */ private function TransformCollectionOptions(array &$aOptions){ $aOptions['entry_type'] = FieldsetType::class; @@ -166,7 +181,7 @@ class SymfonyBridge * @param array $aDescriptions * @param mixed $oData * @param string|null $sName - * @param array|null $aLayout + * @param array $aLayout * * @return \Symfony\Component\Form\FormInterface */ @@ -226,17 +241,22 @@ class SymfonyBridge } /** - * @param $aLayout - * @param $oFormBuilder - * @param array $aDescriptions + * Parse layout description and create layout container types to group fields. + * Note: fields grouped in layout types are removed from descriptions array. * - * @return array + * @param array $aLayout layout description + * @param \Symfony\Component\Form\FormBuilderInterface $oFormBuilder Symfony form builder + * @param array $aDescriptions array of descriptions + * + * @return array created layout types */ - private function CreateLayoutTypes($aLayout, $oFormBuilder, array &$aDescriptions){ - + private function CreateLayoutTypes(array $aLayout, FormBuilderInterface $oFormBuilder, array &$aDescriptions) : array + { + // variables $aResult = []; $sClasses = ''; + // scan layout... foreach ($aLayout as $sKey => $oLayoutElement) { if($sKey === 'css_classes'){ @@ -265,13 +285,24 @@ class SymfonyBridge ]; } - private function CreateLayoutContainerType($oLayoutElement, $oFormBuilder, $sKey, $oType, &$aDescriptions) + /** + * Create a layout container type. + * + * @param array $aLayout layout description + * @param \Symfony\Component\Form\FormBuilderInterface $oFormBuilder Symfony form builder + * @param string $sKey type declaration key + * @param string $sTypeClassName type class name + * @param array $aDescriptions child fields + * + * @return array created layout type + */ + private function CreateLayoutContainerType(array $aLayout, FormBuilderInterface $oFormBuilder, string $sKey, string $sTypeClassName, array &$aDescriptions) : array { - ['types' => $aItems, 'css_classes' => $sCssClasses] = $this->CreateLayoutTypes($oLayoutElement, $oFormBuilder, $aDescriptions); + ['types' => $aItems, 'css_classes' => $sCssClasses] = $this->CreateLayoutTypes($aLayout, $oFormBuilder, $aDescriptions); return [ 'name' => $sKey, - 'type' => $oType, + 'type' => $sTypeClassName, 'options' => [ 'fields' => $aItems, 'attr' => [ @@ -282,5 +313,4 @@ class SymfonyBridge ]; } - } \ No newline at end of file diff --git a/sources/FormSDK/Symfony/Type/Compound/CollectionType.php b/sources/FormSDK/Symfony/Type/Compound/CollectionType.php index 3552de9bb..229bbb80c 100644 --- a/sources/FormSDK/Symfony/Type/Compound/CollectionType.php +++ b/sources/FormSDK/Symfony/Type/Compound/CollectionType.php @@ -32,7 +32,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; * Type representing a collection; * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class CollectionType extends AbstractType { diff --git a/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php b/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php index dad8c57ac..1a4070e3e 100644 --- a/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php +++ b/sources/FormSDK/Symfony/Type/Compound/FieldsetType.php @@ -29,7 +29,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; * Type representing a fieldset; * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class FieldsetType extends AbstractType { diff --git a/sources/FormSDK/Symfony/Type/Layout/ColumnType.php b/sources/FormSDK/Symfony/Type/Layout/ColumnType.php index 61e055625..0d8f12398 100644 --- a/sources/FormSDK/Symfony/Type/Layout/ColumnType.php +++ b/sources/FormSDK/Symfony/Type/Layout/ColumnType.php @@ -25,7 +25,7 @@ use Symfony\Component\Form\AbstractType; * Type representing a layout column; * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class ColumnType extends AbstractType { diff --git a/sources/FormSDK/Symfony/Type/Layout/LayoutType.php b/sources/FormSDK/Symfony/Type/Layout/LayoutType.php index 3f9761e98..f2f9ea800 100644 --- a/sources/FormSDK/Symfony/Type/Layout/LayoutType.php +++ b/sources/FormSDK/Symfony/Type/Layout/LayoutType.php @@ -29,7 +29,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; * Type representing an abstract layout type; * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class LayoutType extends AbstractType { diff --git a/sources/FormSDK/Symfony/Type/Layout/RowType.php b/sources/FormSDK/Symfony/Type/Layout/RowType.php index 219b2582b..e73c2f176 100644 --- a/sources/FormSDK/Symfony/Type/Layout/RowType.php +++ b/sources/FormSDK/Symfony/Type/Layout/RowType.php @@ -25,7 +25,7 @@ use Symfony\Component\Form\AbstractType; * Type representing a layout row; * * @package FormSDK - * @since 3.2.0 + * @since 3.X.0 */ class RowType extends AbstractType { diff --git a/templates/formSDK/theme.html.twig b/templates/formSDK/theme.html.twig index 3420e2c8a..e6c4f2c65 100644 --- a/templates/formSDK/theme.html.twig +++ b/templates/formSDK/theme.html.twig @@ -39,7 +39,7 @@ {% form_theme form2 theme2 %} {% endif %} -