From 6efdc5b352cb72a36236c39f1106afa91afdd0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 24 Oct 2023 13:28:11 +0200 Subject: [PATCH] Cleanup --- .../SuggestionQueryParamConverter.php | 6 ++- src/bundle/Resources/config/services.yaml | 4 ++ .../Event/SuggestionEvent.php} | 4 +- .../Model/Suggestion/Suggestion.php | 22 +++----- .../Provider/ParentLocationProvider.php | 19 +++++++ .../Event/ContentSuggestion.php | 13 ----- .../ContentSuggestionSubscriber.php | 29 +++-------- .../SearchHitToContentSuggestionMapper.php | 20 ++++++-- .../Model/Suggestion/ContentSuggestion.php | 8 +-- src/lib/Model/Suggestion/ParentLocation.php | 40 +++++++++++++++ .../Suggestion/ParentLocationCollection.php | 39 +++++++++++++++ .../Model/Suggestion/SuggestionCollection.php | 3 +- src/lib/Provider/ParentLocationProvider.php | 43 ++++++++++++++++ .../ContentSuggestionNormalizer.php | 38 ++++++++++++++ src/lib/Serializer/SuggestionSerializer.php | 24 +++++++++ src/lib/Service/SuggestionService.php | 6 +-- .../SuggestionQueryParamConverterTest.php | 10 +++- .../Event/SuggestionEventTest.php | 25 ++++++++++ .../ContentSuggestionSubscriberTest.php | 39 ++++++++------- ...SearchHitToContentSuggestionMapperTest.php | 40 ++++++++++++--- .../Suggestion/ContentSuggestionTest.php | 20 ++++---- .../Model/Suggestion/ParentCollectionTest.php | 42 ++++++++++++++++ .../Suggestion/SuggestionCollectionTest.php | 12 ++--- tests/lib/Model/Suggestion/SuggestionTest.php | 40 ++++++++++----- .../Provider/ParentLocationProviderTest.php | 50 +++++++++++++++++++ 25 files changed, 476 insertions(+), 120 deletions(-) rename src/{lib/EventDispatcher/Event/AbstractSuggestion.php => contracts/Event/SuggestionEvent.php} (90%) rename src/{lib => contracts}/Model/Suggestion/Suggestion.php (68%) create mode 100644 src/contracts/Provider/ParentLocationProvider.php delete mode 100644 src/lib/EventDispatcher/Event/ContentSuggestion.php create mode 100644 src/lib/Model/Suggestion/ParentLocation.php create mode 100644 src/lib/Model/Suggestion/ParentLocationCollection.php create mode 100644 src/lib/Provider/ParentLocationProvider.php create mode 100644 src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php create mode 100644 src/lib/Serializer/SuggestionSerializer.php create mode 100644 tests/contracts/EventDispatcher/Event/SuggestionEventTest.php create mode 100644 tests/lib/Model/Suggestion/ParentCollectionTest.php create mode 100644 tests/lib/Provider/ParentLocationProviderTest.php diff --git a/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php b/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php index 1b4d272..1fb3d80 100644 --- a/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php +++ b/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php @@ -22,7 +22,7 @@ public function __construct(int $defaultLimit) $this->defaultLimit = $defaultLimit; } - public function apply(Request $request, ParamConverter $configuration) + public function apply(Request $request, ParamConverter $configuration): bool { $query = $request->get('query'); $limit = $request->query->getInt('limit', $this->defaultLimit); @@ -31,9 +31,11 @@ public function apply(Request $request, ParamConverter $configuration) $suggestionQuery = new SuggestionQuery($query, $limit, $language); $request->attributes->set($configuration->getName(), $suggestionQuery); + + return true; } - public function supports(ParamConverter $configuration) + public function supports(ParamConverter $configuration): bool { return SuggestionQuery::class === $configuration->getClass(); } diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 18072cd..9a7f07b 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -41,3 +41,7 @@ services: $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.min_query_length%' tags: - { name: 'request.param_converter', priority: 0 } + + Ibexa\Search\Provider\ParentLocationProvider: ~ + + Ibexa\Contracts\Search\Provider\ParentLocationProvider: '@Ibexa\Search\Provider\ParentLocationProvider' diff --git a/src/lib/EventDispatcher/Event/AbstractSuggestion.php b/src/contracts/Event/SuggestionEvent.php similarity index 90% rename from src/lib/EventDispatcher/Event/AbstractSuggestion.php rename to src/contracts/Event/SuggestionEvent.php index 2aa33d5..1074770 100644 --- a/src/lib/EventDispatcher/Event/AbstractSuggestion.php +++ b/src/contracts/Event/SuggestionEvent.php @@ -6,12 +6,12 @@ */ declare(strict_types=1); -namespace Ibexa\Search\EventDispatcher\Event; +namespace Ibexa\Contracts\Search\Event; use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; -abstract class AbstractSuggestion +final class SuggestionEvent { private SuggestionCollection $suggestionCollection; diff --git a/src/lib/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php similarity index 68% rename from src/lib/Model/Suggestion/Suggestion.php rename to src/contracts/Model/Suggestion/Suggestion.php index 5ae6d77..f164cbf 100644 --- a/src/lib/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -6,9 +6,10 @@ */ declare(strict_types=1); -namespace Ibexa\Search\Model\Suggestion; +namespace Ibexa\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Core\Repository\Values\ValueObject; +use Ibexa\Search\Model\Suggestion\ParentLocationCollection; abstract class Suggestion extends ValueObject { @@ -18,22 +19,21 @@ abstract class Suggestion extends ValueObject private string $pathString; - /** @var array */ - private array $parentsLocation; + private ParentLocationCollection $parentsLocation; /** - * @param array $parentsLocation + * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations */ public function __construct( float $score, string $name, string $pathString = '', - array $parentsLocation = [] + array $parentLocations = [] ) { $this->score = $score; $this->name = $name; $this->pathString = $pathString; - $this->parentsLocation = $parentsLocation; + $this->parentsLocation = new ParentLocationCollection($parentLocations); parent::__construct(); } @@ -53,18 +53,10 @@ public function getPathString(): string return $this->pathString; } - /** - * @return array - */ - public function getParentsLocation(): array + public function getParentLocations(): ParentLocationCollection { return $this->parentsLocation; } - public function addPath(int $locationId, string $name): void - { - $this->parentsLocation[$locationId] = $name; - } - abstract public function getType(): string; } diff --git a/src/contracts/Provider/ParentLocationProvider.php b/src/contracts/Provider/ParentLocationProvider.php new file mode 100644 index 0000000..130069c --- /dev/null +++ b/src/contracts/Provider/ParentLocationProvider.php @@ -0,0 +1,19 @@ + $parentLocationIds + * + * @return array<\Ibexa\Search\Model\Suggestion\ParentLocation> + */ + public function provide(array $parentLocationIds): array; +} diff --git a/src/lib/EventDispatcher/Event/ContentSuggestion.php b/src/lib/EventDispatcher/Event/ContentSuggestion.php deleted file mode 100644 index c40e9fe..0000000 --- a/src/lib/EventDispatcher/Event/ContentSuggestion.php +++ /dev/null @@ -1,13 +0,0 @@ -searchService = $searchService; $this->contentSuggestionMapper = $contentSuggestionMapper; - $this->locationService = $locationService; } public static function getSubscribedEvents(): array { return [ - ContentSuggestion::class => 'onContentSuggestion', + SuggestionEvent::class => 'onContentSuggestion', ]; } - public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion + public function onContentSuggestion(SuggestionEvent $event): SuggestionEvent { $query = $event->getQuery(); @@ -65,21 +58,13 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion try { $languageFilter = $language ? ['languages' => [$language]] : []; $searchResult = $this->searchService->findContent($query, $languageFilter); - $collection = $event->getSuggestionCollection(); + $suggestionCollection = $event->getSuggestionCollection(); foreach ($searchResult as $result) { - $mappedResult = $this->contentSuggestionMapper->map($result); - if ($mappedResult === null) { + $contentSuggestion = $this->contentSuggestionMapper->map($result); + if ($contentSuggestion === null) { continue; } - - foreach ($mappedResult->getParentsLocation() as $locationId => $name) { - try { - $location = $this->locationService->loadLocation($locationId); - $mappedResult->addPath($locationId, $location->getContent()->getName() ?? ''); - } catch (NotFoundException|UnauthorizedException $e) { - } - } - $collection->append($mappedResult); + $suggestionCollection->append($contentSuggestion); } } catch (InvalidArgumentException $e) { $this->logger ? $this->logger->error($e) : null; diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 97ed337..09f90e2 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -11,6 +11,7 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper as SearchHitToContentSuggestionMapperInterface; +use Ibexa\Contracts\Search\Provider\ParentLocationProvider as ParentLocationProviderInterface; use Ibexa\Core\Repository\Values\Content\Content; use Ibexa\Search\Model\Suggestion\ContentSuggestion; @@ -18,9 +19,14 @@ final class SearchHitToContentSuggestionMapper implements SearchHitToContentSugg { private ConfigResolverInterface $configResolver; - public function __construct(ConfigResolverInterface $configResolver) - { + private ParentLocationProviderInterface $parentLocationProvider; + + public function __construct( + ParentLocationProviderInterface $parentLocationProvider, + ConfigResolverInterface $configResolver + ) { $this->configResolver = $configResolver; + $this->parentLocationProvider = $parentLocationProvider; } public function map(SearchHit $searchHit): ?ContentSuggestion @@ -42,16 +48,20 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $parentsLocation = $mainLocation->path; $position = array_search((string)$rootLocationId, $parentsLocation); if ($position !== false) { - $parentsLocation = array_slice($parentsLocation, (int)$position + 1); + $parentsLocation = array_slice($parentsLocation, (int)$position); } - return new ContentSuggestion( + $parentCollection = $this->parentLocationProvider->provide($parentsLocation); + + $suggestion = new ContentSuggestion( $searchHit->score ?? 50, $content->getContentType()->identifier, $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), implode('/', $parentsLocation), - array_fill_keys($parentsLocation, '') + $parentCollection ); + + return $suggestion; } } diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/lib/Model/Suggestion/ContentSuggestion.php index b70cbbb..dee9eff 100644 --- a/src/lib/Model/Suggestion/ContentSuggestion.php +++ b/src/lib/Model/Suggestion/ContentSuggestion.php @@ -8,6 +8,8 @@ namespace Ibexa\Search\Model\Suggestion; +use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; + final class ContentSuggestion extends Suggestion { private int $contentId; @@ -15,7 +17,7 @@ final class ContentSuggestion extends Suggestion private string $contentTypeIdentifier; /** - * @param array $parentLocation + * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations */ public function __construct( float $score, @@ -23,9 +25,9 @@ public function __construct( string $name, int $contentId, string $pathString = '', - array $parentLocation = [] + array $parentLocations = [] ) { - parent::__construct($score, $name, $pathString, $parentLocation); + parent::__construct($score, $name, $pathString, $parentLocations); $this->contentId = $contentId; $this->contentTypeIdentifier = $contentTypeIdentifier; } diff --git a/src/lib/Model/Suggestion/ParentLocation.php b/src/lib/Model/Suggestion/ParentLocation.php new file mode 100644 index 0000000..b2af609 --- /dev/null +++ b/src/lib/Model/Suggestion/ParentLocation.php @@ -0,0 +1,40 @@ +contentId = $contentId; + $this->locationId = $locationId; + $this->name = $name; + } + + public function getContentId(): int + { + return $this->contentId; + } + + public function getLocationId(): int + { + return $this->locationId; + } + + public function getName(): string + { + return $this->name; + } +} diff --git a/src/lib/Model/Suggestion/ParentLocationCollection.php b/src/lib/Model/Suggestion/ParentLocationCollection.php new file mode 100644 index 0000000..6710147 --- /dev/null +++ b/src/lib/Model/Suggestion/ParentLocationCollection.php @@ -0,0 +1,39 @@ + + */ +final class ParentLocationCollection extends MutableArrayList +{ + /** + * @param mixed $item + */ + public function append($item): void + { + if (!$item instanceof ParentLocation) { + throw new InvalidArgumentException( + '$item', + sprintf( + 'Argument 1 passed to %s::append() must be an instance of %s, %s given', + __CLASS__, + Suggestion::class, + \is_object($item) ? \get_class($item) : \gettype($item) + ) + ); + } + + parent::append($item); + } +} diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index a3ae8aa..13b2e67 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -10,9 +10,10 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; +use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; /** - * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Search\Model\Suggestion\Suggestion> + * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Contracts\Search\Model\Suggestion\Suggestion> */ final class SuggestionCollection extends MutableArrayList { diff --git a/src/lib/Provider/ParentLocationProvider.php b/src/lib/Provider/ParentLocationProvider.php new file mode 100644 index 0000000..aa8188a --- /dev/null +++ b/src/lib/Provider/ParentLocationProvider.php @@ -0,0 +1,43 @@ +locationService = $locationService; + } + + /** + * @param array $parentLocationIds + * + * @return array<\Ibexa\Search\Model\Suggestion\ParentLocation> + */ + public function provide(array $parentLocationIds): array + { + $parentLocations = $this->locationService->loadLocationList($parentLocationIds); + $parentLocationMap = []; + foreach ($parentLocations as $parentLocation) { + $parentLocationMap[] = new ParentLocation( + $parentLocation->getContentInfo()->id, + $parentLocation->id, + $parentLocation->getContentInfo()->name + ); + } + + return $parentLocationMap; + } +} diff --git a/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php new file mode 100644 index 0000000..686ae4e --- /dev/null +++ b/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php @@ -0,0 +1,38 @@ + $object->getName(), + 'type' => $object->getType(), + 'score' => $object->getScore(), + 'pathString' => $object->getPathString(), + 'contentId' => $object->getContentId(), + 'parentsLocation' => $object->getParentLocations(), + 'contentTypeIdentifier' => $object->getContentTypeIdentifier(), + ]; + + return $data; + } + + public function supportsNormalization($data, string $format = null, array $context = []) + { + return $data instanceof ContentSuggestion; + } +} diff --git a/src/lib/Serializer/SuggestionSerializer.php b/src/lib/Serializer/SuggestionSerializer.php new file mode 100644 index 0000000..565bad5 --- /dev/null +++ b/src/lib/Serializer/SuggestionSerializer.php @@ -0,0 +1,24 @@ +eventDispatcher->dispatch( - new ContentSuggestion( + new SuggestionEvent( $query ) ); diff --git a/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php b/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php index 232b990..d47e9ae 100644 --- a/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php +++ b/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php @@ -36,6 +36,9 @@ public function testSupports(string $class, bool $expectedResult): void $this->assertSame($expectedResult, $this->converter->supports($configuration)); } + /** + * @return array + */ public function provideSupportsTestData(): array { return [ @@ -46,6 +49,8 @@ public function provideSupportsTestData(): array /** * @dataProvider provideApplyTestData + * + * @param array{query: string, limit?: int, language?: string|null} $requestData */ public function testApply(array $requestData, SuggestionQuery $expectedSuggestionQuery): void { @@ -53,7 +58,7 @@ public function testApply(array $requestData, SuggestionQuery $expectedSuggestio $configuration->setName('suggestion'); $configuration->setClass(SuggestionQuery::class); - $request = new Request([], [], [], [], [], [], []); + $request = new Request([], [], [], [], [], []); $request->query->add($requestData); $this->converter->apply($request, $configuration); @@ -65,6 +70,9 @@ public function testApply(array $requestData, SuggestionQuery $expectedSuggestio $this->assertEquals($expectedSuggestionQuery, $suggestionQuery); } + /** + * @return array + */ public function provideApplyTestData(): array { return [ diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php new file mode 100644 index 0000000..5d69cb8 --- /dev/null +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -0,0 +1,25 @@ +getSuggestionCollection()); + self::assertInstanceOf(SuggestionQuery::class, $suggestionQuery->getQuery()); + } +} diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php index 14e204d..a966f08 100644 --- a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -8,15 +8,14 @@ namespace Ibexa\Tests\Search\EventDispatcher\EventListener; -use Ibexa\Contracts\Core\Repository\LocationService; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchResult; +use Ibexa\Contracts\Search\Event\SuggestionEvent; use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper; use Ibexa\Core\Repository\SiteAccessAware\SearchService; -use Ibexa\Core\Repository\Values\Content\Location; -use Ibexa\Search\EventDispatcher\Event\ContentSuggestion; use Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber; use Ibexa\Search\Model\Suggestion\ContentSuggestion as ContentSuggestionModel; +use Ibexa\Search\Model\Suggestion\ParentLocation; use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; @@ -25,7 +24,7 @@ final class ContentSuggestionSubscriberTest extends TestCase public function testSubscribedEvents(): void { $this->assertSame( - [ContentSuggestion::class => 'onContentSuggestion'], + [SuggestionEvent::class => 'onContentSuggestion'], ContentSuggestionSubscriber::getSubscribedEvents() ); } @@ -34,12 +33,11 @@ public function testOnContentSuggestion(): void { $query = new SuggestionQuery('test', 10, 'eng-GB'); $searchService = $this->getSearchServiceMock(); - $locationService = $this->getLocationServiceMock(); $mapper = $this->getSearchHitToContentSuggestionMapperMock(); - $subscriber = new ContentSuggestionSubscriber($searchService, $locationService, $mapper); + $subscriber = new ContentSuggestionSubscriber($searchService, $mapper); - $event = new ContentSuggestion($query); + $event = new SuggestionEvent($query); $subscriber->onContentSuggestion($event); $collection = $event->getSuggestionCollection(); @@ -47,6 +45,9 @@ public function testOnContentSuggestion(): void self::assertCount(1, $collection); } + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Core\Repository\SiteAccessAware\SearchService + */ private function getSearchServiceMock(): SearchService { $searchServiceMock = $this->createMock(SearchService::class); @@ -63,21 +64,23 @@ private function getSearchServiceMock(): SearchService return $searchServiceMock; } - private function getLocationServiceMock(): LocationService - { - $locationServiceMock = $this->createMock(LocationService::class); - $locationServiceMock->method('loadLocation')->willReturn( - $this->createMock(Location::class) - ); - - return $locationServiceMock; - } - + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper + */ private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContentSuggestionMapper { $searchHitToContentSuggestionMapperMock = $this->createMock(SearchHitToContentSuggestionMapper::class); $searchHitToContentSuggestionMapperMock->method('map')->willReturn( - new ContentSuggestionModel(10.0, 'test', 'test', 1, 'test', [0 => 'test']) + new ContentSuggestionModel( + 10.0, + 'test', + 'test', + 1, + 'test', + [ + new ParentLocation(1, 2, 'test'), + ] + ) ); return $searchHitToContentSuggestionMapperMock; diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index 46e444d..1e783be 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -11,12 +11,15 @@ use Ibexa\Contracts\Core\Persistence\Content\ContentInfo; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; +use Ibexa\Contracts\Search\Provider\ParentLocationProvider as ParentLocationProviderInterface; use Ibexa\Core\Repository\Values\Content\Content; use Ibexa\Core\Repository\Values\Content\Location; use Ibexa\Core\Repository\Values\Content\VersionInfo; use Ibexa\Core\Repository\Values\ContentType\ContentType; use Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper; use Ibexa\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Search\Model\Suggestion\ParentLocation; +use Ibexa\Search\Model\Suggestion\ParentLocationCollection; use PHPUnit\Framework\TestCase; final class SearchHitToContentSuggestionMapperTest extends TestCase @@ -24,6 +27,7 @@ final class SearchHitToContentSuggestionMapperTest extends TestCase public function testMap(): void { $mapper = new SearchHitToContentSuggestionMapper( + $this->getParentLocationProviderMock(), $this->getConfigResolverMock() ); @@ -56,15 +60,18 @@ public function testMap(): void ]) ); - $this->assertInstanceOf(ContentSuggestion::class, $result); - - $this->assertSame($result->getContentId(), 1); - $this->assertSame($result->getParentsLocation(), [6 => '', 7 => '']); - $this->assertSame($result->getPathString(), '6/7'); - $this->assertSame($result->getName(), 'name_eng'); - $this->assertSame($result->getScore(), 50.0); + self::assertInstanceOf(ContentSuggestion::class, $result); + self::assertSame($result->getContentId(), 1); + self::assertSame($result->getPathString(), '5/6/7'); + self::assertInstanceOf(ParentLocationCollection::class, $result->getParentLocations()); + self::assertCount(3, $result->getParentLocations()); + self::assertSame($result->getName(), 'name_eng'); + self::assertSame($result->getScore(), 50.0); } + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface + */ private function getConfigResolverMock(): ConfigResolverInterface { $configResolverMock = $this->createMock(ConfigResolverInterface::class); @@ -72,4 +79,23 @@ private function getConfigResolverMock(): ConfigResolverInterface return $configResolverMock; } + + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Provider\ParentLocationProvider + */ + private function getParentLocationProviderMock(): ParentLocationProviderInterface + { + $configResolverMock = $this->createMock(ParentLocationProviderInterface::class); + $configResolverMock->method('provide')->willReturnCallback(static function (array $locationIds): array { + $locations = []; + + foreach ($locationIds as $locationId) { + $locations[] = new ParentLocation(10 + $locationId, $locationId, 'parent_' . $locationId); + } + + return $locations; + }); + + return $configResolverMock; + } } diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/lib/Model/Suggestion/ContentSuggestionTest.php index 15db563..263f742 100644 --- a/tests/lib/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/lib/Model/Suggestion/ContentSuggestionTest.php @@ -8,8 +8,10 @@ namespace Ibexa\Tests\Search\Model\Suggestion; +use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; use Ibexa\Search\Model\Suggestion\ContentSuggestion; -use Ibexa\Search\Model\Suggestion\Suggestion; +use Ibexa\Search\Model\Suggestion\ParentLocation; +use Ibexa\Search\Model\Suggestion\ParentLocationCollection; use Ibexa\Tests\Core\Search\TestCase; final class ContentSuggestionTest extends TestCase @@ -22,16 +24,14 @@ public function testCreate(): void 'name', 1, 'text', - [0 => 'text'] + [0 => new ParentLocation(0, 1, 'text')] ); - $this->assertInstanceOf(Suggestion::class, $implementation); - $this->assertSame(1, $implementation->getContentId()); - $this->assertSame('content_type_identifier', $implementation->getContentTypeIdentifier()); - $this->assertSame('content', $implementation->getType()); - $this->assertSame([0 => 'text'], $implementation->getParentsLocation()); - - $implementation->addPath(1, 'text2'); - $this->assertSame([0 => 'text', 1 => 'text2'], $implementation->getParentsLocation()); + self::assertInstanceOf(Suggestion::class, $implementation); + self::assertSame(1, $implementation->getContentId()); + self::assertSame('content_type_identifier', $implementation->getContentTypeIdentifier()); + self::assertSame('content', $implementation->getType()); + self::assertInstanceOf(ParentLocationCollection::class, $implementation->getParentLocations()); + self::assertCount(1, $implementation->getParentLocations()); } } diff --git a/tests/lib/Model/Suggestion/ParentCollectionTest.php b/tests/lib/Model/Suggestion/ParentCollectionTest.php new file mode 100644 index 0000000..5c473fe --- /dev/null +++ b/tests/lib/Model/Suggestion/ParentCollectionTest.php @@ -0,0 +1,42 @@ +append(new ParentLocation(10, 1, 'text_1')); + $collection->append(new ParentLocation(20, 2, 'text_2')); + $collection->append(new ParentLocation(30, 3, 'text_3')); + $collection->append(new ParentLocation(10, 4, 'text_4')); + $collection->append(new ParentLocation(50, 5, 'text_5')); + $collection->append(new ParentLocation(60, 6, 'text_6')); + $collection->append(new ParentLocation(70, 7, 'text_7')); + + self::assertCount(7, $collection); + + foreach ($collection as $item) { + self::assertInstanceOf(ParentLocation::class, $item); + } + + self::expectException(InvalidArgumentException::class); + $collection->append(new \stdClass()); + } +} diff --git a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php index c4e51da..c9ebdf8 100644 --- a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php @@ -18,8 +18,8 @@ final class SuggestionCollectionTest extends TestCase public function testCollection(): void { $collection = new SuggestionCollection(); - $this->assertInstanceOf(MutableArrayList::class, $collection); - $this->assertInstanceOf(SuggestionCollection::class, $collection); + self::assertInstanceOf(MutableArrayList::class, $collection); + self::assertInstanceOf(SuggestionCollection::class, $collection); $collection->append(new ContentSuggestion(10, 'article', 'test', 1)); $collection->append(new ContentSuggestion(20, 'article', 'test2', 1)); @@ -29,16 +29,16 @@ public function testCollection(): void $collection->append(new ContentSuggestion(60, 'article', 'test6', 1)); $collection->append(new ContentSuggestion(70, 'article', 'test7', 1)); - $this->assertCount(7, $collection); + self::assertCount(7, $collection); foreach ($collection as $item) { - $this->assertInstanceOf(ContentSuggestion::class, $item); + self::assertInstanceOf(ContentSuggestion::class, $item); } $collection->sortByScore(); - $this->assertSame(70.0, $collection->first()->getScore()); + self::assertSame(70.0, $collection->first()->getScore()); $collection->truncate(5); - $this->assertCount(5, $collection); + self::assertCount(5, $collection); } } diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php index db8337a..0bfc7ec 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -8,28 +8,44 @@ namespace Ibexa\Tests\Search\Model\Suggestion; -use Ibexa\Search\Model\Suggestion\Suggestion as SuggestionAlias; +use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; +use Ibexa\Search\Model\Suggestion\ParentLocation; use PHPUnit\Framework\TestCase; final class SuggestionTest extends TestCase { public function testSuggestionCreate(): void { - $implementation = new class(50, 'name', 'text', [0 => null]) extends SuggestionAlias { + $implementation = self::createSuggestion( + 0, + 'name', + '2/4/5', + [ + new ParentLocation(10, 1, 'text_1'), + ] + ); + + self::assertInstanceOf(Suggestion::class, $implementation); + self::assertSame('name', $implementation->getName()); + self::assertSame('2/4/5', $implementation->getPathString()); + self::assertSame('test_implementation', $implementation->getType()); + self::assertCount(1, $implementation->getParentLocations()); + } + + /** + * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations + */ + private function createSuggestion( + int $score, + string $name, + string $pathString = '', + array $parentLocations = [] + ): Suggestion { + return new class($score, $name, $pathString, $parentLocations) extends Suggestion { public function getType(): string { return 'test_implementation'; } }; - - $this->assertInstanceOf(SuggestionAlias::class, $implementation); - $this->assertSame('name', $implementation->getName()); - $this->assertSame('text', $implementation->getPathString()); - $this->assertSame([0 => null], $implementation->getParentsLocation()); - $this->assertSame('test_implementation', $implementation->getType()); - - $implementation->addPath(0, 'text'); - $implementation->addPath(1, 'text2'); - $this->assertSame([0 => 'text', 1 => 'text2'], $implementation->getParentsLocation()); } } diff --git a/tests/lib/Provider/ParentLocationProviderTest.php b/tests/lib/Provider/ParentLocationProviderTest.php new file mode 100644 index 0000000..aed9bba --- /dev/null +++ b/tests/lib/Provider/ParentLocationProviderTest.php @@ -0,0 +1,50 @@ +getLocationServiceMock()); + + $parentLocations = $provider->provide([1, 2, 3]); + + self::assertCount(3, $parentLocations); + } + + private function getLocationServiceMock(): LocationService + { + $locationServiceMock = $this->createMock(LocationService::class); + $locationServiceMock->method('loadLocationList')->willReturnCallback(function (array $locationIds): iterable { + foreach ($locationIds as $locationId) { + yield $this->getLocation($locationId); + } + }); + + return $locationServiceMock; + } + + private function getLocation(int $locationId): Location + { + return new Location([ + 'id' => $locationId, + 'contentInfo' => new ContentInfo([ + 'id' => $locationId, + 'name' => 'name_' . $locationId, + ]), + ]); + } +}