Closed artworkad closed 2 years ago
Repo to reproduce the issue: https://github.com/artworkad/enum-cast-validation
Test:
it('requires title_other if title is set to OTHER (Action)', function () {
$post = Post::factory()->make([
'title' => PostTopic::OTHER->value,
'title_other' => null,
]);
StorePostAction::run($post);
})->throws(ValidationException::class);
it('requires title_other if title is set to OTHER (FormRequest)', function () {
$this->post('/posts/', [
'title' => PostTopic::OTHER->value,
'title_other' => null,
])->assertStatus(302);
});
Action:
class StorePostAction
{
use AsAction;
use WithAttributes;
public function rules(): array
{
return [
'post.title' => ['required', new Enum(PostTopic::class)],
'post.title_other' => 'required_if:post.title,' . PostTopic::OTHER->value
];
}
public function handle(Post $post, array $attributes = []): Post
{
$this->set('post', $post)->fill($attributes);
$this->validateAttributes();
$post->save();
return $post;
}
}
Request:
class StorePostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'title' => ['required', new Enum(PostTopic::class)],
'title_other' => 'required_if:title,' . PostTopic::OTHER->value
];
}
}
Post:
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'title_other',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'title' => PostTopic::class
];
}
The action test fails. When 'title' => PostTopic::class
is commented out, it passes again.
Hi @artworkad.
I believe the error is in your validation. You are trying to validate an attribute within a model and not an array. I believe this is not supported by laravel.
it('requires title_other if title is set to OTHER (Action)', function () {
$post = Post::factory()->make([
'title' => PostTopic::OTHER->value,
'title_other' => null,
]);
validator(['post'=>$post],[
'post.title' => ['required', new Enum(PostTopic::class)],
'post.title_other' => 'required_if:post.title,' . PostTopic::OTHER->value
])->validate();
})->throws(ValidationException::class);
So, I suggest another approach.
it('requires title_other if title is set to OTHER (Action)', function () {
$post = Post::factory()->make([
'title' => PostTopic::OTHER->value,
'title_other' => null,
]);
StorePostAction::run($post);
})->throws(ValidationException::class);
class StorePostAction {
use AsAction;
use WithAttributes;
public function rules(): array {
return [
'title' => ['required', new Enum(PostTopic::class)],
'title_other' => 'required_if:post.title,' . PostTopic::OTHER->value,
];
}
public function handle(Post $post, array $attributes = []): Post {
$this->set('post', $post)->fill($attributes);
$this->validateAttributes();
$post->save();
return $post;
}
}
You have 2 examples. Using laravel-actions and using formRequest, but you have different keys in the formRequest rules.
class StorePostAction {
public function rules() {
return [
'post.title' => ['required', new Enum(PostTopic::class)],
'post.title_other' => 'required_if:post.title,' . PostTopic::OTHER->value,
];
}
}
class StorePostRequest extends FormRequest {
public function rules() {
return [
'title' => ['required', new Enum(PostTopic::class)],
'title_other' => 'required_if:title,' . PostTopic::OTHER->value,
];
}
}
@leandrodiogenes Thanks for your feedback!
Validation with nested attributes is supported: https://laravel.com/docs/9.x/validation#a-note-on-nested-attributes. The validation is working in general, just not for "post.title_other". Why? Shouldn't it fail for the other fields aswell?
Both
public static function rules(): array
{
return [
'post.title' => ['required', new Enum(PostTopic::class)],
'post.title_other' => 'required_if:post.title,' . PostTopic::OTHER->value
];
}
and
public static function rules(): array
{
return [
'title' => ['required', new Enum(PostTopic::class)],
'title_other' => 'required_if:title,' . PostTopic::OTHER->value
];
}
work. The difference is, that the first one does not pick up post.title_other rule.
@leandrodiogenes thanks for you help. I fixed this issue by converting post to array:
$this->set('post', $post->toArray())->fill($attributes);
The validation rules work now, even with "post." prefix.
Hello!
I am having an issue with required_if validation and enums. I want to require title_other if title is set to NoteTopic::OTHER->value. The enum is backed by int, so NoteTopic::OTHER->value would be 16.
However validation does not work for title_other. The field is never required. Even if I change the rule directly to 'title_other' => 'required_if:title,16'. All the other rules work fine.
Since that validation works in vanilla laravel I guess the issue may be somewhere in WithAttributes. Inside WithAttributes I logged the rules:
and validation data:
Everything is looking good and the validation should work. However the validation for title_other does not fire. I am using laravel 9.34 and actions 2.4.