在Laravel 5.2中捕获保存和删除的最可靠方法是什么?

问题描述:

我需要运行一些代码,当我的模型之一被保存(创建/更新)或删除。什么是最好的方式来做到这一点?在Laravel 5.2中捕获保存和删除的最可靠方法是什么?

有三种不同的方法,我所知道的:

  1. Override the save and delete methods on the model
  2. Add creating/updating/deleting callbacks in the boot method
  3. Bind an observer in the boot method

我还没有看到这些比较和对比,所以我不不知道有什么区别。我担心这些事件在某些情况下不会发生。

例如,在Django中,如果逐个删除模型,但不是批量删除,则只删除火警。


要清楚,我正在寻找一个比较和对比这些(或其他)方法的答案 - 不是简单地建议做同样的事情的更多的方式。

+0

与Django中的Eloquent一样:“在通过Eloquent执行批量删除语句时,删除和删除的模型事件不会为已删除的模型触发,这是因为在执行delete语句时模型从未被实际检索到。 “ –

+0

@jakubwrona这三种方法都不支持大规模删除?好。还有什么我应该注意的吗?效率有差异吗?他们中的任何一个比其他人更强大/更不可能突破?或者这只是一个偏好问题?为什么有很多方法可以做同样的事情? – mpen

的三种方法,并通过四指@joko其他方法。可能还有更多,但让我们关注4种方法。

让我描述你一一:

1)覆盖在模型上

在这种方法中使用的是OOPD方法重载的保存和删除的方法。您正在重写Laravel的内部方法save,并通过在其上定义自己的save方法来添加附加代码。这应该避免,因为Laravel不断发展,并且可能发生的事情是,如果重大变更完成,就像事情开始失败一样,假设将来使用任何其他方法替代save方法来保存记录。然后,您将不得不创建另一种方法来覆盖该新方法。此处编写代码可能会增加您的模型类文件。你的模型可能会继续处理他不应该处理的事情(例如:发送电子邮件)。 应避免使用此方法。

2)添加创建/更新/删除回调的引导方法

在这里,你是在模型的启动方法定义代码。只有在事件需要处理很少的代码/事情时才应该使用此方法。这种方法的缺点是它使代码更加复杂和混乱,因为你可能像编写函数一样编写所有的逻辑。假设你在创建之前和创建之后必须做些什么。你的boot方法会增长。

3)绑定在引导方法

该方法的观察者是相当不错的。你创建一个观察者类来处理Laravel事件应该发生的事情。它使代码更加清洁并易于维护。

示例:假设您必须在这些方法中编写creating,saving,saved,deleting中的代码。在这种情况下,方法1)和方法2)也不会好做法,因为在

方法1:我们必须创建此4种方法,并覆盖它们,以及支持他们Laravel的未来版本。在这种情况下,模型中的代码也将增长,因为重写此方法

方法2:在这种情况下,您boot方法也会增长,所以你型号的文件将成为一个代码的垃圾。

在方法1和2中,还记得它不是你的模型的职责来完成你要编写的许多东西。就像创建用户时发送电子邮件一样。这些代码最终可能会以created方法写入。

现在假设您有场景需要在created事件上向用户发送电子邮件,以及您需要在客户CRM中创建用户的登录日志用户。那么你将不得不用相同的方法编写代码。也许,你可能不会遵循单一责任原则。我们该怎么办?参见方法4.

4)Other method suggested by @joko

,我在方法4的最终建议的情况。您可以发送电子邮件给用户,并在创建时将其登录到客户CRM中。然后你的方法会做2件事(发送电子邮件和登录CRM)。它可能不遵循单一责任原则。如果更好,我们可以解耦他们两个。然后来这个方法。

class EventServiceProvider extends ServiceProvider 
{ 
    /** 
    * The event listener mappings for the application. 
    * 
    * @var array 
    */ 
    protected $listen = [ 
     'eloquent.saved: App\User' => 'App\Listeners\SendWelcomeEmailToUser' 
     'eloquent.saved: App\User' => 'App\Listeners\LogUserInCRM' 
    ]; 
} 

创建两个listener classes

class SendWelcomeEmailToUser 
{ 
    public function handle(User $user){ 
     // Write code to send email 
    } 
} 

class LogUserInCRM 
{ 
    public function handle(User $user){ 
     // Write code to log 
    } 
} 

