1

当我的一个模型被保存(创建/更新)或删除时,我需要运行一些代码。最好的方法是什么?

我知道三种不同的方式:

  1. 覆盖模型上的保存和删除方法
  2. 在 boot 方法中添加创建/更新/删除回调
  3. 在 boot 方法中绑定一个观察者

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

例如,在 Django 中,仅当您逐个删除模型时才会触发删除,而不是批量删除。


需要明确的是,我正在寻找比较和对比这些(或其他)方法的答案——而不是简单地提出更多的方法来做同样的事情。

4

5 回答 5

3

这只是我对您之前提到的几种方法的看法。

  1. 覆盖模型上的保存和删除方法(如果你覆盖它,那么 Laravel 的下一次更新更改方法的可见性你的代码将不再工作。它会抛出异常或 PHP 错误。你必须修改它才能再次工作)
  2. 在启动方法中添加创建/更新/删除回调(存在于 Laravel 4 中,您应该在 Laravel 5 中再次检查它,可能使用 Event 和 Listener 的不同实现)
  3. 在引导方法中绑定观察者(存在于 Laravel 4 中,您应该在 Laravel 5 中再次检查它,可能使用 Event 和 Listener 的不同实现)

我认为你应该使用 Laravel 提供的 Event 和 Listener。它可能仍然适用于下一个 Laravel 更新。我假设 Event 和 Listener 是 Laravel 中的次要更改区域,并且可能只是更改了不同的方法实现。

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

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

关于 Laravel 事件的文档:

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

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

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

  • 注册事件和监听器。打开 app\Providers\EventServiceProvider.php 然后将 Event 和 Listener 添加到 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 方法作为事件的侦听器,以便您可以在保存或删除后执行特定操作。

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

于 2016-10-17T09:43:30.887 回答
1

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

于 2016-10-17T06:24:40.737 回答
1

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

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

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

于 2016-10-18T00:29:10.987 回答
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类的所有方法执行此操作,还可以添加与应用程序中的所有模型相关的其他方法

于 2016-10-18T18:17:23.590 回答
1

@joko 提到的三种方法和第 4 种方法。可能还有更多,但让我们专注于 4 种方法。

让我一一为您描述:

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

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

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

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

3)在boot方法中绑定一个观察者

这个方法很不错。你创建了一个观察者类来处理 Laravel 事件应该发生的事情。它使代码更干净,更易于维护。

示例:假设您必须在这些方法中以creatingsavingsaved、编写代码。deleting在这种情况下,方法 1) 和方法 2) 不是很好的做法,因为在

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

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

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

假设现在您有一个场景,您需要在事件中向用户发送电子邮件,created并且您需要在客户 CRM 中创建用户的输入日志用户。那么您将不得不以相同的方法为两者编写代码。可能,您可能没有遵循单一责任原则。在这种情况下我们应该怎么做?见方法 4。

4)@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'
    ];
}

创建两个监听器类

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

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

通过这个,您可以分离出代码并使它们更清洁。

我通常更喜欢这种方法,它的模式很干净。它还让您更好地了解事件发生时实际发生的情况。它成为事件到侦听器映射的一个点。

于 2016-10-19T12:55:29.153 回答