在 Laravel 5.2 中捕获保存和删除的最可靠方法是什么?
What's the most reliable way to catch saves and deletes in Laravel 5.2?
当我的一个模型被保存 (created/updated) 或删除时,我需要 运行 一些代码。最好的方法是什么?
我知道三种不同的方式:
- Override the save and delete methods on the model
- Add creating/updating/deleting callbacks in the boot method
- Bind an observer in the boot method
我没有看到这些比较和对比,所以我不知道有什么区别。我担心事件在某些情况下不会触发。
例如,在 Django 中,仅当您逐一删除模型时才会触发删除操作,而不是批量删除。
明确地说,我正在寻找比较和对比这些(或其他)方法的答案 -- 而不是简单地建议更多的方法来做同样的事情。
您可以为模型的每个 create/update 创建事件处理程序,例如添加以缓存刚刚保存到数据库或将要保存到数据库的模型数据,无需 [=13] 更容易检索=]查询电话,
在 delete 调用时,对缓存处理程序事件中的给定键使用 forget 来删除缓存以及从数据库中删除。
前面提到的几种方法,只是我个人的看法。
- 覆盖模型上的保存和删除方法(如果您覆盖它,那么下一次更新 Laravel 更改方法的可见性您的代码将不再工作。它会抛出异常或 PHP 错误.你必须修改它才能再次工作)
- 在启动方法中添加 creating/updating/deleting 回调(存在于 Laravel 4 你应该在 Laravel 5 中再次检查它可能使用 Event 和 Listener 的不同实现)
- 在 boot 方法中绑定一个观察者(存在于 Laravel 4 你应该在 Laravel 5 中再次检查它可能使用 Event 和 Listener 的不同实现)
我认为你应该使用 Laravel 提供的事件和监听器。它可能仍然适用于下一个 Laravel 更新。我假设 Event 和 Listener 是 Laravel 中的微小变化区域,并且可能只是改变了不同的方法实现。
Laravel 应该有开发计划指定 Laravel 的哪一部分将开发为 主要变化区域 (大修改)或 minor change area(小改动)。如果您尝试更改或覆盖主要更改区域,它将无法在下一个 Laravel 更新中使用。
您可以注册事件和监听器来保存和删除记录。 Laravel 在 Model ( Illuminate\Database\Eloquent\Model ) 上有 fireModelEvent 方法 触发特定的 Laravel 事件。如果你已经注册了事件,Dispatcher ( Illuminate\Events\Dispatcher ) 将执行 Listener of Event.
关于 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 方法作为事件的 Listener 以便您可以在保存或删除后执行特定操作。
class YourModel extends Model
{
public function eventSaved(){
// You can add your code to catch save here
}
}
当您需要确切地知道它们是如何完成的时候,我偏向于手动做事。我最近使用这个 Laravel 样板来启动一个项目,我喜欢他们在更新模型时在存储库中手动触发事件的方式:
由于模型应始终通过存储库进行更新,因此您始终需要手动决定如何处理事件。当删除多个模型时,您可以触发自己的事件,并采取相应行动。不过,您的所有选项都可以使用,您只需要找到最适合您需求的选项即可。
您可以创建扩展 Illuminate\Database\Eloquent\Model
class 的抽象 Model
class,并且您的所有模型都将扩展此 class。通过这样的实现,您可以更好地控制模型。例如
<?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
class 的所有方法执行此操作,还可以添加与应用程序中的所有模型相关的其他方法
@joko提到的三种方法和第4种方法。可能还有更多,但让我们关注 4 种方法。
让我一一为您描述:
1) 覆盖模型上的保存和删除方法
在此方法中,您使用的是 OOPD 方法覆盖。您正在重写 Laravel 的内部 save
方法并通过在它之上定义您自己的 save
方法来添加您的附加代码。应该避免这种情况,因为 Laravel 不断发展,如果进行重大更改,事情可能会开始失败,例如假设将来 laravel 将 save
方法替换为任何其他方法来保存记录.然后,您将不得不再次创建另一个方法来覆盖该新方法。此外,在此处编写代码可能会增加您的模型 class 文件。您的模特可能会继续处理他不应该处理的事情(例如:发送电子邮件)。 应该避免这种方法。
2) 在boot方法中添加creating/updating/deleting回调
这里是在模型的 Boot 方法上定义代码。仅当您需要处理的事件很少 code/things 时才应使用此方法。这种方法的缺点是它使代码更加复杂和混乱,因为您可能像函数式编程一样将所有逻辑写在一个文件中。假设您必须在创建之前和创建之后做一些事情。你 boot
方法会成长。
3)在boot方法中绑定观察者
这个方法很不错。您创建了一个观察者 class 来处理 Laravel 事件中应该发生的事情。它使代码更清晰,更易于维护。
例子:假设你要在creating
、saving
、saved
、deleting
这些方法中编写代码。在这种情况下,方法 1) 和方法 2) 不是好的做法,因为在
方法 1: 我们必须创建这 4 个方法并覆盖它们,并在 Laravel 的未来版本中支持它们。在这种情况下,模型中的代码也会因为覆盖此方法而增长
方法 2: 在这种情况下,您的 boot
方法也会增长,因此您的模型文件将变成代码垃圾。
在方法 1 和 2 中还请记住,您的模型不负责执行您要编写的许多内容。就像在创建用户时发送电子邮件一样。您最终可能会在 created
方法中编写这些代码。
假设现在您需要在 created
事件中向用户发送电子邮件,并且需要在客户 CRM 中创建用户的登录日志用户。那么你将不得不用相同的方法为两者编写代码。可能,您在那里可能不遵循单一责任原则。遇到这种情况怎么办?参见方法4。
4)
我在方法4的最后建议的场景。您可以向用户发送电子邮件,并在创建时将其登录到 Customer 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 到 Listener 映射的一个点。
当我的一个模型被保存 (created/updated) 或删除时,我需要 运行 一些代码。最好的方法是什么?
我知道三种不同的方式:
- Override the save and delete methods on the model
- Add creating/updating/deleting callbacks in the boot method
- Bind an observer in the boot method
我没有看到这些比较和对比,所以我不知道有什么区别。我担心事件在某些情况下不会触发。
例如,在 Django 中,仅当您逐一删除模型时才会触发删除操作,而不是批量删除。
明确地说,我正在寻找比较和对比这些(或其他)方法的答案 -- 而不是简单地建议更多的方法来做同样的事情。
您可以为模型的每个 create/update 创建事件处理程序,例如添加以缓存刚刚保存到数据库或将要保存到数据库的模型数据,无需 [=13] 更容易检索=]查询电话, 在 delete 调用时,对缓存处理程序事件中的给定键使用 forget 来删除缓存以及从数据库中删除。
前面提到的几种方法,只是我个人的看法。
- 覆盖模型上的保存和删除方法(如果您覆盖它,那么下一次更新 Laravel 更改方法的可见性您的代码将不再工作。它会抛出异常或 PHP 错误.你必须修改它才能再次工作)
- 在启动方法中添加 creating/updating/deleting 回调(存在于 Laravel 4 你应该在 Laravel 5 中再次检查它可能使用 Event 和 Listener 的不同实现)
- 在 boot 方法中绑定一个观察者(存在于 Laravel 4 你应该在 Laravel 5 中再次检查它可能使用 Event 和 Listener 的不同实现)
我认为你应该使用 Laravel 提供的事件和监听器。它可能仍然适用于下一个 Laravel 更新。我假设 Event 和 Listener 是 Laravel 中的微小变化区域,并且可能只是改变了不同的方法实现。
Laravel 应该有开发计划指定 Laravel 的哪一部分将开发为 主要变化区域 (大修改)或 minor change area(小改动)。如果您尝试更改或覆盖主要更改区域,它将无法在下一个 Laravel 更新中使用。
您可以注册事件和监听器来保存和删除记录。 Laravel 在 Model ( Illuminate\Database\Eloquent\Model ) 上有 fireModelEvent 方法 触发特定的 Laravel 事件。如果你已经注册了事件,Dispatcher ( Illuminate\Events\Dispatcher ) 将执行 Listener of Event.
关于 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 方法作为事件的 Listener 以便您可以在保存或删除后执行特定操作。
class YourModel extends Model
{
public function eventSaved(){
// You can add your code to catch save here
}
}
当您需要确切地知道它们是如何完成的时候,我偏向于手动做事。我最近使用这个 Laravel 样板来启动一个项目,我喜欢他们在更新模型时在存储库中手动触发事件的方式:
由于模型应始终通过存储库进行更新,因此您始终需要手动决定如何处理事件。当删除多个模型时,您可以触发自己的事件,并采取相应行动。不过,您的所有选项都可以使用,您只需要找到最适合您需求的选项即可。
您可以创建扩展 Illuminate\Database\Eloquent\Model
class 的抽象 Model
class,并且您的所有模型都将扩展此 class。通过这样的实现,您可以更好地控制模型。例如
<?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
class 的所有方法执行此操作,还可以添加与应用程序中的所有模型相关的其他方法
@joko提到的三种方法和第4种方法。可能还有更多,但让我们关注 4 种方法。
让我一一为您描述:
1) 覆盖模型上的保存和删除方法
在此方法中,您使用的是 OOPD 方法覆盖。您正在重写 Laravel 的内部 save
方法并通过在它之上定义您自己的 save
方法来添加您的附加代码。应该避免这种情况,因为 Laravel 不断发展,如果进行重大更改,事情可能会开始失败,例如假设将来 laravel 将 save
方法替换为任何其他方法来保存记录.然后,您将不得不再次创建另一个方法来覆盖该新方法。此外,在此处编写代码可能会增加您的模型 class 文件。您的模特可能会继续处理他不应该处理的事情(例如:发送电子邮件)。 应该避免这种方法。
2) 在boot方法中添加creating/updating/deleting回调
这里是在模型的 Boot 方法上定义代码。仅当您需要处理的事件很少 code/things 时才应使用此方法。这种方法的缺点是它使代码更加复杂和混乱,因为您可能像函数式编程一样将所有逻辑写在一个文件中。假设您必须在创建之前和创建之后做一些事情。你 boot
方法会成长。
3)在boot方法中绑定观察者
这个方法很不错。您创建了一个观察者 class 来处理 Laravel 事件中应该发生的事情。它使代码更清晰,更易于维护。
例子:假设你要在creating
、saving
、saved
、deleting
这些方法中编写代码。在这种情况下,方法 1) 和方法 2) 不是好的做法,因为在
方法 1: 我们必须创建这 4 个方法并覆盖它们,并在 Laravel 的未来版本中支持它们。在这种情况下,模型中的代码也会因为覆盖此方法而增长
方法 2: 在这种情况下,您的 boot
方法也会增长,因此您的模型文件将变成代码垃圾。
在方法 1 和 2 中还请记住,您的模型不负责执行您要编写的许多内容。就像在创建用户时发送电子邮件一样。您最终可能会在 created
方法中编写这些代码。
假设现在您需要在 created
事件中向用户发送电子邮件,并且需要在客户 CRM 中创建用户的登录日志用户。那么你将不得不用相同的方法为两者编写代码。可能,您在那里可能不遵循单一责任原则。遇到这种情况怎么办?参见方法4。
4)
我在方法4的最后建议的场景。您可以向用户发送电子邮件,并在创建时将其登录到 Customer 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 到 Listener 映射的一个点。