Laravel 學習筆記之 model validation

在對database進行寫操做前,須要對數據進行validation,如type-check 每個 model column 的定義('type' 這個column必須是enum('card','loan')),這裏使用model event來作。數據庫

在EventServiceProvider(或自定義一個ValidationServiceProvider)中寫上:app

public function boot()
{
        /**
         * Inspired by @see \Illuminate\Foundation\Providers\FormRequestServiceProvider::boot()
         *
         * Note: saving event is always triggered before creating and updating events
         */
        $this->app['events']->listen('eloquent.saving: *', function (string $event_name, array $data): void {
            /** @var \App\Extensions\Illuminate\Database\Eloquent\Model $object */
            $object = $data[0];
            
            $object->validate();
        });
}

'eloquent.saving: *'是表示listen全部model的saving,即任何一個model的寫操做都會觸發該事件。ide

而後寫一個abstract model extends EloquentModel:ui

// \App\Extensions\Illuminate\Database\Eloquent\Model

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Validation\ValidationException;

abstract class Model extends EloquentModel
{
    public function validate():void
    {
        // 1. validate type rules (type-check)
        $validator = $this->getTypeValidator();
        
        if ($validator->fails()) {
            throw new ValidationException($validator);
        }
        
        // $validator = $this->getConstraintValidator();
        // 2. validate constraint rules (sanity-check)
    }

    protected function getTypeValidator()
    {
        return $this->getValidationFactory()->make($this->attributes, static::COLUMN_TYPE_RULES);
    }
    
    protected function getValidationFactory()
    {
        return app(Factory::class);
    }
    
    protected function getConstraintValidator()
    {
        // return $this->getValidationFactory()->make($attributes, static::COLUMN_CONSTRAINT_RULES);
    } 
}

這樣,在每個繼承abstract model的子類中,定義const COLUMN_TYPE_RULES就行,如:this

class Account extends Model
{
    public const COLUMN_TYPE_RULES = [
        'id' => 'integer|between:0,4294967295',
        'source' => 'nullable|in:schwab,orion,yodlee',
        'type' => 'required|in:bank,card,loan',
    ];
}

在寫操做時,提早對每個 model 的 schema definition進行type-check,避免無效碰撞 database。這個feature的目的是從model schema去校驗輸入數據的字段定義是否合法。
另一般除了type-check schema definition 外,還得根據業務須要進行邏輯校驗sanity-check constraint rules,如當建立一個account時,輸入inputs裏的字段person_id不能是child未成年人,等等。這裏業務不一樣,constraint rules不一樣,不作過多解釋。這個feature的目的主要是從邏輯上校驗輸入數據的合法性。code

OK,總之通常狀況下,在寫數據庫前都須要作 model validation,避免無效hit db。orm

相關文章
相關標籤/搜索