diff --git a/src/contracts/Repository/ContentService/RelationListFacadeInterface.php b/src/contracts/Repository/ContentService/RelationListFacadeInterface.php new file mode 100644 index 0000000000..dcd7e6ed7f --- /dev/null +++ b/src/contracts/Repository/ContentService/RelationListFacadeInterface.php @@ -0,0 +1,22 @@ + + */ + public function getRelations(VersionInfo $versionInfo): iterable; +} diff --git a/src/contracts/Repository/Iterator/BatchIteratorAdapter/RelationListIteratorAdapter.php b/src/contracts/Repository/Iterator/BatchIteratorAdapter/RelationListIteratorAdapter.php new file mode 100644 index 0000000000..38ee471fda --- /dev/null +++ b/src/contracts/Repository/Iterator/BatchIteratorAdapter/RelationListIteratorAdapter.php @@ -0,0 +1,42 @@ +contentService->loadRelationList( + $this->versionInfo, + $offset, + $limit, + $this->relationType + )->getIterator(); + + if ($iterator instanceof Iterator) { + return $iterator; + } + + return new IteratorIterator($iterator); + } +} diff --git a/src/contracts/Repository/Values/Content/RelationList/RelationListItemInterface.php b/src/contracts/Repository/Values/Content/RelationList/RelationListItemInterface.php index 06499d694d..2900f1d2c6 100644 --- a/src/contracts/Repository/Values/Content/RelationList/RelationListItemInterface.php +++ b/src/contracts/Repository/Values/Content/RelationList/RelationListItemInterface.php @@ -18,7 +18,7 @@ interface RelationListItemInterface public function getRelation(): ?Relation; /** - * @return bool + * @phpstan-assert-if-true !null $this->getRelation() */ public function hasRelation(): bool; } diff --git a/src/lib/Repository/ContentService/RelationListFacade.php b/src/lib/Repository/ContentService/RelationListFacade.php new file mode 100644 index 0000000000..c23a5241d0 --- /dev/null +++ b/src/lib/Repository/ContentService/RelationListFacade.php @@ -0,0 +1,39 @@ +contentService, + $versionInfo + ) + ); + + /** @var \Ibexa\Contracts\Core\Repository\Values\Content\RelationList\RelationListItemInterface $relationListItem */ + foreach ($relationListIterator as $relationListItem) { + if ($relationListItem->hasRelation()) { + yield $relationListItem->getRelation(); + } + } + } +} diff --git a/src/lib/Resources/settings/repository/inner.yml b/src/lib/Resources/settings/repository/inner.yml index d5098b4811..006910c116 100644 --- a/src/lib/Resources/settings/repository/inner.yml +++ b/src/lib/Resources/settings/repository/inner.yml @@ -272,3 +272,9 @@ services: Ibexa\Core\Repository\Validator\TargetContentValidatorInterface: alias: Ibexa\Core\Repository\Validator\TargetContentValidator + + Ibexa\Contracts\Core\Repository\ContentService\RelationListFacadeInterface: '@Ibexa\Core\Repository\ContentService\RelationListFacade' + + Ibexa\Core\Repository\ContentService\RelationListFacade: + arguments: + $contentService: '@ibexa.api.service.content' diff --git a/tests/lib/Repository/ContentService/RelationListFacadeTest.php b/tests/lib/Repository/ContentService/RelationListFacadeTest.php new file mode 100644 index 0000000000..79a6477ee6 --- /dev/null +++ b/tests/lib/Repository/ContentService/RelationListFacadeTest.php @@ -0,0 +1,101 @@ +contentService = $this->createMock(ContentService::class); + $this->versionInfo = $this->createMock(VersionInfo::class); + $this->relationListFacade = new RelationListFacade($this->contentService); + } + + public function testGetRelationsReturnsEmptyIteratorWhenNoRelations(): void + { + $relationList = $this->createMock(RelationList::class); + $relationList->method('getIterator') + ->willReturn(new \ArrayIterator([])); + + $this->contentService + ->expects(self::once()) + ->method('loadRelationList') + ->with($this->versionInfo) + ->willReturn($relationList); + + $result = iterator_to_array($this->relationListFacade->getRelations($this->versionInfo)); + + self::assertEmpty($result); + } + + public function testGetRelationsIgnoresItemsWithoutRelations(): void + { + $relationListItem = $this->createMock(RelationListItemInterface::class); + $relationListItem + ->method('hasRelation') + ->willReturn(false); + + $relationList = $this->createMock(RelationList::class); + $relationList->method('getIterator') + ->willReturn(new \ArrayIterator([$relationListItem])); + + $this->contentService + ->expects(self::once()) + ->method('loadRelationList') + ->with(self::identicalTo($this->versionInfo)) + ->willReturn($relationList); + + $result = iterator_to_array($this->relationListFacade->getRelations($this->versionInfo)); + + self::assertEmpty($result); + } + + public function testGetRelationsYieldsRelationsWhenPresent(): void + { + $relation = $this->createMock(Relation::class); + + $relationListItem = $this->createMock(RelationListItemInterface::class); + $relationListItem + ->method('hasRelation') + ->willReturn(true); + $relationListItem + ->method('getRelation') + ->willReturn($relation); + + $relationList = $this->createMock(RelationList::class); + $relationList->method('getIterator') + ->willReturn(new \ArrayIterator([$relationListItem])); + + $this->contentService + ->expects(self::once()) + ->method('loadRelationList') + ->with($this->versionInfo) + ->willReturn($relationList); + + $result = iterator_to_array($this->relationListFacade->getRelations($this->versionInfo)); + + self::assertCount(1, $result); + self::assertSame($relation, $result[0]); + } +}