Skip to content

Commit

Permalink
fix: bug with one to many (#722)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil authored Nov 22, 2024
1 parent efadea8 commit 6d08784
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 155 deletions.
18 changes: 11 additions & 7 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,6 @@ protected function normalizeParameters(array $parameters): array
*/
protected function normalizeParameter(string $field, mixed $value): mixed
{
if (\is_array($value)) {
return array_combine(
array_keys($value),
\array_map($this->normalizeParameter(...), array_fill(0, count($value), $field), $value)
);
}

if ($value instanceof LazyValue) {
$value = $value();
}
Expand All @@ -217,10 +210,21 @@ protected function normalizeParameter(string $field, mixed $value): mixed
$value = $value->create();
}

if (FactoryCollection::accepts($value)) {
$value = FactoryCollection::fromFactoriesList($value);
}

if ($value instanceof FactoryCollection) {
$value = $this->normalizeCollection($field, $value);
}

if (\is_array($value)) {
return array_combine(
array_keys($value),
\array_map($this->normalizeParameter(...), array_fill(0, count($value), $field), $value)
);
}

return \is_object($value) ? $this->normalizeObject($value) : $value;
}

Expand Down
53 changes: 50 additions & 3 deletions src/FactoryCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,53 @@ final class FactoryCollection implements \IteratorAggregate
{
/**
* @param Factory<T> $factory
* @phpstan-param \Closure():iterable<Attributes> $items
* @phpstan-param \Closure():iterable<Attributes>|\Closure():iterable<Factory<T>> $items
*/
private function __construct(public readonly Factory $factory, private \Closure $items)
{
}

/**
* @phpstan-assert-if-true non-empty-list<Factory<T>> $potentialFactories
*
* @internal
*/
public static function accepts(mixed $potentialFactories): bool
{
if (!is_array($potentialFactories) || count($potentialFactories) === 0 || !array_is_list($potentialFactories)) {
return false;
}

if (!$potentialFactories[0] instanceof ObjectFactory) {
return false;
}

foreach ($potentialFactories as $potentialFactory) {
if (!$potentialFactory instanceof ObjectFactory
|| $potentialFactory::class() !== $potentialFactories[0]::class()) {
return false;
}
}

return true;
}

/**
* @param array<mixed> $factories
*
* @return self<T>
*
* @internal
*/
public static function fromFactoriesList(array $factories): self
{
if (!self::accepts($factories)) {
throw new \InvalidArgumentException('All factories must be of the same type.');
}

return new self($factories[0], static fn() => $factories);
}

/**
* @param Factory<T> $factory
*
Expand Down Expand Up @@ -81,8 +122,14 @@ public function all(): array
$factories = [];

$i = 1;
foreach (($this->items)() as $attributes) {
$factories[] = $this->factory->with($attributes)->with(['__index' => $i++]);
foreach (($this->items)() as $attributesOrFactory) {
if ($attributesOrFactory instanceof Factory) {
$factories[] = $attributesOrFactory;

continue;
}

$factories[] = $this->factory->with($attributesOrFactory)->with(['__index' => $i++]);
}

return $factories;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Zenstruck\Foundry\Persistence\PersistentObjectFactory;
use Zenstruck\Foundry\Tests\Fixture\Entity\Contact\CascadeContact;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Address\CascadeAddressFactory;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Category\CascadeCategoryFactory;

/**
* @author Kevin Bond <kevinbond@gmail.com>
Expand All @@ -31,7 +32,7 @@ protected function defaults(): array|callable
{
return [
'name' => self::faker()->word(),
// 'category' => CascadeCategoryFactory::new(),
'category' => CascadeCategoryFactory::new(),
'address' => CascadeAddressFactory::new(),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
use Zenstruck\Foundry\Tests\Fixture\Entity\Contact\CascadeContact;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Address\ProxyCascadeAddressFactory;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Category\ProxyCascadeCategoryFactory;

/**
* @author Nicolas PHILIPPE <nikophil@gmail.com>
Expand All @@ -31,7 +32,7 @@ protected function defaults(): array|callable
{
return [
'name' => self::faker()->word(),
// 'category' => ProxyCategoryFactory::new(),
'category' => ProxyCascadeCategoryFactory::new(),
'address' => ProxyCascadeAddressFactory::new(),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function defaults(): array|callable
{
return [
'name' => self::faker()->word(),
// 'category' => ProxyCategoryFactory::new(),
'category' => ProxyCategoryFactory::new(),
'address' => ProxyAddressFactory::new(),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Zenstruck\Foundry\Persistence\PersistentObjectFactory;
use Zenstruck\Foundry\Tests\Fixture\Entity\Contact\StandardContact;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Address\StandardAddressFactory;
use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\Category\StandardCategoryFactory;

/**
* @author Kevin Bond <kevinbond@gmail.com>
Expand All @@ -32,6 +33,7 @@ protected function defaults(): array|callable
return [
'name' => self::faker()->word(),
'address' => StandardAddressFactory::new(),
'category' => StandardCategoryFactory::new(),
];
}
}
40 changes: 20 additions & 20 deletions tests/Integration/ORM/CascadeEntityFactoryRelationshipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ final class CascadeEntityFactoryRelationshipTest extends EntityFactoryRelationsh
*/
public function ensure_to_one_cascade_relations_are_not_pre_persisted(): void
{
$contact = $this->contactFactory()
$contact = self::contactFactory()
->afterInstantiate(function() {
$this->categoryFactory()::repository()->assert()->empty();
$this->addressFactory()::repository()->assert()->empty();
$this->tagFactory()::repository()->assert()->empty();
self::categoryFactory()::repository()->assert()->empty();
self::addressFactory()::repository()->assert()->empty();
self::tagFactory()::repository()->assert()->empty();
})
->create([
'tags' => $this->tagFactory()->many(3),
'category' => $this->categoryFactory(),
'tags' => self::tagFactory()->many(3),
'category' => self::categoryFactory(),
])
;

Expand All @@ -53,14 +53,14 @@ public function ensure_to_one_cascade_relations_are_not_pre_persisted(): void
*/
public function ensure_many_to_many_cascade_relations_are_not_pre_persisted(): void
{
$tag = $this->tagFactory()
$tag = self::tagFactory()
->afterInstantiate(function() {
$this->categoryFactory()::repository()->assert()->empty();
$this->addressFactory()::repository()->assert()->empty();
$this->contactFactory()::repository()->assert()->empty();
self::categoryFactory()::repository()->assert()->empty();
self::addressFactory()::repository()->assert()->empty();
self::contactFactory()::repository()->assert()->empty();
})
->create([
'contacts' => $this->contactFactory()->many(3),
'contacts' => self::contactFactory()->many(3),
])
;

Expand All @@ -76,14 +76,14 @@ public function ensure_many_to_many_cascade_relations_are_not_pre_persisted(): v
*/
public function ensure_one_to_many_cascade_relations_are_not_pre_persisted(): void
{
$category = $this->categoryFactory()
$category = self::categoryFactory()
->afterInstantiate(function() {
$this->contactFactory()::repository()->assert()->empty();
$this->addressFactory()::repository()->assert()->empty();
$this->tagFactory()::repository()->assert()->empty();
self::contactFactory()::repository()->assert()->empty();
self::addressFactory()::repository()->assert()->empty();
self::tagFactory()::repository()->assert()->empty();
})
->create([
'contacts' => $this->contactFactory()->many(3),
'contacts' => self::contactFactory()->many(3),
])
;

Expand All @@ -94,22 +94,22 @@ public function ensure_one_to_many_cascade_relations_are_not_pre_persisted(): vo
}
}

protected function contactFactory(): PersistentObjectFactory
protected static function contactFactory(): PersistentObjectFactory
{
return CascadeContactFactory::new(); // @phpstan-ignore return.type
}

protected function categoryFactory(): PersistentObjectFactory
protected static function categoryFactory(): PersistentObjectFactory
{
return CascadeCategoryFactory::new(); // @phpstan-ignore return.type
}

protected function tagFactory(): PersistentObjectFactory
protected static function tagFactory(): PersistentObjectFactory
{
return CascadeTagFactory::new(); // @phpstan-ignore return.type
}

protected function addressFactory(): PersistentObjectFactory
protected static function addressFactory(): PersistentObjectFactory
{
return CascadeAddressFactory::new(); // @phpstan-ignore return.type
}
Expand Down
Loading

0 comments on commit 6d08784

Please sign in to comment.