通过这个就可以分离出代码,使他们更干净。

我一般都喜欢这种方法,它的模式干净。它也让你更好地认识事件发生时实际发生的事情。它成为Event to Listener映射的单一点。

您可以为模型的每个创建/更新创建事件处理程序,例如添加以缓存刚刚保存到数据库或将要保存到数据库的模型数据,更容易在没有选择查询调用的情况下检索, while删除调用,使用忘记缓存处理程序事件上给定的键来删除缓存以及从数据库中删除。

这只是我以前提到的几种方法的看法。

  1. 覆盖模型上的保存和删除方法(如果覆盖它,然后方法Laravel变化知名度的下一次更新您的代码不试。工作,它会抛出异常或PHP错误。你必须修改它再工作)
  2. 添加创建/更新/删除回调的引导方法(在Laravel 4存在,您应该在Laravel检查一遍使用事件和监听器)
  3. 绑定在开机方法的观察者5也许不同的实现(存在在Laravel 4中,你应该在Laravel 5中再次检查它,也许使用Event和Listener的不同实现)

我想你应该使用Laravel提供的Event和Listener。它可能仍然在下一个Laravel更新。我假设事件和侦听器是Laravel中的一个小变化区域,并且可能只是改变了不同的方法实现。

Laravel应该有哪些Laravel的一部分将发展为重大变化区域(大修改)或微小的变化区域(稍加修改)发展分配的计划。如果您尝试更改或覆盖主要更改区域,则它将无法在下一次Laravel更新中使用。

你可以注册事件和听众为保存和删除记录。 Laravel有fireModelEvent方法模型(Illuminate \ Database \ Eloquent \ Model)它触发特定的Laravel事件。如果您已注册Event,调度员(Illuminate \ Events \ Dispatcher)将执行Event的监听者。

文档关于Laravel活动:

https://laravel.com/docs/5.3/events

https://laravel.com/docs/5.2/events

我假设你有YourModel作为模型,然后做下面的下面的操作。

  • 注册事件和监听器。打开app \ Providers \ EventServiceProvider.php,然后将Event和Listener添加到YourModel的EventServiceProvider.listen属性中,或者按照Laravel Documentation以其他方式创建事件。
 

class EventServiceProvider extends ServiceProvider 
{ 
    /** 
    * The event listener mappings for the application. 
    * 
    * @var array 
    */ 
    protected $listen = [ 
     ... 
     'eloquent.saved: App\YourModel' => [ 
      'App\[email protected]', 
     ], 
    ]; 
} 
 
  • 在App \ YourModel添加 eventSaved方法监听的事件,所以你可以做特定的动作保存或删除后。
 

class YourModel extends Model 
{ 
    public function eventSaved(){ 
     // You can add your code to catch save here 
    } 
} 
 

我偏爱手动做的事情时,你需要知道他们究竟是如何完成的。我最近使用这个Laravel样板启动一个项目,我喜欢的方式,他们手动触发存储库中的事件时,模型更新:

https://github.com/rappasoft/laravel-5-boilerplate/blob/master/app/Repositories/Backend/Access/User/EloquentUserRepository.php

由于模型应该总是通过存储库进行更新,你总能得到手动决定如何处理事件。当多个模型被删除时,您可以触发您自己的事件,并据此采取行动。您的所有选项都可以工作,但您只需找到最适合您需求的选项即可。

您可以创建抽象Model类来扩展Illuminate\Database\Eloquent\Model类,并且您的所有模型都将扩展此类。通过这样的实施,您可以对模型进行更多控制。例如

<?php 

namespace App\Base\Database; 


use Illuminate\Database\Eloquent\Model as BaseModel; 

abstract class Model extends BaseModel 
{ 
    public function save(array $options = []) 
    { 
     //your code here 
     return parent::save($options); 
    } 
} 

可以为Model类的所有方法做到这一点,你也可以加入其他适用于所有车型在您的应用程序

+0

没错,但是会为所有模型启动 - 我只对一个特定的模型感兴趣。 – mpen

+0

@mpen如果你只想在一个模型上使用这个实现,你可以像在我的例子中那样在你的特定模型中覆盖保存函数。 – Kliment

+0

确实。这是我的问题中的选项#1。我更有兴趣知道这是否比其他两种方法有什么优势。 – mpen