diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue71/CaseTest.php b/tests/ORM/Functional/Driver/Common/Integration/Issue71/CaseTest.php new file mode 100644 index 00000000..cf41ba6b --- /dev/null +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue71/CaseTest.php @@ -0,0 +1,155 @@ + [ + 'post-1' => ['comment-1', 'comment-2'], + 'post-2' => [], + ], + 'orm' => [ + 'post-2' => [], + 'post-3' => ['comment-3'], + ], + ]; + + // INNER JOIN on comments drops posts without comments + yield 'JOIN' => [JoinableLoader::JOIN, [ + 'php' => ['post-1' => ['comment-1', 'comment-2']], + 'orm' => ['post-3' => ['comment-3']], + ]]; + yield 'LEFT_JOIN' => [JoinableLoader::LEFT_JOIN, $all]; + yield 'POSTLOAD' => [JoinableLoader::POSTLOAD, $all]; + } + + /** + * @dataProvider loadMethodProvider + */ + public function testFetchData(int $method, array $expected): void + { + $data = $this->select($method)->fetchData(); + + $result = []; + foreach ($data as $tag) { + foreach ($tag['posts'] as $pivot) { + $post = $pivot['@']; + $result[$tag['name']][$post['title']] = \array_column($post['comments'], 'message'); + } + } + + $this->assertSame($expected, $this->normalize($result)); + } + + /** + * @dataProvider loadMethodProvider + */ + public function testFetchAll(int $method, array $expected): void + { + $tags = $this->select($method)->fetchAll(); + + $result = []; + foreach ($tags as $tag) { + foreach ($tag->posts as $post) { + $result[$tag->name][$post->title] = \array_map( + static fn(Entity\Comment $comment): string => $comment->message, + $post->comments, + ); + } + } + + $this->assertSame($expected, $this->normalize($result)); + } + + public function setUp(): void + { + // Init DB + parent::setUp(); + $this->makeTables(); + $this->fillData(); + + $this->loadSchema(__DIR__ . '/schema.php'); + } + + private function select(int $method): Select + { + return (new Select($this->orm, Tag::class)) + ->load('posts', ['method' => $method]) + ->load('posts.comments', ['method' => $method]) + ->orderBy('id', 'DESC'); + } + + /** + * Posts of a tag come in no guaranteed order. + */ + private function normalize(array $result): array + { + foreach ($result as &$posts) { + \ksort($posts); + } + + return $result; + } + + private function makeTables(): void + { + $this->makeTable('tag', [ + 'id' => 'primary', + 'name' => 'string', + ]); + + $this->makeTable('post', [ + 'id' => 'primary', + 'title' => 'string', + ]); + + $this->makeTable('post_tag', [ + 'id' => 'primary', + 'post_id' => 'int', + 'tag_id' => 'int', + ]); + $this->makeFK('post_tag', 'post_id', 'post', 'id', 'NO ACTION', 'NO ACTION'); + $this->makeFK('post_tag', 'tag_id', 'tag', 'id', 'NO ACTION', 'NO ACTION'); + + $this->makeTable('comment', [ + 'id' => 'primary', + 'post_id' => 'int,nullable', + 'message' => 'string', + ]); + $this->makeFK('comment', 'post_id', 'post', 'id', 'NO ACTION', 'NO ACTION'); + } + + private function fillData(): void + { + $this->getDatabase()->table('tag')->insertMultiple(['name'], [['orm'], ['php']]); + $this->getDatabase()->table('post')->insertMultiple(['title'], [['post-1'], ['post-2'], ['post-3']]); + $this->getDatabase()->table('post_tag')->insertMultiple( + ['post_id', 'tag_id'], + [[1, 2], [2, 2], [2, 1], [3, 1]], + ); + $this->getDatabase()->table('comment')->insertMultiple( + ['post_id', 'message'], + [[1, 'comment-1'], [3, 'comment-3'], [1, 'comment-2']], + ); + } +} diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/Comment.php b/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/Comment.php new file mode 100644 index 00000000..af01e6ff --- /dev/null +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/Comment.php @@ -0,0 +1,12 @@ + */ + public iterable $tags = []; + + /** @var iterable */ + public iterable $comments = []; +} diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/PostTag.php b/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/PostTag.php new file mode 100644 index 00000000..deb103d7 --- /dev/null +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue71/Entity/PostTag.php @@ -0,0 +1,10 @@ + */ + public iterable $posts = []; +} diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue71/schema.php b/tests/ORM/Functional/Driver/Common/Integration/Issue71/schema.php new file mode 100644 index 00000000..a25fbbc9 --- /dev/null +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue71/schema.php @@ -0,0 +1,152 @@ + [ + Schema::ENTITY => Tag::class, + Schema::MAPPER => Mapper::class, + Schema::SOURCE => Source::class, + Schema::REPOSITORY => Repository::class, + Schema::DATABASE => 'default', + Schema::TABLE => 'tag', + Schema::PRIMARY_KEY => ['id'], + Schema::FIND_BY_KEYS => ['id'], + Schema::COLUMNS => [ + 'id' => 'id', + 'name' => 'name', + ], + Schema::RELATIONS => [ + 'posts' => [ + Relation::TYPE => Relation::MANY_TO_MANY, + Relation::TARGET => 'post', + Relation::COLLECTION_TYPE => 'array', + Relation::LOAD => Relation::LOAD_PROMISE, + Relation::SCHEMA => [ + Relation::CASCADE => true, + Relation::NULLABLE => false, + Relation::WHERE => [], + Relation::ORDER_BY => [], + Relation::INNER_KEY => ['id'], + Relation::OUTER_KEY => ['id'], + Relation::THROUGH_ENTITY => 'post_tag', + Relation::THROUGH_INNER_KEY => ['tag_id'], + Relation::THROUGH_OUTER_KEY => ['post_id'], + Relation::THROUGH_WHERE => [], + ], + ], + ], + Schema::TYPECAST => [ + 'id' => 'int', + 'name' => 'string', + ], + Schema::SCHEMA => [], + ], + 'post' => [ + Schema::ENTITY => Post::class, + Schema::MAPPER => Mapper::class, + Schema::SOURCE => Source::class, + Schema::REPOSITORY => Repository::class, + Schema::DATABASE => 'default', + Schema::TABLE => 'post', + Schema::PRIMARY_KEY => ['id'], + Schema::FIND_BY_KEYS => ['id'], + Schema::COLUMNS => [ + 'id' => 'id', + 'title' => 'title', + ], + Schema::RELATIONS => [ + 'tags' => [ + Relation::TYPE => Relation::MANY_TO_MANY, + Relation::TARGET => 'tag', + Relation::COLLECTION_TYPE => 'array', + Relation::LOAD => Relation::LOAD_PROMISE, + Relation::SCHEMA => [ + Relation::CASCADE => true, + Relation::NULLABLE => false, + Relation::WHERE => [], + Relation::ORDER_BY => [], + Relation::INNER_KEY => ['id'], + Relation::OUTER_KEY => ['id'], + Relation::THROUGH_ENTITY => 'post_tag', + Relation::THROUGH_INNER_KEY => ['post_id'], + Relation::THROUGH_OUTER_KEY => ['tag_id'], + Relation::THROUGH_WHERE => [], + ], + ], + 'comments' => [ + Relation::TYPE => Relation::HAS_MANY, + Relation::TARGET => 'comment', + Relation::COLLECTION_TYPE => 'array', + Relation::LOAD => Relation::LOAD_PROMISE, + Relation::SCHEMA => [ + Relation::CASCADE => true, + Relation::NULLABLE => true, + Relation::WHERE => [], + Relation::ORDER_BY => ['id' => 'ASC'], + Relation::INNER_KEY => ['id'], + Relation::OUTER_KEY => ['post_id'], + ], + ], + ], + Schema::TYPECAST => [ + 'id' => 'int', + 'title' => 'string', + ], + Schema::SCHEMA => [], + ], + 'post_tag' => [ + Schema::ENTITY => PostTag::class, + Schema::MAPPER => Mapper::class, + Schema::SOURCE => Source::class, + Schema::REPOSITORY => Repository::class, + Schema::DATABASE => 'default', + Schema::TABLE => 'post_tag', + Schema::PRIMARY_KEY => ['id'], + Schema::FIND_BY_KEYS => ['id'], + Schema::COLUMNS => [ + 'id' => 'id', + 'post_id' => 'post_id', + 'tag_id' => 'tag_id', + ], + Schema::RELATIONS => [], + Schema::TYPECAST => [ + 'id' => 'int', + 'post_id' => 'int', + 'tag_id' => 'int', + ], + Schema::SCHEMA => [], + ], + 'comment' => [ + Schema::ENTITY => Comment::class, + Schema::MAPPER => Mapper::class, + Schema::SOURCE => Source::class, + Schema::REPOSITORY => Repository::class, + Schema::DATABASE => 'default', + Schema::TABLE => 'comment', + Schema::PRIMARY_KEY => ['id'], + Schema::FIND_BY_KEYS => ['id'], + Schema::COLUMNS => [ + 'id' => 'id', + 'post_id' => 'post_id', + 'message' => 'message', + ], + Schema::RELATIONS => [], + Schema::TYPECAST => [ + 'id' => 'int', + 'post_id' => 'int', + 'message' => 'string', + ], + Schema::SCHEMA => [], + ], +]; diff --git a/tests/ORM/Functional/Driver/MySQL/Integration/Issue71/CaseTest.php b/tests/ORM/Functional/Driver/MySQL/Integration/Issue71/CaseTest.php new file mode 100644 index 00000000..f6a24adf --- /dev/null +++ b/tests/ORM/Functional/Driver/MySQL/Integration/Issue71/CaseTest.php @@ -0,0 +1,17 @@ +