Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.x] Fix Model::withoutEvents() not registering listeners inside boot() #33149

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Illuminate/Database/Eloquent/Concerns/HasEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Database\Eloquent\Concerns;

use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Events\NullDispatcher;
use Illuminate\Support\Arr;
use InvalidArgumentException;

Expand Down Expand Up @@ -399,7 +400,9 @@ public static function withoutEvents(callable $callback)
{
$dispatcher = static::getEventDispatcher();

static::unsetEventDispatcher();
if ($dispatcher) {
static::setEventDispatcher(new NullDispatcher($dispatcher));
}

try {
return $callback();
Expand Down
139 changes: 139 additions & 0 deletions src/Illuminate/Events/NullDispatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace Illuminate\Events;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Support\Traits\ForwardsCalls;

class NullDispatcher implements DispatcherContract
{
use ForwardsCalls;

/**
* The underlying event dispatcher instance.
*/
protected $dispatcher;

/**
* Create a new event dispatcher instance that does not fire.
*
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @return void
*/
public function __construct(DispatcherContract $dispatcher)
{
$this->dispatcher = $dispatcher;
}

/**
* Don't fire an event.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
* @return void
*/
public function dispatch($event, $payload = [], $halt = false)
{
}

/**
* Don't register an event and payload to be fired later.
*
* @param string $event
* @param array $payload
* @return void
*/
public function push($event, $payload = [])
{
}

/**
* Don't dispatch an event.
*
* @param string|object $event
* @param mixed $payload
* @return array|null
*/
public function until($event, $payload = [])
{
}

/**
* Register an event listener with the dispatcher.
*
* @param string|array $events
* @param \Closure|string $listener
* @return void
*/
public function listen($events, $listener)
{
return $this->dispatcher->listen($events, $listener);
}

/**
* Determine if a given event has listeners.
*
* @param string $eventName
* @return bool
*/
public function hasListeners($eventName)
{
return $this->dispatcher->hasListeners($eventName);
}

/**
* Register an event subscriber with the dispatcher.
*
* @param object|string $subscriber
* @return void
*/
public function subscribe($subscriber)
{
return $this->dispatcher->subscribe($subscriber);
}

/**
* Flush a set of pushed events.
*
* @param string $event
* @return void
*/
public function flush($event)
{
return $this->dispatcher->flush($event);
}

/**
* Remove a set of listeners from the dispatcher.
*
* @param string $event
* @return void
*/
public function forget($event)
{
return $this->dispatcher->forget($event);
}

/**
* Forget all of the queued listeners.
*
* @return void
*/
public function forgetPushed()
{
return $this->dispatcher->forgetPushed();
}

/**
* Dynamically pass method calls to the underlying dispatcher.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->forwardCallTo($this->dispatcher, $method, $parameters);
}
}
52 changes: 52 additions & 0 deletions tests/Integration/Database/EloquentModelWithoutEventsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Illuminate\Tests\Integration\Database;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

/**
* @group integration
*/
class EloquentModelWithoutEventsTest extends DatabaseTestCase
{
protected function setUp(): void
{
parent::setUp();

Schema::create('auto_filled_models', function (Blueprint $table) {
$table->increments('id');
$table->text('project')->nullable();
});
}

public function testWithoutEventsRegistersBootedListenersForLater()
{
$model = AutoFilledModel::withoutEvents(function () {
return AutoFilledModel::create();
});

$this->assertNull($model->project);

$model->save();

$this->assertEquals('Laravel', $model->project);
}
}

class AutoFilledModel extends Model
{
public $table = 'auto_filled_models';
public $timestamps = false;
protected $guarded = ['id'];

public static function boot()
{
parent::boot();

static::saving(function ($model) {
$model->project = 'Laravel';
});
}
}