dwightwatson / validating

Automatically validating Eloquent models for Laravel
MIT License
968 stars 76 forks source link

Validation of dynamic attributes during model creation #234

Closed hlorofos closed 2 years ago

hlorofos commented 2 years ago

I'm using the following construct to pre-fill some Model attributes during its creation:

    protected $throwValidationExceptions = true;

    protected array $rules = [
        'school_id' => 'required',
    ];

  public static function boot()
    {
        parent::boot();

        self::creating(function (self $model) {
            if (\Auth::user()) {
                // Add School from Admin user who created the Room.
                $model->school_id = \Auth::user()->school_id;
            }
        });
    }

and I'm using Room::create($itemData) call to create the Model.

Current behavior

I'm getting the exception The school id field is required.

Expected behavior:

school_id attribute being populated during the Model creation and then validation passes.

dwightwatson commented 2 years ago

I don't think this is a particularly common use-case as it hasn't come up before.

Happy to look over a PR that can handle this with tests, but otherwise this likely won't be changed.

hlorofos commented 2 years ago

Actually after the research I don't see the way we can fix this from validator side, since observer priorities support was dropped a while ago. Instead I worked around the model itself, so that my custom code ran before the validation. Although initially my observer called creating Laravel framework flaws to run the code before validator saving observer. So here is the solution:

    protected array $rules = [
        'school_id' => 'required',
    ];

    public static function boot()
    {
        static::saving(function (self $model) {
            if (!$model->school_id && \Auth::user()) {
                // Add School from Admin user who created the Room.
                $model->school_id = \Auth::user()->school_id;
            }
        });
        parent::boot();
    }
dwightwatson commented 2 years ago

Cool, thanks for following up - glad you found a solution!