模型仅Query后更新, fillable或guarded不生效的解决方案

今天同事问了我一个问题:批量更新为啥guarded的设置无效?

先看代码:

// 模型定义
protected $guarded = ['name'];
// guarded不生效操作
Model::query()->update(['name'=>'Robin']);

这种方式本质是直接执行了sql, 模型本身并没有实例化。只有当模型实例化成对象后,对应的事件才生效。同理,如果直接使用query()->update(), Observer对应的事件也是不生效的。

// guarded生效
$model = Model::query()->find(1);
$model->update(['name'='Robin']);

如何解决?起初靓仔说先把模型都查出来,然后each一下循环改,但是觉得既然都批量了,还改循环,模型还得全查出来不是还得吃资源吗?我一听,有道理,遂着手改造。

看一眼Model的源码:

abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
    /**
     * Create a new Eloquent query builder for the model.
     *
     * @param  \Illuminate\Database\Query\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder|static
     */
    public function newEloquentBuilder($query)
    {
        return new Builder($query);
    }
}

我就不赘述我的心路历程了,总之我发现使用query()后,最终会通过newEloquentBuilder方法得到一个Illuminate\Database\Eloquent\Builder,那么只要重写这个方法,返回一个自定义的Builder即可

开始改造:

随手挑个模型吧,这里用User当小白鼠

class User extends Model
{
    protected $fillable = ['name'];

    public function newEloquentBuilder($query)
    { 
        return new UserBuilder($query, [
            'fillable' => $this->fillable
        ]);
    }
}

自定义UserBuilder

<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Database\Query\Builder as QueryBuilder;

class UserBuilder extends Builder
{

  protected $options;
  /**
   * Create a new Eloquent query builder instance.
   *
   * @param  \Illuminate\Database\Query\Builder  $query
   * @return void
   */
  public function __construct(QueryBuilder $query, $options)
  {
    $this->query = $query;
    $this->options = $options;
  }

  /**
   * Update records in the database.
   *
   * @param  array  $values
   * @return int
   */
  public function update(array $values)
  {
    // $user = Auth::user();
    // unset($query['title']);


    $newValues = Arr::only($values, $this->options['fillable']);

    return parent::update($newValues);
  }
}

现在query()->update()也能通过$fillable限制字段了,问题解决。
本文使用的其实是一种Hack方法,如果大家有更好的解决方案还望不吝指教。

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!