diff --git a/src/Illuminate/Database/Console/Seeds/WithoutModelEvents.php b/src/Illuminate/Database/Console/Seeds/WithoutModelEvents.php new file mode 100644 index 000000000000..acd9ec3f207b --- /dev/null +++ b/src/Illuminate/Database/Console/Seeds/WithoutModelEvents.php @@ -0,0 +1,19 @@ + Model::withoutEvents($callback); + } +} diff --git a/src/Illuminate/Database/Seeder.php b/src/Illuminate/Database/Seeder.php index 560e81c15211..1a7a12e1914d 100755 --- a/src/Illuminate/Database/Seeder.php +++ b/src/Illuminate/Database/Seeder.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Container\Container; +use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Support\Arr; use InvalidArgumentException; @@ -170,8 +171,16 @@ public function __invoke(array $parameters = []) throw new InvalidArgumentException('Method [run] missing from '.get_class($this)); } - return isset($this->container) - ? $this->container->call([$this, 'run'], $parameters) - : $this->run(...$parameters); + $callback = fn () => isset($this->container) + ? $this->container->call([$this, 'run'], $parameters) + : $this->run(...$parameters); + + $uses = array_flip(class_uses_recursive(static::class)); + + if (isset($uses[WithoutModelEvents::class])) { + $callback = $this->withoutModelEvents($callback); + } + + return $callback(); } } diff --git a/tests/Database/SeedCommandTest.php b/tests/Database/SeedCommandTest.php index 215990f30bd2..9d6a1bedfd33 100644 --- a/tests/Database/SeedCommandTest.php +++ b/tests/Database/SeedCommandTest.php @@ -4,9 +4,14 @@ use Illuminate\Console\OutputStyle; use Illuminate\Container\Container; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Console\Seeds\SeedCommand; +use Illuminate\Database\Console\Seeds\WithoutModelEvents; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Seeder; +use Illuminate\Events\NullDispatcher; +use Illuminate\Testing\Assert; use Mockery as m; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\ArrayInput; @@ -46,8 +51,61 @@ public function testHandle() $container->shouldHaveReceived('call')->with([$command, 'handle']); } + public function testWithoutModelEvents() + { + $input = new ArrayInput([ + '--force' => true, + '--database' => 'sqlite', + '--class' => UserWithoutModelEventsSeeder::class, + ]); + $output = new NullOutput; + + $instance = new UserWithoutModelEventsSeeder(); + + $seeder = m::mock($instance); + $seeder->shouldReceive('setContainer')->once()->andReturnSelf(); + $seeder->shouldReceive('setCommand')->once()->andReturnSelf(); + + $resolver = m::mock(ConnectionResolverInterface::class); + $resolver->shouldReceive('getDefaultConnection')->once(); + $resolver->shouldReceive('setDefaultConnection')->once()->with('sqlite'); + + $container = m::mock(Container::class); + $container->shouldReceive('call'); + $container->shouldReceive('environment')->once()->andReturn('testing'); + $container->shouldReceive('make')->with(UserWithoutModelEventsSeeder::class)->andReturn($seeder); + $container->shouldReceive('make')->with(OutputStyle::class, m::any())->andReturn( + new OutputStyle($input, $output) + ); + + $command = new SeedCommand($resolver); + $command->setLaravel($container); + + Model::setEventDispatcher($dispatcher = m::mock(Dispatcher::class)); + + // call run to set up IO, then fire manually. + $command->run($input, $output); + $command->handle(); + + Assert::assertSame($dispatcher, Model::getEventDispatcher()); + + $container->shouldHaveReceived('call')->with([$command, 'handle']); + } + protected function tearDown(): void { + Model::unsetEventDispatcher(); + m::close(); } } + +class UserWithoutModelEventsSeeder extends Seeder +{ + use WithoutModelEvents; + + public function run() + { + Assert::assertInstanceOf(NullDispatcher::class, Model::getEventDispatcher()); + } +}