Reputation: 1147
I am storing an array of strings in my database (db column type is JSON). There is a form that allows users to add a value to this array. I want to make sure there are no duplicates in this array. The notIn validation rule appears be the simplest solution to prevent duplicates but it is case sensitive. So when using notIn I am not able to prevent identical strings that have different capitalization.
$this->validate(request(), [
'choice' => [
'required',
Rule::notIn($choices)
]
]);
Does anyone have recommendation on how I should fix this validation so that the string comparison is case insensitive?
Upvotes: 5
Views: 12774
Reputation: 583
i know it is a little late, but for others i will suggest to use prepareForValidation method inside custom request class; like follow
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterRequest extends FormRequest
{
protected function prepareForValidation()
{
$this->merge([
'choices' => strtolower($this->choices),
]);
}
}
this way user input for choices are always lower case and the request itself is modified too.
Upvotes: 2
Reputation: 624
You could lowercase your input data as well as your current data like this:
$input = request()->all();
$input['choice'] = array_map("strtolower", $input['choice']);
request()->validate($input, [
'choice' => [
'required',
Rule::notIn(array_map("strtolower", $choices))
]
]);
Upvotes: 8
Reputation: 137
You can write your own validation rule class:
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Validation\Concerns\ValidatesAttributes;
use Illuminate\Validation\Rules\In;
class CaseInsensitiveInRule extends In implements Rule
{
use ValidatesAttributes;
private const FORMAT_FUNCTION = 'strtoupper';
public function __construct(array $values)
{
$this->values = array_map(self::FORMAT_FUNCTION, $values);
}
public function passes($attribute, $value)
{
$value = call_user_func(self::FORMAT_FUNCTION, $value);
return $this->validateIn($attribute, $value, $this->values);
}
public function message()
{
return __('validation.invalid_value');
}
}
and next you can create a object in your request class
public function rules(): array
{
return [
'status' => new CaseInsensitiveInRule(['active', 'deleted'])
];
}
Upvotes: 2
Reputation: 1147
Thanks Ramy Herria, I was able to expand his answer to also work in a FormRequest class:
protected function validationData()
{
$all = parent::validationData();
//Convert request value to lowercase
$all['choice'] = strtolower($all['choice']);
return $all;
}
public function rules()
{
$choices = $this->route('modelName')->choices;
return [
'choice' => [
'required',
//Also convert array to lowercase
Rule::notIn(array_map('strtolower', $choices))
]
];
}
Upvotes: 5