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

Fix cascade removal when 1:1 on nonMain side is removed as well #657

Merged
merged 1 commit into from
Mar 21, 2024
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
2 changes: 1 addition & 1 deletion src/Entity/IPropertyContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function &getInjectedValue();

/**
* Returns true if property container has a value.
* This method is called when checking value direcly via property access.
* This method is called when checking value by {@see IEntity::hasValue()} call.
* @internal
*/
public function hasInjectedValue(): bool;
Expand Down
38 changes: 14 additions & 24 deletions src/Repository/RemovalHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ private static function setNulls(
$type = $propertyMeta->relationship->type;
$name = $propertyMeta->name;

$value = $entity->hasValue($name) ? $entity->getValue($name) : null;
if ($value === null || ($value instanceof HasMany && $value->count() === 0)) {
continue;
}
if (!$entity->hasValue($name)) continue;

$value = $entity->getValue($name);
if ($value instanceof HasMany && $value->count() === 0) continue;

$reverseRepository = $model->getRepository($propertyMeta->relationship->repository);
$reverseProperty = $propertyMeta->relationship->property !== null
Expand All @@ -163,40 +163,30 @@ private static function setNulls(
}
}
$property->set([]);
} elseif ($type === Relationship::MANY_HAS_ONE || ($type === Relationship::ONE_HAS_ONE && $propertyMeta->relationship->isMain)) {
} elseif ($type === Relationship::MANY_HAS_ONE || $type === Relationship::ONE_HAS_ONE) {
$property = $entity->getProperty($name);
assert($property instanceof HasOne);
if ($reverseProperty !== null) {
$reverseEntity = $property->getEntity();
if ($reverseEntity === null || isset($queueRemove[spl_object_id($reverseEntity)])) {
// reverse side is also being removed, do not set null to this relationship
// The reverse side is also being removed, do not set null to this relationship.
continue;
}
$pre[] = $reverseEntity->getProperty($reverseProperty->name);
$pre[] = $reverseEntity;
}
$property->set(null, true);
} else {
// $type === Relationship::ONE_HAS_MANY or
// $type === Relationship::ONE_HAS_ONE && !$isMain

if (!$entity->hasValue($name) || $reverseProperty === null) {
continue;
}
// $type === Relationship::ONE_HAS_MANY
if ($reverseProperty === null) continue;

if ($reverseProperty->isNullable) {
if ($type === Relationship::ONE_HAS_MANY) {
$property = $entity->getProperty($name);
assert($property instanceof IRelationshipCollection);
foreach ($property as $subValue) {
$pre[] = $subValue;
}
$property->set([]);
} else {
$property = $entity->getProperty($name);
assert($property instanceof HasOne);
$pre[] = $property->getEntity();
$property->set(null, true);
$property = $entity->getProperty($name);
assert($property instanceof IRelationshipCollection);
foreach ($property as $subValue) {
$pre[] = $subValue;
}
$property->set([]);
} else {
$entityClass = get_class($entity);
$reverseEntityClass = $propertyMeta->relationship->entity;
Expand Down
22 changes: 21 additions & 1 deletion tests/cases/integration/Repository/repository.cascadeRemove.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ namespace NextrasTests\Orm\Integration\Repository;


use Nextras\Orm\Exception\InvalidStateException;
use NextrasTests\Orm\Author;
use NextrasTests\Orm\Book;
use NextrasTests\Orm\Comment;
use NextrasTests\Orm\DataTestCase;
use NextrasTests\Orm\Ean;
use NextrasTests\Orm\Publisher;
use Tester\Assert;


Expand Down Expand Up @@ -52,7 +55,7 @@ class RepositoryCascadeRemoveTest extends DataTestCase
}


public function testSti(): void
public function testSingleTableInheritance(): void
{
$comment = $this->orm->contents->getByIdChecked(2);
Assert::type(Comment::class, $comment);
Expand All @@ -64,6 +67,23 @@ class RepositoryCascadeRemoveTest extends DataTestCase
Assert::false($thread->isPersisted());
Assert::false($comment->isPersisted());
}


public function testCascadeWithOneHasOneRelationship(): void
{
$ean = new Ean();
$ean->code = "TEST";
$book = new Book();
$book->title = 'Title';
$book->ean = $ean;
$book->publisher = new Publisher();
$book->publisher->name = "Test Publisher";
$book->author = new Author();
$book->author->name = "Test";
$this->orm->persistAndFlush($book);
$this->orm->removeAndFlush($book);
Assert::false($book->isPersisted());
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
START TRANSACTION;
INSERT INTO "public"."authors" ("name", "born", "web", "favorite_author_id") VALUES ('Test', '2021-03-21 08:23:00.000000'::timestamp, 'http://www.example.com', NULL);
SELECT CURRVAL('"authors_id_seq"');
INSERT INTO "eans" ("code", "type") VALUES ('TEST', 2);
SELECT CURRVAL('"eans_id_seq"');
INSERT INTO "publishers" ("name") VALUES ('Test Publisher');
SELECT CURRVAL('"publishers_publisher_id_seq"');
INSERT INTO "books" ("title", "author_id", "translator_id", "next_part", "ean_id", "publisher_id", "genre", "published_at", "printed_at", "price", "price_currency", "orig_price_cents", "orig_price_currency") VALUES ('Title', 3, NULL, NULL, 1, 4, 'fantasy', '2021-12-31 23:59:59.000000'::timestamp, NULL, NULL, NULL, NULL, NULL);
SELECT CURRVAL('"books_id_seq"');
COMMIT;
SELECT "books_x_tags"."tag_id", "books_x_tags"."book_id" FROM "tags" AS "tags" LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."tag_id" = "tags"."id") WHERE "books_x_tags"."book_id" IN (5);
SELECT "books".* FROM "books" AS "books" WHERE "books"."next_part" IN (5);
START TRANSACTION;
DELETE FROM "books" WHERE "id" = 5;
DELETE FROM "eans" WHERE "id" = 1;
COMMIT;
Loading