Search code examples
laravellaravel-5laravel-validation

Seeding validation array


I am creating a lot of questions via a seeder. The format I am doing is this

DB::table('questions')->insert([
    'name' => 'questionOne',
    'rule' => 'nullable|max:50|regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/'
]);

Whereby I provide a field name and a validation rule. I was noticing that when applying the above rule, the validation would fail, stating

preg_match(): No ending delimiter '/' found

I done some research and found out that

When using the regex pattern, it may be necessary to specify rules in an array instead of using pipe delimiters, especially if the regular expression contains a pipe character.

As recommended, I changed my seeder to this

DB::table('questions')->insert([
    'name' => 'questionOne',
    'rule' => ['nullable|max:50|regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/']
]);

However, when I try to seed with the above, I get an Array to String conversion error. The way I am applying the validation is like so

$rules = [];
$questions = Question::all();
foreach ($questions as $question) {
    if (!empty($question->rule)) {
        $rules["questions.{$question->id}"] = $question->rule;
    }
}

$this->validate($request, $rules);

Is there any way I can get the above regex to work? One point to note is that only a few questions have this regex, if that matters?

Thanks


Solution

  • When using the regex pattern, it may be necessary to specify rules in an array instead of using pipe delimiters, especially if the regular expression contains a pipe character.

    This is referring to the $rules variable passed into $this->validate; your regex pattern contains a pipe character | which interferes with Laravel's ability to split up the rule string into an array internally.

    Storing the rules in string format with pipe separators also makes it difficult for you to split them into an array upon retrieval from the DB. I'd recommend storing them as a similarly delineated structure like JSON, which would make your seeder:

    DB::table('questions')->insert([
        'name' => 'questionOne',
        'rule' => json_encode([
            'nullable',
            'max:50',
            'regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/'
        ])
    ]);
    

    and validation:

    $rules = [];
    $questions = Question::all();
    foreach ($questions as $question) {
        if (!empty($question->rule)) {
            $rules["questions.{$question->id}"] = json_decode($question->rule, true);
        }
    }
    
    $this->validate($request, $rules);
    

    You would also want to change the rule column type to JSON in your questions table migration.

    To further simplify the code, you could make use of Laravel's attribute casting feature which claims to handle the json_encode/json_decode for you:

    protected $casts = [
        'rule' => 'array',
    ];