我還沒有找到一種方法來直接與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