Laravel Model的$casts使用

xmkl發表於2021-03-08

$castsModel提供的一個型別轉換的陣列,在使用該屬性時,無論是設定資料還是獲取資料,都將會把指定欄位轉換為指定的型別,但只在特定方式下有效:

示例類

class Test extends Model 
{
    protected $casts = [
        'data' => 'json'
    ]
}

有效的例子

獲取資料時

獲取資料時,轉換規則如下:

# fromJson實際執行的是json_decode
protected function castAttribute($key, $value)
{
    if (is_null($value)) {
        return $value;
    }
    switch ($this->getCastType($key)) {
        case 'int':
        case 'integer':
            return (int) $value;
        case 'real':
        case 'float':
        case 'double':
            return (float) $value;
        case 'string':
            return (string) $value;
        case 'bool':
        case 'boolean':
            return (bool) $value;
        case 'object':
            return $this->fromJson($value, true);
        case 'array':
        case 'json':
            return $this->fromJson($value);
        case 'collection':
            return new BaseCollection($this->fromJson($value));
        case 'date':
            return $this->asDate($value);
        case 'datetime':
            return $this->asDateTime($value);
        case 'timestamp':
            return $this->asTimestamp($value);
        default:
            return $value;
    }
}
下面的例子都會應用$casts的型別轉換規則

1.使用了toArray函式

$model = app(Test::class)->find(1)->toArray();

2.使用了toJson函式

# 使用toJson時,他將先呼叫toArray,再呼叫json_encode
$model = app(Test::class)->find(1)->toJson();
設定屬性時

設定屬性時,只對目標型別為時間型別'date', 'datetime'物件型別'array', 'json', 'object', 'collection'做轉換,對其他型別不做處理。時間型別將根據dateFormat設定的格式做處理,物件型別將轉換為json。型別轉換是在setAttribute函式中進行的,所以只要呼叫了setAttribute函式,都會應用$casts屬性做型別轉換。但是如果使用了修改器,如:setDataAttribute$casts將無效。

以下方式將都會應用$casts屬性

1.使用Modelfill()函式填充屬性時

$data = ['data' => ['test' => '這是資料']];
$model = app(Test::class)->fill($data)->save();

2.使用的Modelupdate()函式時

$data = ['data' => ['test' => '這是資料']];
$model = app(Test::class)->update($data);

3.直接給model賦值,這種方式會通過__set去呼叫setAttribute函式

$data = ['test' => '這是資料'];
$model = app(Test::class)->find(1);
$model->data = $data;
$model->save();

4.使用setAttribute函式時

$data = ['test' => '這是資料'];
$model = app(Test::class)->find(1);
$model->setAttribute('data', $data);
$model->save();

無效的例子

它們將無法應用$casts屬性做型別轉換,因為他們都沒有經過ModelsetAttribute函式。

1.使用query直接運算元據將報錯

$data = ['test' => '這是資料'];
$model = app(Test::class);
$model->newQuery()->where('id', 1)->update($data)

2.使用了修改器

# 定義修改器,將不會應用$casts屬性做型別轉換
public function setDataAttribute(array $data)
{
    return json_encode($data);
}

# 雖然經過了setAttribute函式,但是修改器的優先順序比$casts高
$data = ['test' => '這是資料'];
$model = app(Test::class)->fill($data)->save();

以下是setAttribute函式

    /**
     * Set a given attribute on the model.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return $this
     */
    public function setAttribute($key, $value)
    {
        # 檢查修改器
        if ($this->hasSetMutator($key)) {
            $method = 'set'.Str::studly($key).'Attribute';
>
            return $this->{$method}($value);
        }
>
        # 處理日期型別
        elseif ($value && $this->isDateAttribute($key)) {
            $value = $this->fromDateTime($value);
        }

>          #    處理物件型別
        if ($this->isJsonCastable($key) && ! is_null($value)) {
            $value = $this->castAttributeAsJson($key, $value);
        }
>
        # 處理json資料
        if (Str::contains($key, '->')) {
            return $this->fillJsonAttribute($key, $value);
        }
>
        $this->attributes[$key] = $value;
>
        return $this;
    }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章