From fcec026dff8fa7ee6c54aceda184c9721b7c0f78 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 26 Aug 2018 12:29:37 -0600 Subject: [PATCH 1/3] Add support for checking if nested form fields are required for visual indicator --- modules/backend/widgets/Form.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index 4c0fffd32..01e96f23f 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -837,6 +837,24 @@ class Form extends WidgetBase */ if ($field->required === null && $this->model && method_exists($this->model, 'isAttributeRequired')) { $fieldName = implode('.', HtmlHelper::nameToArray($field->fieldName)); + + // Check nested fields + if ($this->isNested) { + // Get the current attribute level + $nameArray = HtmlHelper::nameToArray($this->arrayName); + unset($nameArray[0]); + + // Convert any numeric indexes to wildcards + foreach ($nameArray as $i => $value) { + if (preg_match('/^[0-9]*$/', $value)) { + $nameArray[$i] = '*'; + } + } + + // Recombine names for full attribute name in rules array + $fieldName = implode('.', $nameArray) . ".{$fieldName}"; + } + $field->required = $this->model->isAttributeRequired($fieldName); } From 52d1388e4e7d7165695af889f8dcc861086ad012 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 26 Aug 2018 13:39:49 -0600 Subject: [PATCH 2/3] Automatically use field labels as custom attribute names for a nicer validation message Fixes #2489 --- modules/backend/behaviors/FormController.php | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php index 60f27aa09..71e9567f6 100644 --- a/modules/backend/behaviors/FormController.php +++ b/modules/backend/behaviors/FormController.php @@ -9,6 +9,7 @@ use Input; use Redirect; use Backend; use Backend\Classes\ControllerBehavior; +use October\Rain\Html\Helper as HtmlHelper; use October\Rain\Router\Helper as RouterHelper; use ApplicationException; use Exception; @@ -232,6 +233,7 @@ class FormController extends ControllerBehavior $this->initForm($model); + $this->controller->formSetValidationNames($model); $this->controller->formBeforeSave($model); $this->controller->formBeforeCreate($model); @@ -299,6 +301,7 @@ class FormController extends ControllerBehavior $model = $this->controller->formFindModelObject($recordId); $this->initForm($model); + $this->controller->formSetValidationNames($model); $this->controller->formBeforeSave($model); $this->controller->formBeforeUpdate($model); @@ -678,6 +681,28 @@ class FormController extends ControllerBehavior // Overrides // + /** + * Called before the creation or updating form is saved to override the field names for validation using their labels + */ + public function formSetValidationNames($model) + { + $attributeNames = []; + $form = $this->formGetWidget(); + foreach ($form->getFields() as $field) { + $fieldName = implode('.', HtmlHelper::nameToArray($field->fieldName)); + $attributeNames[$fieldName] = $field->label; + } + if (!property_exists($model, 'attributeNames')) { + $model->addDynamicProperty('attributeNames', $attributeNames); + // Clean up after validation to prevent attributeNames from being handled as a model attribute to be saved in the DB + $model->bindEvent('model.afterValidate', function () use ($model) { + unset($model->attributes['attributeNames']); + }); + } else { + $model->attributeNames = array_merge($attributeNames, (array) $model->attributeNames); + } + } + /** * Called before the creation or updating form is saved. * @param Model From 2d77565e6cbdc26e91a2c1459bf90da79e70c23a Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Wed, 29 Aug 2018 12:19:33 +1000 Subject: [PATCH 3/3] Peer review 52d1388e4e7d7165695af889f8dcc861086ad012 This uses a simpler approach and leverages improvements to the validation trait See https://github.com/octobercms/library/commit/574031d3eea051dce2bcf7079285262ad4f7ac44 Refs #2489 --- modules/backend/behaviors/FormController.php | 24 -------------------- modules/backend/widgets/Form.php | 21 ++++++++++------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php index 71e9567f6..86c47b42c 100644 --- a/modules/backend/behaviors/FormController.php +++ b/modules/backend/behaviors/FormController.php @@ -233,7 +233,6 @@ class FormController extends ControllerBehavior $this->initForm($model); - $this->controller->formSetValidationNames($model); $this->controller->formBeforeSave($model); $this->controller->formBeforeCreate($model); @@ -301,7 +300,6 @@ class FormController extends ControllerBehavior $model = $this->controller->formFindModelObject($recordId); $this->initForm($model); - $this->controller->formSetValidationNames($model); $this->controller->formBeforeSave($model); $this->controller->formBeforeUpdate($model); @@ -681,28 +679,6 @@ class FormController extends ControllerBehavior // Overrides // - /** - * Called before the creation or updating form is saved to override the field names for validation using their labels - */ - public function formSetValidationNames($model) - { - $attributeNames = []; - $form = $this->formGetWidget(); - foreach ($form->getFields() as $field) { - $fieldName = implode('.', HtmlHelper::nameToArray($field->fieldName)); - $attributeNames[$fieldName] = $field->label; - } - if (!property_exists($model, 'attributeNames')) { - $model->addDynamicProperty('attributeNames', $attributeNames); - // Clean up after validation to prevent attributeNames from being handled as a model attribute to be saved in the DB - $model->bindEvent('model.afterValidate', function () use ($model) { - unset($model->attributes['attributeNames']); - }); - } else { - $model->attributeNames = array_merge($attributeNames, (array) $model->attributeNames); - } - } - /** * Called before the creation or updating form is saved. * @param Model diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index 01e96f23f..68a1768a0 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -783,9 +783,11 @@ class Form extends WidgetBase list($fieldName, $fieldContext) = $this->getFieldName($name); $field = new FormField($fieldName, $label); + if ($fieldContext) { $field->context = $fieldContext; } + $field->arrayName = $this->arrayName; $field->idPrefix = $this->getId(); @@ -793,20 +795,17 @@ class Form extends WidgetBase * Simple field type */ if (is_string($config)) { - if ($this->isFormWidget($config) !== false) { $field->displayAs('widget', ['widget' => $config]); } else { $field->displayAs($config); } - } /* * Defined field type */ else { - $fieldType = isset($config['type']) ? $config['type'] : null; if (!is_string($fieldType) && !is_null($fieldType)) { throw new ApplicationException(Lang::get( @@ -824,7 +823,6 @@ class Form extends WidgetBase } $field->displayAs($fieldType, $config); - } /* @@ -832,12 +830,19 @@ class Form extends WidgetBase */ $field->value = $this->getFieldValue($field); + /* + * Apply the field name to the validation engine + */ + $attrName = implode('.', HtmlHelper::nameToArray($field->fieldName)); + + if ($this->model && method_exists($this->model, 'setValidationAttributeName')) { + $this->model->setValidationAttributeName($attrName, $field->label); + } + /* * Check model if field is required */ if ($field->required === null && $this->model && method_exists($this->model, 'isAttributeRequired')) { - $fieldName = implode('.', HtmlHelper::nameToArray($field->fieldName)); - // Check nested fields if ($this->isNested) { // Get the current attribute level @@ -852,10 +857,10 @@ class Form extends WidgetBase } // Recombine names for full attribute name in rules array - $fieldName = implode('.', $nameArray) . ".{$fieldName}"; + $attrName = implode('.', $nameArray) . ".{$attrName}"; } - $field->required = $this->model->isAttributeRequired($fieldName); + $field->required = $this->model->isAttributeRequired($attrName); } /*