I am developing dynamic query builder for the admin users and for the same I am implementing POST API request to store all conditions together in database.
I am stuck with the validation of POST json. I tried different ways to prepare rule array.
Below is the code snippet for validation part.
Controller Action
public function saveConditions(ConditionRequest $request, Action $action): JsonResponse
{
dd($request, $action);
}
ConditionRequest.php
use AppAdminHttpRequestsFormRequest;
use AppRulesConditionsRecursiveConditionRule;
class ConditionRequest extends FormRequest
{
public function rules()
{
return [
'conditions' => ['required', 'array'],
'conditions.*' => [new RecursiveConditionRule()],
];
}
}
RecursiveConditionRule.php
use IlluminateContractsValidationValidationRule;
use IlluminateSupportFacadesValidator;
use IlluminateValidationRule;
use IlluminateValidationValidationException;
use Closure;
class RecursiveConditionRule implements ValidationRule
{
public function validate($attribute, $value, Closure $fail): void
{
$this->validateRecursive($attribute, $value);
}
protected function validateRecursive($attribute, $value): void
{
$conditionRules = [
$attribute => 'array',
"$attribute.type_slug" => ['required', Rule::in(ConditionType::all())],
"$attribute.subjected_table" => ['required_if:type_slug,simple', 'string'],
"$attribute.table_alias" => ['required_if:type_slug,simple', 'string'],
"$attribute.logical_operator" => ['required', Rule::in(Operator::all())],
"$attribute.relation_and_column" => ['nullable', 'string'],
"$attribute.column_type" => ['nullable', 'string', Rule::in(ColumnType::all())],
"$attribute.filter_criteria" => ['nullable', 'string', Rule::in(FilterCriteria::all())],
"$attribute.filter_value" => ['nullable', 'string'],
"$attribute.sub_conditions" => ['required_if:type_slug,group', 'array'],
];
$validator = Validator::make([$attribute => $value], $conditionRules);
if ($validator->fails()) {
throw new ValidationException($validator);
}
if (isset($value['sub_conditions']) && is_array($value['sub_conditions'])) {
foreach ($value['sub_conditions'] as $index => $subCondition) {
$this->validateRecursive("$attribute.sub_conditions.$index", $subCondition);
}
}
}
public function message()
{
return 'The :attribute is invalid.';
}
}
and below is my JSON request sample (It is with dummy data.)
{
"conditions": [
{
"type_slug": "simple",
"subjected_table": "users",
"table_alias": "u",
"logical_operator": "and",
"relation_and_column": "name",
"column_type": "string",
"filter_criteria": "contains",
"filter_value": "john"
},
{
"type_slug": "group",
"logical_operator": "or",
"sub_conditions": [
{
"type_slug": "simple",
"subjected_table": "orders",
"table_alias": "o",
"logical_operator": "and",
"relation_and_column": "invoice.total",
"column_type": "numeric",
"filter_criteria": "greater_than",
"filter_value": 100
},
{
"type_slug": "simple",
"subjected_table": "orders",
"table_alias": "o",
"logical_operator": "and",
"relation_and_column": "status",
"column_type": "string",
"filter_criteria": "contains",
"filter_value": "completed"
},
{
"type_slug": "group",
"logical_operator": "or",
"sub_conditions": [
{
"type_slug": "simple",
"subjected_table": "orders",
"table_alias": "o",
"logical_operator": "and",
"relation_and_column": "total",
"column_type": "numeric",
"filter_criteria": "greater_than",
"filter_value": 100
},
{
"type_slug": "simple",
"subjected_table": "orders",
"table_alias": "o",
"logical_operator": "and",
"relation_and_column": "status",
"column_type": "string",
"filter_criteria": "contains",
"filter_value": "completed"
}
]
}
]
},
{
"type_slug": "simple",
"subjected_table": "products",
"table_alias": "p",
"logical_operator": "or",
"relation_and_column": "title",
"column_type": "string",
"filter_criteria": "contains",
"filter_value": "apple"
},
{
"type_slug": "group",
"logical_operator": "and",
"sub_conditions": [
{
"type_slug": "simple",
"subjected_table": "orders",
"table_alias": "o",
"logical_operator": "and",
"relation_and_column": "total",
"column_type": "numeric",
"filter_criteria": "greater_than",
"filter_value": 200
},
{
"type_slug": "simple",
"subjected_table": "products",
"table_alias": "p",
"logical_operator": "or",
"relation_and_column": "title",
"column_type": "string",
"filter_criteria": "contains",
"filter_value": "banana"
}
]
}
]
}
It gives me below response::
{
"message": "This field is required. (and 1 more error)",
"errors": {
"conditions.0.type_slug": [
"This field is required."
],
"conditions.0.logical_operator": [
"This field is required."
]
}
}
It seems validator is not receiving attribute and values properly for the recursive call. How can I fix this?
2
Answers
I think your validation key should be:
"$attribute.*.type_slug"
rather than"$attribute.type_slug"
However personally, I would focus in building the correct rules array from the input rather than trying to validate recursively. So you can loop through the input recursively and input rules into
$rules
depending on the given fields.Your validator fails since, given your
$rules
array, it expects input data in the form of:but instead you are providing it with data in the form of:
A simple work around it to remove the "dot" syntax from your input keys.