7

I have a form that posts a structure field as an array. The structure array contains definitions of database table columns.

$validator = Validator::make($request->all(), [
    'structure' => 'required|array|min:1',
    'structure.*.name' => 'required|regex:/^[a-z]+[a-z0-9_]+$/',
    'structure.*.type' => 'required|in:integer,decimal,string,text,date,datetime',
    'structure.*.length' => 'nullable|numeric|required_if:structure.*.type,decimal',
    'structure.*.default' => '',
    'structure.*.index' => 'required_if:is_auto_increment,false|boolean',
    'structure.*.is_nullable' => 'required_if:is_auto_increment,false|boolean',
    'structure.*.is_primary' => 'required_if:is_auto_increment,false|boolean',
    'structure.*.is_auto_increment' => 'required_if:structure.type,integer|boolean',
    'structure.*.is_unique' => 'required_if:is_auto_increment,false|boolean',
    'structure.*.decimal' => 'nullable|numeric|required_if:structure.*.type,decimal|lt:structure.*.length',
]);

Without going into explanation of all the rules, one thing should be made sure that the length field is always null when the type is not string or decimal as you cannot assign a length to columns other than these types. So, I am trying to use the sometimes method on the $validator instance.

$validator->sometimes('structure.*.length', 'in:null', function ($input) {
    // how to access the structure type here?
});

My question is inside the closure, how do I make sure that the length is null only for the array element that has the type set to other than string or decimal.

I have tried the dd function and it seems the whole input array is passed to the closure.

$validator->sometimes('structure.*.length', 'in:null', function ($input) {
    dd($input);
});

Here is the output of the dd method.

Output of the <code>dd</code> method

I can use a foreach construct but wouldn't that be inefficient? Checking all the elements for a single element?

How do I check the type only for the array element under consideration?

Is there a Laravel way to do this?

2
  • What's the output of dd($input) inside the closure? Commented Feb 6, 2019 at 8:21
  • @Mozammil Question updated! Commented Feb 6, 2019 at 8:29

2 Answers 2

1

How about thinking opposite? if the Type is String or Decimal, the Length field will become Required.

$validator->sometimes('structure.*.length', 'required', function ($input) {
    return $input->type == 'string' or $input->type == 'decimal';
});
Sign up to request clarification or add additional context in comments.

Comments

0

This is a great question. I took a look at the API for sometimes(). It seems, what you want to do, is currently not possible with it.

A possible alternative could be to use an After Validation Hook. For example:

$validator->after(function ($validator) {
    $attributes = $validator->getData()['structure'];

    foreach($attributes as $key => $value) {
        if(! in_array($value['type'], ['string', 'decimal']) && ! is_null($value['length'])) {
            $validator->errors()->add("structure.{$key}.length", 'Should be null');
        }
    }
});

3 Comments

I am not sure if I should be marking this answer correct since I am asking for something that is not possible and people will keep posting alternate approaches. However, in the interest of keeping things lightweight, your answer seems to be the best one as there is no need to create classes. One comment though. $attributes = array_values(array_only($validator->getData(), 'structure')); can be simplified to $attributes = $validator->getData()['structure'];. If no, can you explain a bit why you choose to go that way?
You could do that. Just a matter of personal preference I guess. It won't fail if for some reason structure is not present in the array.
The validation rules I have posted in the question make sure that structure is an array and has atleast one element.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.