Laravel:使用 Query Builder 或 Eloquent ORM 时在每次插入/更新时执行一些任务

Posted

技术标签:

【中文标题】Laravel:使用 Query Builder 或 Eloquent ORM 时在每次插入/更新时执行一些任务【英文标题】:Laravel: performing some task on every insert/update when using Query Builder or Eloquent ORM 【发布时间】:2013-08-26 05:58:22 【问题描述】:

问题

无论我使用的是 Eloquent 还是 Query Builder,我想自动将 created_bymodified_by 字段添加到 Laravel 4 中数据库表的每次插入/更新。但是,并非我的所有表都有这些字段,因此任何解决方案都必须在添加之前检查这些列是否存在。

尝试的解决方案

我扩展了Illuminate\Database\Eloquent\Model 类并编写了一个覆盖方法save(),以便为每条保存的记录添加一些额外的元数据字段。

这很好,但如果我使用查询生成器执行插入,则会绕过它。查看Model 类,似乎数据库操作实际上是使用查询生成器完成的。

我查看了Illuminate\Database\Query\Builder 模型,看起来我可以为insert()update() 编写覆盖方法。

这是为每次插入/更新执行某些任务的明智方法,还是我以后会遇到麻烦?

【问题讨论】:

试试这个包解决你的问题github.com/fico7489/laravel-revisionable-upgrade 【参考方案1】:

添加到上述答案。你可以这样做。

在 app/models 中创建一个名为 BaseModel.php 的类,扩展 \Eloquent

class BaseModel extends \Eloquent

public static function boot()

    parent::boot();

    static::creating(function($model)
    
        //change to Auth::user() if you are using the default auth provider
        $user = Confide::user();
        $model->created_by = $user->id;
        $model->updated_by = $user->id;
    );

    static::updating(function($model)
    
        //change to Auth::user() if you are using the default auth provider
        $user = Confide::user();
        $model->updated_by = $user->id;
    );
  


然后在您的各个模型类中,您需要扩展 BaseModel 而不是 \Eloquent

class Product extends BaseModel 

    protected $table = 'product';

    //Booting the base model to add created_by and updated_by to all tables
    public static function boot()
    
        parent::boot();
    


现在,每当您保存或更新模型时,created_by 和 updated_by 字段都会自动更新。

注意:这仅在通过 Eloquent 完成保存或更新时有效。对于查询构建器,您可以使用通用方法来获取和附加 created_by 和 update_by 列更新。

【讨论】:

完美!这正是我需要的:) 如何从 queryBuilder 中捕获更新、创建、删除事件?您提供的这些方法仅在使用 Mode 更新、创建、删除时触发。如果模型删除有关系的东西,这将不起作用。【参考方案2】:

您绝不能覆盖 save 方法来覆盖和添加您的功能。

您必须使用 eloquent 提供的模型事件功能来代替。

简单地说,你必须为你的模型定义一个保存事件来覆盖/设置/检查模型要保存的数据。

一个简单的例子放在一个用户模型类中:

//Executed when loading model
public static function boot()

     parent::boot();

     User::creating(function($user)
         $user->value1 = $user->value2 +1;
     );

更多信息: http://four.laravel.com/docs/eloquent#model-events

【讨论】:

我认为模型和模式之间存在混淆。架构在受孕时定义表。模型在运行时定义此表内的数据。您可以检查模型是否具有特定属性,或者为不同的表创建不同的模型以确保安全。 此解决方案不适合 - 我希望它与查询生成器和 Eloquent 一起使用,事件仅适用于模型,即 Eloquent 另外,如果我在添加我的功能后调用父save()方法,这样扩展核心有什么问题?这不是使用 OO 框架的全部意义吗?我离开 CI 是因为我厌倦了不得不编写 hack 来扩展核心,而不仅仅是做一个简单的extend。模型事件和我眼中的 CI 钩子一样糟糕...... 我真的不明白在这种情况下,当有像 eloquent 这样强大的功能可以为您执行此操作时,您必须直接使用查询构建器插入或更新数据。此外,如果您扩展模型,则您的修改在查询构建器中不可用,因为您也必须扩展查询构建器。我认为您正在尝试在这里重新发明***。您能否在您的问题中阐明您的用例,以便我们找到解决方法? 更新了问题。如果另一个程序员在不知道我使用模型事件添加这些元数据字段并使用查询生成器进行插入的情况下向我的应用程序编写了一个快速而肮脏的添加内容怎么办?【参考方案3】:

在 Laravel 中,如果你想从一个点在每次保存/更新时调用一个单个方法,而不对每个扩展模型进行任何额外的更改,你可以有一个用于雄辩事件的自定义侦听器。正如documetation 所说,它只能针对每个模型完成。但是创建自定义监听器允许访问任何模型中的任何事件。

只需向EventServiceProvider 中的boot() 方法添加一个侦听器,如下所示并进行相应修改。

Event::listen(['eloquent.saving: *', 'eloquent.creating: *'], function()
        //your method content
        //returning false will cancel saving the model
 );

请注意,通配符用于匹配任何模型。有关活动的更多信息,请参阅documentation。

【讨论】:

【参考方案4】:

如果您想使用 Query Builder 和 Eloquent 作为解决此问题的唯一方法而不扩展核心组件(我认为没有必要),您可以使用 事件系统。 p>

链接:http://laravel.com/docs/events

因此,您将使用诸如 user.custom.save 之类的事件,然后创建一个用于查询构建器的函数,该函数最终将触发此事件,与 Eloquent 相同。

例子:

class User extends Eloquent

    public function save()
    
        Event::fire('user.custom.save', array($this));
        parent::save();
    

【讨论】:

【参考方案5】:

您可以使用 Venturecraft 可修订包,因为在此包的表格中,您需要的所有信息都已存储,您只需要此包以优雅的方式获取它们: https://github.com/fico7489/laravel-revisionable-upgrade

【讨论】:

以上是关于Laravel:使用 Query Builder 或 Eloquent ORM 时在每次插入/更新时执行一些任务的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:调用未定义的方法 Illuminate\\Database\\Query\\Builder

如何使用 Laravel Eloquent 和 Laravel Query Builder 进行联合查询?

Laravel 查询错误 - 调用未定义的方法 Illuminate\Database\Query\Builder::query()

如何使用 laravel Query Builder 进行复杂查询

使用 SQL Query 或 Laravel SQL Query Builder 创建表/列组合

Laravel中的Query Builder