mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
Move conditionalFieldEnabled to EditableFormField as isDisplayed
This commit is contained in:
parent
b53619477c
commit
a0cedaeb38
@ -2,6 +2,7 @@
|
||||
|
||||
namespace SilverStripe\UserForms\Form;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\Forms\FileField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
@ -27,7 +28,7 @@ class UserFormsRequiredFields extends RequiredFields
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function php($data)
|
||||
{
|
||||
@ -58,18 +59,14 @@ class UserFormsRequiredFields extends RequiredFields
|
||||
// get editable form field - owns display rules for field
|
||||
$editableFormField = $this->getEditableFormFieldByName($fieldName);
|
||||
|
||||
$error = false;
|
||||
|
||||
// validate if there are no display rules or the field is conditionally visible
|
||||
if (!$this->hasDisplayRules($editableFormField) ||
|
||||
$this->conditionalFieldEnabled($editableFormField, $data)) {
|
||||
$error = $this->validateRequired($formField, $data);
|
||||
}
|
||||
// Validate if the field is displayed
|
||||
$error =
|
||||
$editableFormField->isDisplayed($data) &&
|
||||
$this->validateRequired($formField, $data);
|
||||
|
||||
// handle error case
|
||||
if ($formField && $error) {
|
||||
$this->handleError($formField, $fieldName);
|
||||
|
||||
$valid = false;
|
||||
}
|
||||
}
|
||||
@ -77,57 +74,35 @@ class UserFormsRequiredFields extends RequiredFields
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an Editable Form field by its name.
|
||||
* @param string $name
|
||||
* @return EditableFormField
|
||||
*/
|
||||
private function getEditableFormFieldByName($name)
|
||||
{
|
||||
return EditableFormField::get()->filter(['name' => $name])->first();
|
||||
$field = EditableFormField::get()->filter(['Name' => $name])->first();
|
||||
|
||||
if ($field) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
private function hasDisplayRules($field)
|
||||
{
|
||||
return ($field->DisplayRules()->count() > 0);
|
||||
// This should happen if form field data got corrupted
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Could not find EditableFormField with name `%s`',
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
||||
private function conditionalFieldEnabled($editableFormField, $data)
|
||||
{
|
||||
$displayRules = $editableFormField->DisplayRules();
|
||||
|
||||
$conjunction = $editableFormField->DisplayRulesConjunctionNice();
|
||||
|
||||
$displayed = ($editableFormField->ShowOnLoadNice() === 'show');
|
||||
|
||||
// && start with true and find and condition that doesn't satisfy
|
||||
// || start with false and find and condition that satisfies
|
||||
$conditionsSatisfied = ($conjunction === '&&');
|
||||
|
||||
foreach ($displayRules as $rule) {
|
||||
$controllingField = EditableFormField::get()->byID($rule->ConditionFieldID);
|
||||
|
||||
if ($controllingField->DisplayRules()->count() > 0) { // controllingField is also a conditional field
|
||||
// recursively check - if any of the dependant fields are hidden, then this field cannot be visible.
|
||||
if ($this->conditionalFieldEnabled($controllingField, $data)) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
$ruleSatisfied = $rule->validateAgainstFormData($data);
|
||||
|
||||
if ($conjunction === '||' && $ruleSatisfied) {
|
||||
$conditionsSatisfied = true;
|
||||
break;
|
||||
}
|
||||
if ($conjunction === '&&' && !$ruleSatisfied) {
|
||||
$conditionsSatisfied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// initially displayed - condition fails || initially hidden, condition passes
|
||||
return ($displayed xor $conditionsSatisfied);
|
||||
}
|
||||
|
||||
// logic replicated from php() method of parent class SilverStripe\Forms\RequiredFields
|
||||
// TODO refactor to share with parent (would require corrosponding change in framework)
|
||||
private function validateRequired($field, $data)
|
||||
/**
|
||||
* Check if the validation rules for the specified field are met by the provided data.
|
||||
*
|
||||
* @note Logic replicated from php() method of parent class `SilverStripe\Forms\RequiredFields`
|
||||
* @param EditableFormField $field
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
private function validateRequired(FormField $field, array $data)
|
||||
{
|
||||
$error = false;
|
||||
$fieldName = $field->getName();
|
||||
|
@ -57,7 +57,7 @@ use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
|
||||
* @property boolean $ShowOnLoad
|
||||
* @property string $DisplayRulesConjunction
|
||||
* @method UserDefinedForm Parent() Parent page
|
||||
* @method DataList DisplayRules() List of EditableCustomRule objects
|
||||
* @method DataList|EditableCustomRule[] DisplayRules() List of EditableCustomRule objects
|
||||
* @mixin Versioned
|
||||
*/
|
||||
class EditableFormField extends DataObject
|
||||
@ -977,6 +977,48 @@ class EditableFormField extends DataObject
|
||||
return (count($result['selectors'])) ? $result : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this EditableFormField is displayed based on its DisplayRules and the provided data.
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function isDisplayed(array $data)
|
||||
{
|
||||
$displayRules = $this->DisplayRules();
|
||||
|
||||
if ($displayRules->count() === 0) {
|
||||
// If no display rule have been defined, isDisplayed equals the ShowOnLoad property
|
||||
return $this->ShowOnLoad;
|
||||
}
|
||||
|
||||
$conjunction = $this->DisplayRulesConjunctionNice();
|
||||
|
||||
// && start with true and find and condition that doesn't satisfy
|
||||
// || start with false and find and condition that satisfies
|
||||
$conditionsSatisfied = ($conjunction === '&&');
|
||||
|
||||
foreach ($displayRules as $rule) {
|
||||
$controllingField = $rule->ConditionField();
|
||||
|
||||
// recursively check - if any of the dependant fields are hidden, assume the rule can not be satisfied
|
||||
$ruleSatisfied = $controllingField->isDisplayed($data) && $rule->validateAgainstFormData($data);
|
||||
|
||||
if ($conjunction === '||' && $ruleSatisfied) {
|
||||
$conditionsSatisfied = true;
|
||||
break;
|
||||
}
|
||||
if ($conjunction === '&&' && !$ruleSatisfied) {
|
||||
$conditionsSatisfied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// initially displayed - condition fails || initially hidden, condition passes
|
||||
$startDisplayed = $this->ShowOnLoad;
|
||||
return ($startDisplayed xor $conditionsSatisfied);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the set DisplayRulesConjunction with their JS logical operators
|
||||
* @return string
|
||||
|
@ -232,4 +232,58 @@ class EditableFormFieldTest extends FunctionalTest
|
||||
|
||||
$this->assertContains('/images/editabletextfield.png', $field->getIcon());
|
||||
}
|
||||
|
||||
public function displayedProvider()
|
||||
{
|
||||
$one = ['basic_text_name' => 'foobar'];
|
||||
$two = array_merge($one, ['basic_text_name_2' => 'foobar']);
|
||||
|
||||
return [
|
||||
'no display rule AND' => ['alwaysVisible', [], true],
|
||||
'no display rule OR' => ['alwaysVisibleOr', [], true],
|
||||
|
||||
'no display rule hidden AND' => ['neverVisible', [], false],
|
||||
'no display rule hidden OR' => ['neverVisibleOr', [], false],
|
||||
|
||||
'1 unmet display rule AND' => ['singleDisplayRule', [], false],
|
||||
'1 met display rule AND' => ['singleDisplayRule', $one, true],
|
||||
'1 unmet display rule OR' => ['singleDisplayRuleOr', [], false],
|
||||
'1 met display rule OR' => ['singleDisplayRuleOr', $one, true],
|
||||
|
||||
'1 unmet hide rule AND' => ['singleHiddingRule', [], true],
|
||||
'1 met hide rule AND' => ['singleHiddingRule', $one, false],
|
||||
'1 unmet hide rule OR' => ['singleHiddingRuleOr', [], true],
|
||||
'1 met hide rule OR' => ['singleHiddingRuleOr', $one, false],
|
||||
|
||||
'multi display rule AND none met' => ['multiDisplayRule', [], false],
|
||||
'multi display rule AND partially met' => ['multiDisplayRule', $one, false],
|
||||
'multi display rule AND all met' => ['multiDisplayRule', $two, true],
|
||||
|
||||
'multi display rule OR none met' => ['multiDisplayRuleOr', [], false],
|
||||
'multi display rule OR partially met' => ['multiDisplayRuleOr', $one, true],
|
||||
'multi display rule OR all met' => ['multiDisplayRuleOr', $two, true],
|
||||
|
||||
'multi hide rule AND none met' => ['multiHiddingRule', [], true],
|
||||
'multi hide rule AND partially met' => ['multiHiddingRule', $one, true],
|
||||
'multi hide rule AND all met' => ['multiHiddingRule', $two, false],
|
||||
|
||||
'multi hide rule OR none met' => ['multiHiddingRuleOr', [], true],
|
||||
'multi hide rule OR partially met' => ['multiHiddingRuleOr', $one, false],
|
||||
'multi hide rule OR all met' => ['multiHiddingRuleOr', $two, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fieldName
|
||||
* @param $data
|
||||
* @param $expected
|
||||
* @dataProvider displayedProvider
|
||||
*/
|
||||
public function testIsDisplayed($fieldName, $data, bool $expected)
|
||||
{
|
||||
/** @var EditableFormField $field */
|
||||
$field = $this->objFromFixture(EditableTextField::class, $fieldName);
|
||||
$this->assertEquals($expected, $field->isDisplayed($data));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ SilverStripe\UserForms\Model\EditableFormField\EditableTextField:
|
||||
Title: Basic Text Field
|
||||
|
||||
basic-text-2:
|
||||
Name: basic_text_name
|
||||
Name: basic_text_name_2
|
||||
Title: Basic Text Field
|
||||
|
||||
required-text:
|
||||
@ -23,6 +23,83 @@ SilverStripe\UserForms\Model\EditableFormField\EditableTextField:
|
||||
DisplayRulesConjunction: And
|
||||
ShowOnLoad: false
|
||||
|
||||
# No rule
|
||||
alwaysVisible:
|
||||
Name: AlwaysVisible
|
||||
Title: "This field is always visible"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
alwaysVisibleOr:
|
||||
Name: AlwaysVisibleOr
|
||||
Title: "This field is always visible"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
neverVisible:
|
||||
Name: NeverVisible
|
||||
Title: "This field is never visible"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
neverVisibleOr:
|
||||
Name: NeverVisibleOr
|
||||
Title: "This field is never visible"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
# Single rule
|
||||
|
||||
singleDisplayRule:
|
||||
Name: SingleDisplayRule
|
||||
Title: "This field will be displayed if the display rule is tripped"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
singleDisplayRuleOr:
|
||||
Name: SingleDisplayRuleOr
|
||||
Title: "This field will be displayed if the display rule is tripped"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
singleHiddingRule:
|
||||
Name: SingleHiddingRule
|
||||
Title: "This field will be hidden if the display rule is tripped"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
singleHiddingRuleOr:
|
||||
Name: SingleHiddingRuleOr
|
||||
Title: "This field will be hidden if the display rule is tripped"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
# Multi rule
|
||||
multiDisplayRule:
|
||||
Name: MultiDisplayRule
|
||||
Title: "This field will be displayed if displayed if all the rule are met"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
multiDisplayRuleOr:
|
||||
Name: MultiDisplayRuleOr
|
||||
Title: "This field will be displayed if at least one rule is met"
|
||||
ShowOnLoad: false
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
multiHiddingRule:
|
||||
Name: MultiHiddingRule
|
||||
Title: "This field will be hidden if all the rule are met"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: And
|
||||
|
||||
multiHiddingRuleOr:
|
||||
Name: MultiHiddingRuleOr
|
||||
Title: "This field will be hidden if one rule is met"
|
||||
ShowOnLoad: true
|
||||
DisplayRulesConjunction: Or
|
||||
|
||||
|
||||
SilverStripe\UserForms\Model\EditableCustomRule:
|
||||
rule1:
|
||||
Display: Show
|
||||
@ -35,6 +112,66 @@ SilverStripe\UserForms\Model\EditableCustomRule:
|
||||
ConditionOption: HasValue
|
||||
FieldValue: 6
|
||||
|
||||
# Single rules
|
||||
ruleSingleDisplay:
|
||||
Display: Show
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.singleDisplayRule
|
||||
ruleSingleDisplayOr:
|
||||
Display: Show
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.singleDisplayRuleOr
|
||||
ruleSingleHidding:
|
||||
Display: Show
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.singleHiddingRule
|
||||
ruleSingleHiddingOr:
|
||||
Display: Show
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.singleHiddingRuleOr
|
||||
|
||||
# Multi rules
|
||||
ruleMultiDisplay1:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiDisplayRule
|
||||
ruleMultiDisplay2:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text-2
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiDisplayRule
|
||||
|
||||
ruleMultiDisplayOr1:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiDisplayRuleOr
|
||||
ruleMultiDisplayOr2:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text-2
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiDisplayRuleOr
|
||||
|
||||
|
||||
ruleMultiHidding1:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiHiddingRule
|
||||
ruleMultiHidding2:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text-2
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiHiddingRule
|
||||
|
||||
ruleMultiHiddingOr1:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiHiddingRuleOr
|
||||
ruleMultiHiddingOr2:
|
||||
ConditionOption: IsNotBlank
|
||||
ConditionField: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.basic-text-2
|
||||
Parent: =>SilverStripe\UserForms\Model\EditableFormField\EditableTextField.multiHiddingRuleOr
|
||||
|
||||
SilverStripe\UserForms\Model\EditableFormField\EditableOption:
|
||||
option-1:
|
||||
Name: Option1
|
||||
|
Loading…
Reference in New Issue
Block a user