我还没有找到一种方法来直接与Laravel做到这一点。我已经使用应用程序事件和关系继承构建了一个解决方案。
我添加了一个名为trait
其中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);
}
}
有了这个对象,我可以在BelongsToMany
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
});
}
}
我可以把所有时的关系被更新时必须执行的东西。看起来有点复杂,但我认为依靠类似的东西比在每个模型构建中添加逻辑要轻。
希望得到这个帮助!
您的解决方案似乎有效,但对我来说有点复杂。注册每个加载的应用程序,与产品相关的,已保存的处理程序...此外,我使用数据透视表,因此相关模型不是真正的模型,它是一个透视图... 昨天晚上我使用了一个解决方案应用程序事件和事件监听器。我今天将提交它作为答案。 – shulard
当然,请提交您的解决方案,这对未来的访问者和我也有帮助,以便了解它。 –
我已经添加了我的解决方案,您可以查看一下吗? – shulard