Laravel 版本 5.5,模型事件问题

比如使用 User::where('gender', 1)->increment('balance', 1); 更新数据时,模型事件是不触发的,在不更改上述代码的前提下,是否有办法知道数据有变更?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

再有个蠢办法,就是用注册一个DB的监听器,在这个监听器中,你可以监听到所有的sql执行。然后你可以自己想办法,匹配出你需要的sql语句,然后就可以获取参数了。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // 关键代码,监听所有的sql语句
        \DB::listen(function($query){
            // 简单举例
            if(strpos($query, 'update')>=0){
                dd($query->bindings);
            }
        });
    }
}
3年前 评论
荒街! (楼主) 3年前
讨论数量: 3

可以考虑用 event 代替

3年前 评论
荒街! (楼主) 3年前
largezhou 3年前

这里提供一个工作量较小的实现方案,只需要将increment()方法改为incrementWithEvent()即可。将下面的代码复制到你的AppServiceProvider.phpregister()中,然后将你项目中所有使用到increment()方法的代码批量修改为incrementWithEvent(),即可像正常的模型一样,监听更新事件:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // 关键代码,借用「宏」注入自定义的方法
        \Illuminate\Database\Eloquent\Builder::macro('incrementWithEvent', function(String $column, Int $amount = 1){
            $this->getModel()
            ->find($this->pluck('id'))
            ->map(function($model)use($column, $amount){
                $model->{$column} += $amount;
                // 调用save()方法会自动触发model的updated事件
                $model->save();
            });
        });
    }
}

当然,不修改现有increment()代码的话也行。但是需要增加一些其他操作,比较繁琐,看你取舍。主要思想是通过重写Illuminate\Database\Eloquent\Builderincrement()方法,来手动触发updated事件。下面简述下过程:

  • 新建一个MyBuilder类,其继承自Illuminate\Database\Eloquent\Builder。在MyBuilder类中重写increment()方法:
    <?php
    namespace App\Models;
    class MyBuilder extends \Illuminate\Database\Eloquent\Builder
    {
      public function increment($column, $amount = 1, array $extra = [])
      {
          return $this->getModel()
          ->find($this->pluck('id'))
          ->map(function($model)use($column, $amount, $extra){
              foreach ($extra as $key => $value) {
                  $model->{$key} = $value;
              }
              $model->{$column} += $amount;
               // 调用save()方法会自动触发model的updated事件
              $model->save();
          });
      }
    }
  • 修改User继承自一个自定义的父类MyBaseModelMyBaseModel继承自Illuminate\Database\Eloquent\Model。我们在这个自定义的父类中重写newEloquentBuilder($query)方法,使其返回我们写好的MyBuilder:
    <?php
    namespace App\Models;
    class MyBaseModel extends \Illuminate\Database\Eloquent\Model
    {
      public function newEloquentBuilder($query)
      {
          return new \App\Models\MyBuilder($query);
      }
    }
    这个比较麻烦,建议还是第一个方法比较好。
3年前 评论
lddtime 3年前
LiamHao (作者) 3年前
LiamHao (作者) 3年前

再有个蠢办法,就是用注册一个DB的监听器,在这个监听器中,你可以监听到所有的sql执行。然后你可以自己想办法,匹配出你需要的sql语句,然后就可以获取参数了。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // 关键代码,监听所有的sql语句
        \DB::listen(function($query){
            // 简单举例
            if(strpos($query, 'update')>=0){
                dd($query->bindings);
            }
        });
    }
}
3年前 评论
荒街! (楼主) 3年前

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