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');
      
    


如果您想知道isDirtywasChanged 之间的区别,请参阅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 这个答案在我评论后更新了:'( 我赞成您的回答,因为我认为它不值得反对。但是,我认为它的常见做法是编辑对 cme​​ts 答案的微小改进。我猜想使用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-&gt;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:与观察者检查列是不是在更新时更改的主要内容,如果未能解决你的问题,请参考以下文章

使用迁移 Laravel 5.4 更新列

Laravel 检查没有自身更新的唯一规则

如何检查 MySQL JSON 列是不是包含 laravel 中的值?

在 laravel 中删除无符号索引外键。语法错误或访问冲突:1091 Can't DROP;检查列/键是不是存在

如何检查记录是不是已经存在,然后在 laravel 中更新或插入?

我可以检查散列密码是不是等于 laravel 中的特定值?