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

Relationships fixes #620

Merged
merged 2 commits into from
Apr 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 13 additions & 26 deletions src/Relationships/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,53 @@ abstract class HasMany implements IRelationshipCollection


/**
* @var IEntity
* @phpstan-var E
*/
protected $parent;

/** @var PropertyMetadata */
protected $metadata;

/** @var PropertyRelationshipMetadata */
protected $metadataRelationship;
protected IEntity $parent;

/**
* @var ICollection|null
* @phpstan-var ICollection<E>|null
*/
protected $collection;
protected ?ICollection $collection = null;

/**
* @var IEntity[]
* @phpstan-var array<array-key, E>
*/
protected $toAdd = [];
protected array $toAdd = [];

/**
* @var IEntity[]
* @phpstan-var array<array-key, E>
*/
protected $toRemove = [];
protected array $toRemove = [];

/**
* @var IEntity[]
* @phpstan-var array<array-key, E>
*/
protected $tracked = [];
protected array $tracked = [];

/**
* @var IRepository|null
* @phpstan-var IRepository<E>|null
*/
protected $targetRepository;

/** @var bool */
protected $updatingReverseRelationship = false;

/** @var bool */
protected $isModified = false;
protected ?IRepository $targetRepository = null;

/** @var IRelationshipMapper|null */
protected $relationshipMapper;
protected bool $updatingReverseRelationship = false;
protected bool $isModified = false;
protected bool $exposeCollection;

/** @var bool */
protected $exposeCollection;
protected PropertyMetadata $metadata;
protected PropertyRelationshipMetadata $metadataRelationship;
protected ?IRelationshipMapper $relationshipMapper = null;


public function __construct(PropertyMetadata $metadata)
{
assert($metadata->relationship !== null);
$this->metadata = $metadata;
$this->metadataRelationship = $metadata->relationship;
$this->exposeCollection = $this->metadata->args[HasMany::class]['exposeCollection'] ?? false;
$this->exposeCollection = (bool) ($this->metadata->args[HasMany::class]['exposeCollection'] ?? false);
}


Expand Down
58 changes: 31 additions & 27 deletions src/Relationships/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,52 +25,44 @@ abstract class HasOne implements IRelationshipContainer


/**
* @var IEntity
* @phpstan-var E
* @phpstan-var E|null
*/
protected $parent;

/** @var PropertyMetadata */
protected $metadata;

/** @var PropertyRelationshipMetadata */
protected $metadataRelationship;
protected ?IEntity $parent = null;

/**
* @var ICollection
* @phpstan-var ICollection<E>
* @phpstan-var ICollection<E>|null
*/
protected $collection;
protected ?ICollection $collection = null;

/** @var bool Is value validated against storage? */
protected $isValueValidated = true;
/** Is value validated against storage? */
protected bool $isValueValidated = true;

/** @var bool Is raw value loaded from storage and not converted yet? */
protected $isValueFromStorage = false;
/** Is raw value loaded from storage and not converted yet? */
protected bool $isValueFromStorage = false;

/**
* @var IEntity|string|int|null
* @phpstan-var E|string|int|null
*/
protected $value;
protected $value = null;

/**
* @var IEntity[]
* @phpstan-var list<E>
*/
protected $tracked = [];
protected array $tracked = [];

/**
* @var IRepository|null
* @phpstan-var IRepository<E>|null
*/
protected $targetRepository;
protected ?IRepository $targetRepository = null;

/** @var bool */
protected $updatingReverseRelationship = false;
protected bool $updatingReverseRelationship = false;
protected bool $isModified = false;

/** @var bool */
protected $isModified = false;
protected PropertyMetadata $metadata;
protected PropertyRelationshipMetadata $metadataRelationship;


public function __construct(PropertyMetadata $metadata)
Expand Down Expand Up @@ -196,6 +188,7 @@ public function getEntity(): ?IEntity
$value = $this->getValue();

if ($value === null && !$this->metadata->isNullable) {
assert($this->parent !== null);
throw new NullValueException($this->parent, $this->metadata);
}

