From ff902cecfb7174f532965c04be8a7bd63875f285 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 22 Mar 2022 17:01:49 +1300 Subject: [PATCH 01/17] docs: Refactor readme links to use reference style. This aids in readability of the raw file. --- README.md | 68 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 1a6fc3e..f1012e1 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ Thank you to [Signify](https://github.com/signify-nz) for making this module pos This module probices a number of reusable composable validators (including AJAX validation) for use both in the CMS and in frontend forms. -Make sure you check out the [extensions documentation](docs/en/02-extensions.md) at a minimum - some of these should be applied in almost all projects using this module. +Make sure you check out the [extensions documentation][0] at a minimum - some of these should be applied in almost all projects using this module. -If your project has any automated client-side tests, or you are implementing a validator to be compatible with this module, please make sure you read the [client side tests documentation](docs/en/03-client-side-tests.md). +If your project has any automated client-side tests, or you are implementing a validator to be compatible with this module, please make sure you read the [client side tests documentation][1]. ## Install -Install via [composer](https://getcomposer.org): +Install via [composer][2]: ```bash composer require guysartorelli/silverstripe-composable-validators @@ -22,35 +22,59 @@ composer require guysartorelli/silverstripe-composable-validators The `AjaxCompositeValidator` adds a submit handler to your form. This doesn't always interact well with other submit handlers, and can result in either front-end validation being skipped or the form not submitting the way you expect it to, depending on which submit handler gets the event first. For best results, don't add additional submit handlers to the form. -If you're using the `AjaxCompositeValidator` on a form that uses [undefinedoffset/silverstripe-nocaptcha](https://github.com/UndefinedOffset/silverstripe-nocaptcha) 2.3.0 or higher, you should disable form submission handling for the `NocaptchaField` in that form (see instructions in the nocaptcha docs). +If you're using the `AjaxCompositeValidator` on a form that uses [undefinedoffset/silverstripe-nocaptcha][3] 2.3.0 or higher, you should disable form submission handling for the `NocaptchaField` in that form (see instructions in the nocaptcha docs). -## [Available Validators](docs/en/01-validators.md) +## [Available Validators][4] -- **[AjaxCompositeValidator](docs/en/01-validators.md#ajaxcompositevalidator)** -Subclass of [CompositeValidator](https://api.silverstripe.org/4/SilverStripe/Forms/CompositeValidator.html) that provides AJAX validation. Resolves [an issue with losing data](https://github.com/silverstripe/silverstripe-elemental/issues/764), faster turn-around for fixing validation problems, and provides a way to use the same validation for 'client-side' validation of frontend forms. -- **[SimpleFieldsValidator](docs/en/01-validators.md#simplefieldsvalidator)** +- **[AjaxCompositeValidator][5]** +Subclass of [CompositeValidator][6] that provides AJAX validation. Resolves [an issue with losing data][7], faster turn-around for fixing validation problems, and provides a way to use the same validation for 'client-side' validation of frontend forms. +- **[SimpleFieldsValidator][8]** Ensures the internal validation of form fields by calling `validate` on them. -- **[RequiredFieldsValidator](docs/en/01-validators.md#requiredfieldsvalidator)** -Like Silverstripe's [RequiredFields](https://api.silverstripe.org/4/SilverStripe/Forms/RequiredFields.html) validator, but more convenient for use in a `CompositeValidator`. -- **[WarningFieldsValidator](docs/en/01-validators.md#warningfieldsvalidator)** +- **[RequiredFieldsValidator][9]** +Like Silverstripe's [RequiredFields][10] validator, but more convenient for use in a `CompositeValidator`. +- **[WarningFieldsValidator][11]** Displays a warning if some field(s) doesn't have a value. Useful for alerting users about data that is technically valid but may not provide the results they expect -- **[DependentRequiredFieldsValidator](docs/en/01-validators.md#dependentrequiredfieldsvalidator)** -Uses [SearchFilters](https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/) to define fields as required conditionally, based on the values of other fields (e.g. only required if `OtherField` has a value greater than 25). -- **[RequiredBlocksValidator](docs/en/01-validators.md#requiredblocksvalidator)** -Require a specific [elemental block(s)](https://github.com/silverstripe/silverstripe-elemental) to exist in the `ElementalArea`, with optional minimum and maximum numbers of blocks and optional positional validation. -- **[RegexFieldsValidator](docs/en/01-validators.md#regexfieldsvalidator)** +- **[DependentRequiredFieldsValidator][12]** +Uses [SearchFilters][13] to define fields as required conditionally, based on the values of other fields (e.g. only required if `OtherField` has a value greater than 25). +- **[RequiredBlocksValidator][14]** +Require a specific [elemental block(s)][15] to exist in the `ElementalArea`, with optional minimum and maximum numbers of blocks and optional positional validation. +- **[RegexFieldsValidator][16]** Ensure some field(s) matches a specified regex pattern. -### [Abstract Validators](docs/en/01-validators.md#abstract-validators) +### [Abstract Validators][17] -- **[BaseValidator](docs/en/01-validators.md#basevalidator)** +- **[BaseValidator][18]** Includes methods useful for getting the actual `FormField` and its label. -- **[FieldHasValueValidator](docs/en/01-validators.md#fieldhasvaluevalidator)** +- **[FieldHasValueValidator][19]** Subclass of `BaseValidator`. Useful for validators that require logic to check if a field has any value or not. -## [Traits](docs/en/01-validators.md#traits) +## [Traits][20] -- **[ValidatesMultipleFields](docs/en/01-validators.md#validatesmultiplefields)** +- **[ValidatesMultipleFields][21]** Useful for validators that can be fed an array of field names to be validated. -- **[ValidatesMultipleFieldsWithConfig](docs/en/01-validators.md#validatesmultiplefieldswithconfig)** +- **[ValidatesMultipleFieldsWithConfig][22]** Like ValidatesMultipleFields but requires a configuration array for each field to be validated. + +[0]: docs/en/02-extensions.md +[1]: docs/en/03-client-side-tests.md +[2]: https://getcomposer.org +[3]: https://github.com/UndefinedOffset/silverstripe-nocaptcha +[4]: docs/en/01-validators.md +[5]: docs/en/01-validators.md#ajaxcompositevalidator +[6]: https://api.silverstripe.org/4/SilverStripe/Forms/CompositeValidator.html +[7]: https://github.com/silverstripe/silverstripe-elemental/issues/764 +[8]: docs/en/01-validators.md#simplefieldsvalidator +[9]: docs/en/01-validators.md#requiredfieldsvalidator +[10]: https://api.silverstripe.org/4/SilverStripe/Forms/RequiredFields.html +[11]: docs/en/01-validators.md#warningfieldsvalidator +[12]: docs/en/01-validators.md#dependentrequiredfieldsvalidator +[13]: https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/ +[14]: docs/en/01-validators.md#requiredblocksvalidator +[15]: https://github.com/silverstripe/silverstripe-elemental +[16]: docs/en/01-validators.md#regexfieldsvalidator +[17]: docs/en/01-validators.md#abstract-validators +[18]: docs/en/01-validators.md#basevalidator +[19]: docs/en/01-validators.md#fieldhasvaluevalidator +[20]: docs/en/01-validators.md#traits +[21]: docs/en/01-validators.md#validatesmultiplefields +[22]: docs/en/01-validators.md#validatesmultiplefieldswithconfig From a97544ba75996b95ae56ff877efd5f03c6002769 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 22 Mar 2022 17:09:36 +1300 Subject: [PATCH 02/17] docs: Use short form int and bool instead of integer and boolean. This is to conform with PSR12. --- src/Extensions/FormFieldExtension.php | 4 ++-- src/Traits/ValidatesMultipleFields.php | 2 +- src/Validators/AjaxCompositeValidator.php | 16 ++++++++-------- .../DependentRequiredFieldsValidator.php | 4 ++-- src/Validators/FieldHasValueValidator.php | 4 ++-- src/Validators/RegexFieldsValidator.php | 4 ++-- src/Validators/RequiredBlocksValidator.php | 10 +++++----- src/Validators/RequiredFieldsValidator.php | 6 +++--- src/Validators/SimpleFieldsValidator.php | 2 +- src/Validators/WarningFieldsValidator.php | 2 +- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Extensions/FormFieldExtension.php b/src/Extensions/FormFieldExtension.php index 8a463ad..f625db7 100644 --- a/src/Extensions/FormFieldExtension.php +++ b/src/Extensions/FormFieldExtension.php @@ -11,7 +11,7 @@ class FormFieldExtension extends Extension /** * Determine whether this field should be ommitted in SimpleFieldValidator validation. * - * @param boolean $omit + * @param bool $omit * @return FormField */ public function setOmitFieldValidation(bool $omit) @@ -23,7 +23,7 @@ public function setOmitFieldValidation(bool $omit) /** * Get whether this field should be ommitted in SimpleFieldValidator validation. * - * @return boolean + * @return bool */ public function getOmitFieldValidation(): bool { diff --git a/src/Traits/ValidatesMultipleFields.php b/src/Traits/ValidatesMultipleFields.php index 94758c6..6bf987d 100644 --- a/src/Traits/ValidatesMultipleFields.php +++ b/src/Traits/ValidatesMultipleFields.php @@ -102,7 +102,7 @@ public function removeValidation() /** * Declare that this validator can be cached if there are no fields to validate. * - * @return boolean + * @return bool */ public function canBeCached(): bool { diff --git a/src/Validators/AjaxCompositeValidator.php b/src/Validators/AjaxCompositeValidator.php index ce96315..b4105df 100644 --- a/src/Validators/AjaxCompositeValidator.php +++ b/src/Validators/AjaxCompositeValidator.php @@ -21,7 +21,7 @@ class AjaxCompositeValidator extends CompositeValidator /** * Whether the validation hint data attribute should be applied to forms. * - * @var boolean + * @var bool * @config */ private static $add_validation_hint = true; @@ -29,7 +29,7 @@ class AjaxCompositeValidator extends CompositeValidator /** * Per-instance override for add_validation_hint * - * @var boolean|null + * @var bool|null */ private $addValidationHint; @@ -121,8 +121,8 @@ public function getOrAddValidatorByType(string $validatorClass): Validator /** * Check whether this is a legitimate validation request. * - * @param boolean $validAjax - * @return boolean + * @param bool $validAjax + * @return bool */ protected function isValidRequest(bool $validAjax): bool { @@ -166,7 +166,7 @@ public function php($data) /** * Set whether this validator is configured to add a validation hint to the form. * - * @param boolean $addHint + * @param bool $addHint * @return $this */ public function setAddValidationHint(bool $addHint) @@ -178,7 +178,7 @@ public function setAddValidationHint(bool $addHint) /** * True if this validator is configured to add a validation hint to the form. * - * @return boolean + * @return bool */ public function getAddValidationHint(): bool { @@ -191,7 +191,7 @@ public function getAddValidationHint(): bool /** * Set whether this validator is configured to use AJAX validation. * - * @param boolean $ajax + * @param bool $ajax * @return $this */ public function setAjax(bool $ajax) @@ -203,7 +203,7 @@ public function setAjax(bool $ajax) /** * True if this validator is configured to use AJAX validation. * - * @return boolean + * @return bool */ public function getAjax(): bool { diff --git a/src/Validators/DependentRequiredFieldsValidator.php b/src/Validators/DependentRequiredFieldsValidator.php index 5bdc41a..dbe5169 100644 --- a/src/Validators/DependentRequiredFieldsValidator.php +++ b/src/Validators/DependentRequiredFieldsValidator.php @@ -28,7 +28,7 @@ class DependentRequiredFieldsValidator extends FieldHasValueValidator * Validates that the required fields have values if their dependencies are met. * * @param array $data - * @return boolean + * @return bool */ public function php($data) { @@ -78,7 +78,7 @@ public function php($data) * @param FieldList $fields * @param string $fieldName * @param array $filter - * @return boolean True if the field has a value. + * @return bool True if the field has a value. */ protected function validateField($data, FieldList $fields, string $fieldName, array $filter): bool { diff --git a/src/Validators/FieldHasValueValidator.php b/src/Validators/FieldHasValueValidator.php index 2040bfc..85cc2bf 100644 --- a/src/Validators/FieldHasValueValidator.php +++ b/src/Validators/FieldHasValueValidator.php @@ -17,7 +17,7 @@ abstract class FieldHasValueValidator extends BaseValidator * * @param array $data * @param FormField $formField - * @return boolean + * @return bool */ protected function fieldHasValue(array $data, FormField $formField): bool { @@ -59,7 +59,7 @@ protected function fieldHasValue(array $data, FormField $formField): bool * @param string $methodName * @param FormField $formField * @param mixed $value - * @return boolean|null + * @return bool|null */ private function extendedHas(string $methodName, FormField $formField, $value) { diff --git a/src/Validators/RegexFieldsValidator.php b/src/Validators/RegexFieldsValidator.php index 90d3d31..331f8ba 100644 --- a/src/Validators/RegexFieldsValidator.php +++ b/src/Validators/RegexFieldsValidator.php @@ -28,7 +28,7 @@ class RegexFieldsValidator extends BaseValidator * Validates that the fields match their regular expressions. * * @param array $data - * @return boolean + * @return bool */ public function php($data) { @@ -91,7 +91,7 @@ public function php($data) * Check if a value can be casted to string. * * @param mixed $value - * @return boolean + * @return bool */ protected function valueCanBeString($value) { diff --git a/src/Validators/RequiredBlocksValidator.php b/src/Validators/RequiredBlocksValidator.php index f9a6229..0c22640 100644 --- a/src/Validators/RequiredBlocksValidator.php +++ b/src/Validators/RequiredBlocksValidator.php @@ -41,7 +41,7 @@ public function __construct(array $required = []) * Validates that the required blocks exist in the configured positions. * * @param array $data - * @return boolean + * @return bool */ public function php($data) { @@ -163,7 +163,7 @@ protected function validateElementalArea( * Validate that the minimum or maximum number of blocks for this class has not been exceeded. * * @param int[] $requiredConfig - * @param integer $numberOfBlocks + * @param int $numberOfBlocks * @param ArrayList $relevantFields * @param string[] $errors */ @@ -343,7 +343,7 @@ protected function getRelevantFields(ArrayList $elementalAreaFields, array $requ * * @param string $blockClass * @param ArrayList $relevantFields - * @return integer + * @return int */ protected function getNumberOfBlocks(string $blockClass, ArrayList $relevantFields): int { @@ -358,7 +358,7 @@ protected function getNumberOfBlocks(string $blockClass, ArrayList $relevantFiel * Get the localised ordinal string for the number. * e.g. in 'en' locales 1 becomes '1st' * - * @param integer $num + * @param int $num * @return string */ protected function ordinal(int $num): string @@ -409,7 +409,7 @@ protected function normaliseRequiredConfig(array $required): array /** * Declare that this validator can be cached if there are no fields to validate. * - * @return boolean + * @return bool */ public function canBeCached(): bool { diff --git a/src/Validators/RequiredFieldsValidator.php b/src/Validators/RequiredFieldsValidator.php index 9ced152..be32464 100644 --- a/src/Validators/RequiredFieldsValidator.php +++ b/src/Validators/RequiredFieldsValidator.php @@ -21,7 +21,7 @@ class RequiredFieldsValidator extends FieldHasValueValidator * Validates that the required fields have values. * * @param array $data - * @return boolean + * @return bool */ public function php($data) { @@ -45,7 +45,7 @@ public function php($data) * @param array $data * @param FieldList $fields * @param string $fieldName - * @return boolean True if the field has a value. + * @return bool True if the field has a value. */ protected function validateField($data, FieldList $fields, string $fieldName): bool { @@ -83,7 +83,7 @@ protected function validateField($data, FieldList $fields, string $fieldName): b * to do things like show *s on the form template. * * @param string $fieldName - * @return boolean + * @return bool */ public function fieldIsRequired($fieldName) { diff --git a/src/Validators/SimpleFieldsValidator.php b/src/Validators/SimpleFieldsValidator.php index 0905ae4..d464020 100644 --- a/src/Validators/SimpleFieldsValidator.php +++ b/src/Validators/SimpleFieldsValidator.php @@ -28,7 +28,7 @@ class SimpleFieldsValidator extends Validator * Check all fields to ensure they are internally valid. * * @param array $data - * @return boolean + * @return bool */ public function php($data, bool $isAjax = false) { diff --git a/src/Validators/WarningFieldsValidator.php b/src/Validators/WarningFieldsValidator.php index 91c7d35..14bc37a 100644 --- a/src/Validators/WarningFieldsValidator.php +++ b/src/Validators/WarningFieldsValidator.php @@ -52,7 +52,7 @@ public function php($data) * @param array $data * @param FieldList $fields * @param string $fieldName - * @return boolean True if a warning is prepared for the field. + * @return bool True if a warning is prepared for the field. */ protected function validateField($data, FieldList $fields, string $fieldName): bool { From fbc95a1fb551eb79a8c99724aaf97fd9fac2baa9 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 22 Mar 2022 17:21:28 +1300 Subject: [PATCH 03/17] refactor: Add missing return typehints. --- src/Extensions/FormFieldExtension.php | 3 ++- src/Validators/AjaxCompositeValidator.php | 4 ++-- src/Validators/RegexFieldsValidator.php | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Extensions/FormFieldExtension.php b/src/Extensions/FormFieldExtension.php index f625db7..56c4885 100644 --- a/src/Extensions/FormFieldExtension.php +++ b/src/Extensions/FormFieldExtension.php @@ -3,6 +3,7 @@ namespace Signify\ComposableValidators\Extensions; use SilverStripe\Core\Extension; +use SilverStripe\Forms\FormField; class FormFieldExtension extends Extension { @@ -14,7 +15,7 @@ class FormFieldExtension extends Extension * @param bool $omit * @return FormField */ - public function setOmitFieldValidation(bool $omit) + public function setOmitFieldValidation(bool $omit): FormField { $this->omitFieldValidation[$this->owner->getName()] = $omit; return $this->owner; diff --git a/src/Validators/AjaxCompositeValidator.php b/src/Validators/AjaxCompositeValidator.php index b4105df..d5dbb6f 100644 --- a/src/Validators/AjaxCompositeValidator.php +++ b/src/Validators/AjaxCompositeValidator.php @@ -169,7 +169,7 @@ public function php($data) * @param bool $addHint * @return $this */ - public function setAddValidationHint(bool $addHint) + public function setAddValidationHint(bool $addHint): AjaxCompositeValidator { $this->addValidationHint = $addHint; return $this; @@ -194,7 +194,7 @@ public function getAddValidationHint(): bool * @param bool $ajax * @return $this */ - public function setAjax(bool $ajax) + public function setAjax(bool $ajax): AjaxCompositeValidator { $this->ajax = $ajax; return $this; diff --git a/src/Validators/RegexFieldsValidator.php b/src/Validators/RegexFieldsValidator.php index 331f8ba..5bf79ac 100644 --- a/src/Validators/RegexFieldsValidator.php +++ b/src/Validators/RegexFieldsValidator.php @@ -93,7 +93,7 @@ public function php($data) * @param mixed $value * @return bool */ - protected function valueCanBeString($value) + protected function valueCanBeString($value): bool { return $value === null || is_scalar($value) || (is_object($value) && method_exists($value, '__toString')); } From 4a1184d4bf01c5cae62f94bd25f7e8f02fc8129c Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 22 Mar 2022 17:41:23 +1300 Subject: [PATCH 04/17] docs: Surround class names and other code references with backticks. Note that headings do not need backticks. --- README.md | 28 ++++++++++++++-------------- docs/en/01-validators.md | 26 +++++++++++++------------- docs/en/02-extensions.md | 12 ++++++------ docs/en/03-client-side-tests.md | 4 ++-- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index f1012e1..d072673 100644 --- a/README.md +++ b/README.md @@ -26,33 +26,33 @@ If you're using the `AjaxCompositeValidator` on a form that uses [undefinedoffse ## [Available Validators][4] -- **[AjaxCompositeValidator][5]** -Subclass of [CompositeValidator][6] that provides AJAX validation. Resolves [an issue with losing data][7], faster turn-around for fixing validation problems, and provides a way to use the same validation for 'client-side' validation of frontend forms. -- **[SimpleFieldsValidator][8]** +- **[`AjaxCompositeValidator`][5]** +Subclass of [`CompositeValidator`][6] that provides AJAX validation. Resolves [an issue with losing data][7], faster turn-around for fixing validation problems, and provides a way to use the same validation for 'client-side' validation of frontend forms. +- **[`SimpleFieldsValidator`][8]** Ensures the internal validation of form fields by calling `validate` on them. -- **[RequiredFieldsValidator][9]** -Like Silverstripe's [RequiredFields][10] validator, but more convenient for use in a `CompositeValidator`. -- **[WarningFieldsValidator][11]** +- **[`RequiredFieldsValidator`][9]** +Like Silverstripe's [`RequiredFields`][10] validator, but more convenient for use in a `CompositeValidator`. +- **[`WarningFieldsValidator`][11]** Displays a warning if some field(s) doesn't have a value. Useful for alerting users about data that is technically valid but may not provide the results they expect -- **[DependentRequiredFieldsValidator][12]** -Uses [SearchFilters][13] to define fields as required conditionally, based on the values of other fields (e.g. only required if `OtherField` has a value greater than 25). -- **[RequiredBlocksValidator][14]** +- **[`DependentRequiredFieldsValidator`][12]** +Uses [`SearchFilter`s][13] to define fields as required conditionally, based on the values of other fields (e.g. only required if `OtherField` has a value greater than 25). +- **[`RequiredBlocksValidator`][14]** Require a specific [elemental block(s)][15] to exist in the `ElementalArea`, with optional minimum and maximum numbers of blocks and optional positional validation. -- **[RegexFieldsValidator][16]** +- **[`RegexFieldsValidator`][16]** Ensure some field(s) matches a specified regex pattern. ### [Abstract Validators][17] -- **[BaseValidator][18]** +- **[`BaseValidator`][18]** Includes methods useful for getting the actual `FormField` and its label. -- **[FieldHasValueValidator][19]** +- **[`FieldHasValueValidator`][19]** Subclass of `BaseValidator`. Useful for validators that require logic to check if a field has any value or not. ## [Traits][20] -- **[ValidatesMultipleFields][21]** +- **[`ValidatesMultipleFields`][21]** Useful for validators that can be fed an array of field names to be validated. -- **[ValidatesMultipleFieldsWithConfig][22]** +- **[`ValidatesMultipleFieldsWithConfig`][22]** Like ValidatesMultipleFields but requires a configuration array for each field to be validated. [0]: docs/en/02-extensions.md diff --git a/docs/en/01-validators.md b/docs/en/01-validators.md index 0a5fba7..9913965 100644 --- a/docs/en/01-validators.md +++ b/docs/en/01-validators.md @@ -10,7 +10,7 @@ All of these validators can be used in the CMS _and_ in the front-end. Note that to use this validator on the frontend, you will need to expose `jQuery` as a global variable. To avoid providing outdated or redundant copies of jQuery this module doesn't come packaged with it. -As of Silverstripe 4.7.0, all `DataObject`s have a [CompositeValidator](https://api.silverstripe.org/4/SilverStripe/Forms/CompositeValidator.html) automatically for CMS forms. The `AjaxCompositeValidator` is a subclass of that validator and provides AJAX validation that takes affect prior to form submission. When you click a form action that isn't validation exempt, an AJAX request is made to validate the form _prior_ to form submission. If there are any validation errors, form submission will be blocked and validation messages displayed. +As of Silverstripe 4.7.0, all `DataObject`s have a [`CompositeValidator`](https://api.silverstripe.org/4/SilverStripe/Forms/CompositeValidator.html) automatically for CMS forms. The `AjaxCompositeValidator` is a subclass of that validator and provides AJAX validation that takes affect prior to form submission. When you click a form action that isn't validation exempt, an AJAX request is made to validate the form _prior_ to form submission. If there are any validation errors, form submission will be blocked and validation messages displayed. This is useful for situations where data can be lost with the normal Silverstripe validation pipeline (e.g. validating fields on a page that has an [elemental area](https://github.com/silverstripe/silverstripe-elemental) - see [this issue](https://github.com/silverstripe/silverstripe-elemental/issues/764)), and is also faster as it doesn't need to reload the form after validating to display the error messages. @@ -18,7 +18,7 @@ This validator is also extremely useful for front-end forms, as it provides clie ### Usage -If the [DataObjectDefaultAjaxExtension](./02-extensions.md#dataobjectdefaultajaxextension) extension has been applied, calling `parent::getCMSCompositeValidator` inside the `getCMSCompositeValidator` method will return an `AjaxCompositeValidator`, which can then be manipulated. +If the [`DataObjectDefaultAjaxExtension`](./02-extensions.md#dataobjectdefaultajaxextension) extension has been applied, calling `parent::getCMSCompositeValidator` inside the `getCMSCompositeValidator` method will return an `AjaxCompositeValidator`, which can then be manipulated. You can also opt to just return a new `AjaxCompositeValidator` from that method - and in front-end situations, you can instantiate a new `AjaxCompositeValidator` (preferably [via injection](https://docs.silverstripe.org/en/4/developer_guides/extending/injector/) i.e. `AjaxCompositeValidator::create()`). @@ -104,7 +104,7 @@ That specific class is already added by default, but you can add others if you f ## RequiredFieldsValidator -This is a composable replacement for [RequiredFields](https://api.silverstripe.org/4/SilverStripe/Forms/RequiredFields.html). It doesn't perform the internal field validation that validator does, with the assumption that it will be paired with a `SimpleFieldsValidator`. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFields](#validatesmultiplefields) trait. +This is a composable replacement for [`RequiredFields`](https://api.silverstripe.org/4/SilverStripe/Forms/RequiredFields.html). It doesn't perform the internal field validation that validator does, with the assumption that it will be paired with a `SimpleFieldsValidator`. It uses (so has all of the functionality and methods of) the [`ValidatesMultipleFields`](#validatesmultiplefields) trait. Displays a validation error if the field(s) has no value. @@ -115,7 +115,7 @@ This applies to the `WarningFieldsValidator` as well. ## WarningFieldsValidator -Similar to `RequiredFieldsValidator` except instead of blocking the item from saving, this allows the item to save and displays a warning rather than a full validation error. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFields](#validatesmultiplefields) trait. +Similar to `RequiredFieldsValidator` except instead of blocking the item from saving, this allows the item to save and displays a warning rather than a full validation error. It uses (so has all of the functionality and methods of) the [`ValidatesMultipleFields`](#validatesmultiplefields) trait. This can be very useful for alerting users about data that is technically valid but may not provide the results they expect. @@ -123,7 +123,7 @@ Displays a validation warning if the field(s) has no value. ## DependentRequiredFieldsValidator -Allows you to define fields as being required conditionally based on the values of other fields. It uses [SearchFilters](https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/) to provide a variety of ways to compare values, depending on what causes the fields to be required. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. +Allows you to define fields as being required conditionally based on the values of other fields. It uses [`SearchFilters`](https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/) to provide a variety of ways to compare values, depending on what causes the fields to be required. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. In the below example, we have fields with various levels of dependency on whether they are required or not. @@ -218,15 +218,15 @@ RequiredBlocksValidator::create([ The `ElementalArea` field holder template doesn't currently render validation error messages. A [pull request](https://github.com/silverstripe/silverstripe-elemental/pull/921) has been created to remedy this, but in the meantime you must either use the `RequiredBlocksValidator` inside an `AjaxCompositeValidator` (which will display the message regardless of the template) or override the `ElementalAreaField_holder.ss` template in your project. -This validator validates when the page (or other DataObject that has an ElementalArea) is saved or published - but not necessarily when the blocks within the ElementalArea are saved or published. This means content authors can work around the validation errors if they really want to. +This validator validates when the page (or other `DataObject` that has an `ElementalArea`) is saved or published - but not necessarily when the blocks within the `ElementalArea` are saved or published. This means content authors can work around the validation errors if they really want to. ## RegexFieldsValidator -This validator is used to require field values to match a specific regex pattern. Often it will make sense to have this validation inside a custom FormField implementation, but for one-off specific pattern validation of fields that don't warrant their own FormField this validator is perfect. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. +This validator is used to require field values to match a specific regex pattern. Often it will make sense to have this validation inside a custom `FormField` implementation, but for one-off specific pattern validation of fields that don't warrant their own `FormField` this validator is perfect. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. Any value that cannot be converted to a string cannot be checked against regex and so is ignored, and therefore implicitly passes validation. -In the below example, the NotOnlyNumbersField field must match one of the specified regex patterns. +In the below example, the `NotOnlyNumbersField` field must match one of the specified regex patterns. ```php RegexFieldsValidator::create([ @@ -237,14 +237,14 @@ RegexFieldsValidator::create([ ]); ``` -**Note:** If any one of the patterns is matched, it passes validation. If none of the patterns match, all of the corresponding messages are displayed, including a generic prefix. So in the above example, if none of the patterns match the value of NotOnlyNumbersField, the following validation error message will display: +**Note:** If any one of the patterns is matched, it passes validation. If none of the patterns match, all of the corresponding messages are displayed, including a generic prefix. So in the above example, if none of the patterns match the value of `NotOnlyNumbersField`, the following validation error message will display: `The value for "NotOnlyNumbersField" must not consist entirely of numbers or must have only one digit` ## Abstract Validators ### BaseValidator -This abstract class should be used as the superclass for any validator that displays validation messages, as it provides a method to get the correct label for use in validation messages. It also has a method for reliably getting a FormField from a Fieldlist. +This abstract class should be used as the superclass for any validator that displays validation messages, as it provides a method to get the correct label for use in validation messages. It also has a method for reliably getting a `FormField` from a `FieldList`. ```php // Get the actual FormField for the named field. @@ -260,7 +260,7 @@ It also has an abstract method `getValidationHints` which has implications for [ ### FieldHasValueValidator -This abstract class is itself a subclass of `BaseValidator`, and is useful as a superclass for any validator that needs to check if fields have a value. This functionality is used in the [RequiredFieldsValidator](#requiredfieldsvalidator), [WarningFieldsValidator](#warningfieldsvalidator), and [DependentRequiredFieldsValidator](#dependentrequiredfieldsvalidator). +This abstract class is itself a subclass of `BaseValidator`, and is useful as a superclass for any validator that needs to check if fields have a value. This functionality is used in the [`RequiredFieldsValidator`](#requiredfieldsvalidator), [`WarningFieldsValidator`](#warningfieldsvalidator), and [`DependentRequiredFieldsValidator`](#dependentrequiredfieldsvalidator). ```php // Get the actual FormField for the named field. @@ -308,7 +308,7 @@ class MyFieldValueExtension extends Extension ## ValidatesMultipleFields -This trait is used in both the [RequiredFieldsValidator](#requiredfieldsvalidator) and [WarningFieldsValidator](#warningfieldsvalidator). It is useful for any validator that can be fed an array of field names that need to be validated. +This trait is used in both the [`RequiredFieldsValidator`](#requiredfieldsvalidator) and [`WarningFieldsValidator`](#warningfieldsvalidator). It is useful for any validator that can be fed an array of field names that need to be validated. ### Usage @@ -358,6 +358,6 @@ $validator = SomeMultiFieldWithConfigValidator::create([ ]); ``` -Used in [DependentRequiredFieldsValidator](#dependentrequiredfieldsvalidator) and [RegexFieldsValidator](#regexfieldsvalidator). +Used in [`DependentRequiredFieldsValidator`](#dependentrequiredfieldsvalidator) and [`RegexFieldsValidator`](#regexfieldsvalidator). Check the documentation for a specific validator for specifics about the configuration array for that validator. diff --git a/docs/en/02-extensions.md b/docs/en/02-extensions.md index c29efaa..07a685a 100644 --- a/docs/en/02-extensions.md +++ b/docs/en/02-extensions.md @@ -10,10 +10,10 @@ SilverStripe\ORM\DataObject: - Signify\ComposableValidators\Extensions\DataObjectDefaultAjaxExtension ``` -Replaces the default `CompositeValidator` that all `DataObject`s have (see `DataObject::getCMSCompositeValidator()`) with this module's [AjaxCompositeValidator](./01-validators.md#ajaxcompositevalidator). +Replaces the default `CompositeValidator` that all `DataObject`s have (see `DataObject::getCMSCompositeValidator()`) with this module's [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator). Unfortunately at the time of writing these docs, the `CompositeValidator` is instantiated using the `new` keyword instead of using the `create` method, so you can't just replace it outright in the `Injector` - but even if you could, we'd strongly recommend including a `SimpleFieldsValidator`, which would be tricky if possible at all to do via the `Injector`. -This extension also automatically adds a [SimpleFieldsValidator](./01-validators.md#simplefieldsvalidator) to ensure all form fields have valid data. +This extension also automatically adds a [`SimpleFieldsValidator`](./01-validators.md#simplefieldsvalidator) to ensure all form fields have valid data. ## DataObjectValidationExemptionExtension and GridFieldItemRequestValidationExemptionExtension @@ -27,7 +27,7 @@ SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest: - Signify\ComposableValidators\Extensions\GridFieldItemRequestValidationExemptionExtension ``` -For whatever reason, the "delete", "archive", and "restore" actions in Silverstripe are _not_ validation exempt actions. This can cause issues with the [AjaxCompositeValidator](./01-validators.md#ajaxcompositevalidator) which won't let you perform those actions if the data doesn't pass validation. +For whatever reason, the "delete", "archive", and "restore" actions in Silverstripe are _not_ validation exempt actions. This can cause issues with the [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator) which won't let you perform those actions if the data doesn't pass validation. **These extensions are necessary** if you're using the `AjaxCompositeValidator`, but aren't applied by default in case they cause issues in some projects. @@ -39,7 +39,7 @@ SilverStripe\Forms\GridField\GridField: - Signify\ComposableValidators\Extensions\GridFieldMessagesExtension ``` -Ensures validation messages display for a GridField. GridFields didn't display validation messages prior to 4.10.0. +Ensures validation messages display for a `GridField`. `GridField`s didn't display validation messages prior to 4.10.0. # Default extensions @@ -47,8 +47,8 @@ These extensions are already applied by default. They shouldn't interfere with a ## FormExtension -Provides the action used for AJAX validation via the [AjaxCompositeValidator](./01-validators.md#ajaxcompositevalidator). +Provides the action used for AJAX validation via the [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator). ## FormFieldExtension -Provides the `setOmitFieldValidation` and `getOmitFieldValidation` methods to determine if fields should be validated by the [SimpleFieldsValidator](./01-validators.md#simplefieldsvalidator). +Provides the `setOmitFieldValidation` and `getOmitFieldValidation` methods to determine if fields should be validated by the [`SimpleFieldsValidator`](./01-validators.md#simplefieldsvalidator). diff --git a/docs/en/03-client-side-tests.md b/docs/en/03-client-side-tests.md index 7f7b3af..f6c4837 100644 --- a/docs/en/03-client-side-tests.md +++ b/docs/en/03-client-side-tests.md @@ -2,9 +2,9 @@ If your project has any automated client-side tests, be it with [Behat](https://github.com/silverstripe/silverstripe-behat-extension), [Selenium](https://www.selenium.dev), or some other framework, it may be useful to know before you submit a form what validation is required for which fields. -The [AjaxCompositeValidator](./01-validators.md#ajaxcompositevalidator) adds a `data-signify-validation-hints` attribute to any form it is added to. The value of this attribute is an empty JSON array if there is no validation, or a JSON object if there is. The JSON object has field IDs for keys with the validation requirements for that field in JSON objects for values. +The [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator) adds a `data-signify-validation-hints` attribute to any form it is added to. The value of this attribute is an empty JSON array if there is no validation, or a JSON object if there is. The JSON object has field IDs for keys with the validation requirements for that field in JSON objects for values. -The abstract [BaseValidator](./01-validators.md#basevalidator) class provides an abstract `getValidationHints` method which must return an array. This array should contain the full validation requirements of each field that will be validated by a given validator. **You should implement this method in any custom validators you create which you intend to include in an `AjaxCompositeValidator`**. +The abstract [`BaseValidator`](./01-validators.md#basevalidator) class provides an abstract `getValidationHints` method which must return an array. This array should contain the full validation requirements of each field that will be validated by a given validator. **You should implement this method in any custom validators you create which you intend to include in an `AjaxCompositeValidator`**. All of the validators included in this module that perform their own validation implementations implement the `getValidationHints` method, so their validation requirements are included in the validation hints attribute. From 00c1cf41447a787281bec73ddb7502dfaef146bc Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:07:23 +1300 Subject: [PATCH 05/17] docs: Fix some styling issues in docs. Add missing backticks, fix typos, add missing brackets for method names. --- CONTRIBUTING.md | 4 ++-- README.md | 4 ++-- docs/en/01-validators.md | 14 +++++++------- docs/en/02-extensions.md | 4 ++-- docs/en/03-client-side-tests.md | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1435478..4e30bdc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Any feature requests or recommendations should be raised as [an issue](https://g This module adheres to [the Silverstripe module standards](https://docs.silverstripe.org/en/4/developer_guides/extending/modules/#module-standard) Commit messages should be [semantic](https://seesparkbox.com/foundry/semantic_commit_messages), though the style used for this module differs from that reference in the following ways: -- The first letter after the commit type is capitalised. -- A fullstop is placed at the end of the commit message. +- The first letter after the commit type is capitalized. +- A full stop is placed at the end of the commit message. Make sure you also read over [the resources docs](docs/en/00-resources.md) before committing any javascript. diff --git a/README.md b/README.md index d072673..1f8c035 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ If you're using the `AjaxCompositeValidator` on a form that uses [undefinedoffse - **[`AjaxCompositeValidator`][5]** Subclass of [`CompositeValidator`][6] that provides AJAX validation. Resolves [an issue with losing data][7], faster turn-around for fixing validation problems, and provides a way to use the same validation for 'client-side' validation of frontend forms. - **[`SimpleFieldsValidator`][8]** -Ensures the internal validation of form fields by calling `validate` on them. +Ensures the internal validation of form fields by calling `validate()` on them. - **[`RequiredFieldsValidator`][9]** Like Silverstripe's [`RequiredFields`][10] validator, but more convenient for use in a `CompositeValidator`. - **[`WarningFieldsValidator`][11]** @@ -53,7 +53,7 @@ Subclass of `BaseValidator`. Useful for validators that require logic to check i - **[`ValidatesMultipleFields`][21]** Useful for validators that can be fed an array of field names to be validated. - **[`ValidatesMultipleFieldsWithConfig`][22]** -Like ValidatesMultipleFields but requires a configuration array for each field to be validated. +Like `ValidatesMultipleFields` but requires a configuration array for each field to be validated. [0]: docs/en/02-extensions.md [1]: docs/en/03-client-side-tests.md diff --git a/docs/en/01-validators.md b/docs/en/01-validators.md index 9913965..740c320 100644 --- a/docs/en/01-validators.md +++ b/docs/en/01-validators.md @@ -18,7 +18,7 @@ This validator is also extremely useful for front-end forms, as it provides clie ### Usage -If the [`DataObjectDefaultAjaxExtension`](./02-extensions.md#dataobjectdefaultajaxextension) extension has been applied, calling `parent::getCMSCompositeValidator` inside the `getCMSCompositeValidator` method will return an `AjaxCompositeValidator`, which can then be manipulated. +If the [`DataObjectDefaultAjaxExtension`](./02-extensions.md#dataobjectdefaultajaxextension) extension has been applied, calling `parent::getCMSCompositeValidator()` inside the `getCMSCompositeValidator()` method will return an `AjaxCompositeValidator`, which can then be manipulated. You can also opt to just return a new `AjaxCompositeValidator` from that method - and in front-end situations, you can instantiate a new `AjaxCompositeValidator` (preferably [via injection](https://docs.silverstripe.org/en/4/developer_guides/extending/injector/) i.e. `AjaxCompositeValidator::create()`). @@ -123,7 +123,7 @@ Displays a validation warning if the field(s) has no value. ## DependentRequiredFieldsValidator -Allows you to define fields as being required conditionally based on the values of other fields. It uses [`SearchFilters`](https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/) to provide a variety of ways to compare values, depending on what causes the fields to be required. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. +Allows you to define fields as being required conditionally based on the values of other fields. It uses [`SearchFilters`](https://docs.silverstripe.org/en/4/developer_guides/model/searchfilters/) to provide a variety of ways to compare values, depending on what causes the fields to be required. It uses (so has all of the functionality and methods of) the [`ValidatesMultipleFieldsWithConfig`](#validatesmultiplefieldswithconfig) trait. In the below example, we have fields with various levels of dependency on whether they are required or not. @@ -200,7 +200,7 @@ Note that if a maximum number of blocks is defined, blocks can still be created, If more than one `ElementalArea` exists on the `DataObject` being validated, you can define which area(s) the validation applies to. Note that this validation is spread across all areas validated against. This means if you set a minimum of 3 blocks and two elemental areas, there must be 3 blocks spread however the user likes across both areas (e.g. 1 in area 1 and 2 in area 2) rather than requiring 3 blocks in each area. Positional validation is per area, so if a position is defined and a block exists in each area, it must be in the defined position in each of those areas. -If the only configuration set for a block class is the AreaFieldName, a default min value of 1 will be implicitly set. +If the only configuration set for a block class is the `AreaFieldName`, a default min value of 1 will be implicitly set. ```PHP RequiredBlocksValidator::create([ @@ -222,7 +222,7 @@ This validator validates when the page (or other `DataObject` that has an `Eleme ## RegexFieldsValidator -This validator is used to require field values to match a specific regex pattern. Often it will make sense to have this validation inside a custom `FormField` implementation, but for one-off specific pattern validation of fields that don't warrant their own `FormField` this validator is perfect. It uses (so has all of the functionality and methods of) the [ValidatesMultipleFieldsWithConfig](#validatesmultiplefieldswithconfig) trait. +This validator is used to require field values to match a specific regex pattern. Often it will make sense to have this validation inside a custom `FormField` implementation, but for one-off specific pattern validation of fields that don't warrant their own `FormField` this validator is perfect. It uses (so has all of the functionality and methods of) the [`ValidatesMultipleFieldsWithConfig`](#validatesmultiplefieldswithconfig) trait. Any value that cannot be converted to a string cannot be checked against regex and so is ignored, and therefore implicitly passes validation. @@ -256,7 +256,7 @@ $errorMessage = '"' . $this->getFieldLabel($formField) . '" is required'; $this->validationError($fieldName, $errorMessage, 'required'); ``` -It also has an abstract method `getValidationHints` which has implications for [client-side automated testing](./03-client-side-tests.md). +It also has an abstract method `getValidationHints()` which has implications for [client-side automated testing](./03-client-side-tests.md). ### FieldHasValueValidator @@ -273,7 +273,7 @@ $errorMessage = '"' . $this->getFieldLabel($formField) . '" is required'; $this->validationError($fieldName, $errorMessage, 'required'); ``` -The `fieldHasValue` method should correctly identify whether a field has a value or not for all `FormField`s that come packaged in Silverstripe framework itself. It's possible however that some module, or your own code, has a value format that isn't correctly covered by this module. For those situations, you can extend the functionality by implementing `updateFieldHasValue` in an `Extension` class: +The `fieldHasValue()` method should correctly identify whether a field has a value or not for all `FormField`s that come packaged in Silverstripe framework itself. It's possible however that some module, or your own code, has a value format that isn't correctly covered by this module. For those situations, you can extend the functionality by implementing `updateFieldHasValue()` in an `Extension` class: ```yml Signify\ComposableValidators\Validators\FieldHasValueValidator: @@ -347,7 +347,7 @@ Note that the field name passed should _always_ be the name of the `FormField`. ## ValidatesMultipleFieldsWithConfig -This trait is almost identical to `ValidatesMultipleFields` and has all of the same methods, except that `addField` requires two arguments (the field to be validated, and its configuration array), and `addFields` requires a configuration array for each field added. +This trait is almost identical to `ValidatesMultipleFields` and has all of the same methods, except that `addField()` requires two arguments (the field to be validated, and its configuration array), and `addFields()` requires a configuration array for each field added. On instantiation, either no arguments (or an empty array) must be passed, or a valid array of fields with their configuration must be passed. ```php diff --git a/docs/en/02-extensions.md b/docs/en/02-extensions.md index 07a685a..4b2cef5 100644 --- a/docs/en/02-extensions.md +++ b/docs/en/02-extensions.md @@ -11,7 +11,7 @@ SilverStripe\ORM\DataObject: ``` Replaces the default `CompositeValidator` that all `DataObject`s have (see `DataObject::getCMSCompositeValidator()`) with this module's [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator). -Unfortunately at the time of writing these docs, the `CompositeValidator` is instantiated using the `new` keyword instead of using the `create` method, so you can't just replace it outright in the `Injector` - but even if you could, we'd strongly recommend including a `SimpleFieldsValidator`, which would be tricky if possible at all to do via the `Injector`. +Unfortunately at the time of writing these docs, the `CompositeValidator` is instantiated using the `new` keyword instead of using the `create()` method, so you can't just replace it outright in the `Injector` - but even if you could, we'd strongly recommend including a `SimpleFieldsValidator`, which would be tricky if possible at all to do via the `Injector`. This extension also automatically adds a [`SimpleFieldsValidator`](./01-validators.md#simplefieldsvalidator) to ensure all form fields have valid data. @@ -51,4 +51,4 @@ Provides the action used for AJAX validation via the [`AjaxCompositeValidator`]( ## FormFieldExtension -Provides the `setOmitFieldValidation` and `getOmitFieldValidation` methods to determine if fields should be validated by the [`SimpleFieldsValidator`](./01-validators.md#simplefieldsvalidator). +Provides the `setOmitFieldValidation()` and `getOmitFieldValidation()` methods to determine if fields should be validated by the [`SimpleFieldsValidator`](./01-validators.md#simplefieldsvalidator). diff --git a/docs/en/03-client-side-tests.md b/docs/en/03-client-side-tests.md index f6c4837..cdfaafd 100644 --- a/docs/en/03-client-side-tests.md +++ b/docs/en/03-client-side-tests.md @@ -4,9 +4,9 @@ If your project has any automated client-side tests, be it with [Behat](https:// The [`AjaxCompositeValidator`](./01-validators.md#ajaxcompositevalidator) adds a `data-signify-validation-hints` attribute to any form it is added to. The value of this attribute is an empty JSON array if there is no validation, or a JSON object if there is. The JSON object has field IDs for keys with the validation requirements for that field in JSON objects for values. -The abstract [`BaseValidator`](./01-validators.md#basevalidator) class provides an abstract `getValidationHints` method which must return an array. This array should contain the full validation requirements of each field that will be validated by a given validator. **You should implement this method in any custom validators you create which you intend to include in an `AjaxCompositeValidator`**. +The abstract [`BaseValidator`](./01-validators.md#basevalidator) class provides an abstract `getValidationHints()` method which must return an array. This array should contain the full validation requirements of each field that will be validated by a given validator. **You should implement this method in any custom validators you create which you intend to include in an `AjaxCompositeValidator`**. -All of the validators included in this module that perform their own validation implementations implement the `getValidationHints` method, so their validation requirements are included in the validation hints attribute. +All of the validators included in this module that perform their own validation implementations implement the `getValidationHints()` method, so their validation requirements are included in the validation hints attribute. ## Syntax for `data-signify-validation-hints` and `getValidationHints` @@ -14,7 +14,7 @@ As mentioned above, the value of this attribute is an empty JSON array if there All validators include the field's name in the JSON object for that field. The key for that data is 'name'. -All validators include a `tab` key (using the `getTabForField` method provided by `BaseValidator`) for each field being validated if the field is inside a tab. The value is the return value from calling `ID` on the tab. Note that the `TabSet.ss` template prepends this value with "tab-" for the actual ID attribute of the tab link element. +All validators include a `tab` key (using the `getTabForField()` method provided by `BaseValidator`) for each field being validated if the field is inside a tab. The value is the return value from calling `ID` on the tab. Note that the `TabSet.ss` template prepends this value with "tab-" for the actual ID attribute of the tab link element. **See also [the known issue](#tab-sometimes-missing) relating to this.** When implementing `getValidationHints` in your own validators, make sure to document the syntax outputted by those validators so that anyone writing tests for them knows what to expect. @@ -123,10 +123,10 @@ AjaxCompositeValidator::create()->setAddValidationHint(false); Any validation in the `validate` method of a `FormField` or `DataObject` is not currently covered by the validation hints. For any built-in `FormField`s that shouldn't be much of a problem, as the type of the field element and, for `input` elements the `type` attribute (and for non html-5 implementations of some fields the class selectors), already give clues as to the type of data that is valid. -For custom validation this could be worked around by adding a `Validator` that implements `getValidationHints` and simply returns hints for that internal validation, without performing any validation of its own. +For custom validation this could be worked around by adding a `Validator` that implements `getValidationHints()` and simply returns hints for that internal validation, without performing any validation of its own. ### Tab Sometimes Missing -Sometimes the `tab` key may be missing from a field's validation hint even though the field is definitely in a tab. Unfortunately whenever `flattenFields` is called on a `FieldList`, this changes the `containerFieldList` value for that field, so while the form and the field list know where the field resides, the field thinks it is sitting inside the flattened list and doesn't know anything about the original list inside the form. +Sometimes the `tab` key may be missing from a field's validation hint even though the field is definitely in a tab. Unfortunately whenever `flattenFields()` is called on a `FieldList`, this changes the `containerFieldList` value for that field, so while the form and the field list know where the field resides, the field thinks it is sitting inside the flattened list and doesn't know anything about the original list inside the form. This has been [raised as an issue](https://github.com/silverstripe/silverstripe-framework/issues/10054) against `silverstripe/framework` but until it is resolved, tests will have to have an alternative way of finding the field other than relying on the `tab` key in the hint object. From 2c547383d63b0450b5b3e95ba7da076f87e56d73 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:08:55 +1300 Subject: [PATCH 06/17] refactor: Fix linting issue - return shouldn't be used outside functions. --- client/lang/en.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/client/lang/en.js b/client/lang/en.js index 399d010..55969ae 100644 --- a/client/lang/en.js +++ b/client/lang/en.js @@ -1,12 +1,13 @@ /* eslint-disable no-undef */ if (typeof ss === 'undefined' || typeof ss.i18n === 'undefined') { // On the front-end for many applications the silverstripe/admin i18n script won't be loaded. - return; + console.error('Class ss.i18n not defined'); +} else { + ss.i18n.addDictionary('en', { + 'Signify_AjaxCompositeValidator.CANNOT_VALIDATE': 'Could not validate. Aborting AJAX validation.', + 'Signify_AjaxCompositeValidator.CAPTCHA_VALIDATION_ERROR': 'Please answer the captcha.', + 'Signify_AjaxCompositeValidator.VALIDATION_ERROR_TOAST': 'Validation Error', + 'Signify_AjaxCompositeValidator.VALIDATION_ERRORS': 'There are validation errors on this form, please fix them before saving or publishing.', + 'ElementPublishAction.SUCCESS_NOTIFICATION': "Published '{title}' successfully", + }); } -ss.i18n.addDictionary('en', { - 'Signify_AjaxCompositeValidator.CANNOT_VALIDATE': 'Could not validate. Aborting AJAX validation.', - 'Signify_AjaxCompositeValidator.CAPTCHA_VALIDATION_ERROR': 'Please answer the captcha.', - 'Signify_AjaxCompositeValidator.VALIDATION_ERROR_TOAST': 'Validation Error', - 'Signify_AjaxCompositeValidator.VALIDATION_ERRORS': 'There are validation errors on this form, please fix them before saving or publishing.', - 'ElementPublishAction.SUCCESS_NOTIFICATION': "Published '{title}' successfully", -}); From 9e9093a36c3abf0865412b09bc2c77fdb2a5bf25 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:09:24 +1300 Subject: [PATCH 07/17] feat: Explicitly require framework 4.10 and declare php constraint. Apparently the require-dev is used when identifying constraints, so this could have had the effect of constraining framework to 4.10 in a round-about way. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 4274417..c4baeb0 100644 --- a/composer.json +++ b/composer.json @@ -40,11 +40,11 @@ "signify-nz/silverstripe-composable-validators": "self.version" }, "require": { - "silverstripe/framework": "^4.7.0", + "php": "^7.3 || ^8.0", + "silverstripe/framework": "^4.10.0", "signify-nz/silverstripe-searchfilter-arraylist": "^1.0.0" }, "require-dev": { - "silverstripe/framework": "^4.10.0", "silverstripe/cms": "^4.0", "silverstripe/asset-admin": "^1.6", "dnadesign/silverstripe-elemental": "^4.0", From d9c31a353abe7d891cb8e2ebf4875c090be635a2 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:10:40 +1300 Subject: [PATCH 08/17] feat: Add missing return typehints and convert classname to self. --- src/Traits/ValidatesMultipleFields.php | 8 ++++---- src/Traits/ValidatesMultipleFieldsWithConfig.php | 4 ++-- src/Validators/AjaxCompositeValidator.php | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Traits/ValidatesMultipleFields.php b/src/Traits/ValidatesMultipleFields.php index 6bf987d..82865fd 100644 --- a/src/Traits/ValidatesMultipleFields.php +++ b/src/Traits/ValidatesMultipleFields.php @@ -43,7 +43,7 @@ public function getFields(): array * @param string[] $fields * @return $this */ - public function addFields(array $fields) + public function addFields(array $fields): self { $this->fields = array_merge($this->fields, ArrayLib::valuekey($fields)); return $this; @@ -55,7 +55,7 @@ public function addFields(array $fields) * @param string $field * @return $this */ - public function addField(string $field) + public function addField(string $field): self { $this->fields[$field] = $field; return $this; @@ -67,7 +67,7 @@ public function addField(string $field) * @param string $field * @return $this */ - public function removeField(string $field) + public function removeField(string $field): self { unset($this->fields[$field]); return $this; @@ -79,7 +79,7 @@ public function removeField(string $field) * @param string[] $fields * @return $this */ - public function removeFields(array $fields) + public function removeFields(array $fields): self { foreach ($fields as $field) { unset($this->fields[$field]); diff --git a/src/Traits/ValidatesMultipleFieldsWithConfig.php b/src/Traits/ValidatesMultipleFieldsWithConfig.php index 0e5620d..b7b48b2 100644 --- a/src/Traits/ValidatesMultipleFieldsWithConfig.php +++ b/src/Traits/ValidatesMultipleFieldsWithConfig.php @@ -32,7 +32,7 @@ public function getFields(): array * @param string[][] $fields * @return $this */ - public function addFields(array $fields) + public function addFields(array $fields): self { foreach ($fields as $field => $config) { $this->addField($field, $config); @@ -47,7 +47,7 @@ public function addFields(array $fields) * @param string[] $config The config for the field. See documentation for the validator as to what is valid. * @return $this */ - public function addField(string $field, array $config) + public function addField(string $field, array $config): self { if (empty($config)) { throw new InvalidArgumentException('$config cannot be empty.'); diff --git a/src/Validators/AjaxCompositeValidator.php b/src/Validators/AjaxCompositeValidator.php index d5dbb6f..f5c49b1 100644 --- a/src/Validators/AjaxCompositeValidator.php +++ b/src/Validators/AjaxCompositeValidator.php @@ -169,7 +169,7 @@ public function php($data) * @param bool $addHint * @return $this */ - public function setAddValidationHint(bool $addHint): AjaxCompositeValidator + public function setAddValidationHint(bool $addHint): self { $this->addValidationHint = $addHint; return $this; @@ -194,7 +194,7 @@ public function getAddValidationHint(): bool * @param bool $ajax * @return $this */ - public function setAjax(bool $ajax): AjaxCompositeValidator + public function setAjax(bool $ajax): self { $this->ajax = $ajax; return $this; @@ -216,7 +216,7 @@ public function getAjax(): bool * * @param Form|null $oldForm */ - private function addValidationHint(?Form $oldForm) + private function addValidationHint(?Form $oldForm): void { // Always make sure to remove the attribute in case it has been set. $dataAttribute = 'data-signify-validation-hints'; From 43cfa4c7d186c6887443eb97689070a26664e453 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:10:57 +1300 Subject: [PATCH 09/17] chore: Ignore node_modules for phpcs. --- phpcs.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 489db0d..e51fdba 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -5,6 +5,7 @@ */vendor/* */thirdparty/* + */node_modules/* From 8c9ba92866855e28404a06761f85a44baf40fc0e Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:17:36 +1300 Subject: [PATCH 10/17] chore: Don't run phpcs over javascript or css files. --- phpcs.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index e51fdba..b476f32 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -6,6 +6,7 @@ */vendor/* */thirdparty/* */node_modules/* + *\.(css|js) From 2be3368b9c14bad45f7fb6e61f5690c7bf8ee60d Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 13:20:27 +1300 Subject: [PATCH 11/17] refactor: Conform with modified PSR12 linting rules. --- src/Validators/BaseValidator.php | 2 +- src/Validators/DependentRequiredFieldsValidator.php | 4 ++-- src/Validators/RequiredBlocksValidator.php | 8 ++++---- .../ExtensionTests/GridFieldMessagesExtensionTest.php | 10 ++++++++-- .../php/ValidatorTests/AjaxCompositeValidatorTest.php | 1 - .../DependentRequiredFieldsValidatorTest.php | 3 ++- tests/php/ValidatorTests/RegexFieldsValidatorTest.php | 6 ++++-- .../php/ValidatorTests/RequiredFieldsValidatorTest.php | 3 ++- .../php/ValidatorTests/WarningFieldsValidatorTest.php | 3 ++- 9 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Validators/BaseValidator.php b/src/Validators/BaseValidator.php index 93ac51c..7c6df0b 100644 --- a/src/Validators/BaseValidator.php +++ b/src/Validators/BaseValidator.php @@ -15,7 +15,7 @@ abstract class BaseValidator extends Validator * * @return string[] */ - public abstract function getValidationHints(): array; + abstract public function getValidationHints(): array; /** * Get the form field from a field list. diff --git a/src/Validators/DependentRequiredFieldsValidator.php b/src/Validators/DependentRequiredFieldsValidator.php index dbe5169..085bb6f 100644 --- a/src/Validators/DependentRequiredFieldsValidator.php +++ b/src/Validators/DependentRequiredFieldsValidator.php @@ -13,8 +13,8 @@ * A validator used to ensure certain required fields have values if their dependencies are met. * * Configuration arrays for this validator are an array of fields with SearchFilter syntax and the - * corresponding value(s). In this example, 'StartsWithField' will be required only if the value of 'DependencyField' starts - * with the string 'some': + * corresponding value(s). In this example, 'StartsWithField' will be required only if the value of + * 'DependencyField' starts with the string 'some': * $validator->addField('StartsWithField', ['DependencyField:StartsWith' => 'some']); * * This validator is best used within an AjaxCompositeValidator in conjunction with diff --git a/src/Validators/RequiredBlocksValidator.php b/src/Validators/RequiredBlocksValidator.php index 0c22640..23e91f7 100644 --- a/src/Validators/RequiredBlocksValidator.php +++ b/src/Validators/RequiredBlocksValidator.php @@ -224,8 +224,8 @@ protected function setErrorMessages(array $errors) $min = (int)$this->required[$blockClass]['min']; $message .= _t( self::class . '.TOO_FEW', - "Too few '{blockType}' blocks, at least {count} is required.|Too few '{blockType}' blocks," - . ' at least {count} are required.', + "Too few '{blockType}' blocks, at least {count} is required.|Too few '{blockType}'" + . ' blocks, at least {count} are required.', [ 'blockType' => $blockType, 'count' => $min, @@ -236,8 +236,8 @@ protected function setErrorMessages(array $errors) $max = (int)$this->required[$blockClass]['max']; $message .= _t( self::class . '.TOO_MANY', - "Too many '{blockType}' blocks, only {count} is allowed.|Too many '{blockType}' blocks," - . ' up to {count} are allowed.', + "Too many '{blockType}' blocks, only {count} is allowed.|Too many '{blockType}'" + . ' blocks, up to {count} are allowed.', [ 'blockType' => $blockType, 'count' => $max, diff --git a/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php b/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php index 6458822..265ed20 100644 --- a/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php +++ b/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php @@ -30,7 +30,10 @@ public function testValidationMessageDisplaysWithMessages() $form->validationResult(); $gridField->Field(); - $this->assertStringContainsString('

error

', $gridField->getDescription()); + $this->assertStringContainsString( + '

error

', + $gridField->getDescription() + ); } /** @@ -45,6 +48,9 @@ public function testValidationMessageDoesntDisplayWithoutMessages() $form->validationResult(); $gridField->Field(); - $this->assertStringNotContainsString('

', (string)$gridField->getDescription()); + $this->assertStringNotContainsString( + '

', + (string)$gridField->getDescription() + ); } } diff --git a/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php b/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php index 8e9712b..0785cde 100644 --- a/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php +++ b/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php @@ -134,5 +134,4 @@ private function validateHints(Form $form, string $hints) ]; $this->assertSame($expectedHints, $hints); } - } diff --git a/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php b/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php index 8878e69..5dd1a84 100644 --- a/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php @@ -212,7 +212,8 @@ private function setupExpectedMessages($fields) $fieldName = 'DependentField4'; $field = $fields->dataFieldByName($fieldName); $stringFieldTitle = $fields->dataFieldByName('StringField')->Title(); - $messages[$fieldName] = '"' . $field->Title() . "\" is required when the value for \"$stringFieldTitle\" starts with" + $messages[$fieldName] = '"' . $field->Title() + . "\" is required when the value for \"$stringFieldTitle\" starts with" . " 'str', and the value for \"$stringFieldTitle\" does not contain 'nothing', and the" . " value for \"$stringFieldTitle\" ends with 'ing' or 'blah blah'"; diff --git a/tests/php/ValidatorTests/RegexFieldsValidatorTest.php b/tests/php/ValidatorTests/RegexFieldsValidatorTest.php index d89d3a0..53309a4 100644 --- a/tests/php/ValidatorTests/RegexFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/RegexFieldsValidatorTest.php @@ -25,7 +25,8 @@ public function testValidationMessageIfRegexDoesntMatch() $this->assertEquals('validation', $message['messageType']); $this->assertEquals( 'The value for "' . FormField::name_to_label('FieldOne') - . '" must match the pattern /no match/', $message['message'] + . '" must match the pattern /no match/', + $message['message'] ); } @@ -50,7 +51,8 @@ public function testValidationMessageConcatenation() $this->assertEquals('validation', $message['messageType']); $this->assertEquals( 'The value for "' . FormField::name_to_label('FieldOne') - . '" must not match or must pass testing', $message['message'] + . '" must not match or must pass testing', + $message['message'] ); } diff --git a/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php b/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php index 9b0cbe9..d0f862e 100644 --- a/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php @@ -26,7 +26,8 @@ public function testValidationMessageIfEmpty() $this->assertEquals('required', $message['messageType']); $this->assertEquals( '"' . FormField::name_to_label('FieldOne') - . '" is required', $message['message'] + . '" is required', + $message['message'] ); } diff --git a/tests/php/ValidatorTests/WarningFieldsValidatorTest.php b/tests/php/ValidatorTests/WarningFieldsValidatorTest.php index 4f176db..83bf2a8 100644 --- a/tests/php/ValidatorTests/WarningFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/WarningFieldsValidatorTest.php @@ -23,7 +23,8 @@ public function testValidationMessageIfEmpty() $this->assertEquals('warning', $message['messageType']); $this->assertEquals( '"' . FormField::name_to_label('FieldOne') - . '" has no value and will not display or be used', $message['message'] + . '" has no value and will not display or be used', + $message['message'] ); } From 3ef9d4e2f034d58f40f389cfaf3ae73519d1a884 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 14:24:08 +1300 Subject: [PATCH 12/17] fix: Correctly check for the existence of nocaptcha's "nocaptcha_handleCaptcha" function. --- client/src/js/AjaxCompositeValidator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/js/AjaxCompositeValidator.js b/client/src/js/AjaxCompositeValidator.js index 6059180..020640a 100644 --- a/client/src/js/AjaxCompositeValidator.js +++ b/client/src/js/AjaxCompositeValidator.js @@ -182,7 +182,7 @@ // backend. } else { // On the front-end we have to make the form submit. - if (typeof yourFunctionName == 'nocaptcha_handleCaptcha') { + if (typeof nocaptcha_handleCaptcha === 'function') { const form = $form.get(0); nocaptcha_handleCaptcha(form, form.submitWithoutEvent.bind(form)); } else { From 33e62b061e506ef43f812e1c175ff470d01d7257 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 14:24:44 +1300 Subject: [PATCH 13/17] chore: Compile production javascript. --- client/dist/AjaxCompositeValidator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/dist/AjaxCompositeValidator.js b/client/dist/AjaxCompositeValidator.js index eb8a1b5..260f470 100644 --- a/client/dist/AjaxCompositeValidator.js +++ b/client/dist/AjaxCompositeValidator.js @@ -1 +1 @@ -(()=>{var t,a={504:()=>{function t(a){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(a)}!function(a){function e(){return a.isFunction(a.entwine)}function n(t){return a("

