Laravel中多模型观测器的问题

Laravel中多模型观测器的问题,laravel,eloquent,Laravel,Eloquent,我被一个奇怪的问题缠住了。这感觉就像在拉威尔,你不允许有多个模型观察员听同一个事件。就我而言: 父模型 子模型 在上面的示例中,如果我这样做: $instance=MyChild::create() 。。。doSomethingChild()行将不会激发。doSomethingInParent(),没有 但是,如果我在MyChild::creating()之后在子对象中移动parent::boot(),它确实可以工作。(我没有确认doSomethingParent()是否会触发,但我认为不会)

我被一个奇怪的问题缠住了。这感觉就像在拉威尔,你不允许有多个模型观察员听同一个事件。就我而言:

父模型

子模型

在上面的示例中,如果我这样做:

$instance=MyChild::create()

。。。doSomethingChild()行将不会激发。doSomethingInParent(),没有

但是,如果我在MyChild::creating()之后在子对象中移动parent::boot(),它确实可以工作。(我没有确认doSomethingParent()是否会触发,但我认为不会)


Laravel是否可以将多个事件注册到Model::creating()

这个问题很棘手。简短版本:从处理程序中删除返回值,两个事件都将触发。长版本如下

首先,我假设您打算键入
MyParent
(而不是
MyParent
),您的
boot
方法受
保护,而不是
private
,并且在
创建
方法调用中包含了最后的
。否则您的代码将无法运行。:)

然而,你所描述的问题是真实的。其原因是某些雄辩的事件被视为“停顿”事件。也就是说,对于某些事件,如果从事件处理程序(无论是闭包还是PHP回调)返回any非空值,则事件将停止传播。您可以在调度程序中看到这一点

#File: vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php
public function fire($event, $payload = array(), $halt = false)
{
}
看到第三个参数了吗?稍后,当调度器调用事件侦听器时

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

    //...
如果halt为
true
,回调返回任何不为null的内容(
true
false
,sclaer值,
数组
,对象
),则
激发
方法与
返回$response
短路,事件停止传播。这超出了标准“返回
false
以停止事件传播”。有些活动内置了暂停功能

那么,哪些模型事件停止?如果查看基本eloquent模型类中
fireModelEvent
的定义(Laravel将其别名为
eloquent

您可以看到模型的事件默认为停止。因此,如果我们查看触发事件的模型,我们会看到dohalt的事件是

#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);
正如您所看到的,
创建
是一个停止事件,这就是为什么返回任何值(即使是
true
)会停止事件,而您的第二个侦听器没有启动。当模型类希望对事件的返回值执行某些操作时,通常使用停止事件。专门用于
创建

#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
protected function performInsert(Builder $query)
{
    if ($this->fireModelEvent('creating') === false) return false;
    //...
如果您从回调返回
false
,(非null),Laravel实际上将跳过执行
插入操作。同样,这与返回false的标准停止事件传播行为不同。对于这四个模型事件,返回
false
也将取消它们正在侦听的操作


删除返回值(或
returnnull
),您就可以开始了

太棒了!我想如果我想得够仔细的话,这是有道理的。如果一个侦听器取消创建,则其他侦听器不应启动。我只是很惊讶,返回“真”也会停止。不管是谁,很好的解释-谢谢@安东尼:这有点奇怪/不明显,但这里不容易取胜。这就是为什么像Drupal这样的系统有一个用于事件的事件系统,以及一个用于需要操作数据的事件的“钩子”系统。这是一个巨大的惊喜,它的工作方式是如此模糊,以至于应该认为使用它是一种不好的做法。在Laravel文档中曾经有一点关于“取消保存操作”的内容,但现在这一点已经不存在了。您将注意到,“haltable”事件都以
-ing
结束。。。因此,如果您想停止正在处理的某些内容,只需抛出一个异常。免费好处:如果真的发生了,它不会被忽视。
#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);
#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
protected function performInsert(Builder $query)
{
    if ($this->fireModelEvent('creating') === false) return false;
    //...