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

时间:2015-07-13 03:51:35

标签: laravel 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
  4. 我还没有看到这些比较和对比,所以我不知道差异是什么。我担心这些事件会在某些条件下发生火灾。

    例如,在Django中,如果逐个删除模型,则删除仅触发,而不是批量删除。

    要明确的是,我正在寻找能够比较和对比这些(或其他)方法的答案 - 而不仅仅是建议更多的方法来做同样的事情。

5 个答案:

答案 0 :(得分:3)

对于您之前提到的几种方法,我只是我的意见。

  1. 覆盖模型上的保存和删除方法(如果覆盖它,则下一次更新Laravel会更改方法的可见性,您的代码将无法再次运行。它会抛出异常或PHP错误。您必须将其修改为再次工作)
  2. 在引导方法中添加创建/更新/删除回调(存在于Laravel 4中,您应该在Laravel 5中再次检查它可能使用事件和侦听器进行不同的实现)
  3. 在启动方法中绑定一个观察者(存在于Laravel 4中,你应该在Laravel 5中再次检查它可能使用事件和监听器进行不同的实现)
  4. 我认为你应该使用Laravel提供的Event和Listener。它可能仍然适用于下一个Laravel Update。我假设事件和监听器是Laravel中的小变化区域,并且可能只是改变了不同的方法实现。

    Laravel应该制定开发计划,将Laravel的哪一部分开发为主要变更区域(大修改)或次要变更区域(稍加修改)。如果您尝试更改或覆盖主要更改区域,则无法在下一个Laravel更新中使用它。

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

    有关Laravel事件的文档:

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

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

    我假设您将YourModel作为模型,然后在下面执行以下操作。

    • 注册事件和监听器。打开app \ Providers \ EventServiceProvider.php,然后为YourModel的EventServiceProvider.listen属性添加事件和侦听器,或者按照Laravel文档以其他方式创建事件。
    
    class EventServiceProvider extends ServiceProvider
    {
        /**
         * The event listener mappings for the application.
         *
         * @var array
         */
        protected $listen = [
            ...
            'eloquent.saved: App\YourModel' => [
                'App\YourModel@eventSaved',
            ],
        ];
    }
    
    
    • 在App \ YourModel上添加 eventSaved方法作为侦听器 for Event,以便您可以在保存或删除后执行特定操作。
    
    class YourModel extends Model
    {
        public function eventSaved(){
            // You can add your code to catch save here
        }
    }
    
    

答案 1 :(得分:1)

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

答案 2 :(得分:1)

当您需要确切知道他们是如何完成的时候,我会偏向于手动操作。我最近使用这个Laravel Boilerplate来启动一个项目,我喜欢他们在模型更新时手动触发存储库中事件的方式:

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

由于模型应始终通过存储库进行更新,因此您始终可以手动确定如何处理事件。删除多个模型时,您可以触发自己的事件,并采取相应的行动。您的所有选项都可以使用,您只需要找到最适合您需求的选项。

答案 3 :(得分:1)

您可以创建扩展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类的所有方法执行此操作,还可以添加与应用程序中所有模型相关的其他方法

答案 4 :(得分:1)

@joko引用的三种方法和第四种方法。可能还有更多,但我们可以专注于4种方法。

让我逐一向你描述:

1)覆盖模型上的保存和删除方法

在此方法中,您使用OOPD方法覆盖。您正在重写Laravel的interal save方法,并通过在其上定义自己的save方法来添加其他代码。这应该避免,因为Laravel不断发展,如果在未来的laravel替换save方法中使用任何其他方法来保存记录,那么可能会发生事情开始失败。然后,您将不得不创建另一个方法来覆盖该新方法。此处编写代码可能会增加您的模型类文件。你的模型可能会继续处理他不应该处理的事情(例如:发送电子邮件)。 应避免使用此方法。

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

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

3)在引导方法中绑定观察者

这种方法非常好。你创建了一个观察者类来处理Laravel事件应该发生的事情。它使代码更清晰,更易于维护。

示例:假设您必须在这些方法中使用creatingsavingsaveddeleting编写代码。在这种情况下,方法1)和方法2)将不是一个好的做法,因为在

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

方法2:在这种情况下,您的boot方法也会增长,因此您的模型文件将成为一堆代码。

在方法1和方法2中还要记住,您的模型不负责执行您要编写的许多内容。就像在创建用户时发送电子邮件一样您最终可能会使用created方法编写这些代码。

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

4)Other method suggested by @joko

我在方法4结束时建议的场景。您可以向用户发送电子邮件,并在创建时将其登录到客户CRM。然后你的方法将做两件事(发送电子邮件和登录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映射的一个单一点。