Fix logic for multi select (#6)

* Fix logic for multi select

* test case for multi select logic
This commit is contained in:
Chirag 2022-10-03 00:10:10 +05:30 committed by GitHub
parent ef70be9d14
commit 610c71cb69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 124 additions and 28 deletions

View File

@ -6,7 +6,8 @@ use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\DataAwareRule; use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class FormPropertyLogicRule implements Rule, DataAwareRule { class FormPropertyLogicRule implements Rule, DataAwareRule
{
const ACTIONS_VALUES = [ const ACTIONS_VALUES = [
'show-block', 'show-block',
@ -242,7 +243,7 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
'multi_select' => [ 'multi_select' => [
'comparators' => [ 'comparators' => [
'contains' => [ 'contains' => [
'expected_type' => 'object', 'expected_type' => ['object', 'string'],
'format' => [ 'format' => [
'type' => 'uuid', 'type' => 'uuid',
] ]
@ -384,36 +385,37 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
private $field = []; private $field = [];
private $data = []; private $data = [];
private function checkBaseCondition($condtion) { private function checkBaseCondition($condition)
{
if (!isset($condtion['value'])) { if (!isset($condition['value'])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
return; return;
} }
if (!isset($condtion['value']['property_meta'])) { if (!isset($condition['value']['property_meta'])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
return; return;
} }
if (!isset($condtion['value']['property_meta']['type'])) { if (!isset($condition['value']['property_meta']['type'])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
return; return;
} }
if (!isset($condtion['value']['operator'])) { if (!isset($condition['value']['operator'])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
return; return;
} }
if (!isset($condtion['value']['value'])) { if (!isset($condition['value']['value'])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
return; return;
} }
$typeField = $condtion['value']['property_meta']['type']; $typeField = $condition['value']['property_meta']['type'];
$operator = $condtion['value']['operator']; $operator = $condition['value']['operator'];
$value = $condtion['value']['value']; $value = $condition['value']['value'];
if (!isset(self::CONDITION_MAPPING[$typeField])) { if (!isset(self::CONDITION_MAPPING[$typeField])) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
@ -427,18 +429,38 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
$type = self::CONDITION_MAPPING[$typeField]['comparators'][$operator]['expected_type']; $type = self::CONDITION_MAPPING[$typeField]['comparators'][$operator]['expected_type'];
// Type d'objet : string, boolean, number, object if (is_array($type)) {
$foundCorrectType = false;
foreach ($type as $subtype) {
if ($this->valueHasCorrectType($subtype, $value)) {
$foundCorrectType = true;
}
}
if (!$foundCorrectType) {
$this->isConditionCorrect = false;
}
} else {
if (!$this->valueHasCorrectType($type, $value)) {
$this->isConditionCorrect = false;
}
}
}
private function valueHasCorrectType($type, $value)
{
if ( if (
($type === 'string' && gettype($value) !== 'string') || ($type === 'string' && gettype($value) !== 'string') ||
($type === 'boolean' && !is_bool($value)) || ($type === 'boolean' && !is_bool($value)) ||
($type === 'number' && !is_numeric($value)) || ($type === 'number' && !is_numeric($value)) ||
($type === 'object' && !is_array($value)) ($type === 'object' && !is_array($value))
) { ) {
$this->isConditionCorrect = false; return false;
} }
return true;
} }
private function checkConditions($conditions) { private function checkConditions($conditions)
{
if (isset($conditions['operatorIdentifier'])) { if (isset($conditions['operatorIdentifier'])) {
if (($conditions['operatorIdentifier'] !== 'and') && ($conditions['operatorIdentifier'] !== 'or')) { if (($conditions['operatorIdentifier'] !== 'and') && ($conditions['operatorIdentifier'] !== 'or')) {
$this->isConditionCorrect = false; $this->isConditionCorrect = false;
@ -463,19 +485,19 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
} }
} }
private function checkActions($conditions) { private function checkActions($conditions)
{
if (is_array($conditions) && count($conditions) > 0) { if (is_array($conditions) && count($conditions) > 0) {
foreach($conditions as $val){ foreach($conditions as $val){
if (!in_array($val, static::ACTIONS_VALUES) || if (!in_array($val, static::ACTIONS_VALUES) ||
(in_array($this->field["type"], ['nf-text', 'nf-page-break', 'nf-divider', 'nf-image']) && !in_array($val, ['hide-block'])) || (in_array($this->field["type"], ['nf-text', 'nf-page-break', 'nf-divider', 'nf-image']) && !in_array($val, ['hide-block'])) ||
(isset($this->field["hidden"]) && $this->field["hidden"] && !in_array($val, ['show-block','require-answer'])) || (isset($this->field["hidden"]) && $this->field["hidden"] && !in_array($val, ['show-block', 'require-answer'])) ||
(isset($this->field["required"]) && $this->field["required"] && !in_array($val, ['make-it-optional','hide-block'])) (isset($this->field["required"]) && $this->field["required"] && !in_array($val, ['make-it-optional', 'hide-block']))
) { ) {
$this->isActionCorrect = false; $this->isActionCorrect = false;
break; break;
} }
} }
return;
} }
} }
@ -486,7 +508,8 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
* @param mixed $value * @param mixed $value
* @return bool * @return bool
*/ */
public function passes($attribute, $value) { public function passes($attribute, $value)
{
$this->setProperty($attribute); $this->setProperty($attribute);
if(isset($value["conditions"])){ if(isset($value["conditions"])){
$this->checkConditions($value["conditions"]); $this->checkConditions($value["conditions"]);
@ -501,7 +524,8 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
* Get the validation error message. * Get the validation error message.
* *
*/ */
public function message() { public function message()
{
$errorList = []; $errorList = [];
if(!$this->isConditionCorrect){ if(!$this->isConditionCorrect){
$errorList[] = "The logic conditions for ".$this->field['name']." are not complete."; $errorList[] = "The logic conditions for ".$this->field['name']." are not complete.";
@ -527,7 +551,7 @@ class FormPropertyLogicRule implements Rule, DataAwareRule {
private function setProperty(string $attributeKey) private function setProperty(string $attributeKey)
{ {
$attributeKey = Str::of($attributeKey)->replace('.logic','')->toString(); $attributeKey = Str::of($attributeKey)->replace('.logic', '')->toString();
$this->field = \Arr::get($this->data, $attributeKey); $this->field = \Arr::get($this->data, $attributeKey);
} }
} }

View File

@ -81,7 +81,13 @@ class FormLogicConditionChecker
} }
private function checkListContains ($condition, $fieldValue): bool { private function checkListContains ($condition, $fieldValue): bool {
return ($fieldValue) ? (count(array_intersect($condition['value'], $fieldValue)) === count($condition['value'])) : false; if (is_null($fieldValue)) return false;
if (is_array($condition['value'])) {
return count(array_intersect($condition['value'], $fieldValue)) === count($condition['value']);
} else {
return in_array($condition['value'], $fieldValue);
}
} }
private function checkStartsWith ($condition, $fieldValue): bool { private function checkStartsWith ($condition, $fieldValue): bool {

View File

@ -58,7 +58,7 @@ export default {
} }
if (['select', 'multi_select'].includes(this.property.type)) { if (['select', 'multi_select'].includes(this.property.type)) {
componentData.multiple = (this.property.type == 'multi_select') componentData.multiple = false;
componentData.options = this.property[this.property.type].options.map(option => { componentData.options = this.property[this.property.type].options.map(option => {
return { return {
name: option.name, name: option.name,

View File

@ -1,16 +1,16 @@
<template> <template>
<div class="flex px-4 py-1"> <div class="flex flex-wrap px-4 py-1 -ml-1 -mt-1">
<select-input ref="ruleSelect" v-model="selectedRule" class="flex-grow mr-1" <select-input ref="ruleSelect" v-model="selectedRule" class="flex-grow ml-1 mr-1 mt-1"
wrapper-class="relative" placeholder="Add condition on input field" wrapper-class="relative" placeholder="Add condition on input field"
:options="groupCtrl.rules" margin-bottom="" :options="groupCtrl.rules" margin-bottom=""
emit-key="identifier" emit-key="identifier"
option-key="identifier" option-key="identifier"
name="group-control-slot-rule" name="group-control-slot-rule"
/> />
<v-button class="ml-1" color="blue" size="small" :disabled="selectedRule === ''" @click="addRule"> <v-button class="ml-1 mt-1" color="blue" size="small" :disabled="selectedRule === ''" @click="addRule">
Add Condition Add Condition
</v-button> </v-button>
<v-button class="ml-1" color="green" size="small" @click="groupCtrl.newGroup"> <v-button class="ml-1 mt-1" color="green" size="small" @click="groupCtrl.newGroup">
Add Group Add Group
</v-button> </v-button>
</div> </div>

View File

@ -64,7 +64,13 @@ function checkContains (condition, fieldValue) {
} }
function checkListContains (condition, fieldValue) { function checkListContains (condition, fieldValue) {
return (fieldValue && fieldValue.length > 0) ? condition.value.every(r => fieldValue.includes(r)) : false if (!fieldValue) return false
if (Array.isArray(condition.value)) {
return condition.value.every(r => fieldValue.includes(r))
} else {
return fieldValue.includes(condition.value)
}
} }
function checkStartsWith (condition, fieldValue) { function checkStartsWith (condition, fieldValue) {

View File

@ -56,3 +56,63 @@ it('create form with logic', function () {
'message' => 'Form submission saved.' 'message' => 'Form submission saved.'
]); ]);
}); });
it('create form with multi select logic', function () {
$user = $this->actingAsUser();
$workspace = $this->createUserWorkspace($user);
$form = $this->createForm($user, $workspace, [
'properties' => [
[
'id' => "title",
'name' => "Name",
'type' => 'title',
'hidden' => false,
'required' => false,
'logic' => [
"conditions" => [
"operatorIdentifier"=> "and",
"children"=> [
[
"identifier"=> "multi_select",
"value"=> [
"operator"=> "contains",
"property_meta"=> [
'id'=> "93ea3198-353f-440b-8dc9-2ac9a7bee124",
"type"=> "multi_select",
],
"value"=> 'One'
]
]
]
],
"actions" => ['require-answer']
]
]
],
]);
$this->getJson(route('forms.show', $form->slug))
->assertSuccessful()
->assertJson(function (AssertableJson $json) use ($form) {
return $json->where('id', $form->id)
->where('properties', function($values){
return (count($values[0]['logic']) > 0);
})
->etc();
});
// Should submit form
$forData = ['93ea3198-353f-440b-8dc9-2ac9a7bee124' => ["One"]];
$this->postJson(route('forms.answer', $form->slug), $forData)
->assertStatus(422)
->assertJson([
'message' => 'The Name field is required.',
'errors' => [
'title' => [
'The Name field is required.',
],
],
]);
});