diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index d3e1f48fa86f..f3a4c26f2b39 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -91,6 +91,13 @@ abstract class Factory */ protected $expandRelationships = true; + /** + * The relationships that should not be automatically created. + * + * @var array + */ + protected $excludeRelationships = []; + /** * The name of the database connection that will be used to create the models. * @@ -152,6 +159,7 @@ abstract class Factory * @param string|null $connection * @param \Illuminate\Support\Collection|null $recycle * @param bool|null $expandRelationships + * @param array $excludeRelationships */ public function __construct( $count = null, @@ -162,7 +170,8 @@ public function __construct( ?Collection $afterCreating = null, $connection = null, ?Collection $recycle = null, - ?bool $expandRelationships = null + ?bool $expandRelationships = null, + array $excludeRelationships = [], ) { $this->count = $count; $this->states = $states ?? new Collection; @@ -174,6 +183,7 @@ public function __construct( $this->recycle = $recycle ?? new Collection; $this->faker = $this->withFaker(); $this->expandRelationships = $expandRelationships ?? self::$expandRelationshipsByDefault; + $this->excludeRelationships = $excludeRelationships; } /** @@ -505,9 +515,12 @@ protected function parentResolvers() protected function expandAttributes(array $definition) { return (new Collection($definition)) - ->map($evaluateRelations = function ($attribute) { + ->map($evaluateRelations = function ($attribute, $key) { if (! $this->expandRelationships && $attribute instanceof self) { $attribute = null; + } elseif ($attribute instanceof self && + array_intersect([$attribute->modelName(), $key], $this->excludeRelationships)) { + $attribute = null; } elseif ($attribute instanceof self) { $attribute = $this->getRandomRecycledModel($attribute->modelName())?->getKey() ?? $attribute->recycle($this->recycle)->create()->getKey(); @@ -522,7 +535,7 @@ protected function expandAttributes(array $definition) $attribute = $attribute($definition); } - $attribute = $evaluateRelations($attribute); + $attribute = $evaluateRelations($attribute, $key); $definition[$key] = $attribute; @@ -774,11 +787,12 @@ public function count(?int $count) /** * Indicate that related parent models should not be created. * + * @param array> $parents * @return static */ - public function withoutParents() + public function withoutParents($parents = []) { - return $this->newInstance(['expandRelationships' => false]); + return $this->newInstance(! $parents ? ['expandRelationships' => false] : ['excludeRelationships' => $parents]); } /** @@ -820,6 +834,7 @@ protected function newInstance(array $arguments = []) 'connection' => $this->connection, 'recycle' => $this->recycle, 'expandRelationships' => $this->expandRelationships, + 'excludeRelationships' => $this->excludeRelationships, ], $arguments))); } diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index a78c792aa303..ac98ceb2fa41 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -832,6 +832,36 @@ public function test_can_disable_relationships() $this->assertNull($post->user_id); } + public function test_can_disable_relationships_explicitly_by_model_name() + { + $comment = FactoryTestCommentFactory::new() + ->withoutParents([FactoryTestUser::class]) + ->make(); + + $this->assertNull($comment->user_id); + $this->assertNotNull($comment->commentable->id); + } + + public function test_can_disable_relationships_explicitly_by_attribute_name() + { + $comment = FactoryTestCommentFactory::new() + ->withoutParents(['user_id']) + ->make(); + + $this->assertNull($comment->user_id); + $this->assertNotNull($comment->commentable->id); + } + + public function test_can_disable_relationships_explicitly_by_both_attribute_name_and_model_name() + { + $comment = FactoryTestCommentFactory::new() + ->withoutParents(['user_id', FactoryTestPost::class]) + ->make(); + + $this->assertNull($comment->user_id); + $this->assertNull($comment->commentable->id); + } + public function test_can_default_to_without_parents() { FactoryTestPostFactory::dontExpandRelationshipsByDefault();