From bc4624cef6e60b8f711da971f7a466d574f484c6 Mon Sep 17 00:00:00 2001 From: Carl Olsen Date: Mon, 19 Mar 2018 12:20:39 -0400 Subject: [PATCH] add model factory after callbacks with states --- src/Illuminate/Database/Eloquent/Factory.php | 34 ++++++++++- .../Database/Eloquent/FactoryBuilder.php | 61 +++++++++++++++---- .../Database/EloquentFactoryBuilderTest.php | 32 ++++++++++ 3 files changed, 113 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factory.php b/src/Illuminate/Database/Eloquent/Factory.php index 2b76d27adb1d..c7995a0e8e0d 100644 --- a/src/Illuminate/Database/Eloquent/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factory.php @@ -120,7 +120,22 @@ public function state($class, $state, $attributes) */ public function afterMaking($class, $callback) { - $this->afterMaking[$class][] = $callback; + $this->afterMaking[$class]['default'][] = $callback; + + return $this; + } + + /** + * Define a callback to run after making a model with given type. + * + * @param string $class + * @param string $state + * @param callable $callback + * @return $this + */ + public function afterMakingState($class, $state, callable $callback) + { + $this->afterMaking[$class][$state][] = $callback; return $this; } @@ -134,7 +149,22 @@ public function afterMaking($class, $callback) */ public function afterCreating($class, $callback) { - $this->afterCreating[$class][] = $callback; + $this->afterCreating[$class]['default'][] = $callback; + + return $this; + } + + /** + * Define a callback to run after creating a model with given type. + * + * @param string $class + * @param string $state + * @param callable $callback + * @return $this + */ + public function afterCreatingState($class, $state, callable $callback) + { + $this->afterCreating[$class][$state][] = $callback; return $this; } diff --git a/src/Illuminate/Database/Eloquent/FactoryBuilder.php b/src/Illuminate/Database/Eloquent/FactoryBuilder.php index 4160097d0c07..b666560763c4 100644 --- a/src/Illuminate/Database/Eloquent/FactoryBuilder.php +++ b/src/Illuminate/Database/Eloquent/FactoryBuilder.php @@ -300,6 +300,9 @@ protected function applyStates(array $definition, array $attributes = []) { foreach ($this->activeStates as $state) { if (! isset($this->states[$this->class][$state])) { + if ($this->afterStateExists($state)) { + continue; + } throw new InvalidArgumentException("Unable to locate [{$state}] state for [{$this->class}]."); } @@ -366,13 +369,7 @@ protected function expandAttributes(array $attributes) */ public function callAfterMaking($models) { - $models->each(function ($model) { - if (isset($this->afterMaking[$this->class])) { - foreach ($this->afterMaking[$this->class] as $callback) { - $callback($model, $this->faker); - } - } - }); + $this->callAfter($this->afterMaking, $models); } /** @@ -383,12 +380,52 @@ public function callAfterMaking($models) */ public function callAfterCreating($models) { - $models->each(function ($model) { - if (isset($this->afterCreating[$this->class])) { - foreach ($this->afterCreating[$this->class] as $callback) { - $callback($model, $this->faker); - } + $this->callAfter($this->afterCreating, $models); + } + + /** + * Call after callbacks for each model and state. + * + * @param array $afterCallbacks + * @param \Illuminate\Support\Collection $models + * @return void + */ + protected function callAfter(array $afterCallbacks, $models) + { + $states = array_merge([$this->name], $this->activeStates); + + $models->each(function ($model) use ($states, $afterCallbacks) { + foreach ($states as $state) { + $this->callAfterCallbacks($afterCallbacks, $model, $state); } }); } + + /** + * Call after callbacks for each model and state. + * + * @param array $afterCallbacks + * @param Model $model + * @param string $state + * @return void + */ + protected function callAfterCallbacks(array $afterCallbacks, $model, $state) + { + if (!isset($afterCallbacks[$this->class][$state])) { + return; + } + + foreach ($afterCallbacks[$this->class][$state] as $callback) { + $callback($model, $this->faker); + } + } + + /** + * @param string $state + * @return bool + */ + protected function afterStateExists($state) + { + return isset($this->afterMaking[$this->class][$state]) || isset($this->afterCreating[$this->class][$state]); + } } diff --git a/tests/Integration/Database/EloquentFactoryBuilderTest.php b/tests/Integration/Database/EloquentFactoryBuilderTest.php index d2dcbee3040e..23dc1bf2520d 100644 --- a/tests/Integration/Database/EloquentFactoryBuilderTest.php +++ b/tests/Integration/Database/EloquentFactoryBuilderTest.php @@ -51,6 +51,14 @@ protected function getEnvironmentSetUp($app) $user->setRelation('profile', $profile); }); + $factory->afterMakingState(FactoryBuildableUser::class, 'with_callable_server', function (FactoryBuildableUser $user, Generator $faker) { + $server = factory(FactoryBuildableServer::class) + ->states('callable') + ->make(['user_id' => $user->id]); + + $user->servers->push($server); + }); + $factory->define(FactoryBuildableTeam::class, function (Generator $faker) { return [ 'name' => $faker->name, @@ -81,6 +89,12 @@ protected function getEnvironmentSetUp($app) ]; }); + $factory->afterCreatingState(FactoryBuildableUser::class, 'with_callable_server', function(FactoryBuildableUser $user, Generator $faker){ + $server = factory(FactoryBuildableServer::class) + ->states('callable') + ->create(['user_id' => $user->id]); + }); + $factory->state(FactoryBuildableServer::class, 'inline', ['status' => 'inline']); $app->singleton(Factory::class, function ($app) use ($factory) { @@ -234,6 +248,15 @@ public function creating_models_with_after_callback() $this->assertTrue($team->users->contains($team->owner)); } + /** @test **/ + public function creating_models_with_after_callback_states() + { + $user = factory(FactoryBuildableUser::class)->states('with_callable_server')->create(); + + $this->assertNotNull($user->profile); + $this->assertNotNull($user->servers->where('status', 'callable')->first()); + } + /** @test */ public function making_models_with_a_custom_connection() { @@ -251,6 +274,15 @@ public function making_models_with_after_callback() $this->assertNotNull($user->profile); } + + /** @test **/ + public function making_models_with_after_callback_states() + { + $user = factory(FactoryBuildableUser::class)->states('with_callable_server')->make(); + + $this->assertNotNull($user->profile); + $this->assertNotNull($user->servers->where('status', 'callable')->first()); + } } class FactoryBuildableUser extends Model