Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何知道关系是否已在laravel中的给定模型上更新?_Php_Laravel_Laravel 5 - Fatal编程技术网

Php 如何知道关系是否已在laravel中的给定模型上更新?

Php 如何知道关系是否已在laravel中的给定模型上更新?,php,laravel,laravel-5,Php,Laravel,Laravel 5,我目前正在开发一个Laravel应用程序,它使用模型事件在数据库中执行数据验证/同步 我有一张包含重要数据的表格。此表在不同的模型更新时更新。我使用模型事件来处理这个问题。它适用于模型属性示例: <?php Product::saved(function (Product $p) { $dirty = collect($p->getDirty()); if ($dirty->has('ugr') || $dirty->has('ra')) {

我目前正在开发一个Laravel应用程序,它使用模型事件在数据库中执行数据验证/同步

我有一张包含重要数据的表格。此表在不同的模型更新时更新。我使用模型事件来处理这个问题。它适用于模型属性示例:

<?php
Product::saved(function (Product $p) {
    $dirty = collect($p->getDirty());
    if ($dirty->has('ugr') || $dirty->has('ra')) {
        //Do some stuff here
    }
});

没有现成的方法可以做到这一点。实际上,您希望在更新子对象时通知父对象。换句话说,如果任何相关应用程序被更新,您希望触发产品上保存的处理程序

如果我当时的理解是正确的,那么您需要通过产品模型注册处理程序,因为如果您只想在相关子模型更新时通知相关模型,那么您可以简单地在子模型中使用
protected$touchs
属性,这样,如果任何子模型发生更改,父模型将始终更新

因为,您只想跟踪在加载main时加载(急切地)的相关模型的更改,所以需要通过父/主模型本身在相关模型上注册保存的处理程序。如果我仍然在正确的轨道上,那么您可以尝试以下方法:

$product = Product::with('applications')->findOrFail($id);

// Check if there are any Application loaded (eagerly) with Product
if($product->relationLoaded('applications')) {

    // Loop through each Application instance loaded with Product
    $product->applications->each(function($application) use($product) {

        // Register the saved event handler on each Application instance
        $application->saved(function($app) use($product)  {

            // If nothing has been changed do nothing
            if(!count($dirty = $app->getDirty())) return true;

            // Check if prop_1 or prop_2 has been changed in $app
            $props = ['prop_1', 'prop_2']; // You may add more props

            $keys = array_intersect_key($props, array_keys($dirty));

            if(count($keys)) {
                // Do some stuff here
                // You can do something with $product as well
                // If you have saved handler on Product then just try
                // $product->touch(); // it'll trigger that handler on Product
            }
        });
    });
}

希望,你想要我上面描述的东西。顺便说一句,这只是一个想法,您可以使用单独的类/方法在子模型上注册事件处理程序,以保持代码干净。

没有现成的方法可以做到这一点。实际上,您希望在更新子对象时通知父对象。换句话说,如果任何相关应用程序被更新,您希望触发产品上保存的处理程序

如果我当时的理解是正确的,那么您需要通过产品模型注册处理程序,因为如果您只想在相关子模型更新时通知相关模型,那么您可以简单地在子模型中使用
protected$touchs
属性,这样,如果任何子模型发生更改,父模型将始终更新

因为,您只想跟踪在加载main时加载(急切地)的相关模型的更改,所以需要通过父/主模型本身在相关模型上注册保存的处理程序。如果我仍然在正确的轨道上,那么您可以尝试以下方法:

$product = Product::with('applications')->findOrFail($id);

// Check if there are any Application loaded (eagerly) with Product
if($product->relationLoaded('applications')) {

    // Loop through each Application instance loaded with Product
    $product->applications->each(function($application) use($product) {

        // Register the saved event handler on each Application instance
        $application->saved(function($app) use($product)  {

            // If nothing has been changed do nothing
            if(!count($dirty = $app->getDirty())) return true;

            // Check if prop_1 or prop_2 has been changed in $app
            $props = ['prop_1', 'prop_2']; // You may add more props

            $keys = array_intersect_key($props, array_keys($dirty));

            if(count($keys)) {
                // Do some stuff here
                // You can do something with $product as well
                // If you have saved handler on Product then just try
                // $product->touch(); // it'll trigger that handler on Product
            }
        });
    });
}

希望,你想要我上面描述的东西。顺便说一句,这只是一个想法,您可以使用单独的类/方法在子模型上注册事件处理程序,以保持代码干净。

我还没有找到一种直接使用Laravel的方法。我已经使用应用程序事件和关系继承构建了一个解决方案

我添加了一个名为
App\Database\Eloquent\FollowUpdatedRelations
trait
,其目标是通知关系更新:

<?php

namespace App\Database\Eloquent;

use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use App\Library\Decorator;
use App\Events\RelationUpdated;

trait FollowUpdatedRelations
{
    /**
     * The default error bag.
     *
     * @var string
     */
    protected $updatedRelations = [];

    /**
     * Check if the belongs to many relation has been updated
     * @param  BelongsToMany $relation
     * @param  array         $syncResult Result of the `sync` method call
     * @return boolean
     */
    protected function hasBeenUpdated(BelongsToMany $relation, array $syncResult)
    {
        if (isset($syncResult['attached']) && count($syncResult['attached']) > 0) {
            $this->updatedRelations[$relation->getRelationName()] = true;
            event(new RelationUpdated($relation));
        } elseif (isset($syncResult['detached']) && count($syncResult['detached']) > 0) {
            $this->updatedRelations[$relation->getRelationName()] = true;
            event(new RelationUpdated($relation));
        }
    }

    /**
     * Decorate a BelongsToMany to listen to relation update
     * @param  BelongsToMany $relation
     * @return Decorator
     */
    protected function decorateBelongsToMany(BelongsToMany $relation)
    {
        $decorator = new Decorator($relation);
        $decorator->decorate('sync', function ($decorated, $arguments) {
            $updates = call_user_func_array([$decorated, 'sync'], $arguments);
            $this->hasBeenUpdated($decorated, $updates);
            return $updates;
        });

        return $decorator;
    }

    /**
     * Retrieve the list of dirty relations
     * @return array
     */
    public function getDirtyRelations()
    {
        return $this->updatedRelations;
    }
}
使用该对象,我可以在
belongToMany
Laravel关系上创建自定义的
sync
方法。我使用sync方法来跟踪更新,因为它返回数据透视表中的附加、分离和更新模型列表

我只需要计算是否存在附加或分离的模型,并调度相应的事件。我的事件是
App\Events\RelationUpdated
,包含更新的关系作为属性

然后我可以在
EventServiceProvider
中添加一个事件侦听器,如下所示:

<?php

namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use App\Events\RelationUpdated;
use App\Product;

class EventServiceProvider extends ServiceProvider
{
    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        ...

        //When a listened relation is updated, we perform a Model save
        $events->listen(RelationUpdated::class, function ($event) {
            //Here I do my stuff
        });
    }
}

我还没有找到一种直接用Laravel实现这一点的方法。我已经使用应用程序事件和关系继承构建了一个解决方案

我添加了一个名为
App\Database\Eloquent\FollowUpdatedRelations
trait
,其目标是通知关系更新:

<?php

namespace App\Database\Eloquent;

use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use App\Library\Decorator;
use App\Events\RelationUpdated;

trait FollowUpdatedRelations
{
    /**
     * The default error bag.
     *
     * @var string
     */
    protected $updatedRelations = [];

    /**
     * Check if the belongs to many relation has been updated
     * @param  BelongsToMany $relation
     * @param  array         $syncResult Result of the `sync` method call
     * @return boolean
     */
    protected function hasBeenUpdated(BelongsToMany $relation, array $syncResult)
    {
        if (isset($syncResult['attached']) && count($syncResult['attached']) > 0) {
            $this->updatedRelations[$relation->getRelationName()] = true;
            event(new RelationUpdated($relation));
        } elseif (isset($syncResult['detached']) && count($syncResult['detached']) > 0) {
            $this->updatedRelations[$relation->getRelationName()] = true;
            event(new RelationUpdated($relation));
        }
    }

    /**
     * Decorate a BelongsToMany to listen to relation update
     * @param  BelongsToMany $relation
     * @return Decorator
     */
    protected function decorateBelongsToMany(BelongsToMany $relation)
    {
        $decorator = new Decorator($relation);
        $decorator->decorate('sync', function ($decorated, $arguments) {
            $updates = call_user_func_array([$decorated, 'sync'], $arguments);
            $this->hasBeenUpdated($decorated, $updates);
            return $updates;
        });

        return $decorator;
    }

    /**
     * Retrieve the list of dirty relations
     * @return array
     */
    public function getDirtyRelations()
    {
        return $this->updatedRelations;
    }
}
使用该对象,我可以在
belongToMany
Laravel关系上创建自定义的
sync
方法。我使用sync方法来跟踪更新,因为它返回数据透视表中的附加、分离和更新模型列表

我只需要计算是否存在附加或分离的模型,并调度相应的事件。我的事件是
App\Events\RelationUpdated
,包含更新的关系作为属性

然后我可以在
EventServiceProvider
中添加一个事件侦听器,如下所示:

<?php

namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use App\Events\RelationUpdated;
use App\Product;

class EventServiceProvider extends ServiceProvider
{
    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        ...

        //When a listened relation is updated, we perform a Model save
        $events->listen(RelationUpdated::class, function ($event) {
            //Here I do my stuff
        });
    }
}

您的解决方案似乎有效,但对我来说有点复杂。在每个加载的应用程序上注册,与产品、保存的处理程序相关。。。另外,我使用了一个透视表,所以相关的模型不是一个真实的模型,而是一个透视表。。。昨天晚上,我使用应用程序事件和事件侦听器构建了一个解决方案。我今天将提交它作为答案。当然,提交您的解决方案,这样对未来的访问者和我理解它都会有帮助。我已经添加了我的解决方案,您能看一下吗?您的解决方案似乎有效,但对我来说有点复杂。在每个加载的应用程序上注册,与产品、保存的处理程序相关。。。另外,我使用了一个透视表,所以相关的模型不是一个真实的模型,而是一个透视表。。。昨天晚上,我使用应用程序事件和事件侦听器构建了一个解决方案。我将在今天提交它作为答案。当然,提交您的解决方案,以便将来的访问者和我了解它。我添加了我的解决方案,您能看一下吗?此解决方案不适用于Laravel 6此解决方案不适用于Laravel 6