From 19702edc1665cac0b56b7899048ed6e5ce75364a Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Mon, 15 Jun 2026 20:25:37 +0400 Subject: [PATCH 1/5] Add RefersToMorphed relation attribute Add the #[RefersToMorphed] (and @RefersToMorphed) attribute, the morphed counterpart of RefersTo, mirroring BelongsToMorphed. It compiles to the `refersToMorphed` relation type and allows self-linked / cyclic morphed references that BelongsToMorphed cannot persist in a single transaction. Adds functional tests across all four drivers verifying the relation is generated as Relation::REFERS_TO_MORPHED with the morph and inner key columns. Requires cycle/orm with Relation::REFERS_TO_MORPHED and cycle/schema-builder with the `refersToMorphed` schema generator. --- .../Relation/Morphed/RefersToMorphed.php | 58 ++++++++++++++++ .../Fixtures/RefersToMorphed/Comment.php | 28 ++++++++ .../MorphedParentInterface.php | 7 ++ .../Fixtures/RefersToMorphed/Post.php | 23 +++++++ .../Morphed/RefersToMorphedTestCase.php | 66 +++++++++++++++++++ .../Relation/Morphed/RefersToMorphedTest.php | 16 +++++ .../Relation/Morphed/RefersToMorphedTest.php | 16 +++++ .../Relation/Morphed/RefersToMorphedTest.php | 16 +++++ .../Relation/Morphed/RefersToMorphedTest.php | 16 +++++ 9 files changed, 246 insertions(+) create mode 100644 src/Annotation/Relation/Morphed/RefersToMorphed.php create mode 100644 tests/Annotated/Fixtures/RefersToMorphed/Comment.php create mode 100644 tests/Annotated/Fixtures/RefersToMorphed/MorphedParentInterface.php create mode 100644 tests/Annotated/Fixtures/RefersToMorphed/Post.php create mode 100644 tests/Annotated/Functional/Driver/Common/Relation/Morphed/RefersToMorphedTestCase.php create mode 100644 tests/Annotated/Functional/Driver/MySQL/Relation/Morphed/RefersToMorphedTest.php create mode 100644 tests/Annotated/Functional/Driver/Postgres/Relation/Morphed/RefersToMorphedTest.php create mode 100644 tests/Annotated/Functional/Driver/SQLServer/Relation/Morphed/RefersToMorphedTest.php create mode 100644 tests/Annotated/Functional/Driver/SQLite/Relation/Morphed/RefersToMorphedTest.php diff --git a/src/Annotation/Relation/Morphed/RefersToMorphed.php b/src/Annotation/Relation/Morphed/RefersToMorphed.php new file mode 100644 index 00000000..d9f0728d --- /dev/null +++ b/src/Annotation/Relation/Morphed/RefersToMorphed.php @@ -0,0 +1,58 @@ +inverse = $inverse; + + parent::__construct($target, $load); + } +} diff --git a/tests/Annotated/Fixtures/RefersToMorphed/Comment.php b/tests/Annotated/Fixtures/RefersToMorphed/Comment.php new file mode 100644 index 00000000..80f791a9 --- /dev/null +++ b/tests/Annotated/Fixtures/RefersToMorphed/Comment.php @@ -0,0 +1,28 @@ + [__DIR__ . '/../../../../../Fixtures/RefersToMorphed'], + 'exclude' => [], + ])))->classLocator(); + + $r = new Registry($this->dbal); + + $schema = (new Compiler())->compile($r, [ + new Entities(new TokenizerEntityLocator($locator, $reader), $reader), + new ResetTables(), + new MergeColumns($reader), + new GenerateRelations(), + new RenderTables(), + new RenderRelations(), + new MergeIndexes($reader), + new SyncTables(), + new GenerateTypecast(), + ]); + + $this->assertArrayHasKey('parent', $schema['comment'][Schema::RELATIONS]); + $this->assertSame( + Relation::REFERS_TO_MORPHED, + $schema['comment'][Schema::RELATIONS]['parent'][Relation::TYPE], + ); + $this->assertSame( + MorphedParentInterface::class, + $schema['comment'][Schema::RELATIONS]['parent'][Relation::TARGET], + ); + + // Morphed refers-to stores the outer key and the target role on the source entity. + $this->assertContains('parent_id', $schema['comment'][Schema::COLUMNS]); + $this->assertContains('parent_role', $schema['comment'][Schema::COLUMNS]); + } +} diff --git a/tests/Annotated/Functional/Driver/MySQL/Relation/Morphed/RefersToMorphedTest.php b/tests/Annotated/Functional/Driver/MySQL/Relation/Morphed/RefersToMorphedTest.php new file mode 100644 index 00000000..30442dfe --- /dev/null +++ b/tests/Annotated/Functional/Driver/MySQL/Relation/Morphed/RefersToMorphedTest.php @@ -0,0 +1,16 @@ + Date: Mon, 15 Jun 2026 22:10:48 +0400 Subject: [PATCH 2/5] Register RefersToMorphed attribute and bump cycle deps Add the #[RefersToMorphed] IDE metadata (relations.meta-storm.xml) mirroring BelongsToMorphed, and require cycle/orm ^2.18 and cycle/schema-builder ^2.12 which ship the REFERS_TO_MORPHED relation type the attribute compiles to. --- composer.json | 28 ++++++++++++++-------------- resources/relations.meta-storm.xml | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index b6fb0a72..05fe7393 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,12 @@ "email": "wolfy-j@spiralscout.com" }, { - "name": "Aleksei Gagarin (roxblnfk)", - "email": "alexey.gagarin@spiralscout.com" + "name": "Aleksei Gagarin", + "homepage": "https://github.com/roxblnfk" }, { - "name": "Pavel Butchnev (butschster)", - "email": "pavel.buchnev@spiralscout.com" + "name": "Pavel Butchnev", + "homepage": "https://github.com/butschster" }, { "name": "Maksim Smakouz (msmakouz)", @@ -38,20 +38,20 @@ ], "require": { "php": ">=8.1", - "cycle/database": "^2.16", - "cycle/orm": "^2.15", - "cycle/schema-builder": "^2.11.1", - "spiral/attributes": "^2.8|^3.0", - "spiral/tokenizer": "^2.8|^3.0", - "doctrine/inflector": "^2.0" + "cycle/database": "^2.20", + "cycle/orm": "^2.18", + "cycle/schema-builder": "^2.12", + "spiral/attributes": "^2.8 || ^3.1", + "spiral/tokenizer": "^2.8 || ^3.17", + "doctrine/inflector": "^2.1" }, "require-dev": { "buggregator/trap": "^1.15", - "doctrine/annotations": "^1.14.3 || ^2.0.1", - "phpunit/phpunit": "^10.1", - "spiral/code-style": "^2.2", + "doctrine/annotations": "^1.14 || ^2.0", + "phpunit/phpunit": "^10.5", + "spiral/code-style": "^2.3", "spiral/dumper": "^3.3", - "vimeo/psalm": "^5.26 || ^6.0" + "vimeo/psalm": "^5.26 || ^6.16" }, "autoload": { "psr-4": { diff --git a/resources/relations.meta-storm.xml b/resources/relations.meta-storm.xml index 079f7feb..ab739b73 100644 --- a/resources/relations.meta-storm.xml +++ b/resources/relations.meta-storm.xml @@ -159,6 +159,29 @@ + + + + + + + + + + + + + + + + + + + + + + + From 2d656680392ef314eef9032d83115978e47f54e0 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Mon, 15 Jun 2026 22:13:02 +0400 Subject: [PATCH 3/5] Add RefersToMorphed to psalm baseline Suppress the same DeprecatedClass (NamedArgumentConstructor) and InvalidClassConstantType (TYPE) issues already baselined for the sibling relation annotations. Co-Authored-By: Claude Opus 4.8 (1M context) --- psalm-baseline.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index ecb12747..6359999f 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -112,6 +112,14 @@ + + + + + + + + From b1172f6a39bd6565cd188f0c3e48fbf7396d2782 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 16 Jun 2026 00:23:52 +0400 Subject: [PATCH 4/5] Fix RefersToMorphed meta-storm argument indexes The meta-storm `argument` attribute is the 0-based constructor parameter position (confirmed by the docs and the ManyToMany mapping). The morphed constructor is (target, cascade, nullable, innerKey, outerKey, ...), so the correct indexes are target=0, innerKey=3, outerKey=4 - not the 1/1/2 that were mirrored from the (buggy) sibling morphed entries. Without this, the IDE would offer entity completion for the `cascade`/`nullable` parameters instead of `target`/`innerKey`/`outerKey`. Addresses the Copilot review comment on PR #123. Co-Authored-By: Claude Opus 4.8 (1M context) --- resources/relations.meta-storm.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/relations.meta-storm.xml b/resources/relations.meta-storm.xml index ab739b73..2da8ef37 100644 --- a/resources/relations.meta-storm.xml +++ b/resources/relations.meta-storm.xml @@ -161,12 +161,12 @@ - + - + @@ -174,7 +174,7 @@ - + From a5aa9206290336866cb74585ba1746b77eeb914e Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 16 Jun 2026 00:27:50 +0400 Subject: [PATCH 5/5] Fix meta-storm argument indexes for all morphed relations BelongsToMorphed, MorphedHasOne and MorphedHasMany had the same incorrect meta-storm argument indexes as RefersToMorphed: target/innerKey/outerKey were mapped to 1/1/2 while the morphed constructor is (target, cascade, nullable, innerKey, outerKey, ...), i.e. positions 0/3/4. Align all four morphed relations so the IDE offers entity completion for the target and column completion for the real innerKey/outerKey arguments. --- resources/relations.meta-storm.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/relations.meta-storm.xml b/resources/relations.meta-storm.xml index 2da8ef37..9df3a63d 100644 --- a/resources/relations.meta-storm.xml +++ b/resources/relations.meta-storm.xml @@ -138,12 +138,12 @@ - + - + @@ -151,7 +151,7 @@ - + @@ -184,12 +184,12 @@ - + - + @@ -197,7 +197,7 @@ - + @@ -207,12 +207,12 @@ - + - + @@ -220,7 +220,7 @@ - +