Dc3e4 new matrix field (#484)
* fix password reset bug * wip: matrix input * wip: matrix input * wip: matrix input * Fixed matric input component logic * matrix input cleanup * fix lint errors * table border and radius * cleanup, linting * fix component methos * wip matrix input * matrix condition for contains and not contain * patch matrix input condition logic * linting * refactor and cleanup * fix syntax error * Polished the matrix input * Fix linting --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use App\Rules\CustomFieldValidationRule;
|
||||
use App\Rules\MatrixValidationRule;
|
||||
use App\Rules\StorageFile;
|
||||
use App\Rules\ValidHCaptcha;
|
||||
use App\Rules\ValidPhoneInputRule;
|
||||
@@ -82,9 +83,14 @@ class AnswerFormRequest extends FormRequest
|
||||
} elseif ($property['type'] == 'rating') {
|
||||
// For star rating, needs a minimum of 1 star
|
||||
$rules[] = 'min:1';
|
||||
} elseif ($property['type'] == 'matrix') {
|
||||
$rules[] = new MatrixValidationRule($property, true);
|
||||
}
|
||||
} else {
|
||||
$rules[] = 'nullable';
|
||||
if ($property['type'] == 'matrix') {
|
||||
$rules[] = new MatrixValidationRule($property, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean id to escape "."
|
||||
@@ -97,7 +103,7 @@ class AnswerFormRequest extends FormRequest
|
||||
}
|
||||
|
||||
// User custom validation
|
||||
if(!(Str::of($property['type'])->startsWith('nf-')) && isset($property['validation'])) {
|
||||
if (!(Str::of($property['type'])->startsWith('nf-')) && isset($property['validation'])) {
|
||||
$rules[] = (new CustomFieldValidationRule($property['validation'], $data));
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,34 @@ class FormPropertyLogicRule implements DataAwareRule, ValidationRule
|
||||
],
|
||||
],
|
||||
],
|
||||
'matrix' => [
|
||||
'comparators' => [
|
||||
'equals' => [
|
||||
'expected_type' => 'object',
|
||||
'format' => [
|
||||
'type' => 'object',
|
||||
],
|
||||
],
|
||||
'does_not_equal' => [
|
||||
'expected_type' => 'object',
|
||||
'format' => [
|
||||
'type' => 'object',
|
||||
],
|
||||
],
|
||||
'contains' => [
|
||||
'expected_type' => 'object',
|
||||
'format' => [
|
||||
'type' => 'object',
|
||||
],
|
||||
],
|
||||
'does_not_contain' => [
|
||||
'expected_type' => 'object',
|
||||
'format' => [
|
||||
'type' => 'object',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'url' => [
|
||||
'comparators' => [
|
||||
'equals' => [
|
||||
|
||||
61
app/Rules/MatrixValidationRule.php
Normal file
61
app/Rules/MatrixValidationRule.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class MatrixValidationRule implements ValidationRule
|
||||
{
|
||||
protected $field;
|
||||
protected $isRequired;
|
||||
|
||||
public function __construct(array $field, bool $isRequired)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->isRequired = $isRequired;
|
||||
}
|
||||
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
if (!$this->isRequired && empty($value)) {
|
||||
return; // If not required and empty, validation passes
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
$fail('The Matrix field must be an array.');
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = $this->field['rows'];
|
||||
$columns = $this->field['columns'];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if (!array_key_exists($row, $value)) {
|
||||
if ($this->isRequired) {
|
||||
$fail("Missing value for row '{$row}'.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$cellValue = $value[$row];
|
||||
|
||||
if ($cellValue === null) {
|
||||
if ($this->isRequired) {
|
||||
$fail("Value for row '{$row}' is required.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($cellValue, $columns)) {
|
||||
$fail("Invalid value '{$cellValue}' for row '{$row}'.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for extra rows that shouldn't be there
|
||||
$extraRows = array_diff(array_keys($value), $rows);
|
||||
foreach ($extraRows as $extraRow) {
|
||||
$fail("Unexpected row '{$extraRow}' in the matrix.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,8 @@ class FormLogicConditionChecker
|
||||
return $this->multiSelectConditionMet($propertyCondition, $value);
|
||||
case 'files':
|
||||
return $this->filesConditionMet($propertyCondition, $value);
|
||||
case 'matrix':
|
||||
return $this->matrixConditionMet($propertyCondition, $value);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -90,6 +92,30 @@ class FormLogicConditionChecker
|
||||
return \Str::contains($fieldValue, $condition['value']);
|
||||
}
|
||||
|
||||
private function checkMatrixContains($condition, $fieldValue): bool
|
||||
{
|
||||
|
||||
foreach($condition['value'] as $key => $value) {
|
||||
if(!(array_key_exists($key, $condition['value']) && array_key_exists($key, $fieldValue))) {
|
||||
return false;
|
||||
}
|
||||
if($condition['value'][$key] == $fieldValue[$key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkMatrixEquals($condition, $fieldValue): bool
|
||||
{
|
||||
foreach($condition['value'] as $key => $value) {
|
||||
if($condition['value'][$key] !== $fieldValue[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkListContains($condition, $fieldValue): bool
|
||||
{
|
||||
if (is_null($fieldValue)) {
|
||||
@@ -408,4 +434,20 @@ class FormLogicConditionChecker
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function matrixConditionMet(array $propertyCondition, $value): bool
|
||||
{
|
||||
switch ($propertyCondition['operator']) {
|
||||
case 'equals':
|
||||
return $this->checkMatrixEquals($propertyCondition, $value);
|
||||
case 'does_not_equal':
|
||||
return !$this->checkMatrixEquals($propertyCondition, $value);
|
||||
case 'contains':
|
||||
return $this->checkMatrixContains($propertyCondition, $value);
|
||||
case 'does_not_contain':
|
||||
return !$this->checkMatrixContains($propertyCondition, $value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,17 @@ class FormSubmissionFormatter
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMatrixString(array $val): string
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($val as $key => $value) {
|
||||
if ($key !== null && $value !== null) {
|
||||
$parts[] = "$key: $value";
|
||||
}
|
||||
}
|
||||
return implode(' | ', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nice "FieldName": "Field Response" array
|
||||
* - If createLink enabled, returns html link for emails and links
|
||||
@@ -145,7 +156,9 @@ class FormSubmissionFormatter
|
||||
} else {
|
||||
$returnArray[$field['name']] = $val;
|
||||
}
|
||||
} elseif (in_array($field['type'], ['files', 'signature'])) {
|
||||
} elseif ($field['type'] == 'matrix' && is_array($data[$field['id']])) {
|
||||
$returnArray[$field['name']] = $this->getMatrixString($data[$field['id']]);
|
||||
} elseif ($field['type'] == 'files') {
|
||||
if ($this->outputStringsOnly) {
|
||||
$formId = $this->form->id;
|
||||
$returnArray[$field['name']] = implode(
|
||||
@@ -219,7 +232,9 @@ class FormSubmissionFormatter
|
||||
} else {
|
||||
$field['value'] = $val;
|
||||
}
|
||||
} elseif (in_array($field['type'], ['files', 'signature'])) {
|
||||
} elseif ($field['type'] == 'matrix') {
|
||||
$field['value'] = str_replace(' | ', "\n", $this->getMatrixString($data[$field['id']]));
|
||||
} elseif ($field['type'] == 'files') {
|
||||
if ($this->outputStringsOnly) {
|
||||
$formId = $this->form->id;
|
||||
$field['value'] = implode(
|
||||
|
||||
Reference in New Issue
Block a user