我遇到了一个奇怪的问题。感觉就像在Laravel中一样,你不允许多个模特观察者听同一个事件。就我而言:
父模型
class MyParent extends Eloquent {
private static function boot()
{
parent::boot();
$called_class = get_called_class();
$called_class::creating(function($model) {
doSomethingInParent();
return true;
}
}
}
儿童模型
class MyChild extends myParent {
private static function boot()
{
parent::boot();
MyChild::creating(function($model) {
doSomethingInChild();
return true;
}
}
}
在上面的例子中,如果我这样做:
$ instance = MyChild :: create();
...行doSomethingInChild()不会触发。 doSomethingInParent(),确实。
如果我在 MyChild :: creating()之后移动子中的parent :: boot(),则它确实有效。 (我没有确认doSomethingInParent()是否会触发,但我认为它不会发生
Laravel可以在Model :: creating()中注册多个事件吗?
答案 0 :(得分:17)
这个很棘手。简短版本:从您的处理程序中删除您的返回值,这两个事件都将触发。长版如下。
首先,我假设您打算键入MyParent
(而非myParent
),表示您的boot
方法是protected
,而不是{ {1}},并且您在private
方法调用中包含了最终)
。否则您的代码不会运行。 :)
但是,您描述的问题是真实的。其原因是某些Eloquent事件被认为是“停止”事件。也就是说,对于某些事件,如果从事件处理程序返回任何非空值(无论是闭包还是PHP回调),该事件将停止传播。您可以在调度程序中看到这一点
create
看到第三个参数#File: vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php
public function fire($event, $payload = array(), $halt = false)
{
}
?稍后,调度员调用事件监听器
$halt
如果暂停为#File: vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php
foreach ($this->getListeners($event) as $listener)
{
$response = call_user_func_array($listener, $payload);
// If a response is returned from the listener and event halting is enabled
// we will just return this response, and not call the rest of the event
// listeners. Otherwise we will add the response on the response list.
if ( ! is_null($response) && $halt)
{
array_pop($this->firing);
return $response;
}
//...
且回复任何非空(true
,true
,sclaer值为false
,一个array
),object
方法与fire
短路,事件停止传播。这超出了标准“返回return $response
以停止事件传播”。有些事件已经停止了。
那么,哪些模型事件停止了?如果你看一下基础雄辩模型类中false
的定义(Laravel将其称为fireModelEvent
)
Eloquent
您可以看到模型的事件默认停止。因此,如果我们通过模型查看触发事件,我们会看到执行暂停的事件
#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
protected function fireModelEvent($event, $halt = true)
{
//...
}
和不停止的事件是
#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
$this->fireModelEvent('deleting')
$this->fireModelEvent('saving')
$this->fireModelEvent('updating')
$this->fireModelEvent('creating')
正如您所看到的,#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
$this->fireModelEvent('booting', false);
$this->fireModelEvent('booted', false);
$this->fireModelEvent('deleted', false);
$this->fireModelEvent('saved', false);
$this->fireModelEvent('updated', false);
$this->fireModelEvent('created', false);
是一个暂停事件,这就是为什么返回任何值,甚至creating
,停止事件并且您的第二个侦听器没有触发。当Model类想要对事件的返回值执行某些操作时,通常会使用暂停事件。特别针对true
creating
如果从回调中返回#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
protected function performInsert(Builder $query)
{
if ($this->fireModelEvent('creating') === false) return false;
//...
,(非null),Laravel实际上会跳过执行false
。同样,这与标准停止事件传播的行为不同,返回false 。对于这四个模型事件,返回INSERT
也将取消他们正在侦听的操作。
删除返回值(或false
),你就可以了。