【问题标题】:Laravel Eloquent Events - implement to save model if UpdatedLaravel Eloquent Events - 如果更新,实现保存模型
【发布时间】:2018-01-23 17:12:49
【问题描述】:

我在控制器中有这样的代码:

for($i=0; $i<$number_of_tourists; $i++) {

$tourist = Tourist::updateOrCreate(['doc_number' => $request['doc_number'][$i]],
$tourist_to_update);

}

因此,updateOrCreate 方法可以 1) 更新记录,2) 创建新记录 3) 如果 $tourist_to_update 等于数据库中已有的记录,则保持记录不变。

我只想在 'tourist' 表中的记录被更新时才将 $tourist_to_update 保存到 $array[] 中(而不是在创建新记录或没有任何变化时)。

据我所知,Eloquent 事件 https://laravel.com/docs/5.4/eloquent#eventsupdatingupdated 事件,似乎符合我的需求。

问题是我看了几个教程还是不明白怎么用。

我知道如何在 Tourist 模型中注册 Eloquent 事件:

protected static function boot()
{
    parent::boot();

    static::updating(function ($model) {

    });
}

谁能解释我如何通过 Eloquent 事件实现我的目标?

提前谢谢你。

【问题讨论】:

  • 所以你想创建一个新数组$array 只包含更新的记录?
  • @TheFallen 是的:) 完全正确!

标签: laravel-events


【解决方案1】:

这是一种更复杂的方法,但如果您只想获取数据已更改的更新记录,这是可行的。在您的控制器方法中添加:

app()->singleton('touristsCollector', function ($app) {
    $collector = new \stdClass;
    $collector->updated = [];

    return $collector;
});

for($i = 0; $i < $number_of_tourists; $i++) {
    $tourist = Tourist::updateOrCreate(
        ['doc_number' => $request['doc_number'][$i]],
        $tourist_to_update
    );
}

$collector = resolve('touristsCollector');
var_dump( $collector->updated ); // Only updated tourists which have data changed

这基本上将向应用容器添加一个标准 PHP 类,该类将从模型事件中收集所有更新的游客。在您的模型中添加:

protected static function boot()
{
    parent::boot();

    static::updated(function ($model) {
        $collector = resolve('touristsCollector');
        $collector->updated[] = $model;
    });
}

这将基本上从应用程序容器中获取 PHP 类,仅在其某些属性已更新时添加旅游模型。

【讨论】:

  • 哇,这就是我一直在寻找的——使用 Eloquent 模型来完成这件事!:) 你真的是大师!:) 我有一些问题:如果我改变,我看不出有什么区别静态:更新”到“静态:更新”。那么有什么区别呢?:)
  • 在哪里可以阅读更多关于 'app()->singleton' 和 '\stdClass' 的信息?:)
  • @SergejFomin, updating 事件即使属性相同也会触发,updated 只会在数据发生一些变化时触发,所以你需要updated 事件。跨度>
  • @SergejFomin,这是应用容器绑定laravel.com/docs/5.4/container#bindingstdClass 是一个匿名的PHP 库标准类,你可以使用一个普通数组来代替这个类。
【解决方案2】:

如果模型已创建,属性wasRecentlyCreated 将设置为 true,因此您可以通过以下方式检查模型是新的还是更新的:

$updated = [];

for($i = 0; $i < $number_of_tourists; $i++) {
    $currentTourist = ['doc_number' => $request['doc_number'][$i]];
    $tourist = Tourist::updateOrCreate($currentTourist, $tourist_to_update);

    if ( $tourist->wasRecentlyCreated ) {
        continue; // Go to next loop if this tourist was created now
    }

    $updated[] = $tourist;
}

【讨论】:

  • 谢谢你,堕落者。但我觉得有问题。 'updateOrCreate',除了更新和创建之外,还有第三种行为: 3) 如果 $tourist_to_update 等于数据库中已有的,则保持记录不变。我认为您的代码会将已经在数据库中且不需要更新或创建的游客添加到 $updated[ ] 数组中。我刚刚实现了你的代码。是的,它确实将不变的游客添加到数组 $updated...:(
  • @SergejFomin,是的,你是对的,要只获取更新的那些,你可以将 updated_at 时间戳与当前时间进行比较或查看我的其他答案。
【解决方案3】:

如果您总是想在更新旅游表中的行时执行特定代码,我建议创建一个observer 来监听updatedcreate 调用。

<?php

namespace App\Observers;

use App\Tourist;

class TouristObserver
{
    /**
     * Listen to the User created event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(Tourist $user)
    {
        // this will always trigger when you created a new entry
    }

    /**
     * Listen to the User deleting event.
     *
     * @param  \App\Tourist $user
     * @return void
     */
    public function updated(Tourist $user)
    {
        // this will always trigger when actually a row was updated
    }
}

您所要做的就是像这样在AppServiceProvider 中注册观察者:

public function boot()
{
    Tourist::observe(\App\Observer\TouristObserver::class);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 2017-09-13
    • 2016-08-28
    相关资源
    最近更新 更多