Skip to content

Commit

Permalink
fix: can create inversed one to one with non nullable
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil committed Dec 1, 2024
1 parent 8cbee90 commit 86ab481
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 3 deletions.
15 changes: 12 additions & 3 deletions src/Persistence/PersistentObjectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
use Zenstruck\Foundry\Persistence\Exception\NotEnoughObjects;
use Zenstruck\Foundry\Persistence\Exception\RefreshObjectFailed;

use function Zenstruck\Foundry\get;

/**
* @author Kevin Bond <[email protected]>
*
Expand Down Expand Up @@ -271,13 +273,20 @@ protected function normalizeParameter(string $field, mixed $value): mixed

// handle inversed OneToOne
if ($relationshipMetadata && !$relationshipMetadata->isCollection && $inverseField = $relationshipMetadata->inverseField) {
$this->tempAfterPersist[] = static function(object $object) use ($value, $inverseField, $pm) {
$inversedObject = unproxy($value->create());
$this->tempAfterPersist[] = static function(object $object) use ($value, $inverseField, $pm, $inversedObject) {
$value->create([$inverseField => $object]);
$pm->refresh($object);
$oldObj = get($inversedObject, $inverseField);
delete($inversedObject);
if ($oldObj) {
delete($oldObj); // @phpstan-ignore argument.templateType
}
};

// creation delegated to afterPersist hook - return empty array here
return null;
// let's already add the current inversedObject,
// but we'll need to remove all its potential "owning side entity" afterward (see the after persist closure)
return $inversedObject;
}

if (Configuration::instance()->persistence()->relationshipMetadata(static::class(), $value::class(), $field)?->isCascadePersist) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Zenstruck\Foundry\Tests\Fixture\Entity\EdgeCases\InversedOneToOneWithNonNullableOwning;

use Doctrine\ORM\Mapping as ORM;

/**
* @author Nicolas PHILIPPE <[email protected]>
*/
#[ORM\Entity]
class InverseSide
{
#[ORM\Id]
#[ORM\Column]
#[ORM\GeneratedValue(strategy: 'AUTO')]
public ?int $id = null;

public function __construct(
#[ORM\OneToOne(mappedBy: 'inverseSide')]
public OwningSide $owningSide
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Zenstruck\Foundry\Tests\Fixture\Entity\EdgeCases\InversedOneToOneWithNonNullableOwning;

use Doctrine\ORM\Mapping as ORM;

/**
* @author Nicolas PHILIPPE <[email protected]>
*/
#[ORM\Entity]
class OwningSide
{
#[ORM\Id]
#[ORM\Column]
#[ORM\GeneratedValue(strategy: 'AUTO')]
public ?int $id = null;

#[ORM\OneToOne(inversedBy: 'owningSide')]
public InverseSide|null $inverseSide = null;
}
18 changes: 18 additions & 0 deletions tests/Integration/ORM/EdgeCasesRelationshipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Zenstruck\Foundry\Tests\Integration\ORM;

use Zenstruck\Foundry\Tests\Fixture\Entity\EdgeCases\InversedOneToOneWithNonNullableOwning;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Foundry\Persistence\PersistentObjectFactory;
use Zenstruck\Foundry\Persistence\Proxy;
Expand All @@ -25,6 +26,7 @@
use Zenstruck\Foundry\Tests\Fixture\Stories\GlobalStory;
use Zenstruck\Foundry\Tests\Integration\RequiresORM;

use function Zenstruck\Foundry\factory;
use function Zenstruck\Foundry\Persistence\flush_after;
use function Zenstruck\Foundry\Persistence\persistent_factory;
use function Zenstruck\Foundry\Persistence\proxy_factory;
Expand Down Expand Up @@ -106,6 +108,22 @@ public static function richDomainMandatoryRelationshipFactoryProvider(): iterabl
];
}

/**
* @test
*/
public function inverse_one_to_one_with_non_nullable_inverse_side(): void
{
$owningSideFactory = persistent_factory(InversedOneToOneWithNonNullableOwning\OwningSide::class);
$inverseSideFactory = persistent_factory(InversedOneToOneWithNonNullableOwning\InverseSide::class);

$inverseSide = $inverseSideFactory->create(['owningSide' => $owningSideFactory]);

$owningSideFactory::assert()->count(1);
$inverseSideFactory::assert()->count(1);

self::assertSame($inverseSide, $inverseSide->owningSide->inverseSide);
}

/**
* @test
*/
Expand Down

0 comments on commit 86ab481

Please sign in to comment.