").text(t).html()}function i(t){return t.replace(/\n/g,"
")}function r(t,a){var e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if("undefined"!=typeof ss&&void 0!==ss.i18n)return ss.i18n.inject(ss.i18n._t(t,a),e);if(e){var n=new RegExp("{([A-Za-z0-9_]*)}","g");a=a.replace(n,(function(t,a){return e[a]?e[a]:t}))}return a}function o(t,i){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,o=n(t);a.isFunction(a.noticeAdd)&&a.noticeAdd({text:o,type:i,stayTime:5e3,inEffect:{left:"0",opacity:"show"}}),e()||null==r||a("body,html").animate({scrollTop:r.offset().top},500)}function s(t,a){var e="".concat(t.attr("id"),"_"),n=t.find("#".concat(e,"error"));n.text(a),a?(n.addClass("validation validation-bar"),n.show(),n.attr("tabindex",-1),n.focus()):(n.removeClass("validation"),n.hide())}function l(t,n){n.addClass("validationerror"),s(n,r("Signify_AjaxCompositeValidator.VALIDATION_ERRORS","There are validation errors on this form, please fix them before saving or publishing."));for(var l="".concat(n.attr("id"),"_"),d=0;d").html(i(c.message)).addClass("js-ajax-validation message ".concat(c.messageType)).attr("id","".concat(u,"_validation-message"));e()?b.insertBefore(v):(v.addClass("holder-required"),b.addClass("form__message form__message--required"),b.insertAfter(v)),a("#".concat(u)).data("old-described-by",a("#".concat(u)).attr("aria-describedby")),a("#".concat(u)).attr("aria-describedby","".concat(u,"_validation-message"))}else{a("
").html(i(c.message)).addClass("js-ajax-validation message ".concat(c.messageType)).insertAfter(n.find("#".concat(l,"error")))}}o(r("Signify_AjaxCompositeValidator.VALIDATION_ERROR_TOAST","Validation Error"),"error",n)}function d(t){s(t,""),t.removeClass("validationerror"),t.find(".holder-required").removeClass("holder-required"),t.find(".js-ajax-validation").remove(),t.find("a.ui-tabs-anchor").each((function(t,e){a(e).removeClass("font-icon-attention-1 tab-validation"),e.className=e.className.replace(new RegExp(/tab-validation--\w*/g,""))})),t.find("[aria-describedby]").each((function(t,e){var n=a(e);n.data("old-described-by")&&(n.attr("aria-describedby",n.data("old-described-by")),n.data("old-described-by",null))}))}function c(t,a){if(e()){if(a){var n=t.closest(".cms-container");n.length&&n.submitForm(t,a)}}else if("nocaptcha_handleCaptcha"==typeof yourFunctionName){var i=t.get(0);nocaptcha_handleCaptcha(i,i.submitWithoutEvent.bind(i))}else t.get(0).submitWithoutEvent()}function u(e,n,i){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:a;if(e.preventDefault(),!n){var u,f,v,m,b=null!==(u=e.delegatedEvent)&&void 0!==u?u:e,p=null!==(f=b.originalEvent)&&void 0!==f?f:b,h=s(null!==(v=p.submitter)&&void 0!==v?v:p.target);if(h.hasClass("element-editor__hover-bar-area"))return!1;null!==(m=h.attr("name"))&&void 0!==m&&m.startsWith("action_")&&(n=h.get(0))}s(n).attr("disabled",!0);var g=void 0!==i?i:s(this);function y(a){var e=!1;!0!==a&&a.length&&(e=!0);var i=g.find("div.g-recaptcha");if(i.length>0&&"object"===("undefined"==typeof grecaptcha?"undefined":t(grecaptcha))){var o=i.data("widgetid");if(null!=o&&!grecaptcha.getResponse(o)){!0===a&&(a=[]);var d=r("Signify_AjaxCompositeValidator.CAPTCHA_VALIDATION_ERROR","Please answer the captcha.");a.push({fieldName:null,message:d,messageType:"required"}),e=!0}}return g.removeClass("js-validating"),e?(l(a,g),s(n).attr("disabled",!1),s(n).removeClass("loading"),!1):c(g,n)}function _(t,a,e){return o(r("Signify_AjaxCompositeValidator.CANNOT_VALIDATE","Could not validate. Aborting AJAX validation."),"error"),console.error("Error with AJAX validation request: ".concat(a,": ").concat(e)),c(g,n)}g.addClass("js-validating"),d(g);var A=g.data("validation-link"),C=g.serializeArray();return C.push({name:"action_app_ajaxValidate",value:"1"}),n&&C.push({name:"_original_action",value:n.getAttribute("name")}),s.ajax({type:"POST",url:A,data:C,success:y,error:_}),!1}if(!e())return a("form.js-multi-validator-ajax").on("submit",u),void a("form.js-multi-validator-ajax").each((function(t,e){e.submitWithoutEvent=e.submit,e.submit=function(){var t;"function"==typeof Event?t=new Event("submit",{bubbles:!0,cancelable:!0}):(t=document.createEvent("Event")).initEvent("submit",!0,!0),t.submitter=a(e).find('button[type="submit"], input[type="submit"]').get(0),e.dispatchEvent(t)}}));a.entwine("ss",(function(t){t("form.js-multi-validator-ajax").entwine({onsubmit:function(a,e){return u(a,e,this,t)}})}))}(jQuery)},1:()=>{}},e={};function n(t){var i=e[t];if(void 0!==i)return i.exports;var r=e[t]={exports:{}};return a[t](r,r.exports,n),r.exports}n.m=a,t=[],n.O=(a,e,i,r)=>{if(!e){var o=1/0;for(c=0;c=r)&&Object.keys(n.O).every((t=>n.O[t](e[l])))?e.splice(l--,1):(s=!1,r0&&t[c-1][2]>r;c--)t[c]=t[c-1];t[c]=[e,i,r]},n.o=(t,a)=>Object.prototype.hasOwnProperty.call(t,a),(()=>{var t={458:0,177:0};n.O.j=a=>0===t[a];var a=(a,e)=>{var i,r,[o,s,l]=e,d=0;for(i in s)n.o(s,i)&&(n.m[i]=s[i]);if(l)var c=l(n);for(a&&a(e);dn(504)));var i=n.O(void 0,[177],(()=>n(1)));i=n.O(i)})(); \ No newline at end of file +(()=>{var t,a={504:()=>{function t(a){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(a)}!function(a){function e(){return a.isFunction(a.entwine)}function n(t){return a("
").text(t).html()}function i(t){return t.replace(/\n/g,"
")}function r(t,a){var e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if("undefined"!=typeof ss&&void 0!==ss.i18n)return ss.i18n.inject(ss.i18n._t(t,a),e);if(e){var n=new RegExp("{([A-Za-z0-9_]*)}","g");a=a.replace(n,(function(t,a){return e[a]?e[a]:t}))}return a}function o(t,i){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,o=n(t);a.isFunction(a.noticeAdd)&&a.noticeAdd({text:o,type:i,stayTime:5e3,inEffect:{left:"0",opacity:"show"}}),e()||null==r||a("body,html").animate({scrollTop:r.offset().top},500)}function s(t,a){var e="".concat(t.attr("id"),"_"),n=t.find("#".concat(e,"error"));n.text(a),a?(n.addClass("validation validation-bar"),n.show(),n.attr("tabindex",-1),n.focus()):(n.removeClass("validation"),n.hide())}function l(t,n){n.addClass("validationerror"),s(n,r("Signify_AjaxCompositeValidator.VALIDATION_ERRORS","There are validation errors on this form, please fix them before saving or publishing."));for(var l="".concat(n.attr("id"),"_"),d=0;d").html(i(c.message)).addClass("js-ajax-validation message ".concat(c.messageType)).attr("id","".concat(u,"_validation-message"));e()?b.insertBefore(v):(v.addClass("holder-required"),b.addClass("form__message form__message--required"),b.insertAfter(v)),a("#".concat(u)).data("old-described-by",a("#".concat(u)).attr("aria-describedby")),a("#".concat(u)).attr("aria-describedby","".concat(u,"_validation-message"))}else{a("
").html(i(c.message)).addClass("js-ajax-validation message ".concat(c.messageType)).insertAfter(n.find("#".concat(l,"error")))}}o(r("Signify_AjaxCompositeValidator.VALIDATION_ERROR_TOAST","Validation Error"),"error",n)}function d(t){s(t,""),t.removeClass("validationerror"),t.find(".holder-required").removeClass("holder-required"),t.find(".js-ajax-validation").remove(),t.find("a.ui-tabs-anchor").each((function(t,e){a(e).removeClass("font-icon-attention-1 tab-validation"),e.className=e.className.replace(new RegExp(/tab-validation--\w*/g,""))})),t.find("[aria-describedby]").each((function(t,e){var n=a(e);n.data("old-described-by")&&(n.attr("aria-describedby",n.data("old-described-by")),n.data("old-described-by",null))}))}function c(t,a){if(e()){if(a){var n=t.closest(".cms-container");n.length&&n.submitForm(t,a)}}else if("function"==typeof nocaptcha_handleCaptcha){var i=t.get(0);nocaptcha_handleCaptcha(i,i.submitWithoutEvent.bind(i))}else t.get(0).submitWithoutEvent()}function u(e,n,i){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:a;if(e.preventDefault(),!n){var u,f,v,m,b=null!==(u=e.delegatedEvent)&&void 0!==u?u:e,p=null!==(f=b.originalEvent)&&void 0!==f?f:b,h=s(null!==(v=p.submitter)&&void 0!==v?v:p.target);if(h.hasClass("element-editor__hover-bar-area"))return!1;null!==(m=h.attr("name"))&&void 0!==m&&m.startsWith("action_")&&(n=h.get(0))}s(n).attr("disabled",!0);var g=void 0!==i?i:s(this);function y(a){var e=!1;!0!==a&&a.length&&(e=!0);var i=g.find("div.g-recaptcha");if(i.length>0&&"object"===("undefined"==typeof grecaptcha?"undefined":t(grecaptcha))){var o=i.data("widgetid");if(null!=o&&!grecaptcha.getResponse(o)){!0===a&&(a=[]);var d=r("Signify_AjaxCompositeValidator.CAPTCHA_VALIDATION_ERROR","Please answer the captcha.");a.push({fieldName:null,message:d,messageType:"required"}),e=!0}}return g.removeClass("js-validating"),e?(l(a,g),s(n).attr("disabled",!1),s(n).removeClass("loading"),!1):c(g,n)}function _(t,a,e){return o(r("Signify_AjaxCompositeValidator.CANNOT_VALIDATE","Could not validate. Aborting AJAX validation."),"error"),console.error("Error with AJAX validation request: ".concat(a,": ").concat(e)),c(g,n)}g.addClass("js-validating"),d(g);var A=g.data("validation-link"),C=g.serializeArray();return C.push({name:"action_app_ajaxValidate",value:"1"}),n&&C.push({name:"_original_action",value:n.getAttribute("name")}),s.ajax({type:"POST",url:A,data:C,success:y,error:_}),!1}if(!e())return a("form.js-multi-validator-ajax").on("submit",u),void a("form.js-multi-validator-ajax").each((function(t,e){e.submitWithoutEvent=e.submit,e.submit=function(){var t;"function"==typeof Event?t=new Event("submit",{bubbles:!0,cancelable:!0}):(t=document.createEvent("Event")).initEvent("submit",!0,!0),t.submitter=a(e).find('button[type="submit"], input[type="submit"]').get(0),e.dispatchEvent(t)}}));a.entwine("ss",(function(t){t("form.js-multi-validator-ajax").entwine({onsubmit:function(a,e){return u(a,e,this,t)}})}))}(jQuery)},1:()=>{}},e={};function n(t){var i=e[t];if(void 0!==i)return i.exports;var r=e[t]={exports:{}};return a[t](r,r.exports,n),r.exports}n.m=a,t=[],n.O=(a,e,i,r)=>{if(!e){var o=1/0;for(c=0;c=r)&&Object.keys(n.O).every((t=>n.O[t](e[l])))?e.splice(l--,1):(s=!1,r0&&t[c-1][2]>r;c--)t[c]=t[c-1];t[c]=[e,i,r]},n.o=(t,a)=>Object.prototype.hasOwnProperty.call(t,a),(()=>{var t={458:0,177:0};n.O.j=a=>0===t[a];var a=(a,e)=>{var i,r,[o,s,l]=e,d=0;for(i in s)n.o(s,i)&&(n.m[i]=s[i]);if(l)var c=l(n);for(a&&a(e);dn(504)));var i=n.O(void 0,[177],(()=>n(1)));i=n.O(i)})(); \ No newline at end of file From 0fd8827b4ddd2b71f9ef58c92398ab832a4a52b8 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 23 Mar 2022 14:30:08 +1300 Subject: [PATCH 14/17] refactor: Add missing return typehints to tests. --- .../DataObjectDefaultAjaxExtensionTest.php | 2 +- ...ObjectValidationExemptionExtensionTest.php | 2 +- ...equestValidationExemptionExtensionTest.php | 2 +- .../GridFieldMessagesExtensionTest.php | 4 +- .../ValidatesMultipleFieldsTest.php | 16 +++---- .../ValidatesMultipleFieldsWithConfigTest.php | 18 ++++---- .../AjaxCompositeValidatorTest.php | 14 +++---- .../DependentRequiredFieldsValidatorTest.php | 18 ++++---- .../FieldHasValueValidatorTest.php | 14 +++---- .../RegexFieldsValidatorTest.php | 22 +++++----- .../RequiredBlocksValidatorTest.php | 42 +++++++++---------- .../RequiredFieldsValidatorTest.php | 12 +++--- .../SimpleFieldsValidatorTest.php | 10 ++--- .../WarningFieldsValidatorTest.php | 8 ++-- 14 files changed, 92 insertions(+), 92 deletions(-) diff --git a/tests/php/ExtensionTests/DataObjectDefaultAjaxExtensionTest.php b/tests/php/ExtensionTests/DataObjectDefaultAjaxExtensionTest.php index a8cb4c9..435bd19 100644 --- a/tests/php/ExtensionTests/DataObjectDefaultAjaxExtensionTest.php +++ b/tests/php/ExtensionTests/DataObjectDefaultAjaxExtensionTest.php @@ -14,7 +14,7 @@ class DataObjectDefaultAjaxExtensionTest extends SapphireTest DataObject::class => [DataObjectDefaultAjaxExtension::class], ]; - public function testValidatorIsReplaced() + public function testValidatorIsReplaced(): void { $dataObject = new TestElementalBlock(); $validator = $dataObject->getCMSCompositeValidator(); diff --git a/tests/php/ExtensionTests/DataObjectValidationExemptionExtensionTest.php b/tests/php/ExtensionTests/DataObjectValidationExemptionExtensionTest.php index 2aa4363..ef3301f 100644 --- a/tests/php/ExtensionTests/DataObjectValidationExemptionExtensionTest.php +++ b/tests/php/ExtensionTests/DataObjectValidationExemptionExtensionTest.php @@ -18,7 +18,7 @@ class DataObjectValidationExemptionExtensionTest extends SapphireTest /** * These actions should be validation exempt if they're present. */ - public function testActionsAreValidationExempt() + public function testActionsAreValidationExempt(): void { $page = new TestSiteTree(); $actions = $page->getCMSActions(); diff --git a/tests/php/ExtensionTests/GridFieldItemRequestValidationExemptionExtensionTest.php b/tests/php/ExtensionTests/GridFieldItemRequestValidationExemptionExtensionTest.php index ae2094a..eb8eef2 100644 --- a/tests/php/ExtensionTests/GridFieldItemRequestValidationExemptionExtensionTest.php +++ b/tests/php/ExtensionTests/GridFieldItemRequestValidationExemptionExtensionTest.php @@ -18,7 +18,7 @@ class GridFieldItemRequestValidationExemptionExtensionTest extends SapphireTest /** * These actions should be validation exempt if they're present. */ - public function testActionsAreValidationExempt() + public function testActionsAreValidationExempt(): void { $itemRequest = new GridFieldDetailForm_ItemRequest( new GridField('testField'), diff --git a/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php b/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php index 265ed20..829fbc6 100644 --- a/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php +++ b/tests/php/ExtensionTests/GridFieldMessagesExtensionTest.php @@ -21,7 +21,7 @@ class GridFieldMessagesExtensionTest extends SapphireTest /** * A gridfield that fails validation should display the validation error in the description. */ - public function testValidationMessageDisplaysWithMessages() + public function testValidationMessageDisplaysWithMessages(): void { $gridField = new GridField('testfield', 'testfield', new ArrayList(), new GridFieldConfig()); $fieldList = new FieldList([$gridField]); @@ -39,7 +39,7 @@ public function testValidationMessageDisplaysWithMessages() /** * A gridfield that passes validation should not display a validation error in the description. */ - public function testValidationMessageDoesntDisplayWithoutMessages() + public function testValidationMessageDoesntDisplayWithoutMessages(): void { $gridField = new GridField('testfield', 'testfield', new ArrayList(), new GridFieldConfig()); $fieldList = new FieldList([$gridField]); diff --git a/tests/php/TraitTests/ValidatesMultipleFieldsTest.php b/tests/php/TraitTests/ValidatesMultipleFieldsTest.php index 0620856..69720fc 100644 --- a/tests/php/TraitTests/ValidatesMultipleFieldsTest.php +++ b/tests/php/TraitTests/ValidatesMultipleFieldsTest.php @@ -19,7 +19,7 @@ private function getFieldsForTests() /** * Should be able to instantiate with no arguments. */ - public function testConstructingWithoutFields() + public function testConstructingWithoutFields(): void { $validator = new TestMultiFieldValidator(); $this->assertEmpty($validator->getFields()); @@ -28,7 +28,7 @@ public function testConstructingWithoutFields() /** * Should be able to instantiate with an array of field names. */ - public function testConstructingWithArray() + public function testConstructingWithArray(): void { $fields = $this->getFieldsForTests(); $validator = new TestMultiFieldValidator($fields); @@ -38,7 +38,7 @@ public function testConstructingWithArray() /** * Should be able to instantiate with an argument list of field names. */ - public function testConstructingWithArguments() + public function testConstructingWithArguments(): void { $validator = new TestMultiFieldValidator( 'Title', @@ -52,7 +52,7 @@ public function testConstructingWithArguments() /** * Should be able to remove all fields at once. */ - public function testRemoveValidation() + public function testRemoveValidation(): void { $validator = new TestMultiFieldValidator($this->getFieldsForTests()); $validator->removeValidation(); @@ -62,7 +62,7 @@ public function testRemoveValidation() /** * Should be able to remove fields one at a time, by name. */ - public function testRemoveField() + public function testRemoveField(): void { $fields = $this->getFieldsForTests(); $validator = new TestMultiFieldValidator($fields); @@ -82,7 +82,7 @@ public function testRemoveField() /** * Should be able to remove many fields at once by name. */ - public function testRemoveFields() + public function testRemoveFields(): void { $fields = $this->getFieldsForTests(); $validator = new TestMultiFieldValidator($fields); @@ -98,7 +98,7 @@ public function testRemoveFields() /** * Should be able to add fields one at a time, by name. */ - public function testAddField() + public function testAddField(): void { $validator = new TestMultiFieldValidator(); // Add a couple of fields. @@ -126,7 +126,7 @@ public function testAddField() /** * Should be able to add many fields at once by name. */ - public function testAddFields() + public function testAddFields(): void { $validator = new TestMultiFieldValidator(); // Add a couple of fields. diff --git a/tests/php/TraitTests/ValidatesMultipleFieldsWithConfigTest.php b/tests/php/TraitTests/ValidatesMultipleFieldsWithConfigTest.php index 3a5ee2c..1c67c7f 100644 --- a/tests/php/TraitTests/ValidatesMultipleFieldsWithConfigTest.php +++ b/tests/php/TraitTests/ValidatesMultipleFieldsWithConfigTest.php @@ -7,7 +7,7 @@ class ValidatesMultipleFieldsWithConfigTest extends SapphireTest { - private function getFieldsForTests() + private function getFieldsForTests(): array { return [ 'Title' => ['config1'], @@ -20,7 +20,7 @@ private function getFieldsForTests() /** * Should be able to instantiate with no arguments or an empty array. */ - public function testConstructingWithoutFields() + public function testConstructingWithoutFields(): void { $validator = new TestMultiFieldWithConfigValidator(); $this->assertEmpty($validator->getFields()); @@ -31,7 +31,7 @@ public function testConstructingWithoutFields() /** * Should be able to instantiate with an array of field names and configuration arrays. */ - public function testConstructingWithArray() + public function testConstructingWithArray(): void { $fields = $this->getFieldsForTests(); $validator = new TestMultiFieldWithConfigValidator($fields); @@ -41,7 +41,7 @@ public function testConstructingWithArray() /** * Should not be able to instantiate with an array of field names and empty configuration arrays. */ - public function testConstructingWithEmptyArray() + public function testConstructingWithEmptyArray(): void { $this->expectException(InvalidArgumentException::class); new TestMultiFieldWithConfigValidator(['someField' => []]); @@ -50,7 +50,7 @@ public function testConstructingWithEmptyArray() /** * Should be able to remove all fields at once. */ - public function testRemoveValidation() + public function testRemoveValidation(): void { $validator = new TestMultiFieldWithConfigValidator($this->getFieldsForTests()); $validator->removeValidation(); @@ -60,7 +60,7 @@ public function testRemoveValidation() /** * Should be able to remove fields one at a time, by name. */ - public function testRemoveField() + public function testRemoveField(): void { $fields = $this->getFieldsForTests(); $fieldNames = array_keys($fields); @@ -83,7 +83,7 @@ public function testRemoveField() /** * Should be able to remove many fields at once by name. */ - public function testRemoveFields() + public function testRemoveFields(): void { $fields = $this->getFieldsForTests(); $fieldNames = array_keys($fields); @@ -102,7 +102,7 @@ public function testRemoveFields() /** * Should be able to add fields one at a time, by name. */ - public function testAddField() + public function testAddField(): void { $validator = new TestMultiFieldWithConfigValidator(); // Add a couple of fields. @@ -130,7 +130,7 @@ public function testAddField() /** * Should be able to add many fields at once by name. */ - public function testAddFields() + public function testAddFields(): void { $validator = new TestMultiFieldWithConfigValidator(); // Add a couple of fields. diff --git a/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php b/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php index 0785cde..ac8f0c7 100644 --- a/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php +++ b/tests/php/ValidatorTests/AjaxCompositeValidatorTest.php @@ -20,7 +20,7 @@ class AjaxCompositeValidatorTest extends SapphireTest * Validation hints for all validators should be added to the form. * If setting a new form, the validation hints should be removed from the old form. */ - public function testHasValidatorHints() + public function testHasValidatorHints(): void { $validator = $this->getNewValidatorInstance(); // Test form has validation hints from all validators. @@ -36,7 +36,7 @@ public function testHasValidatorHints() /** * Setting setAddValidationHint to false should result in no validation hints being set. */ - public function testInstanceOmitsValidatorHints() + public function testInstanceOmitsValidatorHints(): void { $validator = $this->getNewValidatorInstance(); $validator->setAddValidationHint(false); @@ -47,7 +47,7 @@ public function testInstanceOmitsValidatorHints() /** * Setting add_validation_hint to false should result in no validation hints being set. */ - public function testConfigOmitsValidatorHints() + public function testConfigOmitsValidatorHints(): void { Config::modify()->set(AjaxCompositeValidator::class, 'add_validation_hint', false); $validator = $this->getNewValidatorInstance(); @@ -59,7 +59,7 @@ public function testConfigOmitsValidatorHints() /** * All validators added through the addValidators method should be present in the validator. */ - public function testAddValidators() + public function testAddValidators(): void { $compositeValidator = new AjaxCompositeValidator(); $compositeValidator->addValidators([ @@ -82,7 +82,7 @@ public function testAddValidators() * If there is no validator of that type, one should be created and added to the composite validator. * Otherwise the existing validator should be returned. */ - public function testGetOrAddValidatorByType() + public function testGetOrAddValidatorByType(): void { $compositeValidator = new AjaxCompositeValidator(); // Confirm validator starts empty. @@ -102,7 +102,7 @@ public function testGetOrAddValidatorByType() * * @return AjaxCompositeValidator */ - private function getNewValidatorInstance() + private function getNewValidatorInstance(): AjaxCompositeValidator { $compositeValidator = new AjaxCompositeValidator(); $compositeValidator->addValidators([ @@ -119,7 +119,7 @@ private function getNewValidatorInstance() * @param Form $form The form which has the hints * @param string $hints The hints on the form */ - private function validateHints(Form $form, string $hints) + private function validateHints(Form $form, string $hints): void { $hints = json_decode($hints, true); $expectedHints = [ diff --git a/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php b/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php index 5dd1a84..2690c56 100644 --- a/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/DependentRequiredFieldsValidatorTest.php @@ -19,7 +19,7 @@ class DependentRequiredFieldsValidatorTest extends SapphireTest * that functionality comes from the signify-nz/silverstripe-searchfilter-arraylist * module which has unit tests for that. */ - public function testFieldNotRequiredIfDependencyNotMet() + public function testFieldNotRequiredIfDependencyNotMet(): void { $form = TestFormGenerator::getForm( [ @@ -41,7 +41,7 @@ public function testFieldNotRequiredIfDependencyNotMet() * that functionality comes from the signify-nz/silverstripe-searchfilter-arraylist * module which has unit tests for that. */ - public function testFieldRequiredIfDependencyMet() + public function testFieldRequiredIfDependencyMet(): void { $form = TestFormGenerator::getForm( [ @@ -73,7 +73,7 @@ public function testFieldRequiredIfDependencyMet() * that functionality comes from the signify-nz/silverstripe-searchfilter-arraylist * module which has unit tests for that. */ - public function testFieldRequiredIfNullishDependencyMet() + public function testFieldRequiredIfNullishDependencyMet(): void { $form = TestFormGenerator::getForm( [ @@ -95,7 +95,7 @@ public function testFieldRequiredIfNullishDependencyMet() * If the dependency field is missing, the field should not be required. * There's no way for the user to set the field if the field doesn't exist. */ - public function testFieldNotRequiredIfDependencyIsMissing() + public function testFieldNotRequiredIfDependencyIsMissing(): void { $form = TestFormGenerator::getForm( [ @@ -112,7 +112,7 @@ public function testFieldNotRequiredIfDependencyIsMissing() /** * If the required field doesn't exist, there should be no validation error message. */ - public function testNoValidationMessageIfFieldMissing() + public function testNoValidationMessageIfFieldMissing(): void { $form = TestFormGenerator::getForm( [ @@ -130,7 +130,7 @@ public function testNoValidationMessageIfFieldMissing() /** * Check that validation messages are correctly constructed to reflect the dependencies. */ - public function testSearchFilterValidationMessages() + public function testSearchFilterValidationMessages(): void { $fields = $this->setupMessageFields(); $validator = new DependentRequiredFieldsValidator([ @@ -160,7 +160,7 @@ public function testSearchFilterValidationMessages() * * @return FieldList */ - private function setupMessageFields() + private function setupMessageFields(): FieldList { $fieldList = new FieldList([ new TextField('DependentField1'), @@ -188,7 +188,7 @@ private function setupMessageFields() * @param FieldList $fields * @return string[] */ - private function setupExpectedMessages($fields) + private function setupExpectedMessages($fields): array { $messages = []; $fieldName = 'DependentField1'; @@ -230,7 +230,7 @@ private function setupExpectedMessages($fields) * All of the fields that are in both the form AND the validator should have the correct 'dependencies' validation * hints. */ - public function testValidationHints() + public function testValidationHints(): void { $form = TestFormGenerator::getForm( $formFields = [ diff --git a/tests/php/ValidatorTests/FieldHasValueValidatorTest.php b/tests/php/ValidatorTests/FieldHasValueValidatorTest.php index a966e71..0781229 100644 --- a/tests/php/ValidatorTests/FieldHasValueValidatorTest.php +++ b/tests/php/ValidatorTests/FieldHasValueValidatorTest.php @@ -46,7 +46,7 @@ public static function setUpBeforeClass(): void TestSiteTree::create()->publishSingle(); } - public function testSubmittedTextFieldValueDetection() + public function testSubmittedTextFieldValueDetection(): void { $result = $this->submitTestForm( [new TextField('TextFieldError')], @@ -63,7 +63,7 @@ public function testSubmittedTextFieldValueDetection() $this->assertEquals('success', $result->getBody()); } - public function testSubmittedSelectFieldValueDetection() + public function testSubmittedSelectFieldValueDetection(): void { $result = $this->submitTestForm( [new DropdownField('DropdownFieldError', null, [1,2,3])], @@ -80,7 +80,7 @@ public function testSubmittedSelectFieldValueDetection() $this->assertEquals('success', $result->getBody()); } - public function testSubmittedMultiSelectFieldValueDetection() + public function testSubmittedMultiSelectFieldValueDetection(): void { $result = $this->submitTestForm( [new ListboxField('ListboxFieldError', null, [1,2,3])], @@ -97,7 +97,7 @@ public function testSubmittedMultiSelectFieldValueDetection() $this->assertEquals('success', $result->getBody()); } - public function testSubmittedDatetimeFieldValueDetection() + public function testSubmittedDatetimeFieldValueDetection(): void { $result = $this->submitTestForm( [new DatetimeField('DatetimeFieldError')], @@ -114,7 +114,7 @@ public function testSubmittedDatetimeFieldValueDetection() $this->assertEquals('success', $result->getBody()); } - public function testSubmittedTreeDropdownFieldValueDetection() + public function testSubmittedTreeDropdownFieldValueDetection(): void { $result = $this->submitTestForm( [new TreeDropdownField('TreeDropdownFieldError', null, SiteTree::class)], @@ -131,7 +131,7 @@ public function testSubmittedTreeDropdownFieldValueDetection() $this->assertEquals('success', $result->getBody()); } - public function testSubmittedGridFieldValueDetection() + public function testSubmittedGridFieldValueDetection(): void { $emptyList = new ArrayList(); $emptyList->setDataClass(SiteTree::class); @@ -154,7 +154,7 @@ public function testSubmittedGridFieldValueDetection() * If an extension class implements updateFieldHasValue and returns a boolean value, that * value should be respected. If it returns null, the normal value checking logic proceeds. */ - public function testUpdateFieldHasValue() + public function testUpdateFieldHasValue(): void { TestFieldHasValueValidator::add_extension(TestFieldValueModifierExtension::class); diff --git a/tests/php/ValidatorTests/RegexFieldsValidatorTest.php b/tests/php/ValidatorTests/RegexFieldsValidatorTest.php index 53309a4..7e81fdd 100644 --- a/tests/php/ValidatorTests/RegexFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/RegexFieldsValidatorTest.php @@ -12,7 +12,7 @@ class RegexFieldsValidatorTest extends SapphireTest /** * If the value doesn't match the regex pattern, there should be a validation error message. */ - public function testValidationMessageIfRegexDoesntMatch() + public function testValidationMessageIfRegexDoesntMatch(): void { $form = TestFormGenerator::getForm( ['FieldOne' => 'value1'], @@ -33,7 +33,7 @@ public function testValidationMessageIfRegexDoesntMatch() /** * If the value doesn't match any regex pattern, validation error messages should correctly concatenate. */ - public function testValidationMessageConcatenation() + public function testValidationMessageConcatenation(): void { $form = TestFormGenerator::getForm( ['FieldOne' => 'value1'], @@ -59,7 +59,7 @@ public function testValidationMessageConcatenation() /** * If the value matches the regex pattern, there should be no validation error message. */ - public function testNoValidationMessageIfRegexMatches() + public function testNoValidationMessageIfRegexMatches(): void { $form = TestFormGenerator::getForm( ['FieldOne' => 'value1'], @@ -74,7 +74,7 @@ public function testNoValidationMessageIfRegexMatches() /** * If the value matches ANY regex pattern, there should be no validation error message. */ - public function testNoValidationMessageIfRegexMatchesAny() + public function testNoValidationMessageIfRegexMatchesAny(): void { $form = TestFormGenerator::getForm( ['FieldOne' => 'value1'], @@ -95,7 +95,7 @@ public function testNoValidationMessageIfRegexMatchesAny() /** * If the regex field doesn't exist, there should be no validation error message. */ - public function testNoValidationMessageIfFieldMissing() + public function testNoValidationMessageIfFieldMissing(): void { $form = TestFormGenerator::getForm( ['FieldOne' => 'value1'], @@ -110,7 +110,7 @@ public function testNoValidationMessageIfFieldMissing() /** * Objects that can be cast to string should be correctly validated. */ - public function testStringableObjectValue() + public function testStringableObjectValue(): void { TestFormGenerator::getForm( ['FieldOne'], @@ -133,7 +133,7 @@ public function testStringableObjectValue() /** * Null values should be correctly validated. */ - public function testNullValue() + public function testNullValue(): void { TestFormGenerator::getForm( ['FieldOne'], @@ -156,7 +156,7 @@ public function testNullValue() /** * Numeric values should be correctly validated. */ - public function testNumericValue() + public function testNumericValue(): void { TestFormGenerator::getForm( ['FieldOne'], @@ -179,7 +179,7 @@ public function testNumericValue() /** * Objects that cannot be cast to string should be ignored. */ - public function testNonStringableObjectValueIsIgnored() + public function testNonStringableObjectValueIsIgnored(): void { TestFormGenerator::getForm( ['FieldOne'], @@ -194,7 +194,7 @@ public function testNonStringableObjectValueIsIgnored() /** * Arrays cannot be cast to string and should be ignored. */ - public function testArrayValueIsIgnored() + public function testArrayValueIsIgnored(): void { TestFormGenerator::getForm( ['FieldOne'], @@ -210,7 +210,7 @@ public function testArrayValueIsIgnored() * All of the fields that are in both the form AND the validator should have the correct 'regex' validation * hints. */ - public function testValidationHints() + public function testValidationHints(): void { $form = TestFormGenerator::getForm( $formFields = [ diff --git a/tests/php/ValidatorTests/RequiredBlocksValidatorTest.php b/tests/php/ValidatorTests/RequiredBlocksValidatorTest.php index c4f5bc9..24bac68 100644 --- a/tests/php/ValidatorTests/RequiredBlocksValidatorTest.php +++ b/tests/php/ValidatorTests/RequiredBlocksValidatorTest.php @@ -14,7 +14,7 @@ class RequiredBlocksValidatorTest extends SapphireTest { - private function getForm($elementalAreas, $validator = null) + private function getForm($elementalAreas, $validator = null): Form { $areas = []; foreach ($elementalAreas as $fieldName => $blockClasses) { @@ -35,7 +35,7 @@ private function getForm($elementalAreas, $validator = null) /** * If a block is explicitly required but missing, a validation error is expected. */ - public function testMissingBlocks() + public function testMissingBlocks(): void { $form = $this->getForm([ 'AreaField', @@ -54,7 +54,7 @@ public function testMissingBlocks() /** * If a block is implicitly required but missing, a validation error is expected. */ - public function testDefaultConfigFailure() + public function testDefaultConfigFailure(): void { $form = $this->getForm([ 'AreaField', @@ -70,7 +70,7 @@ public function testDefaultConfigFailure() /** * If a block is implicitly required and present missing, there should be no validation error. */ - public function testDefaultConfigPass() + public function testDefaultConfigPass(): void { $form = $this->getForm([ 'AreaField' => [ @@ -88,7 +88,7 @@ public function testDefaultConfigPass() /** * If there are too many of the given block type, a validation error is expected. */ - public function testTooManyBlocks() + public function testTooManyBlocks(): void { // One block allowed. $form = $this->getForm([ @@ -126,7 +126,7 @@ public function testTooManyBlocks() /** * If there are not too many of the given block type, there should be no validation error. */ - public function testNotTooManyBlocks() + public function testNotTooManyBlocks(): void { // Allowed 3, have <= 3. $form = $this->getForm([ @@ -161,7 +161,7 @@ public function testNotTooManyBlocks() /** * If there are not enough of the given block type, a validation error is expected. */ - public function testNotEnoughBlocks() + public function testNotEnoughBlocks(): void { // One block, but less than the minimum expected. $form = $this->getForm([ @@ -195,7 +195,7 @@ public function testNotEnoughBlocks() /** * If there are enough of the given block type, there should be no validation error. */ - public function testEnoughBlocks() + public function testEnoughBlocks(): void { $form = $this->getForm([ 'AreaField' => [ @@ -216,7 +216,7 @@ public function testEnoughBlocks() /** * If the block is out of position, a validation error is expected. */ - public function testBlockOutOfPositionFromTop() + public function testBlockOutOfPositionFromTop(): void { // Not AT top. $form = $this->getForm([ @@ -254,7 +254,7 @@ public function testBlockOutOfPositionFromTop() /** * If the block is in position, there should be no validation error. */ - public function testBlockInPositionFromTop() + public function testBlockInPositionFromTop(): void { // At top. $form = $this->getForm([ @@ -308,7 +308,7 @@ public function testBlockInPositionFromTop() /** * If the block is out of position, a validation error is expected. */ - public function testBlockOutOfPositionFromBottom() + public function testBlockOutOfPositionFromBottom(): void { // Not AT bottom. $form = $this->getForm([ @@ -346,7 +346,7 @@ public function testBlockOutOfPositionFromBottom() /** * If the block is in position, there should be no validation error. */ - public function testBlockInPositionFromBottom() + public function testBlockInPositionFromBottom(): void { // At bottom. $form = $this->getForm([ @@ -400,7 +400,7 @@ public function testBlockInPositionFromBottom() /** * If the block is out of position in any area, a validation error is expected. */ - public function testMultipleAreasBlockOutOfPosition() + public function testMultipleAreasBlockOutOfPosition(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -425,7 +425,7 @@ public function testMultipleAreasBlockOutOfPosition() /** * If the block in position in all areas, there should be no validation error. */ - public function testMultipleAreasBlockInPosition() + public function testMultipleAreasBlockInPosition(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -450,7 +450,7 @@ public function testMultipleAreasBlockInPosition() /** * If there are not enough blocks across all areas, a validation error is expected. */ - public function testMultipleAreasNotEnoughBlocks() + public function testMultipleAreasNotEnoughBlocks(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -474,7 +474,7 @@ public function testMultipleAreasNotEnoughBlocks() /** * If there are enough blocks across all areas, there should be no validation error. */ - public function testMultipleAreasEnoughBlocks() + public function testMultipleAreasEnoughBlocks(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -499,7 +499,7 @@ public function testMultipleAreasEnoughBlocks() /** * If there are too many blocks across all areas, a validation error is expected. */ - public function testMultipleAreasTooManyBlocks() + public function testMultipleAreasTooManyBlocks(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -524,7 +524,7 @@ public function testMultipleAreasTooManyBlocks() /** * If there are not too many blocks across all areas, there should be no validation error. */ - public function testMultipleAreasNotTooManyBlocks() + public function testMultipleAreasNotTooManyBlocks(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -549,7 +549,7 @@ public function testMultipleAreasNotTooManyBlocks() /** * If there are too many blocks in the specified area, a validation error is expected. */ - public function testValidateSpecificAreaInvalid() + public function testValidateSpecificAreaInvalid(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -576,7 +576,7 @@ public function testValidateSpecificAreaInvalid() /** * If there are not too many blocks in the specified area, there should be no validation error. */ - public function testValidateSpecificAreaValid() + public function testValidateSpecificAreaValid(): void { $form = $this->getForm([ 'AreaField1' => [ @@ -605,7 +605,7 @@ public function testValidateSpecificAreaValid() /** * All of the fields that are in both the form AND the validator should have 'required-elements' validation hints. */ - public function testValidationHints() + public function testValidationHints(): void { $fieldList = new FieldList(); $fieldList->add(new TabSet('Root')); diff --git a/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php b/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php index d0f862e..82754d1 100644 --- a/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/RequiredFieldsValidatorTest.php @@ -15,7 +15,7 @@ class RequiredFieldsValidatorTest extends SapphireTest * If the required field has no value, there should be a validation error message * and the validation result should be invalid. */ - public function testValidationMessageIfEmpty() + public function testValidationMessageIfEmpty(): void { $form = TestFormGenerator::getForm(['FieldOne'], new RequiredFieldsValidator(['FieldOne'])); $result = $form->validationResult(); @@ -34,7 +34,7 @@ public function testValidationMessageIfEmpty() /** * If the required field has a value, there should be no validation error message. */ - public function testNoValidationMessageIfNotEmpty() + public function testNoValidationMessageIfNotEmpty(): void { $form = TestFormGenerator::getForm(['FieldOne' => 'someValue'], new RequiredFieldsValidator(['FieldOne'])); $result = $form->validationResult(); @@ -46,7 +46,7 @@ public function testNoValidationMessageIfNotEmpty() /** * If the required field doesn't exist, there should be no validation error message. */ - public function testNoValidationMessageIfFieldMissing() + public function testNoValidationMessageIfFieldMissing(): void { $form = TestFormGenerator::getForm(['FieldOne'], new RequiredFieldsValidator(['MissingField'])); $result = $form->validationResult(); @@ -58,7 +58,7 @@ public function testNoValidationMessageIfFieldMissing() /** * All of the fields that are in both the form AND the validator should have 'required' validation hints. */ - public function testValidationHints() + public function testValidationHints(): void { $form = TestFormGenerator::getForm( $formFields = [ @@ -97,7 +97,7 @@ public function testValidationHints() /** * Required fields need to 'know' they are required. */ - public function testFieldIsRequired() + public function testFieldIsRequired(): void { // Get the validator. $validator = new RequiredFieldsValidator( @@ -134,7 +134,7 @@ public function testFieldIsRequired() * Upload fields need to have the 'aria-required' attribute set to true. * Pretty well all other fields set this themselves. */ - public function testUploadFieldHasAriaRequired() + public function testUploadFieldHasAriaRequired(): void { $validator = new RequiredFieldsValidator('UploadField1'); $fields = new FieldList([ diff --git a/tests/php/ValidatorTests/SimpleFieldsValidatorTest.php b/tests/php/ValidatorTests/SimpleFieldsValidatorTest.php index 993b750..576801f 100644 --- a/tests/php/ValidatorTests/SimpleFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/SimpleFieldsValidatorTest.php @@ -17,7 +17,7 @@ class SimpleFieldsValidatorTest extends SapphireTest FormField::class => [FormFieldExtension::class], ]; - private function getForm($value = null, $withValidator = true) + private function getForm($value = null, $withValidator = true): Form { $fieldList = new FieldList([ $emailField = new EmailField('EmailField'), @@ -30,7 +30,7 @@ private function getForm($value = null, $withValidator = true) /** * If the field has an invalid value, there should be a validation error. */ - public function testValidationErrorWithInvalidValue() + public function testValidationErrorWithInvalidValue(): void { $form = $this->getForm('not an email address'); $result = $form->validationResult(); @@ -42,7 +42,7 @@ public function testValidationErrorWithInvalidValue() /** * If the field has a valid value, there should be no validation error. */ - public function testNoValidationErrorWithValidValue() + public function testNoValidationErrorWithValidValue(): void { $form = $this->getForm('email@example.com'); $result = $form->validationResult(); @@ -56,7 +56,7 @@ public function testNoValidationErrorWithValidValue() * * This test is basically to check if this validator is even still needed. */ - public function testNoValidationErrorWithNoValidator() + public function testNoValidationErrorWithNoValidator(): void { $form = $this->getForm('not an email address', false); $form->setValidator(new CompositeValidator()); @@ -69,7 +69,7 @@ public function testNoValidationErrorWithNoValidator() /** * If the field is omitting field validation, the invalid value shouldn't be validated. */ - public function testNoValidationErrorWithOmitValidation() + public function testNoValidationErrorWithOmitValidation(): void { $form = $this->getForm('not an email address'); $field = $form->Fields()->dataFieldByName('EmailField'); diff --git a/tests/php/ValidatorTests/WarningFieldsValidatorTest.php b/tests/php/ValidatorTests/WarningFieldsValidatorTest.php index 83bf2a8..fb86c6b 100644 --- a/tests/php/ValidatorTests/WarningFieldsValidatorTest.php +++ b/tests/php/ValidatorTests/WarningFieldsValidatorTest.php @@ -12,7 +12,7 @@ class WarningFieldsValidatorTest extends SapphireTest * If the warning field has no value, there should be a validation warning message * but the validation result should be valid. */ - public function testValidationMessageIfEmpty() + public function testValidationMessageIfEmpty(): void { $form = TestFormGenerator::getForm(['FieldOne'], new WarningFieldsValidator(['FieldOne'])); $result = $form->validationResult(); @@ -31,7 +31,7 @@ public function testValidationMessageIfEmpty() /** * If the warning field has a value, there should be no validation warning message. */ - public function testNoValidationMessageIfNotEmpty() + public function testNoValidationMessageIfNotEmpty(): void { $form = TestFormGenerator::getForm(['FieldOne' => 'someValue'], new WarningFieldsValidator(['FieldOne'])); $result = $form->validationResult(); @@ -43,7 +43,7 @@ public function testNoValidationMessageIfNotEmpty() /** * If the warning field doesn't exist, there should be no validation warning message. */ - public function testNoValidationMessageIfFieldMissing() + public function testNoValidationMessageIfFieldMissing(): void { $form = TestFormGenerator::getForm(['FieldOne'], new WarningFieldsValidator(['MissingField'])); $result = $form->validationResult(); @@ -55,7 +55,7 @@ public function testNoValidationMessageIfFieldMissing() /** * There should be no validation hints for warning field validation. */ - public function testValidationHints() + public function testValidationHints(): void { TestFormGenerator::getForm( [ From 699c8d15fb97b8eca9ba24ecbec572306e18685f Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 11 Jul 2023 11:36:52 +1200 Subject: [PATCH 15/17] chore: Fix js linting issues. --- client/src/js/AjaxCompositeValidator.js | 6 ++++-- package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/src/js/AjaxCompositeValidator.js b/client/src/js/AjaxCompositeValidator.js index 020640a..6c844ab 100644 --- a/client/src/js/AjaxCompositeValidator.js +++ b/client/src/js/AjaxCompositeValidator.js @@ -1,3 +1,4 @@ +/* global nocaptcha_handleCaptcha */ /* eslint-disable-next-line func-names */ (function ($) { function isBackendForm() { @@ -179,14 +180,15 @@ } } // I'm honestly not sure by what magic it happens but the form submits correctly on the - // backend. + // backend, so no action is required here. } else { // On the front-end we have to make the form submit. + // eslint-disable-next-line no-lonely-if, camelcase if (typeof nocaptcha_handleCaptcha === 'function') { const form = $form.get(0); nocaptcha_handleCaptcha(form, form.submitWithoutEvent.bind(form)); } else { - $form.get(0).submitWithoutEvent(); + $form.get(0).submitWithoutEvent(); } } } diff --git a/package.json b/package.json index bfc14bc..5455477 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "watch": "mix watch", "package": "mix --production", "lint": "yarn lint-js", - "lint-js": "eslint src/js" + "lint-js": "eslint client/src/js" }, "dependencies": { "eslint-webpack-plugin": "^2.0.0", From fcc5fbeb3d05cf5ec15305463949ecfb63238405 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 11 Jul 2023 11:37:18 +1200 Subject: [PATCH 16/17] chore: Update browserslist --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 17b4ae3..39fa2da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1713,9 +1713,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001243: - version "1.0.30001248" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz#26ab45e340f155ea5da2920dadb76a533cb8ebce" - integrity sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw== + version "1.0.30001514" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz" + integrity sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ== chalk@^2.0.0: version "2.4.2" From 1df6657b0781a379226f62383b470486367bbf55 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 11 Jul 2023 11:45:51 +1200 Subject: [PATCH 17/17] chore: Fix php linting issues. --- phpcs.xml.dist | 3 +++ src/Validators/SimpleFieldsValidator.php | 1 - tests/php/TestOnlyClasses/TestValidator.php | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index b476f32..83c9eda 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -2,6 +2,9 @@ Coding standard for SilverStripe 4.x + src + tests + */vendor/* */thirdparty/* diff --git a/src/Validators/SimpleFieldsValidator.php b/src/Validators/SimpleFieldsValidator.php index d464020..fe78de3 100644 --- a/src/Validators/SimpleFieldsValidator.php +++ b/src/Validators/SimpleFieldsValidator.php @@ -13,7 +13,6 @@ * This class is to avoid the use of, say, RequiredFields::create([]), which * relies on an implementation detail to ensure that fields are validated. */ - class SimpleFieldsValidator extends Validator { /** diff --git a/tests/php/TestOnlyClasses/TestValidator.php b/tests/php/TestOnlyClasses/TestValidator.php index 340d7d1..3a92569 100644 --- a/tests/php/TestOnlyClasses/TestValidator.php +++ b/tests/php/TestOnlyClasses/TestValidator.php @@ -10,7 +10,6 @@ */ class TestValidator extends Validator implements TestOnly { - /** * Requires a specific field for test purposes. *