Laravel Eloquent 之 Fill 方法解析

上一次分析了 Laravel 中的模型事件与观察者模式,此次来解析一下 Eloquent 中的 fillphp

Laravel 的童鞋应该都知道,fill 方法是一个给 Eloquent 实例赋值属性的方法,让咱们点开 fill 方法先看一看它的源码:数组

这里笔者所使用的版本为 Laravel 5.5最新版,为了方便阅读,删除掉了注释框架

public function fill(array $attributes)
{
    $totallyGuarded = $this->totallyGuarded();

    foreach ($this->fillableFromArray($attributes) as $key => $value) {
        $key = $this->removeTableFromKey($key);

        if ($this->isFillable($key)) {
            $this->setAttribute($key, $value);
        } elseif ($totallyGuarded) {
            throw new MassAssignmentException($key);
        }
    }

    return $this;
}

首先能够看到,Laravel 会先去调用一个自身的 totallyGuarded 方法,让咱们点开这个方法:函数

public function totallyGuarded()
{
   return count($this->getFillable()) == 0 && $this->getGuarded() == ['*'];
}

能够看到这个方法的做用就是去获取自身的 fillableguarded,而后判断他们是否都为 不可批量赋值 状态,最后返回一个布尔值this

// 返回一个 True or False 的布尔值
// 若是未设置 fillable 与 guarded,则会返回 True (注意,在这种状况下,此 `Model` 是不容许批量赋值任何属性的哦)
// 反之则返回 False
$totallyGuarded = $this->totallyGuarded();

Ok,让咱们回到刚才的 fill 方法继续往下看设计

接下来是一个 foreach 循环,可是在循环以前,Laravel 对传入的赋值属性执行了 fillableFromArray 这个方法,再点进去看一下,code

protected function fillableFromArray(array $attributes)
{
    if (count($this->getFillable()) > 0 && ! static::$unguarded) {
        return array_intersect_key($attributes, array_flip($this->getFillable()));
    }

    return $attributes;
}

此方法会检测你是否在 fillable 数组中定义了值,若是定义了值,则会返回 fillableattributes 相交的值,若是没有,则返回 attributes 自身事件

而后回到 fill ,在调用 fillableFromArray 对参数进行处理以后,如今返回的值只剩咱们容许批量赋值的属性了 (若是你定义了)ip

循环第一行,先使用 removeTableFromKey 对参数的 Key 进行处理,删除键中的表名,此方法就不作过多讲解,只是一个字符串拆分取值的函数rem

$key = $this->removeTableFromKey($key);

接着往下看,Laravel对将要进行填充的每一个属性都调用了 isFillable 方法来确保此属性是能够被填充的,让咱们看一看它的源码:

public function isFillable($key)
{
   if (static::$unguarded) {
       return true;
   }

   if (in_array($key, $this->getFillable())) {
       return true;
   }

   if ($this->isGuarded($key)) {
       return false;
   }

   return empty($this->getFillable()) &&
       ! Str::startsWith($key, '_');
}

能够看到,在此方法中 Laravel 先判断了此 Model 是否禁用了守卫 (guarded),若是此 Model 并未启用守卫,那么直接返回 True

if (static::$unguarded) {
    return true;
}

若是启用了守卫,那么会判断一下此属性是否存在于 fillable 数组中,若是存在,则返回 True,

if (in_array($key, $this->getFillable())) {
    return true;
}

若是此属性不存在于 fillable 数组中,那么 Laravel 会再次判断此属性是否存在于 guarded 数组中,若是存在于此数组中,那么此属性就不是一个能够被批量赋值的属性,那么就会直接返回 False

if ($this->isGuarded($key)) {
    return false;
}

若是以上都不符合,那么 Laravel 在最后会判断一下自身的 fillable 数组是为空而且此属性是以 _ 开头,而后返回一个布尔值

return empty($this->getFillable()) && ! Str::startsWith($key, '_');

而后回到 fill 方法接着看,若是此属性经过了 isFillable 方法的过滤,那么将此属性赋值给自身 (由于时间有限,setAttribute 这个方法就不细讲啦~),

$this->setAttribute($key, $value);

若是没有经过 isFillable 方法的过滤,那么 Laravel 会判断一下自身 Model 是否处于不限制任何属性批量赋值的状态,若是不是,那么 Laravel 会直接抛出一个 Exception

// 判断此属性是否经过了检测
if ($this->isFillable($key)) {
    // 将此属性赋值给自身
    $this->setAttribute($key, $value);

// 若是没有经过检测,那么判断一下自身 `Model` 是否为所有不可批量赋值状态,若是是,那么会抛出一个 `Exception`
} elseif ($totallyGuarded) {
    throw new MassAssignmentException($key);
}

在对全部的属性进行检测而且赋值后, Laravel 会将自身返回

return $this;

解析完毕,以上就是 fill 方法的源码啦~,最后来一个小结

在你调用 fill 方法的时候,Laravel 首先就会去检测当前 Model 的状态,

当你设置了 fillable 数组,没有设置 guarded 数组时,那么此 Model 会处于 仅可批量赋值指定属性 的状态
当你没有设置 fillable 数组,却设置了 guarded 数组时,那么此 Model 会处于 可批量赋值任何属性 的状态
至于你同时设置了 fillableguarded 数组的状况就不去讨论了,由于这样作自己就是被 Laravel 所禁止的

而后调用 fillableFromArray 去获取 attributesfillable 数组的交集,若是你没有定义 fillable 或者禁用掉了守卫,那么此方法会直接返回 attributes

而后 Laravel 会对返回的数组作一个循环,在这个循环中 Laravel 会对每个属性调用 isFillable 方法检测这个属性是否能够被填充,若是没有经过此方法的检测(不存在于fillable 数组中而且没有设置 guarded 数组或存在于 guarded 数组中),那么 Laravel会检测当前 Model 是否处于 仅可批量赋值指定属性 状态,若是是,那么会直接抛出一个 Exception

而后 Laravel 会返回完成赋值操做后的 $this

以上就是 Eloquentfill 方法的源码解析啦~,Laravel 的源码读下来仍是很清晰易懂的~,不得再也不次佩服 Laravel 的设计,不愧为 巨匠级框架

相关文章
相关标签/搜索