From ffdf9856113cf4e9ff259d45eff6ba9592c7fbd7 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sun, 11 Mar 2018 09:11:33 -0700 Subject: [PATCH 1/5] add after callback for model factories --- src/Illuminate/Database/Eloquent/Factory.php | 29 +++++++++++++- .../Database/Eloquent/FactoryBuilder.php | 38 +++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Factory.php b/src/Illuminate/Database/Eloquent/Factory.php index 8b6104c3de0b..4927acb10d9b 100644 --- a/src/Illuminate/Database/Eloquent/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factory.php @@ -22,6 +22,13 @@ class Factory implements ArrayAccess */ protected $states = []; + /** + * The registered callbacks. + * + * @var array + */ + protected $after = []; + /** * The Faker instance for the builder. * @@ -97,6 +104,26 @@ public function state($class, $state, $attributes) return $this; } + /** + * Define a callback to run after an action. + * + * @param string $class + * @param string $action + * @param callable $callback + * @return $this + */ + public function after($class, $action, $callback = null) + { + if (is_callable($action) && $callback === null) { + $callback = $action; + $action = 'create'; + } + + $this->after[$class][$action] = $callback; + + return $this; + } + /** * Create an instance of the given model and persist it to the database. * @@ -184,7 +211,7 @@ public function raw($class, array $attributes = [], $name = 'default') */ public function of($class, $name = 'default') { - return new FactoryBuilder($class, $name, $this->definitions, $this->states, $this->faker); + return new FactoryBuilder($class, $name, $this->definitions, $this->states, $this->after, $this->faker); } /** diff --git a/src/Illuminate/Database/Eloquent/FactoryBuilder.php b/src/Illuminate/Database/Eloquent/FactoryBuilder.php index 7f4eccaa9da8..2499419ad355 100644 --- a/src/Illuminate/Database/Eloquent/FactoryBuilder.php +++ b/src/Illuminate/Database/Eloquent/FactoryBuilder.php @@ -45,6 +45,13 @@ class FactoryBuilder */ protected $states; + /** + * The model callbacks. + * + * @var array + */ + protected $after = []; + /** * The states to apply. * @@ -76,13 +83,14 @@ class FactoryBuilder * @param \Faker\Generator $faker * @return void */ - public function __construct($class, $name, array $definitions, array $states, Faker $faker) + public function __construct($class, $name, array $definitions, array $states, array $after, Faker $faker) { $this->name = $name; $this->class = $class; $this->faker = $faker; $this->states = $states; $this->definitions = $definitions; + $this->after = $after; } /** @@ -149,8 +157,10 @@ public function create(array $attributes = []) if ($results instanceof Model) { $this->store(collect([$results])); + $this->applyAfter(collect([$results]), 'create'); } else { $this->store($results); + $this->applyAfter($results, 'create'); } return $results; @@ -182,16 +192,18 @@ protected function store($results) public function make(array $attributes = []) { if ($this->amount === null) { - return $this->makeInstance($attributes); + $instance = $this->makeInstance($attributes); + return $this->applyAfter(collect([$instance]), 'make'); } if ($this->amount < 1) { return (new $this->class)->newCollection(); } - return (new $this->class)->newCollection(array_map(function () use ($attributes) { + $instances = (new $this->class)->newCollection(array_map(function () use ($attributes) { return $this->makeInstance($attributes); }, range(1, $this->amount))); + return $this->applyAfter($instances, 'make'); } /** @@ -328,4 +340,24 @@ protected function expandAttributes(array $attributes) return $attributes; } + + /** + * Run after callback on a collection of models + * + * @param \Illuminate\Support\Collection $results + * @param string $action + * @return void + */ + public function applyAfter($models, $action) + { + $models->each(function ($model) use ($action) { + if (! isset($this->after[$this->class][$action])) { + return; + } + + call_user_func_array($this->after[$this->class][$action], [$model, $this->faker]); + }); + + return $models; + } } From 1797a6bce27dff33064c31237743ed9ae60bfc6f Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sun, 11 Mar 2018 09:50:43 -0700 Subject: [PATCH 2/5] apply style-ci fixes --- src/Illuminate/Database/Eloquent/FactoryBuilder.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/FactoryBuilder.php b/src/Illuminate/Database/Eloquent/FactoryBuilder.php index 2499419ad355..3bd52c410a88 100644 --- a/src/Illuminate/Database/Eloquent/FactoryBuilder.php +++ b/src/Illuminate/Database/Eloquent/FactoryBuilder.php @@ -193,6 +193,7 @@ public function make(array $attributes = []) { if ($this->amount === null) { $instance = $this->makeInstance($attributes); + return $this->applyAfter(collect([$instance]), 'make'); } @@ -203,6 +204,7 @@ public function make(array $attributes = []) $instances = (new $this->class)->newCollection(array_map(function () use ($attributes) { return $this->makeInstance($attributes); }, range(1, $this->amount))); + return $this->applyAfter($instances, 'make'); } @@ -342,7 +344,7 @@ protected function expandAttributes(array $attributes) } /** - * Run after callback on a collection of models + * Run after callback on a collection of models. * * @param \Illuminate\Support\Collection $results * @param string $action From d15cfe3c57e53467445f6ca599091ac13ccd2356 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sun, 11 Mar 2018 10:10:57 -0700 Subject: [PATCH 3/5] fix existing tests --- src/Illuminate/Database/Eloquent/FactoryBuilder.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/FactoryBuilder.php b/src/Illuminate/Database/Eloquent/FactoryBuilder.php index 3bd52c410a88..ca8bc65287a7 100644 --- a/src/Illuminate/Database/Eloquent/FactoryBuilder.php +++ b/src/Illuminate/Database/Eloquent/FactoryBuilder.php @@ -193,8 +193,9 @@ public function make(array $attributes = []) { if ($this->amount === null) { $instance = $this->makeInstance($attributes); + $this->applyAfter(collect([$instance]), 'make'); - return $this->applyAfter(collect([$instance]), 'make'); + return $instance; } if ($this->amount < 1) { @@ -204,8 +205,9 @@ public function make(array $attributes = []) $instances = (new $this->class)->newCollection(array_map(function () use ($attributes) { return $this->makeInstance($attributes); }, range(1, $this->amount))); + $this->applyAfter($instances, 'make'); - return $this->applyAfter($instances, 'make'); + return $instances; } /** @@ -346,7 +348,7 @@ protected function expandAttributes(array $attributes) /** * Run after callback on a collection of models. * - * @param \Illuminate\Support\Collection $results + * @param \Illuminate\Support\Collection $models * @param string $action * @return void */ @@ -359,7 +361,5 @@ public function applyAfter($models, $action) call_user_func_array($this->after[$this->class][$action], [$model, $this->faker]); }); - - return $models; } } From 591d2194b731804c438301a82522190c4397581c Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sun, 11 Mar 2018 10:53:12 -0700 Subject: [PATCH 4/5] add new tests --- .../Database/EloquentFactoryBuilderTest.php | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/Integration/Database/EloquentFactoryBuilderTest.php b/tests/Integration/Database/EloquentFactoryBuilderTest.php index 395b652d5e76..44e6a6c37fb0 100644 --- a/tests/Integration/Database/EloquentFactoryBuilderTest.php +++ b/tests/Integration/Database/EloquentFactoryBuilderTest.php @@ -38,6 +38,32 @@ protected function getEnvironmentSetUp($app) ]; }); + $factory->define(FactoryBuildableProfile::class, function (Generator $faker) { + return [ + 'user_id' => function () { + return factory(FactoryBuildableUser::class)->create()->id; + } + ]; + }); + + $factory->after(FactoryBuildableUser::class, 'make', function (FactoryBuildableUser $user, Generator $faker) { + $profile =factory(FactoryBuildableProfile::class)->make(['user_id' => $user->id]); + $user->setRelation('profile', $profile); + }); + + $factory->define(FactoryBuildableTeam::class, function (Generator $faker) { + return [ + 'name' => $faker->name, + 'owner_id' => function () { + return factory(FactoryBuildableUser::class)->create()->id; + }, + ]; + }); + + $factory->after(FactoryBuildableTeam::class, function (FactoryBuildableTeam $team, Generator $faker) { + $team->users()->attach($team->owner); + }); + $factory->define(FactoryBuildableServer::class, function (Generator $faker) { return [ 'name' => $faker->name, @@ -72,6 +98,23 @@ public function setUp() $table->string('email'); }); + Schema::create('profiles', function ($table) { + $table->increments('id'); + $table->unsignedInteger('user_id'); + }); + + Schema::create('teams', function ($table) { + $table->increments('id'); + $table->string('name'); + $table->string('owner_id'); + }); + + Schema::create('team_users', function ($table) { + $table->increments('id'); + $table->unsignedInteger('team_id'); + $table->unsignedInteger('user_id'); + }); + Schema::connection('alternative-connection')->create('users', function ($table) { $table->increments('id'); $table->string('name'); @@ -183,6 +226,14 @@ public function creating_models_on_custom_connection() $this->assertTrue($user->is($dbUser)); } + /** @test **/ + public function creating_models_with_after_callback() + { + $team = factory(FactoryBuildableTeam::class)->create(); + + $this->assertTrue($team->users->contains($team->owner)); + } + /** @test */ public function making_models_with_a_custom_connection() { @@ -192,6 +243,14 @@ public function making_models_with_a_custom_connection() $this->assertEquals('alternative-connection', $user->getConnectionName()); } + + /** @test **/ + public function making_models_with_after_callback() + { + $user = factory(FactoryBuildableUser::class)->make(); + + $this->assertNotNull($user->profile); + } } class FactoryBuildableUser extends Model @@ -204,6 +263,45 @@ public function servers() { return $this->hasMany(FactoryBuildableServer::class, 'user_id'); } + + public function profile() + { + return $this->hasOne(FactoryBuildableProfile::class, 'user_id'); + } +} + +class FactoryBuildableProfile extends Model +{ + public $table = 'profiles'; + public $timestamps = false; + protected $guarded = ['id']; + + public function user() + { + return $this->belongsTo(FactoryBuildableUser::class, 'user_id'); + } +} + +class FactoryBuildableTeam extends Model +{ + public $table = 'teams'; + public $timestamps = false; + protected $guarded = ['id']; + + public function owner() + { + return $this->belongsTo(FactoryBuildableUser::class, 'owner_id'); + } + + public function users() + { + return $this->belongsToMany( + FactoryBuildableUser::class, + 'team_users', + 'team_id', + 'user_id' + ); + } } class FactoryBuildableServer extends Model From 889970a5f9bc4747b8d71ae36a74db237787f3c7 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sun, 11 Mar 2018 10:55:44 -0700 Subject: [PATCH 5/5] apply style-ci fixes --- tests/Integration/Database/EloquentFactoryBuilderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Database/EloquentFactoryBuilderTest.php b/tests/Integration/Database/EloquentFactoryBuilderTest.php index 44e6a6c37fb0..c87c8b01f5d3 100644 --- a/tests/Integration/Database/EloquentFactoryBuilderTest.php +++ b/tests/Integration/Database/EloquentFactoryBuilderTest.php @@ -42,12 +42,12 @@ protected function getEnvironmentSetUp($app) return [ 'user_id' => function () { return factory(FactoryBuildableUser::class)->create()->id; - } + }, ]; }); $factory->after(FactoryBuildableUser::class, 'make', function (FactoryBuildableUser $user, Generator $faker) { - $profile =factory(FactoryBuildableProfile::class)->make(['user_id' => $user->id]); + $profile = factory(FactoryBuildableProfile::class)->make(['user_id' => $user->id]); $user->setRelation('profile', $profile); });