Skip to content

Commit c1d8da6

Browse files
authored
Respect pendingAttributes in factories (#55558)
1 parent 18a2f33 commit c1d8da6

File tree

4 files changed

+99
-4
lines changed

4 files changed

+99
-4
lines changed

src/Illuminate/Database/Eloquent/Factories/BelongsToManyRelationship.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ public function __construct($factory, $pivot, $relationship)
5050
*/
5151
public function createFor(Model $model)
5252
{
53-
Collection::wrap($this->factory instanceof Factory ? $this->factory->create([], $model) : $this->factory)->each(function ($attachable) use ($model) {
53+
$relationship = $model->{$this->relationship}();
54+
55+
Collection::wrap($this->factory instanceof Factory ? $this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $model) : $this->factory)->each(function ($attachable) use ($model) {
5456
$model->{$this->relationship}()->attach(
5557
$attachable,
5658
is_callable($this->pivot) ? call_user_func($this->pivot, $model) : $this->pivot

src/Illuminate/Database/Eloquent/Factories/Factory.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,21 @@ public function state($state)
530530
]);
531531
}
532532

533+
/**
534+
* Prepend a new state transformation to the model definition.
535+
*
536+
* @param (callable(array<string, mixed>, TModel|null): array<string, mixed>)|array<string, mixed> $state
537+
* @return static
538+
*/
539+
public function prependState($state)
540+
{
541+
return $this->newInstance([
542+
'states' => $this->states->prepend(
543+
is_callable($state) ? $state : fn () => $state,
544+
),
545+
]);
546+
}
547+
533548
/**
534549
* Set a single model attribute.
535550
*

src/Illuminate/Database/Eloquent/Factories/Relationship.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@ public function createFor(Model $parent)
4949
$this->factory->state([
5050
$relationship->getMorphType() => $relationship->getMorphClass(),
5151
$relationship->getForeignKeyName() => $relationship->getParentKey(),
52-
])->create([], $parent);
52+
])->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent);
5353
} elseif ($relationship instanceof HasOneOrMany) {
5454
$this->factory->state([
5555
$relationship->getForeignKeyName() => $relationship->getParentKey(),
56-
])->create([], $parent);
56+
])->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent);
5757
} elseif ($relationship instanceof BelongsToMany) {
58-
$relationship->attach($this->factory->create([], $parent));
58+
$relationship->attach(
59+
$this->factory->prependState($relationship->getQuery()->pendingAttributes)->create([], $parent)
60+
);
5961
}
6062
}
6163

tests/Database/DatabaseEloquentFactoryTest.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,62 @@ public function test_factory_global_model_resolver()
850850
$this->assertEquals(FactoryTestGuessModelFactory::new()->modelName(), FactoryTestGuessModel::class);
851851
}
852852

853+
public function test_factory_model_has_many_relationship_has_pending_attributes()
854+
{
855+
FactoryTestUser::factory()->has(new FactoryTestPostFactory(), 'postsWithFooBarBazAsTitle')->create();
856+
857+
$this->assertEquals('foo bar baz', FactoryTestPost::first()->title);
858+
}
859+
860+
public function test_factory_model_has_many_relationship_has_pending_attributes_override()
861+
{
862+
FactoryTestUser::factory()->has((new FactoryTestPostFactory())->state(['title' => 'other title']), 'postsWithFooBarBazAsTitle')->create();
863+
864+
$this->assertEquals('other title', FactoryTestPost::first()->title);
865+
}
866+
867+
public function test_factory_model_has_one_relationship_has_pending_attributes()
868+
{
869+
FactoryTestUser::factory()->has(new FactoryTestPostFactory(), 'postWithFooBarBazAsTitle')->create();
870+
871+
$this->assertEquals('foo bar baz', FactoryTestPost::first()->title);
872+
}
873+
874+
public function test_factory_model_has_one_relationship_has_pending_attributes_override()
875+
{
876+
FactoryTestUser::factory()->has((new FactoryTestPostFactory())->state(['title' => 'other title']), 'postWithFooBarBazAsTitle')->create();
877+
878+
$this->assertEquals('other title', FactoryTestPost::first()->title);
879+
}
880+
881+
public function test_factory_model_belongs_to_many_relationship_has_pending_attributes()
882+
{
883+
FactoryTestUser::factory()->has(new FactoryTestRoleFactory(), 'rolesWithFooBarBazAsName')->create();
884+
885+
$this->assertEquals('foo bar baz', FactoryTestRole::first()->name);
886+
}
887+
888+
public function test_factory_model_belongs_to_many_relationship_has_pending_attributes_override()
889+
{
890+
FactoryTestUser::factory()->has((new FactoryTestRoleFactory())->state(['name' => 'other name']), 'rolesWithFooBarBazAsName')->create();
891+
892+
$this->assertEquals('other name', FactoryTestRole::first()->name);
893+
}
894+
895+
public function test_factory_model_morph_many_relationship_has_pending_attributes()
896+
{
897+
(new FactoryTestPostFactory())->has(new FactoryTestCommentFactory(), 'commentsWithFooBarBazAsBody')->create();
898+
899+
$this->assertEquals('foo bar baz', FactoryTestComment::first()->body);
900+
}
901+
902+
public function test_factory_model_morph_many_relationship_has_pending_attributes_override()
903+
{
904+
(new FactoryTestPostFactory())->has((new FactoryTestCommentFactory())->state(['body' => 'other body']), 'commentsWithFooBarBazAsBody')->create();
905+
906+
$this->assertEquals('other body', FactoryTestComment::first()->body);
907+
}
908+
853909
/**
854910
* Get a database connection instance.
855911
*
@@ -895,11 +951,26 @@ public function posts()
895951
return $this->hasMany(FactoryTestPost::class, 'user_id');
896952
}
897953

954+
public function postsWithFooBarBazAsTitle()
955+
{
956+
return $this->hasMany(FactoryTestPost::class, 'user_id')->withAttributes(['title' => 'foo bar baz']);
957+
}
958+
959+
public function postWithFooBarBazAsTitle()
960+
{
961+
return $this->hasOne(FactoryTestPost::class, 'user_id')->withAttributes(['title' => 'foo bar baz']);
962+
}
963+
898964
public function roles()
899965
{
900966
return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin');
901967
}
902968

969+
public function rolesWithFooBarBazAsName()
970+
{
971+
return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin')->withAttributes(['name' => 'foo bar baz']);
972+
}
973+
903974
public function factoryTestRoles()
904975
{
905976
return $this->belongsToMany(FactoryTestRole::class, 'role_user', 'user_id', 'role_id')->withPivot('admin');
@@ -944,6 +1015,11 @@ public function comments()
9441015
{
9451016
return $this->morphMany(FactoryTestComment::class, 'commentable');
9461017
}
1018+
1019+
public function commentsWithFooBarBazAsBody()
1020+
{
1021+
return $this->morphMany(FactoryTestComment::class, 'commentable')->withAttributes(['body' => 'foo bar baz']);
1022+
}
9471023
}
9481024

9491025
class FactoryTestCommentFactory extends Factory

0 commit comments

Comments
 (0)