Php 如何知道关系是否已在laravel中的给定模型上更新?
我目前正在开发一个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')) {
<?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