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

时间:2016-09-19 15:10:13

标签: php laravel laravel-5

我目前正在使用Laravel应用程序,该应用程序使用Model事件在数据库中执行数据验证/同步。

我有一张包含重要数据的表格。此表针对不同的模型更新进行了更新。我使用模型事件来处理它。它适用于模型属性示例:

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

凭借这种逻辑,我可以限制我的东西&#34;在特定模型属性更新上执行。

如何对Product关系进行此类检查?

我可以通过applications上的Product方法访问ManyToMany关系,如何知道链接的应用程序列表自模型加载后是否已更改?

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

我还没有找到一种方法直接与Laravel一起做这件事。我已经使用Application事件和Relation继承构建了一个解决方案。

我添加了名为trait的{​​{1}},其目标是通知关系更新:

App\Database\Eloquent\FollowUpdatedRelations

我在模型中使用了这个特性,我需要遵循关系更新,并且我已经更新了关系定义:

<?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;
    }
}

<?php ... class Product extends Model { use FollowUpdatedRelations; .... /** * Defines relationship with App\Applications model * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function applications() { return $this->decorateBelongsToMany( $this->belongsToMany('App\Application', 'product_application') ); } } 类包装一个对象并添加覆盖方法的能力:

App\Library\Decorator

使用该对象,我可以在<?php namespace App\Library; use Closure; class Decorator { /** * Decorated instance * @var mixed */ private $decorated; private $methods = []; /** * Decorate given instance * @param mixed $toDecorate */ public function __construct($toDecorate) { $this->decorated = $toDecorate; } /** * Decorate a method * @param string $name * @param Closure $callback Method to run instead of decorated one */ public function decorate($name, Closure $callback) { $this->methods[$name] = $callback; return $this; } /** * Call a method on decorated instance * @param string $name * @param array $arguments * @return mixed */ public function __call($name, $arguments) { if (isset($this->methods[$name])) { return call_user_func_array($this->methods[$name], [$this->decorated, $arguments]); } return call_user_func_array([$this->decorated, $name], $arguments); } } Laravel关系上创建自定义sync方法。我使用sync方法来跟踪更新,因为它返回数据透视表中附加,分离和更新模型的列表。

我只需要计算是否有附加或分离的模型并调度相应的事件。我的活动是BelongsToMany,其中包含已更新的关系作为属性。

然后我可以在App\Events\RelationUpdated中添加一个事件监听器:

EventServiceProvider

我可以放置关系更新时必须执行的所有内容。看起来有点复杂,但我认为依赖于这样的东西比在每个模型构造上添加逻辑要轻。

希望这有帮助!

答案 1 :(得分:1)

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

如果我的理解是正确的,那么你需要通过Product模型注册处理程序,因为如果你只想通知它相关的子模型更新的相关模型,那么你可以简单地使用 AWS.config.update({ accessKeyId: $rootScope.s3.akey, secretAccessKey: $rootScope.s3.skey }); s3=new AWS.S3({apiVersion: '2006-03-01'}); s3.listObjects({Bucket:$rootScope.s3.bucket}, function(err,data){ if(err) console.log(err); else console.log(data); }) 属性如果更改了任何子模型,则子模型将始终更新父模型。

因为,您希望仅跟踪更改主要加载时(急切地)加载的相关模型,因此您需要通过父/主模型本身在相关模型上注册已保存的处理程序。如果我仍然在正确的轨道上,你可以尝试这样的事情:

protected $touches

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