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

[8.x] Add support for attaching existing model instances in factories #35494

Merged
merged 9 commits into from Dec 7, 2020
Expand Up @@ -10,7 +10,7 @@ class BelongsToManyRelationship
/**
* The related factory instance.
*
* @var \Illuminate\Database\Eloquent\Factories\Factory
* @var \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model
*/
protected $factory;

Expand All @@ -31,12 +31,12 @@ class BelongsToManyRelationship
/**
* Create a new attached relationship definition.
*
* @param \Illuminate\Database\Eloquent\Factories\Factory $factory
* @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model $factory
* @param callable|array $pivot
* @param string $relationship
* @return void
*/
public function __construct(Factory $factory, $pivot, $relationship)
public function __construct($factory, $pivot, $relationship)
{
$this->factory = $factory;
$this->pivot = $pivot;
Expand All @@ -51,7 +51,7 @@ public function __construct(Factory $factory, $pivot, $relationship)
*/
public function createFor(Model $model)
{
Collection::wrap($this->factory->create([], $model))->each(function ($attachable) use ($model) {
Collection::wrap($this->factory instanceof Factory ? $this->factory->create([], $model) : $this->factory)->each(function ($attachable) use ($model) {
$model->{$this->relationship}()->attach(
$attachable,
is_callable($this->pivot) ? call_user_func($this->pivot, $model) : $this->pivot
Expand Down
Expand Up @@ -10,7 +10,7 @@ class BelongsToRelationship
/**
* The related factory instance.
*
* @var \Illuminate\Database\Eloquent\Factories\Factory
* @var \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Database\Eloquent\Model
*/
protected $factory;

Expand All @@ -31,11 +31,11 @@ class BelongsToRelationship
/**
* Create a new "belongs to" relationship definition.
*
* @param \Illuminate\Database\Eloquent\Factories\Factory $factory
* @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Database\Eloquent\Model $factory
* @param string $relationship
* @return void
*/
public function __construct(Factory $factory, $relationship)
public function __construct($factory, $relationship)
{
$this->factory = $factory;
$this->relationship = $relationship;
Expand All @@ -52,7 +52,7 @@ public function attributesFor(Model $model)
$relationship = $model->{$this->relationship}();

return $relationship instanceof MorphTo ? [
$relationship->getMorphType() => $this->factory->newModel()->getMorphClass(),
$relationship->getMorphType() => $this->factory instanceof Factory ? $this->factory->newModel()->getMorphClass() : $this->factory->getMorphClass(),
$relationship->getForeignKeyName() => $this->resolver($relationship->getOwnerKeyName()),
] : [
$relationship->getForeignKeyName() => $this->resolver($relationship->getOwnerKeyName()),
Expand All @@ -69,7 +69,7 @@ protected function resolver($key)
{
return function () use ($key) {
if (! $this->resolved) {
$instance = $this->factory->create();
$instance = $this->factory instanceof Factory ? $this->factory->create() : $this->factory;

return $this->resolved = $key ? $instance->{$key} : $instance->getKey();
}
Expand Down
8 changes: 4 additions & 4 deletions src/Illuminate/Database/Eloquent/Factories/Factory.php
Expand Up @@ -481,12 +481,12 @@ protected function guessRelationship(string $related)
/**
* Define an attached relationship for the model.
*
* @param \Illuminate\Database\Eloquent\Factories\Factory $factory
* @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model $factory
* @param callable|array $pivot
* @param string|null $relationship
* @return static
*/
public function hasAttached(self $factory, $pivot = [], $relationship = null)
public function hasAttached($factory, $pivot = [], $relationship = null)
{
return $this->newInstance([
'has' => $this->has->concat([new BelongsToManyRelationship(
Expand All @@ -500,11 +500,11 @@ public function hasAttached(self $factory, $pivot = [], $relationship = null)
/**
* Define a parent relationship for the model.
*
* @param \Illuminate\Database\Eloquent\Factories\Factory $factory
* @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Database\Eloquent\Model $factory
* @param string|null $relationship
* @return static
*/
public function for(self $factory, $relationship = null)
public function for($factory, $relationship = null)
{
return $this->newInstance(['for' => $this->for->concat([new BelongsToRelationship(
$factory,
Expand Down
52 changes: 52 additions & 0 deletions tests/Database/DatabaseEloquentFactoryTest.php
Expand Up @@ -250,6 +250,21 @@ public function test_belongs_to_relationship()
$this->assertCount(3, FactoryTestPost::all());
}

public function test_belongs_to_relationship_with_existing_model_instance()
{
$user = FactoryTestUserFactory::new(['name' => 'Taylor Otwell'])->create();
$posts = FactoryTestPostFactory::times(3)
->for($user, 'user')
->create();

$this->assertCount(3, $posts->filter(function ($post) use ($user) {
return $post->user->is($user);
}));

$this->assertCount(1, FactoryTestUser::all());
$this->assertCount(3, FactoryTestPost::all());
}

public function test_morph_to_relationship()
{
$posts = FactoryTestCommentFactory::times(3)
Expand All @@ -263,6 +278,20 @@ public function test_morph_to_relationship()
$this->assertCount(3, FactoryTestComment::all());
}

public function test_morph_to_relationship_with_existing_model_instance()
{
$post = FactoryTestPostFactory::new(['title' => 'Test Title'])->create();
$posts = FactoryTestCommentFactory::times(3)
->for($post, 'commentable')
->create();

$this->assertSame('Test Title', FactoryTestPost::first()->title);
$this->assertCount(3, FactoryTestPost::first()->comments);

$this->assertCount(1, FactoryTestPost::all());
$this->assertCount(3, FactoryTestComment::all());
}

public function test_belongs_to_many_relationship()
{
$users = FactoryTestUserFactory::times(3)
Expand Down Expand Up @@ -290,6 +319,29 @@ public function test_belongs_to_many_relationship()
unset($_SERVER['__test.role.creating-user']);
}

public function test_belongs_to_many_relationship_with_existing_model_instances()
{
$roles = FactoryTestRoleFactory::times(3)
->afterCreating(function ($role) {
$_SERVER['__test.role.creating-role'] = $role;
})
->create();
FactoryTestUserFactory::times(3)
->hasAttached($roles, ['admin' => 'Y'], 'roles')
->create();

$this->assertCount(3, FactoryTestRole::all());

$user = FactoryTestUser::latest()->first();

$this->assertCount(3, $user->roles);
$this->assertSame('Y', $user->roles->first()->pivot->admin);

$this->assertInstanceOf(Eloquent::class, $_SERVER['__test.role.creating-role']);

unset($_SERVER['__test.role.creating-role']);
}

public function test_sequences()
{
$users = FactoryTestUserFactory::times(2)->sequence(
Expand Down