资讯专栏INFORMATION COLUMN

Laravel Eloquent 之 Fill 方法解析

skinner / 3680人阅读

摘要:上一次分析了中的模型事件与观察者模式这次来解析一下中的用的童鞋应该都知道方法是一个给实例赋值属性的方法让我们点开方法先看一看它的源码这里笔者所使用的版本为最新版为了方便阅读删除掉了注释首先可以看到会先去调用一个自身的方法让我们点开

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

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,然后判断他们是否都为 不可批量赋值 状态,最后返回一个布尔值

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

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

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

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 对参数进行处理之后,现在返回的值只剩我们允许批量赋值的属性了 (如果你定义了)

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

$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 的设计,不愧为 巨匠级框架

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26186.html

相关文章

  • Laravel源码解析Model

    摘要:根据单一责任开发原则来讲,在的开发过程中每个表都应建立一个对外服务和调用。类似于这样解析的数据操作分两种它们除了有各自的特色外,基本的数据操作都是通过调用方法去完成整个。内并没有太多的代码,大多都是处理数据库链接。 showImg(https://segmentfault.com/img/bVbhjvY?w=600&h=296); 前言 提前预祝猿人们国庆快乐,吃好、喝好、玩好,我会在...

    CloudwiseAPM 评论0 收藏0
  • Laravel 学习笔记 Query Builder 源码解析(下)

    摘要:,看下源码返回很容易知道返回值是,然后将该值存储在变量中,这时。看下的源码去除掉字符后为返回从源码中可知道返回值为,这时。 说明:本文主要学习下Query Builder编译Fluent Api为SQL的细节和执行SQL的过程。实际上,上一篇聊到了IlluminateDatabaseQueryBuilder这个非常重要的类,这个类含有三个主要的武器:MySqlConnection, M...

    qpal 评论0 收藏0
  • 【整理】LaravelEloquent ORM 相关操作

    摘要:软删除当模型被软删除后,它们并没有真的从数据库删除,而是在模型上设置一个属性并插入数据库,如果模型有一个非空值,那么该模型已经被软删除了。 Laravel 中Eloquent ORM 相关操作 定义 操作 获取(查询) 获取集合,(查询列表) 返回值是 IlluminateDatabaseEloquentCollection 的一个实例 获取所有的数据 use AppUser; $us...

    dongfangyiyu 评论0 收藏0
  • PHP 项目中单独使用 Laravel Eloquent 查询语句来避免 SQL 注入

    摘要:是一个记录当前应用所受威胁情况的项目。怎么做呢用参数化查询对数据格式化,并使查询语句与数据分离。使用参数化查询,可以确保程序远离注入风险。例子如下除此之外,还有一种安全的做法,就是在项目中使用对象关系映射或者是查询构造器。 showImg(https://segmentfault.com/img/remote/1460000018641613?w=1680&h=859); OWASP ...

    dayday_up 评论0 收藏0
  • 个人整理, 阅读过的好文章 (每天随时更新)

    摘要:大家有好的文章可以在评论下面分享出来共同进步本文链接数组使用之道程序员进阶学习书籍参考指南教你在不使用框架的情况下也能写出现代化代码巧用数组函数框架中间件实现没错,这就是面向对象编程设计模式需要遵循的个基本原则令人困惑的在中使用协程实现多任 大家有好的文章,可以在评论下面分享出来, 共同进步! 本文github链接 php PHP 数组使用之道 PHP程序员进阶学习书籍参考指南 教你...

    Chiclaim 评论0 收藏0

发表评论

0条评论

skinner

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<