Expand All @@ -212,7 +205,7 @@ public function isModified(): bool
/**
* @return mixed|null
*/
protected function getPrimaryValue()
protected function getPrimaryValue(): mixed
{
if ($this->value instanceof IEntity) {
if ($this->value->hasValue('id')) {
Expand All @@ -231,7 +224,7 @@ protected function getPrimaryValue()
*/
protected function getValue(bool $allowPreloadContainer = true): ?IEntity
{
if (!$this->isValueValidated && $this->value !== null) {
if (!$this->isValueValidated && ($this->value !== null || $this->metadata->isNullable)) {
$this->initValue($allowPreloadContainer);
}

Expand Down Expand Up @@ -274,7 +267,9 @@ protected function getTargetRepository(): IRepository
{
if ($this->targetRepository === null) {
/** @var IRepository<E> $targetRepository */
$targetRepository = $this->parent->getRepository()->getModel()
$targetRepository = $this->getParentEntity()
->getRepository()
->getModel()
->getRepository($this->metadataRelationship->repository);
$this->targetRepository = $targetRepository;
}
Expand All @@ -296,6 +291,15 @@ protected function getCollection(): ICollection
}


/**
* @return E
*/
protected function getParentEntity(): IEntity
{
return $this->parent ?? throw new InvalidStateException('Relationship is not attached to a parent entity.');
}


/**
* @param IEntity|string|int|null $entity
* @phpstan-param E|string|int|null $entity
Expand All @@ -309,7 +313,7 @@ protected function createEntity($entity, bool $allowNull): ?IEntity

} elseif ($entity === null) {
if (!$this->metadata->isNullable && !$allowNull) {
throw new NullValueException($this->parent, $this->metadata);
throw new NullValueException($this->getParentEntity(), $this->metadata);
}
return null;

Expand Down
10 changes: 5 additions & 5 deletions src/Relationships/ManyHasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ protected function createCollection(): ICollection
{
/** @var ICollection<E> $collection */
$collection = $this->getTargetRepository()->getMapper()->createCollectionManyHasOne($this->metadata);
return $collection->setRelationshipParent($this->parent);
return $collection->setRelationshipParent($this->getParentEntity());
}


protected function modify(): void
{
$this->isModified = true;
$this->parent->setAsModified($this->metadata->name);
$this->getParentEntity()->setAsModified($this->metadata->name);
}


Expand All @@ -40,13 +40,13 @@ protected function updateRelationship(?IEntity $oldEntity, ?IEntity $newEntity,
if ($oldEntity !== null) {
$property = $oldEntity->getProperty($key);
assert($property instanceof OneHasMany);
$property->remove($this->parent);
$property->remove($this->getParentEntity());
}

if ($newEntity !== null) {
$property = $newEntity->getProperty($key);
assert($property instanceof OneHasMany);
$property->add($this->parent);
$property->add($this->getParentEntity());
}
$this->updatingReverseRelationship = false;
}
Expand All @@ -62,7 +62,7 @@ protected function initReverseRelationship(?IEntity $entity): void
$this->updatingReverseRelationship = true;
$property = $entity->getProperty($key);
assert($property instanceof OneHasMany);
$property->trackEntity($this->parent);
$property->trackEntity($this->getParentEntity());
$this->updatingReverseRelationship = false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Relationships/OneHasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected function createCollection(): ICollection
{
/** @var ICollection<E> $collection */
$collection = $this->getTargetRepository()->getMapper()->createCollectionOneHasOne($this->metadata);
return $collection->setRelationshipParent($this->parent);
return $collection->setRelationshipParent($this->getParentEntity());
}


Expand Down Expand Up @@ -61,7 +61,7 @@ protected function modify(): void
{
$this->isModified = true;
if ($this->metadataRelationship->isMain) {
$this->parent->setAsModified($this->metadata->name);
$this->getParentEntity()->setAsModified($this->metadata->name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
namespace NextrasTests\Orm\Integration\Relationships;


use Nextras\Orm\Relationships\HasMany;
use Nextras\Orm\Relationships\HasOne;
use NextrasTests\Orm\Book;
use NextrasTests\Orm\DataTestCase;
use NextrasTests\Orm\Ean;
use NextrasTests\Orm\Photo;
use NextrasTests\Orm\PhotoAlbum;
use Tester\Assert;


Expand Down Expand Up @@ -45,6 +46,29 @@ class RelationshipOneHasOneTest extends DataTestCase
}


public function testReadOnNullable(): void
{
$album = new PhotoAlbum();
$album->title = 'Test';
$this->orm->photoAlbums->persist($album);

$photo = new Photo();
$photo->title = 'Test';
$photo->album = $album;
$photo->previewFor = $album;
$this->orm->photos->persistAndFlush($photo);

$photoId = $photo->id;
$albumId = $album->id;
$this->orm->clear();

$photo = $this->orm->photos->getByIdChecked($photoId);
$album = $photo->previewFor;
Assert::notNull($album);
Assert::equal($albumId, $album->id);
}


public function testPersistence(): void
{
$this->orm->clear();
Expand Down Expand Up @@ -95,6 +119,7 @@ class RelationshipOneHasOneTest extends DataTestCase
}


/** @noinspection PhpFieldImmediatelyRewrittenInspection */
public function testUpdateRelationship(): void
{
$book1 = new Book();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
START TRANSACTION;
INSERT INTO "photo_albums" ("title", "preview_id") VALUES ('Test', NULL);
SELECT CURRVAL('photo_albums_id_seq');
INSERT INTO "photos" ("title", "album_id") VALUES ('Test', 1);
SELECT CURRVAL('photos_id_seq');
UPDATE "photo_albums" SET "preview_id" = 1 WHERE "id" = 1;
COMMIT;
SELECT "photos".* FROM "photos" AS "photos" WHERE (("photos"."id" = 1));
SELECT "photo_albums".* FROM "photo_albums" AS "photo_albums" WHERE "photo_albums"."preview_id" IN (1);