Laravel:与观察者检查列是不是在更新时更改
Posted
技术标签:
【中文标题】Laravel:与观察者检查列是不是在更新时更改【英文标题】:Laravel: Check with Observer if Column was Changed on UpdateLaravel:与观察者检查列是否在更新时更改 【发布时间】:2018-07-25 09:13:39 【问题描述】:我正在使用Observer 来查看用户是否更新。
每当用户是updated
时,我想检查他的email
是否已更改。
这样的事情可能吗?
class UserObserver
/**
* Listen to the User created event.
*
* @param \App\User $user
* @return void
*/
public function updating(User $user)
// if($user->hasChangedEmailInThisUpdate()) ?
【问题讨论】:
您的意思是isDirty
方法?还有wasChanged
。
@tadman 是的!这就是我要找的。这与观察者兼容吗?我认为更新是在将更改分配给user
之后调用,但在存储之前调用,对吧?
我不能 100% 确定细节,因此您可能需要在这里进行试验。脏跟踪是许多 ORM 的共同特征,包括 Eloquent。
【参考方案1】:
编辑:感谢https://***.com/a/54307753/2311074 getOriginal
正如tadman
在 cmets 中已经说过的,isDirty
方法可以解决问题:
class UserObserver
/**
* Listen to the User updating event.
*
* @param \App\User $user
* @return void
*/
public function updating(User $user)
if($user->isDirty('email'))
// email has changed
$new_email = $user->email;
$old_email = $user->getOriginal('email');
如果您想知道isDirty
和wasChanged
之间的区别,请参阅https://***.com/a/49350664/2311074
【讨论】:
非常感谢,这就是我正在搜索的内容。 不需要再次从数据库中传输模型,请参阅我的更新版本的答案【参考方案2】:您不必再次从数据库中获取用户。以下应该有效:
public function updating(User $user)
if($user->isDirty('email'))
// email has changed
$new_email = $user->email;
$old_email = $user->getOriginal('email');
【讨论】:
我赞成您对已接受答案的评论,但由于它现在是重复的,所以对此表示反对 @aowie1 这个答案在我评论后更新了:'( 我赞成您的回答,因为我认为它不值得反对。但是,我认为它的常见做法是编辑对 cmets 答案的微小改进。我猜想使用getOriginal
而不是find
只是一个小改进,因为两者都有效,而答案的主要部分是如何查找模型是否已更改:这就是isDirty
方法。也许在这种情况下,如果您通过编辑我的问题并更改行来提出请求会更好。这也会给你学分。【参考方案3】:
您应该使用updated
模型事件将列更改与原始事件进行比较,而不是使用updating
事件。请看下面的代码。
AppServiceProvider.php
<?php
namespace App\Providers;
use App\Models\User;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
public function boot()
User::updated(function($user)
$changes = array_diff($user->getOriginal(), $user->getAttributes());
if(array_key_exists('email',$changes))
/* do your things. */
);
解释:
获得差异后,您需要使用array_key_exists
检查电子邮件字段是否已更新。
【讨论】:
有一个快捷方式可以检查字段是否已更新:laravel.com/docs/8.x/eloquent#examining-attribute-changes 所以你可以改用if($user->wasChanged('email'))
^^
@D.Petrov 正确,但如果您必须捕获多个字段,那么您需要为每一列正确写入,因此这是处理多列数据的有效方法。【参考方案4】:
聚会有点晚了,但可能对未来寻求类似解决方案的开发者有所帮助。
我建议使用包 Laravel Attribute Observer,作为污染您的服务提供者或使用 isDirty()
和 wasChanged()
样板填充您的观察者的替代方法。
所以你的用例应该是这样的:
class UserObserver
/**
* Handle changes to the "email" field of User on "updating" events.
*
* @param \App\User $user
* @param string $newValue The current value of the field
* @param string $oldValue The previous value of the field
* @return void
*/
public function onEmailUpdating(User $user, string $newValue, string $oldValue)
// Your logic goes here...
Laravel Attribute Observer 当您要在一个或多个模型上观察大量属性时特别有用。
免责声明:我是 Laravel Attribute Observer 的作者。如果它可以为您节省一些开发时间,请考虑请我喝杯咖啡。
【讨论】:
以上是关于Laravel:与观察者检查列是不是在更新时更改的主要内容,如果未能解决你的问题,请参考以下文章
如何检查 MySQL JSON 列是不是包含 laravel 中的值?
在 laravel 中删除无符号索引外键。语法错误或访问冲突:1091 Can't DROP;检查列/键是不是存在