From fb6b64275ba81968bee36dc7182a0feedf0cebf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Mon, 18 Sep 2023 15:06:28 +0200 Subject: [PATCH 01/66] Added autocomplete configuration --- .../Parser/SiteAccessAware/Autocomplete.php | 102 ++++++++++++++++++ src/bundle/IbexaSearchBundle.php | 2 + 2 files changed, 104 insertions(+) create mode 100644 src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php new file mode 100644 index 0000000..a61a7ca --- /dev/null +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php @@ -0,0 +1,102 @@ + $scopeSettings + */ + public function mapConfig( + array &$scopeSettings, + $currentScope, + ContextualizerInterface $contextualizer + ): void { + if (empty($scopeSettings['search'])) { + return; + } + + $settings = $scopeSettings['search']; + + $this->addAutocompleteParameters($settings, $currentScope, $contextualizer); + } + + public function addSemanticConfig(NodeBuilder $nodeBuilder): void + { + $rootProductCatalogNode = $nodeBuilder->arrayNode('search'); + $rootProductCatalogNode->append($this->addAutocompleteConfiguration()); + } + + /** + * @param array $settings + */ + private function addAutocompleteParameters( + $settings, + string $currentScope, + ContextualizerInterface $contextualizer + ): void { + if (isset($settings['autocomplete']['min_search_test_length'])) { + $contextualizer->setContextualParameter( + 'autocomplete.min_search_test_length', + $currentScope, + $settings['autocomplete']['min_search_test_length'], + ); + } + if (isset($settings['catalogs']['result_limit'])) { + $contextualizer->setContextualParameter( + 'autocomplete.result_limit', + $currentScope, + $settings['catalogs']['result_limit'], + ); + } + } + + private function addAutocompleteConfiguration(): ArrayNodeDefinition + { + $treeBuilder = new TreeBuilder('autocomplete'); + $node = $treeBuilder->getRootNode(); + + $node + ->children() + ->integerNode('min_search_test_length') + ->isRequired() + ->defaultValue(3) + ->min(3) + ->end() + ->integerNode('result_limit') + ->isRequired() + ->defaultValue(5) + ->min(5) + ->end() + ->end(); + + return $node; + } +} diff --git a/src/bundle/IbexaSearchBundle.php b/src/bundle/IbexaSearchBundle.php index 45ea758..8d80ba9 100644 --- a/src/bundle/IbexaSearchBundle.php +++ b/src/bundle/IbexaSearchBundle.php @@ -8,6 +8,7 @@ use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\Search; use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SearchView; +use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\Autocomplete; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -21,6 +22,7 @@ public function build(ContainerBuilder $container) $core->addDefaultSettings(__DIR__ . '/Resources/config', ['default_settings.yaml']); $core->addConfigParser(new Search()); $core->addConfigParser(new SearchView()); + $core->addConfigParser(new Autocomplete()); } } From 4e67ad56676d8cde4ef00abad203d8b15db82f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 19 Sep 2023 09:57:06 +0200 Subject: [PATCH 02/66] Added tests --- composer.json | 3 +- ...utocomplete.php => AutocompleteParser.php} | 27 +++-- src/bundle/IbexaSearchBundle.php | 4 +- .../AutocompleteParserTest.php | 102 ++++++++++++++++++ 4 files changed, 119 insertions(+), 17 deletions(-) rename src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/{Autocomplete.php => AutocompleteParser.php} (80%) create mode 100644 tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php diff --git a/composer.json b/composer.json index 39ff8a1..3ecc74f 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "ibexa/doctrine-schema": "~4.6.x-dev", "phpstan/phpstan": "^1.10", "phpstan/phpstan-phpunit": "^1.3", - "phpstan/phpstan-symfony": "^1.3" + "phpstan/phpstan-symfony": "^1.3", + "matthiasnoback/symfony-dependency-injection-test": "^4.3" }, "scripts": { "fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php --show-progress=dots", diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php similarity index 80% rename from src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php rename to src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php index a61a7ca..8914172 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/Autocomplete.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php @@ -29,7 +29,7 @@ * result_limit: 5 * ``` */ -class Autocomplete extends AbstractParser +final class AutocompleteParser extends AbstractParser { /** * @param array $scopeSettings @@ -62,19 +62,18 @@ private function addAutocompleteParameters( string $currentScope, ContextualizerInterface $contextualizer ): void { - if (isset($settings['autocomplete']['min_search_test_length'])) { - $contextualizer->setContextualParameter( - 'autocomplete.min_search_test_length', - $currentScope, - $settings['autocomplete']['min_search_test_length'], - ); - } - if (isset($settings['catalogs']['result_limit'])) { - $contextualizer->setContextualParameter( - 'autocomplete.result_limit', - $currentScope, - $settings['catalogs']['result_limit'], - ); + $names = [ + 'min_search_test_length', + 'result_limit', + ]; + foreach ($names as $name) { + if (isset($settings['autocomplete'][$name])) { + $contextualizer->setContextualParameter( + 'search.autocomplete.' . $name, + $currentScope, + $settings['autocomplete'][$name] + ); + } } } diff --git a/src/bundle/IbexaSearchBundle.php b/src/bundle/IbexaSearchBundle.php index 8d80ba9..79cbe79 100644 --- a/src/bundle/IbexaSearchBundle.php +++ b/src/bundle/IbexaSearchBundle.php @@ -8,7 +8,7 @@ use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\Search; use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SearchView; -use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\Autocomplete; +use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\AutocompleteParser; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -22,7 +22,7 @@ public function build(ContainerBuilder $container) $core->addDefaultSettings(__DIR__ . '/Resources/config', ['default_settings.yaml']); $core->addConfigParser(new Search()); $core->addConfigParser(new SearchView()); - $core->addConfigParser(new Autocomplete()); + $core->addConfigParser(new AutocompleteParser()); } } diff --git a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php new file mode 100644 index 0000000..28f0d14 --- /dev/null +++ b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php @@ -0,0 +1,102 @@ + $config + * @param array $expected + * @param array $expectedNotSet + */ + public function testSettings(array $config, array $expected, array $expectedNotSet = []): void + { + $this->load([ + 'system' => [ + 'ibexa_demo_site' => $config, + ], + ]); + + foreach ($expected as $key => $val) { + $this->assertConfigResolverParameterValue($key, $val, 'ibexa_demo_site'); + } + + foreach ($expectedNotSet as $key) { + $this->assertConfigResolverParameterIsNotSet($key, 'ibexa_demo_site'); + } + } + + /** + * @phpstan-return iterable< + * string, + * array{ + * array, + * array, + * 2?: array, + * }, + * > + */ + public function dataProviderForTestSettings(): iterable + { + yield 'empty configuration' => [ + [], + [], + [ + 'search.autocomplete.min_search_test_length', + 'search.autocomplete.result_limit', + ], + ]; + + yield 'autocomplete' => [ + [ + 'search' => [ + 'autocomplete' => [ + 'min_search_test_length' => 10, + 'result_limit' => 10, + ], + ], + ], + [ + 'search.autocomplete.min_search_test_length' => 10, + 'search.autocomplete.result_limit' => 10, + ], + ]; + } + + private function assertConfigResolverParameterIsNotSet(string $parameterName, ?string $scope = null): void + { + $chainConfigResolver = $this->getConfigResolver(); + try { + $chainConfigResolver->getParameter($parameterName, 'ibexa.site_access.config', $scope); + self::fail(sprintf('Parameter "%s" should not exist in scope "%s"', $parameterName, $scope)); + } catch (Exception $e) { + self::assertInstanceOf(ParameterNotFoundException::class, $e); + } + } +} From 2c7a5e388e772f911d84d225b34bb3a7085c5a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Mon, 9 Oct 2023 17:31:47 +0200 Subject: [PATCH 03/66] Search Autocomplete Endpoint --- composer.json | 3 +- .../SearchAutoCompleteController.php | 41 +++++++++++++ src/bundle/Resources/config/routing.yaml | 6 ++ src/bundle/Resources/config/services.yaml | 54 +++++++++------- .../Event/PostAutoCompleteSearch.php | 25 ++++++++ .../Event/PreAutoCompleteSearch.php | 25 ++++++++ ...archResultToSuggestionCollectionMapper.php | 35 +++++++++++ src/lib/Model/Suggestion.php | 61 +++++++++++++++++++ src/lib/Model/SuggestionCollection.php | 14 +++++ src/lib/Service/SearchAutoCompleteService.php | 52 ++++++++++++++++ 10 files changed, 293 insertions(+), 23 deletions(-) create mode 100644 src/bundle/Controller/SearchAutoCompleteController.php create mode 100644 src/lib/EventDispatcher/Event/PostAutoCompleteSearch.php create mode 100644 src/lib/EventDispatcher/Event/PreAutoCompleteSearch.php create mode 100644 src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php create mode 100644 src/lib/Model/Suggestion.php create mode 100644 src/lib/Model/SuggestionCollection.php create mode 100644 src/lib/Service/SearchAutoCompleteService.php diff --git a/composer.json b/composer.json index 3ecc74f..aed7538 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "symfony/config": "^5.0", "symfony/form": "^5.0", "symfony/event-dispatcher": "^5.0", - "pagerfanta/pagerfanta": "^2.1" + "pagerfanta/pagerfanta": "^2.1", + "symfony/serializer": "^5.4" }, "require-dev": { "phpunit/phpunit": "^8.5", diff --git a/src/bundle/Controller/SearchAutoCompleteController.php b/src/bundle/Controller/SearchAutoCompleteController.php new file mode 100644 index 0000000..ce9edce --- /dev/null +++ b/src/bundle/Controller/SearchAutoCompleteController.php @@ -0,0 +1,41 @@ +autoCompleteService = $autocompleteService; + $this->serializer = $serializer; + } + + public function suggestAction(Request $request): Response + { + $search = $request->get('search'); + $language = $request->get('language'); + $limit = (int) $request->get('limit'); + + $result = $this->autoCompleteService->suggest($search, $limit, $language); + + $serializedResults = $this->serializer->serialize($result, 'json'); + + return new Response($serializedResults, 200); + } +} diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index 28e9439..d16f4f3 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -3,3 +3,9 @@ ibexa.search: methods: ['GET'] defaults: _controller: 'Ibexa\Bundle\Search\Controller\SearchController::searchAction' + +ibexa.search_autocomplete: + path: /autocomplete + methods: ['GET'] + defaults: + _controller: 'Ibexa\Bundle\Search\Controller\SearchAutoCompleteController::suggestAction' diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 86e94a3..9ea6508 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -1,25 +1,35 @@ imports: - - { resource: forms.yaml } - - { resource: twig.yaml } - - { resource: sorting_definitions.yaml } - - { resource: views.yaml } + - { resource: forms.yaml } + - { resource: twig.yaml } + - { resource: sorting_definitions.yaml } + - { resource: views.yaml } services: - _defaults: - autoconfigure: true - autowire: true - public: false - - Ibexa\Bundle\Search\Controller\SearchController: - tags: - - controller.service_arguments - - Ibexa\Search\Mapper\PagerSearchContentToDataMapper: - arguments: - $contentTypeService: '@ibexa.api.service.content_type' - $userService: '@ibexa.api.service.user' - $userLanguagePreferenceProvider: '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider' - $translationHelper: '@Ibexa\Core\Helper\TranslationHelper' - $languageService: '@ibexa.api.service.language' - - Ibexa\Search\QueryType\SearchQueryType: ~ + _defaults: + autoconfigure: true + autowire: true + public: false + + Ibexa\Bundle\Search\Controller\SearchController: + tags: + - controller.service_arguments + + Ibexa\Bundle\Search\Controller\SearchAutoCompleteController: + tags: + - controller.service_arguments + + Ibexa\Search\Mapper\PagerSearchContentToDataMapper: + arguments: + $contentTypeService: '@ibexa.api.service.content_type' + $userService: '@ibexa.api.service.user' + $userLanguagePreferenceProvider: '@Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider' + $translationHelper: '@Ibexa\Core\Helper\TranslationHelper' + $languageService: '@ibexa.api.service.language' + + Ibexa\Search\QueryType\SearchQueryType: ~ + + Ibexa\Search\Service\SearchAutoCompleteService: ~ + + Ibexa\Search\Mapper\SearchResultToSuggestionCollectionMapper: ~ + + Ibexa\Search\EventDispatcher\EventListener\BreadCrumbSubscriber: ~ diff --git a/src/lib/EventDispatcher/Event/PostAutoCompleteSearch.php b/src/lib/EventDispatcher/Event/PostAutoCompleteSearch.php new file mode 100644 index 0000000..1d07007 --- /dev/null +++ b/src/lib/EventDispatcher/Event/PostAutoCompleteSearch.php @@ -0,0 +1,25 @@ +suggestionCollection = $suggestionCollection; + } + + public function getSuggestionCollection(): SuggestionCollection + { + return $this->suggestionCollection; + } +} diff --git a/src/lib/EventDispatcher/Event/PreAutoCompleteSearch.php b/src/lib/EventDispatcher/Event/PreAutoCompleteSearch.php new file mode 100644 index 0000000..56966b1 --- /dev/null +++ b/src/lib/EventDispatcher/Event/PreAutoCompleteSearch.php @@ -0,0 +1,25 @@ +query = $query; + } + + public function getQuery(): Query + { + return $this->query; + } +} diff --git a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php new file mode 100644 index 0000000..c095fd0 --- /dev/null +++ b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php @@ -0,0 +1,35 @@ +valueObject; + + $collection[] = new Suggestion( + $result->valueObject->contentInfo->id, + $content->getFieldValue('title', $language)->text, + $result->valueObject->contentInfo->getContentType()->identifier, + $result->valueObject->contentInfo->mainLocation->pathString, + $result->valueObject->contentInfo->mainLocation->path + ); + } + + return new SuggestionCollection($collection); + } +} diff --git a/src/lib/Model/Suggestion.php b/src/lib/Model/Suggestion.php new file mode 100644 index 0000000..4d4f9b5 --- /dev/null +++ b/src/lib/Model/Suggestion.php @@ -0,0 +1,61 @@ +contentId = $contentId; + $this->contentName = $contentName; + $this->contentTypeIdentifier = $contentTypeIdentifier; + $this->pathString = $pathString; + $this->parentsLocation = $parentsLocation; + + parent::__construct($properties); + } + + public function getContentId(): int + { + return $this->contentId; + } + + public function getContentName(): string + { + return $this->contentName; + } + + public function getContentTypeIdentifier(): string + { + return $this->contentTypeIdentifier; + } + + public function getPathString(): string + { + return $this->pathString; + } + + public function getParentsLocation(): array + { + return $this->parentsLocation; + } +} diff --git a/src/lib/Model/SuggestionCollection.php b/src/lib/Model/SuggestionCollection.php new file mode 100644 index 0000000..08f208e --- /dev/null +++ b/src/lib/Model/SuggestionCollection.php @@ -0,0 +1,14 @@ +searchService = $searchService; + $this->eventDispatcher = $eventDispatcher; + $this->suggestionCollectionMapper = $suggestionCollectionMapper; + } + + /** + * @return array + */ + public function suggest(string $value, int $limit, ?string $language = null): SuggestionCollection + { + $criterion = new Query\Criterion\FullText($value); + $query = new Query(['filter' => $criterion, 'limit' => $limit]); + /** @var PreAutoCompleteSearch $preEvent */ + $preEvent = $this->eventDispatcher->dispatch(new PreAutoCompleteSearch($query)); + $searchResult = $this->searchService->findContent($preEvent->getQuery()); + + $mappedResult = $this->suggestionCollectionMapper->transform($searchResult, $language); + + /** @var PostAutoCompleteSearch $postEvent */ + $postEvent = $this->eventDispatcher->dispatch(new PostAutoCompleteSearch($mappedResult)); + + return $postEvent->getSuggestionCollection(); + } +} From 885f626199ad94fb16707e3ccd34b2731c760c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 11 Oct 2023 08:50:42 +0200 Subject: [PATCH 04/66] Breadcrumps subscriber --- .../EventListener/BreadCrumbSubscriber.php | 43 +++++++++++++++++++ ...archResultToSuggestionCollectionMapper.php | 2 +- src/lib/Model/Suggestion.php | 5 +++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php diff --git a/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php b/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php new file mode 100644 index 0000000..34e33a2 --- /dev/null +++ b/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php @@ -0,0 +1,43 @@ +locationService = $locationService; + } + + public static function getSubscribedEvents(): array + { + return [ + PostAutoCompleteSearch::class => 'onPostAutoCompleteSearch', + ]; + } + + public function onPostAutoCompleteSearch(PostAutoCompleteSearch $event): PostAutoCompleteSearch + { + /** @var Suggestion $suggestion */ + foreach ($event->getSuggestionCollection() as $suggestion){ + foreach ($suggestion->getParentsLocation() as $locationId => $name){ + $location = $this->locationService->loadLocation($locationId); + $suggestion->addPath($locationId, $location->contentInfo->name); + } + + } + + return $event; + } +} diff --git a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php index c095fd0..3d57fa2 100644 --- a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php +++ b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php @@ -26,7 +26,7 @@ public function transform(SearchResult $searchResult, ?string $language = null): $content->getFieldValue('title', $language)->text, $result->valueObject->contentInfo->getContentType()->identifier, $result->valueObject->contentInfo->mainLocation->pathString, - $result->valueObject->contentInfo->mainLocation->path + array_flip($result->valueObject->contentInfo->mainLocation->path) ); } diff --git a/src/lib/Model/Suggestion.php b/src/lib/Model/Suggestion.php index 4d4f9b5..6d6ecc5 100644 --- a/src/lib/Model/Suggestion.php +++ b/src/lib/Model/Suggestion.php @@ -58,4 +58,9 @@ public function getParentsLocation(): array { return $this->parentsLocation; } + + public function addPath(int $locationId, string $name) + { + $this->parentsLocation[$locationId] = $name; + } } From 7966db21e87801e4d0e83772d509fef65a1d5ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 11 Oct 2023 12:45:48 +0200 Subject: [PATCH 05/66] Removed root location --- .../EventListener/BreadCrumbSubscriber.php | 11 +++++----- ...archResultToSuggestionCollectionMapper.php | 21 ++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php b/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php index 34e33a2..dc41ff9 100644 --- a/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php @@ -7,15 +7,17 @@ namespace Ibexa\Search\EventDispatcher\EventListener; +use Ibexa\Contracts\Core\Repository\LocationService; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Search\EventDispatcher\Event\PostAutoCompleteSearch; use Ibexa\Search\Model\Suggestion; use Symfony\Component\EventDispatcher\EventSubscriberInterface; final class BreadCrumbSubscriber implements EventSubscriberInterface { - private \Ibexa\Contracts\Core\Repository\LocationService $locationService; + private LocationService $locationService; - public function __construct(\Ibexa\Contracts\Core\Repository\LocationService $locationService) + public function __construct(LocationService $locationService) { $this->locationService = $locationService; } @@ -30,12 +32,11 @@ public static function getSubscribedEvents(): array public function onPostAutoCompleteSearch(PostAutoCompleteSearch $event): PostAutoCompleteSearch { /** @var Suggestion $suggestion */ - foreach ($event->getSuggestionCollection() as $suggestion){ - foreach ($suggestion->getParentsLocation() as $locationId => $name){ + foreach ($event->getSuggestionCollection() as $suggestion) { + foreach ($suggestion->getParentsLocation() as $locationId => $name) { $location = $this->locationService->loadLocation($locationId); $suggestion->addPath($locationId, $location->contentInfo->name); } - } return $event; diff --git a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php index 3d57fa2..1c747a3 100644 --- a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php +++ b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php @@ -8,25 +8,40 @@ namespace Ibexa\Search\Mapper; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchResult; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Search\Model\Suggestion; use Ibexa\Search\Model\SuggestionCollection; -class SearchResultToSuggestionCollectionMapper +final class SearchResultToSuggestionCollectionMapper { + private ConfigResolverInterface $configResolver; + + public function __construct(ConfigResolverInterface $configResolver) + { + $this->configResolver = $configResolver; + } + public function transform(SearchResult $searchResult, ?string $language = null): SuggestionCollection { + $rootLocationId = $this->configResolver->getParameter('content.tree_root.location_id'); $collection = []; /** @var \Ibexa\Core\Repository\Values\Content\Content $result */ foreach ($searchResult as $result) { /** @var \Ibexa\Core\Repository\Values\Content\Content $content */ $content = $result->valueObject; + $parentsLocation = $result->valueObject->contentInfo->mainLocation->path; + $position = array_search((string)$rootLocationId, $parentsLocation); + if ($position !== false) { + $parentsLocation = array_slice($parentsLocation, $position); + } + $collection[] = new Suggestion( $result->valueObject->contentInfo->id, $content->getFieldValue('title', $language)->text, $result->valueObject->contentInfo->getContentType()->identifier, - $result->valueObject->contentInfo->mainLocation->pathString, - array_flip($result->valueObject->contentInfo->mainLocation->path) + implode('/', $parentsLocation), + array_flip($parentsLocation) ); } From 527468d4610b8ab19387d08dc2abcf59cae86486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 11 Oct 2023 12:56:23 +0200 Subject: [PATCH 06/66] Proper Json Response --- src/bundle/Controller/SearchAutoCompleteController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bundle/Controller/SearchAutoCompleteController.php b/src/bundle/Controller/SearchAutoCompleteController.php index ce9edce..3c1ef02 100644 --- a/src/bundle/Controller/SearchAutoCompleteController.php +++ b/src/bundle/Controller/SearchAutoCompleteController.php @@ -9,6 +9,7 @@ use Ibexa\Search\Service\SearchAutoCompleteService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Serializer\SerializerInterface; @@ -36,6 +37,6 @@ public function suggestAction(Request $request): Response $serializedResults = $this->serializer->serialize($result, 'json'); - return new Response($serializedResults, 200); + return (new JsonResponse(null, 200))->setJson($serializedResults); } } From e8a862dd4aec954b982ad2a3b550d49cdfc95436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 11 Oct 2023 14:17:03 +0200 Subject: [PATCH 07/66] Code style fixes, PHPStan fixed --- .../Controller/SearchAutoCompleteController.php | 2 ++ .../Event/PostAutoCompleteSearch.php | 1 + .../Event/PreAutoCompleteSearch.php | 1 + .../EventListener/BreadCrumbSubscriber.php | 5 ++--- .../SearchResultToSuggestionCollectionMapper.php | 3 ++- src/lib/Model/Suggestion.php | 15 ++++++++++++++- src/lib/Model/SuggestionCollection.php | 6 ++++++ src/lib/Service/SearchAutoCompleteService.php | 9 ++++++--- 8 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/bundle/Controller/SearchAutoCompleteController.php b/src/bundle/Controller/SearchAutoCompleteController.php index 3c1ef02..3d99781 100644 --- a/src/bundle/Controller/SearchAutoCompleteController.php +++ b/src/bundle/Controller/SearchAutoCompleteController.php @@ -1,4 +1,5 @@ getSuggestionCollection() as $suggestion) { foreach ($suggestion->getParentsLocation() as $locationId => $name) { $location = $this->locationService->loadLocation($locationId); diff --git a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php index 1c747a3..99d713a 100644 --- a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php +++ b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php @@ -1,4 +1,5 @@ configResolver->getParameter('content.tree_root.location_id'); $collection = []; - /** @var \Ibexa\Core\Repository\Values\Content\Content $result */ + /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit $result */ foreach ($searchResult as $result) { /** @var \Ibexa\Core\Repository\Values\Content\Content $content */ $content = $result->valueObject; diff --git a/src/lib/Model/Suggestion.php b/src/lib/Model/Suggestion.php index 6d6ecc5..014cfcd 100644 --- a/src/lib/Model/Suggestion.php +++ b/src/lib/Model/Suggestion.php @@ -1,4 +1,5 @@ */ private array $parentsLocation; + /** + * @param array $parentsLocation + * @param array $properties + */ public function __construct( int $contentId, string $contentName, @@ -54,12 +64,15 @@ public function getPathString(): string return $this->pathString; } + /** + * @return array + */ public function getParentsLocation(): array { return $this->parentsLocation; } - public function addPath(int $locationId, string $name) + public function addPath(int $locationId, string $name): void { $this->parentsLocation[$locationId] = $name; } diff --git a/src/lib/Model/SuggestionCollection.php b/src/lib/Model/SuggestionCollection.php index 08f208e..55e72cd 100644 --- a/src/lib/Model/SuggestionCollection.php +++ b/src/lib/Model/SuggestionCollection.php @@ -1,4 +1,5 @@ + */ final class SuggestionCollection extends ArrayList { } diff --git a/src/lib/Service/SearchAutoCompleteService.php b/src/lib/Service/SearchAutoCompleteService.php index 10c92d6..8d0a071 100644 --- a/src/lib/Service/SearchAutoCompleteService.php +++ b/src/lib/Service/SearchAutoCompleteService.php @@ -1,4 +1,5 @@ + * @return \Ibexa\Search\Model\SuggestionCollection */ public function suggest(string $value, int $limit, ?string $language = null): SuggestionCollection { $criterion = new Query\Criterion\FullText($value); $query = new Query(['filter' => $criterion, 'limit' => $limit]); - /** @var PreAutoCompleteSearch $preEvent */ + /** @var \Ibexa\Search\EventDispatcher\Event\PreAutoCompleteSearch $preEvent */ $preEvent = $this->eventDispatcher->dispatch(new PreAutoCompleteSearch($query)); $searchResult = $this->searchService->findContent($preEvent->getQuery()); $mappedResult = $this->suggestionCollectionMapper->transform($searchResult, $language); - /** @var PostAutoCompleteSearch $postEvent */ + /** @var \Ibexa\Search\EventDispatcher\Event\PostAutoCompleteSearch $postEvent */ $postEvent = $this->eventDispatcher->dispatch(new PostAutoCompleteSearch($mappedResult)); return $postEvent->getSuggestionCollection(); From d1e4c95ccd996ec241752df794b284575243efa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 12 Oct 2023 09:05:54 +0200 Subject: [PATCH 08/66] Fixed response return type --- src/bundle/Controller/SearchAutoCompleteController.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bundle/Controller/SearchAutoCompleteController.php b/src/bundle/Controller/SearchAutoCompleteController.php index 3d99781..65f4c6a 100644 --- a/src/bundle/Controller/SearchAutoCompleteController.php +++ b/src/bundle/Controller/SearchAutoCompleteController.php @@ -12,7 +12,6 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Serializer\SerializerInterface; final class SearchAutoCompleteController extends AbstractController @@ -29,7 +28,7 @@ public function __construct( $this->serializer = $serializer; } - public function suggestAction(Request $request): Response + public function suggestAction(Request $request): JsonResponse { $search = $request->get('search'); $language = $request->get('language'); From 64b2ec2974681fbc8e83d9540710ea04f3d004d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 17 Oct 2023 16:13:17 +0200 Subject: [PATCH 09/66] Refactored extension point --- ...ontroller.php => SuggestionController.php} | 18 +++-- src/bundle/Resources/config/routing.yaml | 2 +- src/bundle/Resources/config/services.yaml | 10 ++- src/contracts/Event/AfterSuggestionEvent.php | 46 +++++++++++ src/contracts/Event/BeforeSuggestionEvent.php | 46 +++++++++++ .../Decorator/SuggestionServiceDecorator.php | 28 +++++++ .../Service/SuggestionServiceInterface.php | 17 ++++ ...pleteSearch.php => AbstractSuggestion.php} | 12 ++- .../Event/ContentSuggestion.php | 13 +++ .../Event/PreAutoCompleteSearch.php | 26 ------ .../ContentSuggestionSubscriber.php | 69 ++++++++++++++++ ...CrumbSubscriber.php => PathSubscriber.php} | 19 +++-- .../SearchHitToContentSuggestionMapper.php | 44 +++++++++++ ...archResultToSuggestionCollectionMapper.php | 51 ------------ src/lib/Model/Suggestion.php | 79 ------------------- .../Model/Suggestion/ContentSuggestion.php | 43 ++++++++++ src/lib/Model/Suggestion/Suggestion.php | 51 ++++++++++++ .../Model/Suggestion/SuggestionCollection.php | 20 +++++ src/lib/Model/SuggestionCollection.php | 20 ----- src/lib/Model/SuggestionQuery.php | 40 ++++++++++ src/lib/Service/Event/SuggestionService.php | 55 +++++++++++++ src/lib/Service/SearchAutoCompleteService.php | 55 ------------- src/lib/Service/SuggestionService.php | 37 +++++++++ 23 files changed, 545 insertions(+), 256 deletions(-) rename src/bundle/Controller/{SearchAutoCompleteController.php => SuggestionController.php} (66%) create mode 100644 src/contracts/Event/AfterSuggestionEvent.php create mode 100644 src/contracts/Event/BeforeSuggestionEvent.php create mode 100644 src/contracts/Service/Decorator/SuggestionServiceDecorator.php create mode 100644 src/contracts/Service/SuggestionServiceInterface.php rename src/lib/EventDispatcher/Event/{PostAutoCompleteSearch.php => AbstractSuggestion.php} (58%) create mode 100644 src/lib/EventDispatcher/Event/ContentSuggestion.php delete mode 100644 src/lib/EventDispatcher/Event/PreAutoCompleteSearch.php create mode 100644 src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php rename src/lib/EventDispatcher/EventListener/{BreadCrumbSubscriber.php => PathSubscriber.php} (52%) create mode 100644 src/lib/Mapper/SearchHitToContentSuggestionMapper.php delete mode 100644 src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php delete mode 100644 src/lib/Model/Suggestion.php create mode 100644 src/lib/Model/Suggestion/ContentSuggestion.php create mode 100644 src/lib/Model/Suggestion/Suggestion.php create mode 100644 src/lib/Model/Suggestion/SuggestionCollection.php delete mode 100644 src/lib/Model/SuggestionCollection.php create mode 100644 src/lib/Model/SuggestionQuery.php create mode 100644 src/lib/Service/Event/SuggestionService.php delete mode 100644 src/lib/Service/SearchAutoCompleteService.php create mode 100644 src/lib/Service/SuggestionService.php diff --git a/src/bundle/Controller/SearchAutoCompleteController.php b/src/bundle/Controller/SuggestionController.php similarity index 66% rename from src/bundle/Controller/SearchAutoCompleteController.php rename to src/bundle/Controller/SuggestionController.php index 65f4c6a..3a5a69c 100644 --- a/src/bundle/Controller/SearchAutoCompleteController.php +++ b/src/bundle/Controller/SuggestionController.php @@ -8,33 +8,35 @@ namespace Ibexa\Bundle\Search\Controller; -use Ibexa\Search\Service\SearchAutoCompleteService; +use Ibexa\Search\Model\SuggestionQuery; +use Ibexa\Search\Service\SuggestionService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer\SerializerInterface; -final class SearchAutoCompleteController extends AbstractController +final class SuggestionController extends AbstractController { - private SearchAutoCompleteService $autoCompleteService; + private SuggestionService $suggestionService; private SerializerInterface $serializer; public function __construct( SerializerInterface $serializer, - SearchAutoCompleteService $autocompleteService + SuggestionService $suggestionService ) { - $this->autoCompleteService = $autocompleteService; + $this->suggestionService = $suggestionService; $this->serializer = $serializer; } public function suggestAction(Request $request): JsonResponse { - $search = $request->get('search'); - $language = $request->get('language'); + $query = $request->get('query'); $limit = (int) $request->get('limit'); + $language = $request->get('language'); - $result = $this->autoCompleteService->suggest($search, $limit, $language); + $suggestionQuery = new SuggestionQuery($query, $limit, $language); + $result = $this->suggestionService->suggest($suggestionQuery); $serializedResults = $this->serializer->serialize($result, 'json'); diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index d16f4f3..074a656 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -8,4 +8,4 @@ ibexa.search_autocomplete: path: /autocomplete methods: ['GET'] defaults: - _controller: 'Ibexa\Bundle\Search\Controller\SearchAutoCompleteController::suggestAction' + _controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 9ea6508..7e11532 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -14,7 +14,7 @@ services: tags: - controller.service_arguments - Ibexa\Bundle\Search\Controller\SearchAutoCompleteController: + Ibexa\Bundle\Search\Controller\SuggestionController: tags: - controller.service_arguments @@ -28,8 +28,10 @@ services: Ibexa\Search\QueryType\SearchQueryType: ~ - Ibexa\Search\Service\SearchAutoCompleteService: ~ + Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ - Ibexa\Search\Mapper\SearchResultToSuggestionCollectionMapper: ~ + Ibexa\Search\EventDispatcher\EventListener\PathSubscriber: ~ - Ibexa\Search\EventDispatcher\EventListener\BreadCrumbSubscriber: ~ + Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ + + Ibexa\Search\Service\SuggestionService: ~ diff --git a/src/contracts/Event/AfterSuggestionEvent.php b/src/contracts/Event/AfterSuggestionEvent.php new file mode 100644 index 0000000..e581c6a --- /dev/null +++ b/src/contracts/Event/AfterSuggestionEvent.php @@ -0,0 +1,46 @@ +query = $query; + $this->suggestionCollection = $suggestionCollection; + } + + public function setQuery(SuggestionQuery $query): void + { + $this->query = $query; + } + + public function getQuery(): SuggestionQuery + { + return $this->query; + } + + public function setSuggestionCollection(SuggestionCollection $suggestionCollection): void + { + $this->suggestionCollection = $suggestionCollection; + } + + public function getSuggestionCollection(): SuggestionCollection + { + return $this->suggestionCollection; + } +} diff --git a/src/contracts/Event/BeforeSuggestionEvent.php b/src/contracts/Event/BeforeSuggestionEvent.php new file mode 100644 index 0000000..f5610d9 --- /dev/null +++ b/src/contracts/Event/BeforeSuggestionEvent.php @@ -0,0 +1,46 @@ +query = $query; + $this->suggestionCollection = $suggestionCollection; + } + + public function setQuery(SuggestionQuery $query): void + { + $this->query = $query; + } + + public function getQuery(): SuggestionQuery + { + return $this->query; + } + + public function getSuggestionCollection(): SuggestionCollection + { + return $this->suggestionCollection; + } + + public function setSuggestionCollection(SuggestionCollection $suggestionCollection): void + { + $this->suggestionCollection = $suggestionCollection; + } +} diff --git a/src/contracts/Service/Decorator/SuggestionServiceDecorator.php b/src/contracts/Service/Decorator/SuggestionServiceDecorator.php new file mode 100644 index 0000000..3dfadd8 --- /dev/null +++ b/src/contracts/Service/Decorator/SuggestionServiceDecorator.php @@ -0,0 +1,28 @@ +innerService = $innerService; + } + + public function suggest(SuggestionQuery $query): SuggestionCollection + { + return $this->innerService->suggest($query); + } +} diff --git a/src/contracts/Service/SuggestionServiceInterface.php b/src/contracts/Service/SuggestionServiceInterface.php new file mode 100644 index 0000000..bf57ed5 --- /dev/null +++ b/src/contracts/Service/SuggestionServiceInterface.php @@ -0,0 +1,17 @@ +suggestionCollection = $suggestionCollection; + $this->suggestionCollection = new SuggestionCollection(); + $this->query = $query; } public function getSuggestionCollection(): SuggestionCollection diff --git a/src/lib/EventDispatcher/Event/ContentSuggestion.php b/src/lib/EventDispatcher/Event/ContentSuggestion.php new file mode 100644 index 0000000..c40e9fe --- /dev/null +++ b/src/lib/EventDispatcher/Event/ContentSuggestion.php @@ -0,0 +1,13 @@ +query = $query; - } - - public function getQuery(): Query - { - return $this->query; - } -} diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php new file mode 100644 index 0000000..565975a --- /dev/null +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -0,0 +1,69 @@ +searchService = $searchService; + $this->contentSuggestionMapper = $contentSuggestionMapper; + } + + public static function getSubscribedEvents(): array + { + return [ + ContentSuggestion::class => 'onContentSuggestion', + ]; + } + + public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion + { + $value = $event->getValue(); + $limit = $event->getLimit(); + $language = $event->getLanguage(); + + var_dump($value, $limit, $language); + + $criterion = new FullText($value); + $query = new Query(['filter' => $criterion, 'limit' => $limit]); + + try { + $searchResult = $this->searchService->findContent($query); + var_dump($searchResult); + $collection = $event->getSuggestionCollection(); + foreach ($searchResult as $result) { + $mappedResult = $this->contentSuggestionMapper->map($result); + $collection->append($mappedResult); + } + } catch (InvalidArgumentException $e) { + $this->logger->error($e); + } + + return $event; + } +} diff --git a/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php b/src/lib/EventDispatcher/EventListener/PathSubscriber.php similarity index 52% rename from src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php rename to src/lib/EventDispatcher/EventListener/PathSubscriber.php index 499ee3d..6393da8 100644 --- a/src/lib/EventDispatcher/EventListener/BreadCrumbSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/PathSubscriber.php @@ -9,10 +9,10 @@ namespace Ibexa\Search\EventDispatcher\EventListener; use Ibexa\Contracts\Core\Repository\LocationService; -use Ibexa\Search\EventDispatcher\Event\PostAutoCompleteSearch; +use Ibexa\Search\EventDispatcher\Event\AbstractSuggestion; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -final class BreadCrumbSubscriber implements EventSubscriberInterface +final class PathSubscriber implements EventSubscriberInterface { private LocationService $locationService; @@ -24,17 +24,20 @@ public function __construct(LocationService $locationService) public static function getSubscribedEvents(): array { return [ - PostAutoCompleteSearch::class => 'onPostAutoCompleteSearch', + AbstractSuggestion::class => 'onSuggestion', ]; } - public function onPostAutoCompleteSearch(PostAutoCompleteSearch $event): PostAutoCompleteSearch + public function onSuggestion(AbstractSuggestion $event): AbstractSuggestion { - /** @var \Ibexa\Search\Model\Suggestion $suggestion */ foreach ($event->getSuggestionCollection() as $suggestion) { - foreach ($suggestion->getParentsLocation() as $locationId => $name) { - $location = $this->locationService->loadLocation($locationId); - $suggestion->addPath($locationId, $location->contentInfo->name); + foreach ($suggestion->get() as $locationId => $name) { + try { + $location = $this->locationService->loadLocation($locationId); + $suggestion->addPath($locationId, $location->contentInfo->name); + } catch (\Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException $e) { + } catch (\Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException $e) { + } } } diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php new file mode 100644 index 0000000..f9918eb --- /dev/null +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -0,0 +1,44 @@ +configResolver = $configResolver; + } + + public function map(SearchHit $searchHit): ContentSuggestion + { + $content = $searchHit->getValueObject(); + + $rootLocationId = $this->configResolver->getParameter('content.tree_root.location_id'); + + $parentsLocation = $content->contentInfo->mainLocation->path; + $position = array_search((string)$rootLocationId, $parentsLocation); + if ($position !== false) { + $parentsLocation = array_slice($parentsLocation, $position); + } + + return new ContentSuggestion( + $content->contentInfo->id, + $content->contentInfo->getContentType()->identifier, + $content->getFieldValue('title')->text, + implode('/', $parentsLocation), + array_flip($parentsLocation) + ); + } +} diff --git a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php b/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php deleted file mode 100644 index 99d713a..0000000 --- a/src/lib/Mapper/SearchResultToSuggestionCollectionMapper.php +++ /dev/null @@ -1,51 +0,0 @@ -configResolver = $configResolver; - } - - public function transform(SearchResult $searchResult, ?string $language = null): SuggestionCollection - { - $rootLocationId = $this->configResolver->getParameter('content.tree_root.location_id'); - $collection = []; - /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit $result */ - foreach ($searchResult as $result) { - /** @var \Ibexa\Core\Repository\Values\Content\Content $content */ - $content = $result->valueObject; - - $parentsLocation = $result->valueObject->contentInfo->mainLocation->path; - $position = array_search((string)$rootLocationId, $parentsLocation); - if ($position !== false) { - $parentsLocation = array_slice($parentsLocation, $position); - } - - $collection[] = new Suggestion( - $result->valueObject->contentInfo->id, - $content->getFieldValue('title', $language)->text, - $result->valueObject->contentInfo->getContentType()->identifier, - implode('/', $parentsLocation), - array_flip($parentsLocation) - ); - } - - return new SuggestionCollection($collection); - } -} diff --git a/src/lib/Model/Suggestion.php b/src/lib/Model/Suggestion.php deleted file mode 100644 index 014cfcd..0000000 --- a/src/lib/Model/Suggestion.php +++ /dev/null @@ -1,79 +0,0 @@ - */ - private array $parentsLocation; - - /** - * @param array $parentsLocation - * @param array $properties - */ - public function __construct( - int $contentId, - string $contentName, - string $contentTypeIdentifier, - string $pathString, - array $parentsLocation, - array $properties = [] - ) { - $this->contentId = $contentId; - $this->contentName = $contentName; - $this->contentTypeIdentifier = $contentTypeIdentifier; - $this->pathString = $pathString; - $this->parentsLocation = $parentsLocation; - - parent::__construct($properties); - } - - public function getContentId(): int - { - return $this->contentId; - } - - public function getContentName(): string - { - return $this->contentName; - } - - public function getContentTypeIdentifier(): string - { - return $this->contentTypeIdentifier; - } - - public function getPathString(): string - { - return $this->pathString; - } - - /** - * @return array - */ - public function getParentsLocation(): array - { - return $this->parentsLocation; - } - - public function addPath(int $locationId, string $name): void - { - $this->parentsLocation[$locationId] = $name; - } -} diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/lib/Model/Suggestion/ContentSuggestion.php new file mode 100644 index 0000000..d195923 --- /dev/null +++ b/src/lib/Model/Suggestion/ContentSuggestion.php @@ -0,0 +1,43 @@ +contentId = $contentId; + $this->contentTypeIdentifier = $contentTypeIdentifier; + } + + public function getContentId(): int + { + return $this->contentId; + } + + public function getContentTypeIdentifier(): string + { + return $this->contentTypeIdentifier; + } + + public function getType(): string + { + return 'content'; + } +} diff --git a/src/lib/Model/Suggestion/Suggestion.php b/src/lib/Model/Suggestion/Suggestion.php new file mode 100644 index 0000000..4e4a33d --- /dev/null +++ b/src/lib/Model/Suggestion/Suggestion.php @@ -0,0 +1,51 @@ + */ + private array $parentsLocation; + + /** + * @param array $parentsLocation + */ + public function __construct( + string $name, + string $pathString = '', + array $parentsLocation = [] + ) { + $this->name = $name; + $this->pathString = $pathString; + $this->parentsLocation = $parentsLocation; + + parent::__construct(); + } + + /** + * @return array + */ + public function getParentsLocation(): array + { + return $this->parentsLocation; + } + + public function addPath(int $locationId, string $name): void + { + $this->parentsLocation[$locationId] = $name; + } + + abstract public function getType(): string; +} diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php new file mode 100644 index 0000000..4bcabc7 --- /dev/null +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -0,0 +1,20 @@ + + */ +final class SuggestionCollection extends MutableArrayList +{ +} diff --git a/src/lib/Model/SuggestionCollection.php b/src/lib/Model/SuggestionCollection.php deleted file mode 100644 index 55e72cd..0000000 --- a/src/lib/Model/SuggestionCollection.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ -final class SuggestionCollection extends ArrayList -{ -} diff --git a/src/lib/Model/SuggestionQuery.php b/src/lib/Model/SuggestionQuery.php new file mode 100644 index 0000000..1498300 --- /dev/null +++ b/src/lib/Model/SuggestionQuery.php @@ -0,0 +1,40 @@ +query = $query; + $this->limit = $limit; + $this->language = $language; + } + + public function getQuery(): string + { + return $this->query; + } + + public function getLimit(): int + { + return $this->limit; + } + + public function getLanguage(): ?string + { + return $this->language; + } +} diff --git a/src/lib/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php new file mode 100644 index 0000000..e879845 --- /dev/null +++ b/src/lib/Service/Event/SuggestionService.php @@ -0,0 +1,55 @@ +eventDispatcher = $eventDispatcher; + } + + public function suggest(SuggestionQuery $query): SuggestionCollection + { + $beforeEvent = $this->eventDispatcher->dispatch( + new BeforeSuggestionEvent( + $query, + new SuggestionCollection() + ) + ); + + if ($beforeEvent->isPropagationStopped()) { + return $beforeEvent->getSuggestionCollection(); + } + + $result = $this->innerService->suggest($beforeEvent->getQuery()); + + $afterEvent = $this->eventDispatcher->dispatch( + new AfterSuggestionEvent( + $query, + $result + ) + ); + + return $afterEvent->getSuggestionCollection(); + } +} diff --git a/src/lib/Service/SearchAutoCompleteService.php b/src/lib/Service/SearchAutoCompleteService.php deleted file mode 100644 index 8d0a071..0000000 --- a/src/lib/Service/SearchAutoCompleteService.php +++ /dev/null @@ -1,55 +0,0 @@ -searchService = $searchService; - $this->eventDispatcher = $eventDispatcher; - $this->suggestionCollectionMapper = $suggestionCollectionMapper; - } - - /** - * @return \Ibexa\Search\Model\SuggestionCollection - */ - public function suggest(string $value, int $limit, ?string $language = null): SuggestionCollection - { - $criterion = new Query\Criterion\FullText($value); - $query = new Query(['filter' => $criterion, 'limit' => $limit]); - /** @var \Ibexa\Search\EventDispatcher\Event\PreAutoCompleteSearch $preEvent */ - $preEvent = $this->eventDispatcher->dispatch(new PreAutoCompleteSearch($query)); - $searchResult = $this->searchService->findContent($preEvent->getQuery()); - - $mappedResult = $this->suggestionCollectionMapper->transform($searchResult, $language); - - /** @var \Ibexa\Search\EventDispatcher\Event\PostAutoCompleteSearch $postEvent */ - $postEvent = $this->eventDispatcher->dispatch(new PostAutoCompleteSearch($mappedResult)); - - return $postEvent->getSuggestionCollection(); - } -} diff --git a/src/lib/Service/SuggestionService.php b/src/lib/Service/SuggestionService.php new file mode 100644 index 0000000..e4fcfd1 --- /dev/null +++ b/src/lib/Service/SuggestionService.php @@ -0,0 +1,37 @@ +eventDispatcher = $eventDispatcher; + } + + public function suggest(SuggestionQuery $query): SuggestionCollection + { + /** @var \Ibexa\Search\EventDispatcher\Event\ContentSuggestion $event */ + $event = $this->eventDispatcher->dispatch( + new ContentSuggestion( + $query + ) + ); + + return $event->getSuggestionCollection(); + } +} From 94cf57b3441198aeb1e5672840b6ac5b52f52248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 18 Oct 2023 10:15:55 +0200 Subject: [PATCH 10/66] Added improvements --- src/bundle/Resources/config/routing.yaml | 4 ++-- .../EventDispatcher/Event/AbstractSuggestion.php | 5 +++++ .../EventListener/ContentSuggestionSubscriber.php | 15 +++++++-------- src/lib/Model/Suggestion/ContentSuggestion.php | 7 +++++++ src/lib/Model/Suggestion/Suggestion.php | 10 ++++++++++ src/lib/Model/Suggestion/SuggestionCollection.php | 2 +- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index 074a656..290c576 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -4,8 +4,8 @@ ibexa.search: defaults: _controller: 'Ibexa\Bundle\Search\Controller\SearchController::searchAction' -ibexa.search_autocomplete: - path: /autocomplete +ibexa.search.suggestion: + path: /suggestion methods: ['GET'] defaults: _controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' diff --git a/src/lib/EventDispatcher/Event/AbstractSuggestion.php b/src/lib/EventDispatcher/Event/AbstractSuggestion.php index e9485d3..2aa33d5 100644 --- a/src/lib/EventDispatcher/Event/AbstractSuggestion.php +++ b/src/lib/EventDispatcher/Event/AbstractSuggestion.php @@ -27,4 +27,9 @@ public function getSuggestionCollection(): SuggestionCollection { return $this->suggestionCollection; } + + public function getQuery(): SuggestionQuery + { + return $this->query; + } } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 565975a..1fd08ab 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -43,25 +43,24 @@ public static function getSubscribedEvents(): array public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion { - $value = $event->getValue(); - $limit = $event->getLimit(); - $language = $event->getLanguage(); - - var_dump($value, $limit, $language); + $query = $event->getQuery(); + $value = $query->getQuery(); + $limit = $query->getLimit(); + $language = $query->getLanguage(); $criterion = new FullText($value); $query = new Query(['filter' => $criterion, 'limit' => $limit]); try { - $searchResult = $this->searchService->findContent($query); - var_dump($searchResult); + $languageFilter = $language ? ['languages' => [$language]] : []; + $searchResult = $this->searchService->findContent($query, $languageFilter); $collection = $event->getSuggestionCollection(); foreach ($searchResult as $result) { $mappedResult = $this->contentSuggestionMapper->map($result); $collection->append($mappedResult); } } catch (InvalidArgumentException $e) { - $this->logger->error($e); + $this->logger ? $this->logger->error($e) : null; } return $event; diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/lib/Model/Suggestion/ContentSuggestion.php index d195923..fbbd698 100644 --- a/src/lib/Model/Suggestion/ContentSuggestion.php +++ b/src/lib/Model/Suggestion/ContentSuggestion.php @@ -14,6 +14,13 @@ final class ContentSuggestion extends Suggestion private string $contentTypeIdentifier; + /** + * @param int $contentId + * @param string $contentTypeIdentifier + * @param string $name + * @param string $pathString + * @param array $parentLocation + */ public function __construct( int $contentId, string $contentTypeIdentifier, diff --git a/src/lib/Model/Suggestion/Suggestion.php b/src/lib/Model/Suggestion/Suggestion.php index 4e4a33d..4e9655b 100644 --- a/src/lib/Model/Suggestion/Suggestion.php +++ b/src/lib/Model/Suggestion/Suggestion.php @@ -34,6 +34,16 @@ public function __construct( parent::__construct(); } + public function getName(): string + { + return $this->name; + } + + public function getPathString(): string + { + return $this->pathString; + } + /** * @return array */ diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index 4bcabc7..09ab770 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -12,7 +12,7 @@ /** * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList< - * \Ibexa\Search\Model\ContentSuggestion + * \Ibexa\Search\Model\Suggestion\ContentSuggestion * > */ final class SuggestionCollection extends MutableArrayList From a5b5db39cc2a7d4a8040a915512c46222df3d692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 19 Oct 2023 12:54:51 +0200 Subject: [PATCH 11/66] Fixed suggestion configuration --- ...ompleteParser.php => SuggestionParser.php} | 19 +++++++++--------- src/bundle/IbexaSearchBundle.php | 4 ++-- .../ContentSuggestionSubscriber.php | 1 + .../AutocompleteParserTest.php | 20 +++++++++---------- 4 files changed, 23 insertions(+), 21 deletions(-) rename src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/{AutocompleteParser.php => SuggestionParser.php} (84%) diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php similarity index 84% rename from src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php rename to src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php index 8914172..3d456cb 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/AutocompleteParser.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php @@ -24,12 +24,12 @@ * system: * default: # configuration per siteaccess or siteaccess group * search: - * autocomplete: - * min_search_test_length: 3 + * suggestion: + * min_query_length: 3 * result_limit: 5 * ``` */ -final class AutocompleteParser extends AbstractParser +final class SuggestionParser extends AbstractParser { /** * @param array $scopeSettings @@ -63,15 +63,15 @@ private function addAutocompleteParameters( ContextualizerInterface $contextualizer ): void { $names = [ - 'min_search_test_length', + 'min_query_length', 'result_limit', ]; foreach ($names as $name) { - if (isset($settings['autocomplete'][$name])) { + if (isset($settings['suggestion'][$name])) { $contextualizer->setContextualParameter( - 'search.autocomplete.' . $name, + 'search.suggestion.' . $name, $currentScope, - $settings['autocomplete'][$name] + $settings['suggestion'][$name] ); } } @@ -79,12 +79,13 @@ private function addAutocompleteParameters( private function addAutocompleteConfiguration(): ArrayNodeDefinition { - $treeBuilder = new TreeBuilder('autocomplete'); + $treeBuilder = new TreeBuilder('suggestion'); $node = $treeBuilder->getRootNode(); $node + ->addDefaultsIfNotSet() ->children() - ->integerNode('min_search_test_length') + ->integerNode('min_query_length') ->isRequired() ->defaultValue(3) ->min(3) diff --git a/src/bundle/IbexaSearchBundle.php b/src/bundle/IbexaSearchBundle.php index 79cbe79..70f6170 100644 --- a/src/bundle/IbexaSearchBundle.php +++ b/src/bundle/IbexaSearchBundle.php @@ -8,7 +8,7 @@ use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\Search; use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SearchView; -use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\AutocompleteParser; +use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\SuggestionParser; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -22,7 +22,7 @@ public function build(ContainerBuilder $container) $core->addDefaultSettings(__DIR__ . '/Resources/config', ['default_settings.yaml']); $core->addConfigParser(new Search()); $core->addConfigParser(new SearchView()); - $core->addConfigParser(new AutocompleteParser()); + $core->addConfigParser(new SuggestionParser()); } } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 1fd08ab..5f07be3 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -44,6 +44,7 @@ public static function getSubscribedEvents(): array public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion { $query = $event->getQuery(); + $value = $query->getQuery(); $limit = $query->getLimit(); $language = $query->getLanguage(); diff --git a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php index 28f0d14..4ef2c71 100644 --- a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php +++ b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php @@ -10,12 +10,12 @@ use Exception; use Ibexa\Bundle\Core\DependencyInjection\IbexaCoreExtension; -use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\AutocompleteParser; +use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\SuggestionParser; use Ibexa\Core\MVC\Exception\ParameterNotFoundException; use Ibexa\Tests\Bundle\Core\DependencyInjection\Configuration\Parser\AbstractParserTestCase; /** - * @covers \Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\AutocompleteParser + * @covers \Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\SuggestionParser */ final class AutocompleteParserTest extends AbstractParserTestCase { @@ -23,7 +23,7 @@ protected function getContainerExtensions(): array { return [ new IbexaCoreExtension([ - new AutocompleteParser(), + new SuggestionParser(), ]), ]; } @@ -68,23 +68,23 @@ public function dataProviderForTestSettings(): iterable [], [], [ - 'search.autocomplete.min_search_test_length', - 'search.autocomplete.result_limit', + 'search.suggestion.min_query_length', + 'search.suggestion.result_limit', ], ]; - yield 'autocomplete' => [ + yield 'suggestion' => [ [ 'search' => [ - 'autocomplete' => [ - 'min_search_test_length' => 10, + 'suggestion' => [ + 'min_query_length' => 10, 'result_limit' => 10, ], ], ], [ - 'search.autocomplete.min_search_test_length' => 10, - 'search.autocomplete.result_limit' => 10, + 'search.suggestion.min_query_length' => 10, + 'search.suggestion.result_limit' => 10, ], ]; } From d8fb68894740a2ece62176b1df8077d90c5adc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 19 Oct 2023 14:39:42 +0200 Subject: [PATCH 12/66] Added tests --- .../SiteAccessAware/SuggestionParser.php | 8 +- .../ContentSuggestionSubscriber.php | 3 +- .../SearchHitToContentSuggestionMapper.php | 5 +- .../Model/Suggestion/SuggestionCollection.php | 21 +++- src/lib/Service/Event/SuggestionService.php | 3 +- ...arserTest.php => SuggestionParserTest.php} | 2 +- ...SearchHitToContentSuggestionMapperTest.php | 67 +++++++++++++ .../Suggestion/ContentSuggestionTest.php | 36 +++++++ .../Suggestion/SuggestionCollectionTest.php | 36 +++++++ tests/lib/Model/Suggestion/SuggestionTest.php | 34 +++++++ .../Service/Event/SuggestionServiceTest.php | 99 +++++++++++++++++++ tests/lib/Service/SuggestionServiceTest.php | 44 +++++++++ 12 files changed, 347 insertions(+), 11 deletions(-) rename tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/{AutocompleteParserTest.php => SuggestionParserTest.php} (97%) create mode 100644 tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php create mode 100644 tests/lib/Model/Suggestion/ContentSuggestionTest.php create mode 100644 tests/lib/Model/Suggestion/SuggestionCollectionTest.php create mode 100644 tests/lib/Model/Suggestion/SuggestionTest.php create mode 100644 tests/lib/Service/Event/SuggestionServiceTest.php create mode 100644 tests/lib/Service/SuggestionServiceTest.php diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php index 3d456cb..788af50 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php @@ -45,19 +45,19 @@ public function mapConfig( $settings = $scopeSettings['search']; - $this->addAutocompleteParameters($settings, $currentScope, $contextualizer); + $this->addSuggestionParameters($settings, $currentScope, $contextualizer); } public function addSemanticConfig(NodeBuilder $nodeBuilder): void { $rootProductCatalogNode = $nodeBuilder->arrayNode('search'); - $rootProductCatalogNode->append($this->addAutocompleteConfiguration()); + $rootProductCatalogNode->append($this->addSuggestionConfiguration()); } /** * @param array $settings */ - private function addAutocompleteParameters( + private function addSuggestionParameters( $settings, string $currentScope, ContextualizerInterface $contextualizer @@ -77,7 +77,7 @@ private function addAutocompleteParameters( } } - private function addAutocompleteConfiguration(): ArrayNodeDefinition + private function addSuggestionConfiguration(): ArrayNodeDefinition { $treeBuilder = new TreeBuilder('suggestion'); $node = $treeBuilder->getRootNode(); diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 5f07be3..2799918 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -10,7 +10,6 @@ use Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException; use Ibexa\Contracts\Core\Repository\Values\Content\Query; -use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\FullText; use Ibexa\Core\Repository\SiteAccessAware\SearchService; use Ibexa\Search\EventDispatcher\Event\ContentSuggestion; use Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper; @@ -49,7 +48,7 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion $limit = $query->getLimit(); $language = $query->getLanguage(); - $criterion = new FullText($value); + $criterion = new Query\Criterion\FullText($value); $query = new Query(['filter' => $criterion, 'limit' => $limit]); try { diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index f9918eb..94f62bd 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -23,11 +23,12 @@ public function __construct(ConfigResolverInterface $configResolver) public function map(SearchHit $searchHit): ContentSuggestion { - $content = $searchHit->getValueObject(); + /** @var \Ibexa\Contracts\Core\Repository\Values\ValueObject $content */ + $content = $searchHit->valueObject; $rootLocationId = $this->configResolver->getParameter('content.tree_root.location_id'); - $parentsLocation = $content->contentInfo->mainLocation->path; + $parentsLocation = $content->versionInfo->contentInfo->mainLocation->path; $position = array_search((string)$rootLocationId, $parentsLocation); if ($position !== false) { $parentsLocation = array_slice($parentsLocation, $position); diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index 09ab770..35caefc 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -12,9 +12,28 @@ /** * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList< - * \Ibexa\Search\Model\Suggestion\ContentSuggestion + * \Ibexa\Search\Model\Suggestion\Suggestion + * |\Ibexa\Search\Model\Suggestion\ContentSuggestion * > */ final class SuggestionCollection extends MutableArrayList { + /** + * @param Suggestion $item + */ + public function append($item): void + { + if (!$item instanceof Suggestion) { + throw new \TypeError( + \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/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php index e879845..5006fcf 100644 --- a/src/lib/Service/Event/SuggestionService.php +++ b/src/lib/Service/Event/SuggestionService.php @@ -11,6 +11,7 @@ use Ibexa\Contracts\Search\Event\AfterSuggestionEvent; use Ibexa\Contracts\Search\Event\BeforeSuggestionEvent; use Ibexa\Contracts\Search\Service\Decorator\SuggestionServiceDecorator; +use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -20,7 +21,7 @@ final class SuggestionService extends SuggestionServiceDecorator private EventDispatcherInterface $eventDispatcher; public function __construct( - SuggestionServiceDecorator $innerService, + SuggestionServiceInterface $innerService, EventDispatcherInterface $eventDispatcher ) { parent::__construct($innerService); diff --git a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/SuggestionParserTest.php similarity index 97% rename from tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php rename to tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/SuggestionParserTest.php index 4ef2c71..27c335f 100644 --- a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/AutocompleteParserTest.php +++ b/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/SuggestionParserTest.php @@ -17,7 +17,7 @@ /** * @covers \Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\SiteAccessAware\SuggestionParser */ -final class AutocompleteParserTest extends AbstractParserTestCase +final class SuggestionParserTest extends AbstractParserTestCase { protected function getContainerExtensions(): array { diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php new file mode 100644 index 0000000..b6eba2a --- /dev/null +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -0,0 +1,67 @@ +markTestIncomplete('This test has not been implemented yet.'); + + $mapper = new SearchHitToContentSuggestionMapper( + $this->getConfigResolverMock() + ); + + $result = $mapper->map( + new SearchHit([ + 'valueObject' => new Content([ + 'id' => 1, + 'contentInfo' => new ContentInfo([ + 'name' => 'name', + 'mainLanguageCode' => 'eng-GB', + 'mainLocation' => new Location([ + 'pathString' => [1, 2, 3], + ]), + 'contentTypeId' => 1, + ]), + 'versionInfo' => new VersionInfo([ + 'contentInfo' => new ContentInfo([ + 'name' => 'name', + 'mainLanguageCode' => 'eng-GB', + 'contentTypeId' => 1, + ]), + ]), + 'contentType' => new ContentType([ + 'identifier' => 'content_type_identifier', + ]), + ]), + ]) + ); + $this->assertInstanceOf(ContentSuggestion::class, $result); + } + + private function getConfigResolverMock(): ConfigResolverInterface + { + $configResolverMock = $this->createMock(ConfigResolverInterface::class); + $configResolverMock->method('getParameter')->willReturn(5); + + return $configResolverMock; + } +} diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/lib/Model/Suggestion/ContentSuggestionTest.php new file mode 100644 index 0000000..871ed27 --- /dev/null +++ b/tests/lib/Model/Suggestion/ContentSuggestionTest.php @@ -0,0 +1,36 @@ + '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()); + } +} diff --git a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php new file mode 100644 index 0000000..1eaba4a --- /dev/null +++ b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php @@ -0,0 +1,36 @@ +assertInstanceOf(MutableArrayList::class, $collection); + $this->assertInstanceOf(SuggestionCollection::class, $collection); + + $collection->append(new ContentSuggestion(1, 'article', 'test')); + $collection->append(new ContentSuggestion(2, 'article', 'test2')); + + $this->assertCount(2, $collection); + + foreach ($collection as $item) { + $this->assertInstanceOf(ContentSuggestion::class, $item); + } + + $this->expectException(\TypeError::class); + $collection->append(new \stdClass()); + } +} diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php new file mode 100644 index 0000000..dc0b827 --- /dev/null +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -0,0 +1,34 @@ + 'text']) extends SuggestionAlias { + 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 => 'text'], $implementation->getParentsLocation()); + $this->assertSame('test_implementation', $implementation->getType()); + + $implementation->addPath(1, 'text2'); + $this->assertSame([0 => 'text', 1 => 'text2'], $implementation->getParentsLocation()); + } +} diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php new file mode 100644 index 0000000..4701fec --- /dev/null +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -0,0 +1,99 @@ +getEventDispatcherMock(); + $eventDispatcherMock + ->method('dispatch') + ->withConsecutive( + [ + $this->isInstanceOf(BeforeSuggestionEvent::class), + ], + [ + $this->isInstanceOf(AfterSuggestionEvent::class), + ] + ) + ->willReturnCallback( + static function ($event) { + return $event; + } + ); + + $innerServiceMock = $this->getSuggestionServiceMock(); + $innerServiceMock + ->method('suggest') + ->willReturn(new SuggestionCollection()); + + $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); + + $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); + self::assertInstanceOf(SuggestionCollection::class, $result); + } + + public function testSuggestionStopPropagation(): void + { + $eventDispatcherMock = $this->getEventDispatcherMock(); + $eventDispatcherMock + ->expects(self::once()) + ->method('dispatch') + ->withConsecutive( + [ + $this->isInstanceOf(BeforeSuggestionEvent::class), + ] + ) + ->willReturnCallback( + static function (BeforeSuggestionEvent $event) { + $event->stopPropagation(); + + return $event; + } + ); + + $innerServiceMock = $this->getSuggestionServiceMock(); + $innerServiceMock + ->method('suggest') + ->willReturn(new SuggestionCollection()); + + $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); + + $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); + self::assertInstanceOf(SuggestionCollection::class, $result); + } + + private function getSuggestionServiceMock(): SuggestionServiceInterface + { + $suggestionServiceMock = $this->getMockBuilder(SuggestionServiceInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + return $suggestionServiceMock; + } + + private function getEventDispatcherMock(): EventDispatcherInterface + { + $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + return $eventDispatcherMock; + } +} diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php new file mode 100644 index 0000000..f285742 --- /dev/null +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -0,0 +1,44 @@ +getEventDispatcherMock(); + $eventDispatcherMock + ->method('dispatch') + ->willReturnCallback( + static function ($event) { + return $event; + } + ); + + $service = new SuggestionService($eventDispatcherMock); + $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); + + self::assertInstanceOf(SuggestionCollection::class, $result); + } + + private function getEventDispatcherMock(): EventDispatcherInterface + { + $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + return $eventDispatcherMock; + } +} From bb0781c45ed201a021ebacd1375e30eb876459d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Mon, 23 Oct 2023 14:19:31 +0200 Subject: [PATCH 13/66] Added Truncate functionality --- src/bundle/Resources/config/services.yaml | 4 +- .../SearchHitToContentSuggestionMapper.php | 17 ++++ .../ContentSuggestionSubscriber.php | 29 ++++++- .../EventListener/PathSubscriber.php | 46 ---------- .../SearchHitToContentSuggestionMapper.php | 28 ++++-- .../Model/Suggestion/ContentSuggestion.php | 11 +-- src/lib/Model/Suggestion/Suggestion.php | 15 +++- .../Model/Suggestion/SuggestionCollection.php | 19 +++-- src/lib/Service/SuggestionService.php | 6 +- .../ContentSuggestionSubscriberTest.php | 85 +++++++++++++++++++ ...SearchHitToContentSuggestionMapperTest.php | 26 ++++-- .../Suggestion/ContentSuggestionTest.php | 1 + .../Suggestion/SuggestionCollectionTest.php | 18 ++-- tests/lib/Model/Suggestion/SuggestionTest.php | 4 +- .../Service/Event/SuggestionServiceTest.php | 6 ++ tests/lib/Service/SuggestionServiceTest.php | 6 +- 16 files changed, 229 insertions(+), 92 deletions(-) create mode 100644 src/contracts/Mapper/SearchHitToContentSuggestionMapper.php delete mode 100644 src/lib/EventDispatcher/EventListener/PathSubscriber.php create mode 100644 tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 7e11532..6ea54f6 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -30,8 +30,8 @@ services: Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ - Ibexa\Search\EventDispatcher\EventListener\PathSubscriber: ~ - Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ + Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' + Ibexa\Search\Service\SuggestionService: ~ diff --git a/src/contracts/Mapper/SearchHitToContentSuggestionMapper.php b/src/contracts/Mapper/SearchHitToContentSuggestionMapper.php new file mode 100644 index 0000000..49259fb --- /dev/null +++ b/src/contracts/Mapper/SearchHitToContentSuggestionMapper.php @@ -0,0 +1,17 @@ +searchService = $searchService; $this->contentSuggestionMapper = $contentSuggestionMapper; + $this->locationService = $locationService; } public static function getSubscribedEvents(): array @@ -48,8 +55,12 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion $limit = $query->getLimit(); $language = $query->getLanguage(); - $criterion = new Query\Criterion\FullText($value); - $query = new Query(['filter' => $criterion, 'limit' => $limit]); + $query = new Query( + [ + 'query' => new Query\Criterion\FullText($value), + 'limit' => $limit, + ] + ); try { $languageFilter = $language ? ['languages' => [$language]] : []; @@ -57,6 +68,18 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion $collection = $event->getSuggestionCollection(); foreach ($searchResult as $result) { $mappedResult = $this->contentSuggestionMapper->map($result); + if ($mappedResult === null) { + continue; + } + + foreach ($mappedResult->getParentsLocation() as $locationId => $name) { + try { + $location = $this->locationService->loadLocation($locationId); + $mappedResult->addPath($locationId, (string) $location->getContent()->getName()); + } catch (NotFoundException $e) { + } catch (UnauthorizedException $e) { + } + } $collection->append($mappedResult); } } catch (InvalidArgumentException $e) { diff --git a/src/lib/EventDispatcher/EventListener/PathSubscriber.php b/src/lib/EventDispatcher/EventListener/PathSubscriber.php deleted file mode 100644 index 6393da8..0000000 --- a/src/lib/EventDispatcher/EventListener/PathSubscriber.php +++ /dev/null @@ -1,46 +0,0 @@ -locationService = $locationService; - } - - public static function getSubscribedEvents(): array - { - return [ - AbstractSuggestion::class => 'onSuggestion', - ]; - } - - public function onSuggestion(AbstractSuggestion $event): AbstractSuggestion - { - foreach ($event->getSuggestionCollection() as $suggestion) { - foreach ($suggestion->get() as $locationId => $name) { - try { - $location = $this->locationService->loadLocation($locationId); - $suggestion->addPath($locationId, $location->contentInfo->name); - } catch (\Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException $e) { - } catch (\Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException $e) { - } - } - } - - return $event; - } -} diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 94f62bd..1abd9a5 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -10,9 +10,11 @@ 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\Core\Repository\Values\Content\Content; use Ibexa\Search\Model\Suggestion\ContentSuggestion; -final class SearchHitToContentSuggestionMapper +final class SearchHitToContentSuggestionMapper implements SearchHitToContentSuggestionMapperInterface { private ConfigResolverInterface $configResolver; @@ -21,23 +23,33 @@ public function __construct(ConfigResolverInterface $configResolver) $this->configResolver = $configResolver; } - public function map(SearchHit $searchHit): ContentSuggestion + public function map(SearchHit $searchHit): ?ContentSuggestion { - /** @var \Ibexa\Contracts\Core\Repository\Values\ValueObject $content */ $content = $searchHit->valueObject; + if (!$content instanceof Content) { + return null; + } + $rootLocationId = $this->configResolver->getParameter('content.tree_root.location_id'); - $parentsLocation = $content->versionInfo->contentInfo->mainLocation->path; + $mainLocation = $content->getVersionInfo()->getContentInfo()->getMainLocation(); + + if ($mainLocation === null) { + return null; + } + + $parentsLocation = $mainLocation->path; $position = array_search((string)$rootLocationId, $parentsLocation); if ($position !== false) { - $parentsLocation = array_slice($parentsLocation, $position); + $parentsLocation = array_slice($parentsLocation, (int)$position + 1); } return new ContentSuggestion( - $content->contentInfo->id, - $content->contentInfo->getContentType()->identifier, - $content->getFieldValue('title')->text, + $searchHit->score ?? 50, + $content->getContentType()->identifier, + $content->getName() ?? '', + $content->getVersionInfo()->getContentInfo()->getId(), implode('/', $parentsLocation), array_flip($parentsLocation) ); diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/lib/Model/Suggestion/ContentSuggestion.php index fbbd698..f62cbb1 100644 --- a/src/lib/Model/Suggestion/ContentSuggestion.php +++ b/src/lib/Model/Suggestion/ContentSuggestion.php @@ -15,20 +15,17 @@ final class ContentSuggestion extends Suggestion private string $contentTypeIdentifier; /** - * @param int $contentId - * @param string $contentTypeIdentifier - * @param string $name - * @param string $pathString - * @param array $parentLocation + * @param array $parentLocation */ public function __construct( - int $contentId, + float $score, string $contentTypeIdentifier, string $name, + int $contentId, string $pathString = '', array $parentLocation = [] ) { - parent::__construct($name, $pathString, $parentLocation); + parent::__construct($score, $name, $pathString, $parentLocation); $this->contentId = $contentId; $this->contentTypeIdentifier = $contentTypeIdentifier; } diff --git a/src/lib/Model/Suggestion/Suggestion.php b/src/lib/Model/Suggestion/Suggestion.php index 4e9655b..58aafe1 100644 --- a/src/lib/Model/Suggestion/Suggestion.php +++ b/src/lib/Model/Suggestion/Suggestion.php @@ -12,21 +12,25 @@ abstract class Suggestion extends ValueObject { + private float $score; + private string $name; private string $pathString; - /** @var array */ + /** @var array */ private array $parentsLocation; /** - * @param array $parentsLocation + * @param array $parentsLocation */ public function __construct( + float $score, string $name, string $pathString = '', array $parentsLocation = [] ) { + $this->score = $score; $this->name = $name; $this->pathString = $pathString; $this->parentsLocation = $parentsLocation; @@ -34,6 +38,11 @@ public function __construct( parent::__construct(); } + public function getScore(): float + { + return $this->score; + } + public function getName(): string { return $this->name; @@ -45,7 +54,7 @@ public function getPathString(): string } /** - * @return array + * @return array */ public function getParentsLocation(): array { diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index 35caefc..3ee9450 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -11,15 +11,12 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; /** - * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList< - * \Ibexa\Search\Model\Suggestion\Suggestion - * |\Ibexa\Search\Model\Suggestion\ContentSuggestion - * > + * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Search\Model\Suggestion\Suggestion> */ final class SuggestionCollection extends MutableArrayList { /** - * @param Suggestion $item + * @param mixed $item */ public function append($item): void { @@ -36,4 +33,16 @@ public function append($item): void parent::append($item); } + + public function sortByScore(): void + { + usort($this->items, static function ($a, $b) { + return $b->getScore() <=> $a->getScore(); + }); + } + + public function truncate(int $count): void + { + $this->items = array_slice($this->items, 0, $count); + } } diff --git a/src/lib/Service/SuggestionService.php b/src/lib/Service/SuggestionService.php index e4fcfd1..64f5c4c 100644 --- a/src/lib/Service/SuggestionService.php +++ b/src/lib/Service/SuggestionService.php @@ -32,6 +32,10 @@ public function suggest(SuggestionQuery $query): SuggestionCollection ) ); - return $event->getSuggestionCollection(); + $collection = $event->getSuggestionCollection(); + $collection->sortByScore(); + $collection->truncate($query->getLimit()); + + return $collection; } } diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php new file mode 100644 index 0000000..14e204d --- /dev/null +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -0,0 +1,85 @@ +assertSame( + [ContentSuggestion::class => 'onContentSuggestion'], + ContentSuggestionSubscriber::getSubscribedEvents() + ); + } + + 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); + + $event = new ContentSuggestion($query); + $subscriber->onContentSuggestion($event); + + $collection = $event->getSuggestionCollection(); + + self::assertCount(1, $collection); + } + + private function getSearchServiceMock(): SearchService + { + $searchServiceMock = $this->createMock(SearchService::class); + $searchServiceMock->method('findContent')->willReturn( + new SearchResult( + [ + 'searchHits' => [ + $this->createMock(SearchHit::class), + ], + ] + ) + ); + + return $searchServiceMock; + } + + private function getLocationServiceMock(): LocationService + { + $locationServiceMock = $this->createMock(LocationService::class); + $locationServiceMock->method('loadLocation')->willReturn( + $this->createMock(Location::class) + ); + + return $locationServiceMock; + } + + private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContentSuggestionMapper + { + $searchHitToContentSuggestionMapperMock = $this->createMock(SearchHitToContentSuggestionMapper::class); + $searchHitToContentSuggestionMapperMock->method('map')->willReturn( + new ContentSuggestionModel(10.0, 'test', 'test', 1, 'test', [0 => 'test']) + ); + + return $searchHitToContentSuggestionMapperMock; + } +} diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index b6eba2a..3778dd9 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -9,11 +9,11 @@ namespace Ibexa\Tests\Search\Mapper; use Ibexa\Contracts\Core\Persistence\Content\ContentInfo; -use Ibexa\Contracts\Core\Persistence\Content\Location; -use Ibexa\Contracts\Core\Persistence\Content\VersionInfo; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; 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; @@ -23,8 +23,6 @@ final class SearchHitToContentSuggestionMapperTest extends TestCase { public function testMap(): void { - $this->markTestIncomplete('This test has not been implemented yet.'); - $mapper = new SearchHitToContentSuggestionMapper( $this->getConfigResolverMock() ); @@ -36,16 +34,19 @@ public function testMap(): void 'contentInfo' => new ContentInfo([ 'name' => 'name', 'mainLanguageCode' => 'eng-GB', - 'mainLocation' => new Location([ - 'pathString' => [1, 2, 3], - ]), + 'mainLocationId' => 1, 'contentTypeId' => 1, ]), 'versionInfo' => new VersionInfo([ - 'contentInfo' => new ContentInfo([ - 'name' => 'name', + 'initialLanguageCode' => 'eng-GB', + 'names' => ['eng-GB' => 'name_eng'], + 'contentInfo' => new \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo([ + 'id' => 1, 'mainLanguageCode' => 'eng-GB', 'contentTypeId' => 1, + 'mainLocation' => new Location([ + 'path' => [1, 2, 3, 4, 5, 6, 7], + ]), ]), ]), 'contentType' => new ContentType([ @@ -54,7 +55,14 @@ public function testMap(): void ]), ]) ); + $this->assertInstanceOf(ContentSuggestion::class, $result); + + $this->assertSame($result->getContentId(), 1); + $this->assertSame($result->getParentsLocation(), [6 => 'x', 7 => 'y']); + $this->assertSame($result->getPathString(), '6/7'); + $this->assertSame($result->getName(), 'name_eng'); + $this->assertSame($result->getScore(), 50.0); } private function getConfigResolverMock(): ConfigResolverInterface diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/lib/Model/Suggestion/ContentSuggestionTest.php index 871ed27..15db563 100644 --- a/tests/lib/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/lib/Model/Suggestion/ContentSuggestionTest.php @@ -20,6 +20,7 @@ public function testCreate(): void 1, 'content_type_identifier', 'name', + 1, 'text', [0 => 'text'] ); diff --git a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php index 1eaba4a..c4e51da 100644 --- a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php @@ -21,16 +21,24 @@ public function testCollection(): void $this->assertInstanceOf(MutableArrayList::class, $collection); $this->assertInstanceOf(SuggestionCollection::class, $collection); - $collection->append(new ContentSuggestion(1, 'article', 'test')); - $collection->append(new ContentSuggestion(2, 'article', 'test2')); + $collection->append(new ContentSuggestion(10, 'article', 'test', 1)); + $collection->append(new ContentSuggestion(20, 'article', 'test2', 1)); + $collection->append(new ContentSuggestion(30, 'article', 'test3', 1)); + $collection->append(new ContentSuggestion(10, 'article', 'test4', 1)); + $collection->append(new ContentSuggestion(50, 'article', 'test5', 1)); + $collection->append(new ContentSuggestion(60, 'article', 'test6', 1)); + $collection->append(new ContentSuggestion(70, 'article', 'test7', 1)); - $this->assertCount(2, $collection); + $this->assertCount(7, $collection); foreach ($collection as $item) { $this->assertInstanceOf(ContentSuggestion::class, $item); } - $this->expectException(\TypeError::class); - $collection->append(new \stdClass()); + $collection->sortByScore(); + $this->assertSame(70.0, $collection->first()->getScore()); + + $collection->truncate(5); + $this->assertCount(5, $collection); } } diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php index dc0b827..0281e74 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -15,7 +15,7 @@ final class SuggestionTest extends TestCase { public function testSuggestionCreate(): void { - $implementation = new class('name', 'text', [0 => 'text']) extends SuggestionAlias { + $implementation = new class(50, 'name', 'text', [0]) extends SuggestionAlias { public function getType(): string { return 'test_implementation'; @@ -25,7 +25,7 @@ public function getType(): string $this->assertInstanceOf(SuggestionAlias::class, $implementation); $this->assertSame('name', $implementation->getName()); $this->assertSame('text', $implementation->getPathString()); - $this->assertSame([0 => 'text'], $implementation->getParentsLocation()); + $this->assertSame([0], $implementation->getParentsLocation()); $this->assertSame('test_implementation', $implementation->getType()); $implementation->addPath(1, 'text2'); diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 4701fec..10aee63 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -79,6 +79,9 @@ static function (BeforeSuggestionEvent $event) { self::assertInstanceOf(SuggestionCollection::class, $result); } + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Service\SuggestionServiceInterface + */ private function getSuggestionServiceMock(): SuggestionServiceInterface { $suggestionServiceMock = $this->getMockBuilder(SuggestionServiceInterface::class) @@ -88,6 +91,9 @@ private function getSuggestionServiceMock(): SuggestionServiceInterface return $suggestionServiceMock; } + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Symfony\Contracts\EventDispatcher\EventDispatcherInterface + */ private function getEventDispatcherMock(): EventDispatcherInterface { $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php index f285742..4005258 100644 --- a/tests/lib/Service/SuggestionServiceTest.php +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -8,6 +8,7 @@ namespace Ibexa\Tests\Search\Service; +use Ibexa\Search\EventDispatcher\Event\AbstractSuggestion; use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\SuggestionService; @@ -22,7 +23,7 @@ public function testSuggestion(): void $eventDispatcherMock ->method('dispatch') ->willReturnCallback( - static function ($event) { + static function (AbstractSuggestion $event): AbstractSuggestion { return $event; } ); @@ -33,6 +34,9 @@ static function ($event) { self::assertInstanceOf(SuggestionCollection::class, $result); } + /** + * @return \PHPUnit\Framework\MockObject\MockObject|\Symfony\Contracts\EventDispatcher\EventDispatcherInterface + */ private function getEventDispatcherMock(): EventDispatcherInterface { $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) From bfa10216b3335040ef0e2016dfc0d108a2de6d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Mon, 23 Oct 2023 15:19:31 +0200 Subject: [PATCH 14/66] Fixed tests and models --- .../EventListener/ContentSuggestionSubscriber.php | 2 +- src/lib/Mapper/SearchHitToContentSuggestionMapper.php | 2 +- src/lib/Model/Suggestion/ContentSuggestion.php | 2 +- src/lib/Model/Suggestion/Suggestion.php | 6 +++--- tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php | 2 +- tests/lib/Model/Suggestion/SuggestionTest.php | 5 +++-- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 7360d5b..ccb72c5 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -75,7 +75,7 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion foreach ($mappedResult->getParentsLocation() as $locationId => $name) { try { $location = $this->locationService->loadLocation($locationId); - $mappedResult->addPath($locationId, (string) $location->getContent()->getName()); + $mappedResult->addPath($locationId, $location->getContent()->getName() ?? ''); } catch (NotFoundException $e) { } catch (UnauthorizedException $e) { } diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 1abd9a5..97ed337 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -51,7 +51,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), implode('/', $parentsLocation), - array_flip($parentsLocation) + array_fill_keys($parentsLocation, '') ); } } diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/lib/Model/Suggestion/ContentSuggestion.php index f62cbb1..b70cbbb 100644 --- a/src/lib/Model/Suggestion/ContentSuggestion.php +++ b/src/lib/Model/Suggestion/ContentSuggestion.php @@ -15,7 +15,7 @@ final class ContentSuggestion extends Suggestion private string $contentTypeIdentifier; /** - * @param array $parentLocation + * @param array $parentLocation */ public function __construct( float $score, diff --git a/src/lib/Model/Suggestion/Suggestion.php b/src/lib/Model/Suggestion/Suggestion.php index 58aafe1..5ae6d77 100644 --- a/src/lib/Model/Suggestion/Suggestion.php +++ b/src/lib/Model/Suggestion/Suggestion.php @@ -18,11 +18,11 @@ abstract class Suggestion extends ValueObject private string $pathString; - /** @var array */ + /** @var array */ private array $parentsLocation; /** - * @param array $parentsLocation + * @param array $parentsLocation */ public function __construct( float $score, @@ -54,7 +54,7 @@ public function getPathString(): string } /** - * @return array + * @return array */ public function getParentsLocation(): array { diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index 3778dd9..46e444d 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -59,7 +59,7 @@ public function testMap(): void $this->assertInstanceOf(ContentSuggestion::class, $result); $this->assertSame($result->getContentId(), 1); - $this->assertSame($result->getParentsLocation(), [6 => 'x', 7 => 'y']); + $this->assertSame($result->getParentsLocation(), [6 => '', 7 => '']); $this->assertSame($result->getPathString(), '6/7'); $this->assertSame($result->getName(), 'name_eng'); $this->assertSame($result->getScore(), 50.0); diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php index 0281e74..db8337a 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -15,7 +15,7 @@ final class SuggestionTest extends TestCase { public function testSuggestionCreate(): void { - $implementation = new class(50, 'name', 'text', [0]) extends SuggestionAlias { + $implementation = new class(50, 'name', 'text', [0 => null]) extends SuggestionAlias { public function getType(): string { return 'test_implementation'; @@ -25,9 +25,10 @@ public function getType(): string $this->assertInstanceOf(SuggestionAlias::class, $implementation); $this->assertSame('name', $implementation->getName()); $this->assertSame('text', $implementation->getPathString()); - $this->assertSame([0], $implementation->getParentsLocation()); + $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()); } From 3d8fe63d8157863f0e926e55df6902e80e9ab9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Mon, 23 Oct 2023 15:21:10 +0200 Subject: [PATCH 15/66] Generated baseline --- phpstan-baseline.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0083772..ba9018e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -250,6 +250,11 @@ parameters: count: 1 path: src/lib/Mapper/PagerSearchContentToDataMapper.php + - + message: "#^Property Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Search\\\\SearchHit\\:\\:\\$score \\(float\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: src/lib/Mapper/SearchHitToContentSuggestionMapper.php + - message: "#^Method Ibexa\\\\Search\\\\QueryType\\\\SearchQueryType\\:\\:doGetQuery\\(\\) has parameter \\$parameters with no value type specified in iterable type array\\.$#" count: 1 From 12d95474cdb735e9b87be971350e1bf1fefbff32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 24 Oct 2023 10:17:47 +0200 Subject: [PATCH 16/66] Fixed code suggestions --- .../Controller/SuggestionController.php | 8 +--- .../SuggestionQueryParamConverter.php | 40 +++++++++++++++++++ src/bundle/Resources/config/routing.yaml | 3 +- src/bundle/Resources/config/services.yaml | 6 +++ .../ContentSuggestionSubscriber.php | 3 +- .../Model/Suggestion/SuggestionCollection.php | 6 ++- .../Service/Event/SuggestionServiceTest.php | 12 +----- tests/lib/Service/SuggestionServiceTest.php | 7 +--- 8 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php diff --git a/src/bundle/Controller/SuggestionController.php b/src/bundle/Controller/SuggestionController.php index 3a5a69c..68e2e7c 100644 --- a/src/bundle/Controller/SuggestionController.php +++ b/src/bundle/Controller/SuggestionController.php @@ -12,7 +12,6 @@ use Ibexa\Search\Service\SuggestionService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer\SerializerInterface; final class SuggestionController extends AbstractController @@ -29,13 +28,8 @@ public function __construct( $this->serializer = $serializer; } - public function suggestAction(Request $request): JsonResponse + public function suggestAction(SuggestionQuery $suggestionQuery): JsonResponse { - $query = $request->get('query'); - $limit = (int) $request->get('limit'); - $language = $request->get('language'); - - $suggestionQuery = new SuggestionQuery($query, $limit, $language); $result = $this->suggestionService->suggest($suggestionQuery); $serializedResults = $this->serializer->serialize($result, 'json'); diff --git a/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php b/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php new file mode 100644 index 0000000..1b4d272 --- /dev/null +++ b/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php @@ -0,0 +1,40 @@ +defaultLimit = $defaultLimit; + } + + public function apply(Request $request, ParamConverter $configuration) + { + $query = $request->get('query'); + $limit = $request->query->getInt('limit', $this->defaultLimit); + $language = $request->get('language'); + + $suggestionQuery = new SuggestionQuery($query, $limit, $language); + + $request->attributes->set($configuration->getName(), $suggestionQuery); + } + + public function supports(ParamConverter $configuration) + { + return SuggestionQuery::class === $configuration->getClass(); + } +} diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index 290c576..6e54cca 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -7,5 +7,4 @@ ibexa.search: ibexa.search.suggestion: path: /suggestion methods: ['GET'] - defaults: - _controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' + controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 6ea54f6..18072cd 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -35,3 +35,9 @@ services: Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' Ibexa\Search\Service\SuggestionService: ~ + + Ibexa\Bundle\Search\Request\ParamConverter\SuggestionQueryParamConverter: + arguments: + $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.min_query_length%' + tags: + - { name: 'request.param_converter', priority: 0 } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index ccb72c5..aa1ba05 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -76,8 +76,7 @@ public function onContentSuggestion(ContentSuggestion $event): ContentSuggestion try { $location = $this->locationService->loadLocation($locationId); $mappedResult->addPath($locationId, $location->getContent()->getName() ?? ''); - } catch (NotFoundException $e) { - } catch (UnauthorizedException $e) { + } catch (NotFoundException|UnauthorizedException $e) { } } $collection->append($mappedResult); diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index 3ee9450..a3ae8aa 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -9,6 +9,7 @@ namespace Ibexa\Search\Model\Suggestion; use Ibexa\Contracts\Core\Collection\MutableArrayList; +use Ibexa\Contracts\Core\Exception\InvalidArgumentException; /** * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Search\Model\Suggestion\Suggestion> @@ -21,8 +22,9 @@ final class SuggestionCollection extends MutableArrayList public function append($item): void { if (!$item instanceof Suggestion) { - throw new \TypeError( - \sprintf( + throw new InvalidArgumentException( + '$item', + sprintf( 'Argument 1 passed to %s::append() must be an instance of %s, %s given', __CLASS__, Suggestion::class, diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 10aee63..8b7bdfc 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -32,11 +32,7 @@ public function testSuggestion(): void $this->isInstanceOf(AfterSuggestionEvent::class), ] ) - ->willReturnCallback( - static function ($event) { - return $event; - } - ); + ->willReturnArgument(0); $innerServiceMock = $this->getSuggestionServiceMock(); $innerServiceMock @@ -55,11 +51,7 @@ public function testSuggestionStopPropagation(): void $eventDispatcherMock ->expects(self::once()) ->method('dispatch') - ->withConsecutive( - [ - $this->isInstanceOf(BeforeSuggestionEvent::class), - ] - ) + ->with(self::isInstanceOf(BeforeSuggestionEvent::class)) ->willReturnCallback( static function (BeforeSuggestionEvent $event) { $event->stopPropagation(); diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php index 4005258..341bc9a 100644 --- a/tests/lib/Service/SuggestionServiceTest.php +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -8,7 +8,6 @@ namespace Ibexa\Tests\Search\Service; -use Ibexa\Search\EventDispatcher\Event\AbstractSuggestion; use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\SuggestionService; @@ -22,11 +21,7 @@ public function testSuggestion(): void $eventDispatcherMock = $this->getEventDispatcherMock(); $eventDispatcherMock ->method('dispatch') - ->willReturnCallback( - static function (AbstractSuggestion $event): AbstractSuggestion { - return $event; - } - ); + ->willReturnArgument(0); $service = new SuggestionService($eventDispatcherMock); $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); From b1689ab420f72b9677fc5c5e079fb4af82b99198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 24 Oct 2023 10:27:27 +0200 Subject: [PATCH 17/66] Added ParamConverter test --- .../SuggestionQueryParamConverterTest.php | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php diff --git a/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php b/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php new file mode 100644 index 0000000..232b990 --- /dev/null +++ b/tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php @@ -0,0 +1,85 @@ +converter = new SuggestionQueryParamConverter(self::DEFAULT_LIMIT); + } + + /** + * @dataProvider provideSupportsTestData + */ + public function testSupports(string $class, bool $expectedResult): void + { + $configuration = new ParamConverter([]); + $configuration->setClass($class); + + $this->assertSame($expectedResult, $this->converter->supports($configuration)); + } + + public function provideSupportsTestData(): array + { + return [ + 'Supports SuggestionQuery' => [SuggestionQuery::class, true], + 'Does not support other classes' => [\stdClass::class, false], + ]; + } + + /** + * @dataProvider provideApplyTestData + */ + public function testApply(array $requestData, SuggestionQuery $expectedSuggestionQuery): void + { + $configuration = new ParamConverter([]); + $configuration->setName('suggestion'); + $configuration->setClass(SuggestionQuery::class); + + $request = new Request([], [], [], [], [], [], []); + $request->query->add($requestData); + + $this->converter->apply($request, $configuration); + + /** @var \Ibexa\Search\Model\SuggestionQuery $suggestionQuery */ + $suggestionQuery = $request->attributes->get('suggestion'); + + $this->assertInstanceOf(SuggestionQuery::class, $suggestionQuery); + $this->assertEquals($expectedSuggestionQuery, $suggestionQuery); + } + + public function provideApplyTestData(): array + { + return [ + 'All parameters provided' => [ + ['query' => 'test', 'limit' => 5, 'language' => 'en'], + new SuggestionQuery('test', 5, 'en'), + ], + 'Only query provided' => [ + ['query' => 'test'], + new SuggestionQuery('test', self::DEFAULT_LIMIT, null), + ], + 'Limit falls back to default' => [ + ['query' => 'test', 'language' => 'en'], + new SuggestionQuery('test', self::DEFAULT_LIMIT, 'en'), + ], + ]; + } +} 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 18/66] 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, + ]), + ]); + } +} From c61c78148fb79a5ca124d436dc03ac4f1c2cd639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 24 Oct 2023 15:43:33 +0200 Subject: [PATCH 19/66] More improvements --- composer.json | 4 +- .../Controller/SuggestionController.php | 17 +++++---- src/bundle/Resources/config/services.yaml | 2 + .../ContentSuggestionNormalizer.php | 38 ------------------- src/lib/Serializer/SuggestionSerializer.php | 35 +++++++++++++++-- .../Event/SuggestionEventTest.php | 2 +- 6 files changed, 47 insertions(+), 51 deletions(-) delete mode 100644 src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php diff --git a/composer.json b/composer.json index aed7538..236fe58 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,10 @@ }, "autoload-dev": { "psr-4": { - "Ibexa\\Tests\\Search\\": "tests/lib/", "Ibexa\\Tests\\Bundle\\Search\\": "tests/bundle/", + "Ibexa\\Tests\\Contracts\\Search\\": "tests/contracts/", + "Ibexa\\Tests\\Search\\": "tests/lib/", + "Ibexa\\Platform\\Tests\\Contracts\\Search\\": "tests/contracts/", "Ibexa\\Platform\\Tests\\Bundle\\Search\\": "tests/bundle/", "Ibexa\\Platform\\Tests\\Search\\": "tests/lib/" } diff --git a/src/bundle/Controller/SuggestionController.php b/src/bundle/Controller/SuggestionController.php index 68e2e7c..1da4351 100644 --- a/src/bundle/Controller/SuggestionController.php +++ b/src/bundle/Controller/SuggestionController.php @@ -9,31 +9,32 @@ namespace Ibexa\Bundle\Search\Controller; use Ibexa\Search\Model\SuggestionQuery; +use Ibexa\Search\Serializer\SuggestionSerializer; use Ibexa\Search\Service\SuggestionService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\Serializer\SerializerInterface; final class SuggestionController extends AbstractController { private SuggestionService $suggestionService; - private SerializerInterface $serializer; - public function __construct( - SerializerInterface $serializer, SuggestionService $suggestionService ) { $this->suggestionService = $suggestionService; - $this->serializer = $serializer; + } + + public static function getSubscribedServices(): array + { + return array_merge(parent::getSubscribedServices(), [ + 'serializer' => SuggestionSerializer::class, + ]); } public function suggestAction(SuggestionQuery $suggestionQuery): JsonResponse { $result = $this->suggestionService->suggest($suggestionQuery); - $serializedResults = $this->serializer->serialize($result, 'json'); - - return (new JsonResponse(null, 200))->setJson($serializedResults); + return $this->json($result); } } diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 9a7f07b..6e8477f 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -45,3 +45,5 @@ services: Ibexa\Search\Provider\ParentLocationProvider: ~ Ibexa\Contracts\Search\Provider\ParentLocationProvider: '@Ibexa\Search\Provider\ParentLocationProvider' + + Ibexa\Search\Serializer\SuggestionSerializer: ~ diff --git a/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php deleted file mode 100644 index 686ae4e..0000000 --- a/src/lib/Serializer/Normalizer/ContentSuggestionNormalizer.php +++ /dev/null @@ -1,38 +0,0 @@ - $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 index 565bad5..fd8cf18 100644 --- a/src/lib/Serializer/SuggestionSerializer.php +++ b/src/lib/Serializer/SuggestionSerializer.php @@ -8,17 +8,46 @@ namespace Ibexa\Search\Serializer; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerInterface; final class SuggestionSerializer implements SerializerInterface { - public function serialize($data, string $format, array $context = []) + private SerializerInterface $serializer; + + public function __construct() + { + $encoders = [new JsonEncoder()]; + + $defaultContext = [ + AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => static function ($object) { + return $object->getId(); + }, + ]; + + $normalizers = [new ObjectNormalizer(null, null, null, null, null, null, $defaultContext)]; + + $this->serializer = new Serializer($normalizers, $encoders); + } + + /** + * @param mixed $data + * @param array $context + */ + public function serialize($data, string $format, array $context = []): string { - // TODO: Implement serialize() method. + return $this->serializer->serialize($data, $format, $context); } + /** + * @param mixed $data + * @param array $context + */ public function deserialize($data, string $type, string $format, array $context = []) { - // TODO: Implement deserialize() method. + return $this->serializer->deserialize($data, $type, $format, $context); } } diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index 5d69cb8..4c8b297 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -13,7 +13,7 @@ use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; -class SuggestionEventTest extends TestCase +final class SuggestionEventTest extends TestCase { public function testConstruct(): void { From fe7f398f07471c39603d664f1b60b541b00a5dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 25 Oct 2023 13:09:07 +0200 Subject: [PATCH 20/66] Code review fixes --- .../Parser/SiteAccessAware/SuggestionParser.php | 2 +- src/bundle/Resources/config/routing.yaml | 2 +- src/bundle/Resources/config/services.yaml | 6 +++--- ...rchHitToContentSuggestionMapperInterface.php} | 4 ++-- .../Model/Suggestion/ContentSuggestion.php | 15 +++++++++++---- .../Model/Suggestion/ParentLocation.php | 2 +- src/contracts/Model/Suggestion/Suggestion.php | 2 +- ...r.php => ParentLocationProviderInterface.php} | 4 ++-- .../ContentSuggestionSubscriber.php | 6 +++--- .../SearchHitToContentSuggestionMapper.php | 9 +++++---- .../Suggestion/ParentLocationCollection.php | 3 ++- .../Model/Suggestion/SuggestionCollection.php | 2 +- src/lib/Provider/ParentLocationProvider.php | 8 ++++---- src/lib/Serializer/SuggestionSerializer.php | 2 +- .../SiteAccessAware/SuggestionParserTest.php | 0 .../ContentSuggestionSubscriberTest.php | 13 +++++++------ .../SearchHitToContentSuggestionMapperTest.php | 9 +++++---- .../Model/Suggestion/ContentSuggestionTest.php | 5 +++-- .../Model/Suggestion/ParentCollectionTest.php | 2 +- .../Suggestion/SuggestionCollectionTest.php | 16 ++++++++-------- tests/lib/Model/Suggestion/SuggestionTest.php | 4 ++-- .../lib/Service/Event/SuggestionServiceTest.php | 2 +- 22 files changed, 65 insertions(+), 53 deletions(-) rename src/contracts/Mapper/{SearchHitToContentSuggestionMapper.php => SearchHitToContentSuggestionMapperInterface.php} (76%) rename src/{lib => contracts}/Model/Suggestion/ContentSuggestion.php (75%) rename src/{lib => contracts}/Model/Suggestion/ParentLocation.php (93%) rename src/contracts/Provider/{ParentLocationProvider.php => ParentLocationProviderInterface.php} (76%) rename tests/bundle/DependencyInjection/{Cofniguration => Configuration}/Parser/SiteAccessAware/SuggestionParserTest.php (100%) diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php index 788af50..fe68827 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php @@ -58,7 +58,7 @@ public function addSemanticConfig(NodeBuilder $nodeBuilder): void * @param array $settings */ private function addSuggestionParameters( - $settings, + array $settings, string $currentScope, ContextualizerInterface $contextualizer ): void { diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index 6e54cca..1d211c0 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -6,5 +6,5 @@ ibexa.search: ibexa.search.suggestion: path: /suggestion - methods: ['GET'] + methods: [GET] controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 6e8477f..ec5bebf 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -32,18 +32,18 @@ services: Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ - Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' + Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' Ibexa\Search\Service\SuggestionService: ~ Ibexa\Bundle\Search\Request\ParamConverter\SuggestionQueryParamConverter: arguments: - $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.min_query_length%' + $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' tags: - { name: 'request.param_converter', priority: 0 } Ibexa\Search\Provider\ParentLocationProvider: ~ - Ibexa\Contracts\Search\Provider\ParentLocationProvider: '@Ibexa\Search\Provider\ParentLocationProvider' + Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface: '@Ibexa\Search\Provider\ParentLocationProvider' Ibexa\Search\Serializer\SuggestionSerializer: ~ diff --git a/src/contracts/Mapper/SearchHitToContentSuggestionMapper.php b/src/contracts/Mapper/SearchHitToContentSuggestionMapperInterface.php similarity index 76% rename from src/contracts/Mapper/SearchHitToContentSuggestionMapper.php rename to src/contracts/Mapper/SearchHitToContentSuggestionMapperInterface.php index 49259fb..28e8332 100644 --- a/src/contracts/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/contracts/Mapper/SearchHitToContentSuggestionMapperInterface.php @@ -9,9 +9,9 @@ namespace Ibexa\Contracts\Search\Mapper; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; -use Ibexa\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; -interface SearchHitToContentSuggestionMapper +interface SearchHitToContentSuggestionMapperInterface { public function map(SearchHit $searchHit): ?ContentSuggestion; } diff --git a/src/lib/Model/Suggestion/ContentSuggestion.php b/src/contracts/Model/Suggestion/ContentSuggestion.php similarity index 75% rename from src/lib/Model/Suggestion/ContentSuggestion.php rename to src/contracts/Model/Suggestion/ContentSuggestion.php index dee9eff..5e8111b 100644 --- a/src/lib/Model/Suggestion/ContentSuggestion.php +++ b/src/contracts/Model/Suggestion/ContentSuggestion.php @@ -6,30 +6,32 @@ */ declare(strict_types=1); -namespace Ibexa\Search\Model\Suggestion; - -use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; +namespace Ibexa\Contracts\Search\Model\Suggestion; final class ContentSuggestion extends Suggestion { private int $contentId; + private int $locationId; + private string $contentTypeIdentifier; /** - * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations + * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations */ public function __construct( float $score, string $contentTypeIdentifier, string $name, int $contentId, + int $locationId, string $pathString = '', array $parentLocations = [] ) { parent::__construct($score, $name, $pathString, $parentLocations); $this->contentId = $contentId; $this->contentTypeIdentifier = $contentTypeIdentifier; + $this->locationId = $locationId; } public function getContentId(): int @@ -37,6 +39,11 @@ public function getContentId(): int return $this->contentId; } + public function getLocationId(): int + { + return $this->locationId; + } + public function getContentTypeIdentifier(): string { return $this->contentTypeIdentifier; diff --git a/src/lib/Model/Suggestion/ParentLocation.php b/src/contracts/Model/Suggestion/ParentLocation.php similarity index 93% rename from src/lib/Model/Suggestion/ParentLocation.php rename to src/contracts/Model/Suggestion/ParentLocation.php index b2af609..d3776ab 100644 --- a/src/lib/Model/Suggestion/ParentLocation.php +++ b/src/contracts/Model/Suggestion/ParentLocation.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Search\Model\Suggestion; +namespace Ibexa\Contracts\Search\Model\Suggestion; final class ParentLocation { diff --git a/src/contracts/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php index f164cbf..814e8ff 100644 --- a/src/contracts/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -22,7 +22,7 @@ abstract class Suggestion extends ValueObject private ParentLocationCollection $parentsLocation; /** - * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations + * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations */ public function __construct( float $score, diff --git a/src/contracts/Provider/ParentLocationProvider.php b/src/contracts/Provider/ParentLocationProviderInterface.php similarity index 76% rename from src/contracts/Provider/ParentLocationProvider.php rename to src/contracts/Provider/ParentLocationProviderInterface.php index 130069c..68bd611 100644 --- a/src/contracts/Provider/ParentLocationProvider.php +++ b/src/contracts/Provider/ParentLocationProviderInterface.php @@ -8,12 +8,12 @@ namespace Ibexa\Contracts\Search\Provider; -interface ParentLocationProvider +interface ParentLocationProviderInterface { /** * @param array $parentLocationIds * - * @return array<\Ibexa\Search\Model\Suggestion\ParentLocation> + * @return array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> */ public function provide(array $parentLocationIds): array; } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index c80c070..9fa6b5b 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -11,7 +11,7 @@ use Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException; use Ibexa\Contracts\Core\Repository\Values\Content\Query; use Ibexa\Contracts\Search\Event\SuggestionEvent; -use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper; +use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; use Ibexa\Core\Repository\SiteAccessAware\SearchService; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; @@ -23,11 +23,11 @@ final class ContentSuggestionSubscriber implements EventSubscriberInterface, Log private SearchService $searchService; - private SearchHitToContentSuggestionMapper $contentSuggestionMapper; + private SearchHitToContentSuggestionMapperInterface $contentSuggestionMapper; public function __construct( SearchService $searchService, - SearchHitToContentSuggestionMapper $contentSuggestionMapper + SearchHitToContentSuggestionMapperInterface $contentSuggestionMapper ) { $this->searchService = $searchService; $this->contentSuggestionMapper = $contentSuggestionMapper; diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 09f90e2..fa8fab8 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -8,12 +8,12 @@ namespace Ibexa\Search\Mapper; +use Ibexa\Contracts\Core\Repository\Values\Content\Content; 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; +use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; +use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface; final class SearchHitToContentSuggestionMapper implements SearchHitToContentSuggestionMapperInterface { @@ -58,6 +58,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $content->getContentType()->identifier, $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), + $content->getVersionInfo()->getContentInfo()->getMainLocation()->id, implode('/', $parentsLocation), $parentCollection ); diff --git a/src/lib/Model/Suggestion/ParentLocationCollection.php b/src/lib/Model/Suggestion/ParentLocationCollection.php index 6710147..4dab861 100644 --- a/src/lib/Model/Suggestion/ParentLocationCollection.php +++ b/src/lib/Model/Suggestion/ParentLocationCollection.php @@ -10,10 +10,11 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; /** - * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Search\Model\Suggestion\ParentLocation> + * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> */ final class ParentLocationCollection extends MutableArrayList { diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/lib/Model/Suggestion/SuggestionCollection.php index 13b2e67..affa113 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/lib/Model/Suggestion/SuggestionCollection.php @@ -39,7 +39,7 @@ public function append($item): void public function sortByScore(): void { - usort($this->items, static function ($a, $b) { + usort($this->items, static function ($a, $b): int { return $b->getScore() <=> $a->getScore(); }); } diff --git a/src/lib/Provider/ParentLocationProvider.php b/src/lib/Provider/ParentLocationProvider.php index aa8188a..aa29266 100644 --- a/src/lib/Provider/ParentLocationProvider.php +++ b/src/lib/Provider/ParentLocationProvider.php @@ -9,10 +9,10 @@ namespace Ibexa\Search\Provider; use Ibexa\Contracts\Core\Repository\LocationService; -use Ibexa\Contracts\Search\Provider\ParentLocationProvider as ParentLocationMapperInterface; -use Ibexa\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface; -final class ParentLocationProvider implements ParentLocationMapperInterface +final class ParentLocationProvider implements ParentLocationProviderInterface { private LocationService $locationService; @@ -24,7 +24,7 @@ public function __construct(LocationService $locationService) /** * @param array $parentLocationIds * - * @return array<\Ibexa\Search\Model\Suggestion\ParentLocation> + * @return array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> */ public function provide(array $parentLocationIds): array { diff --git a/src/lib/Serializer/SuggestionSerializer.php b/src/lib/Serializer/SuggestionSerializer.php index fd8cf18..05251b4 100644 --- a/src/lib/Serializer/SuggestionSerializer.php +++ b/src/lib/Serializer/SuggestionSerializer.php @@ -23,7 +23,7 @@ public function __construct() $encoders = [new JsonEncoder()]; $defaultContext = [ - AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => static function ($object) { + AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => static function ($object): int { return $object->getId(); }, ]; diff --git a/tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/SuggestionParserTest.php b/tests/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParserTest.php similarity index 100% rename from tests/bundle/DependencyInjection/Cofniguration/Parser/SiteAccessAware/SuggestionParserTest.php rename to tests/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParserTest.php diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php index a966f08..1b1164a 100644 --- a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -11,11 +11,11 @@ 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\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; +use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion as ContentSuggestionModel; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Core\Repository\SiteAccessAware\SearchService; 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; @@ -65,17 +65,18 @@ private function getSearchServiceMock(): SearchService } /** - * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapper + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface */ - private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContentSuggestionMapper + private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContentSuggestionMapperInterface { - $searchHitToContentSuggestionMapperMock = $this->createMock(SearchHitToContentSuggestionMapper::class); + $searchHitToContentSuggestionMapperMock = $this->createMock(SearchHitToContentSuggestionMapperInterface::class); $searchHitToContentSuggestionMapperMock->method('map')->willReturn( new ContentSuggestionModel( 10.0, 'test', 'test', 1, + 2, 'test', [ new ParentLocation(1, 2, 'test'), diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index 1e783be..ffc30a7 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -11,14 +11,14 @@ 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\Contracts\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface 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; @@ -49,6 +49,7 @@ public function testMap(): void 'mainLanguageCode' => 'eng-GB', 'contentTypeId' => 1, 'mainLocation' => new Location([ + 'id' => 8, 'path' => [1, 2, 3, 4, 5, 6, 7], ]), ]), @@ -81,7 +82,7 @@ private function getConfigResolverMock(): ConfigResolverInterface } /** - * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Provider\ParentLocationProvider + * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface */ private function getParentLocationProviderMock(): ParentLocationProviderInterface { diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/lib/Model/Suggestion/ContentSuggestionTest.php index 263f742..9ada15c 100644 --- a/tests/lib/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/lib/Model/Suggestion/ContentSuggestionTest.php @@ -8,9 +8,9 @@ namespace Ibexa\Tests\Search\Model\Suggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; -use Ibexa\Search\Model\Suggestion\ContentSuggestion; -use Ibexa\Search\Model\Suggestion\ParentLocation; use Ibexa\Search\Model\Suggestion\ParentLocationCollection; use Ibexa\Tests\Core\Search\TestCase; @@ -23,6 +23,7 @@ public function testCreate(): void 'content_type_identifier', 'name', 1, + 2, 'text', [0 => new ParentLocation(0, 1, 'text')] ); diff --git a/tests/lib/Model/Suggestion/ParentCollectionTest.php b/tests/lib/Model/Suggestion/ParentCollectionTest.php index 5c473fe..cc43abd 100644 --- a/tests/lib/Model/Suggestion/ParentCollectionTest.php +++ b/tests/lib/Model/Suggestion/ParentCollectionTest.php @@ -10,7 +10,7 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; -use Ibexa\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Search\Model\Suggestion\ParentLocationCollection; use PHPUnit\Framework\TestCase; diff --git a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php index c9ebdf8..c9d53c5 100644 --- a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionCollectionTest.php @@ -9,7 +9,7 @@ namespace Ibexa\Tests\Search\Model\Suggestion; use Ibexa\Contracts\Core\Collection\MutableArrayList; -use Ibexa\Search\Model\Suggestion\ContentSuggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Search\Model\Suggestion\SuggestionCollection; use PHPUnit\Framework\TestCase; @@ -21,13 +21,13 @@ public function testCollection(): void 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)); - $collection->append(new ContentSuggestion(30, 'article', 'test3', 1)); - $collection->append(new ContentSuggestion(10, 'article', 'test4', 1)); - $collection->append(new ContentSuggestion(50, 'article', 'test5', 1)); - $collection->append(new ContentSuggestion(60, 'article', 'test6', 1)); - $collection->append(new ContentSuggestion(70, 'article', 'test7', 1)); + $collection->append(new ContentSuggestion(10, 'article', 'test', 1, 2)); + $collection->append(new ContentSuggestion(20, 'article', 'test2', 1, 2)); + $collection->append(new ContentSuggestion(30, 'article', 'test3', 1, 2)); + $collection->append(new ContentSuggestion(10, 'article', 'test4', 1, 2)); + $collection->append(new ContentSuggestion(50, 'article', 'test5', 1, 2)); + $collection->append(new ContentSuggestion(60, 'article', 'test6', 1, 2)); + $collection->append(new ContentSuggestion(70, 'article', 'test7', 1, 2)); self::assertCount(7, $collection); diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php index 0bfc7ec..02a241b 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -8,8 +8,8 @@ namespace Ibexa\Tests\Search\Model\Suggestion; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; -use Ibexa\Search\Model\Suggestion\ParentLocation; use PHPUnit\Framework\TestCase; final class SuggestionTest extends TestCase @@ -33,7 +33,7 @@ public function testSuggestionCreate(): void } /** - * @param array<\Ibexa\Search\Model\Suggestion\ParentLocation> $parentLocations + * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations */ private function createSuggestion( int $score, diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 8b7bdfc..3cc1a06 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -53,7 +53,7 @@ public function testSuggestionStopPropagation(): void ->method('dispatch') ->with(self::isInstanceOf(BeforeSuggestionEvent::class)) ->willReturnCallback( - static function (BeforeSuggestionEvent $event) { + static function (BeforeSuggestionEvent $event): BeforeSuggestionEvent { $event->stopPropagation(); return $event; From 96858778b65c56c5b101415deae70df4c7c64588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 10:03:25 +0200 Subject: [PATCH 21/66] Added Custom Suggestion Normalizers --- src/bundle/Resources/config/services.yaml | 31 ++----------- .../config/services/controllers.yaml | 13 ++++++ .../config/services/normalizers.yaml | 24 ++++++++++ .../config/services/suggestions.yaml | 37 +++++++++++++++ .../Model/Suggestion/ContentSuggestion.php | 5 --- src/contracts/Model/Suggestion/Suggestion.php | 2 - .../SearchHitToContentSuggestionMapper.php | 2 +- .../ContentSuggestionNormalizer.php | 45 +++++++++++++++++++ .../ParentLocationCollectionNormalizer.php | 43 ++++++++++++++++++ .../Suggestion/ParentLocationNormalizer.php | 34 ++++++++++++++ src/lib/Serializer/SuggestionSerializer.php | 40 +---------------- .../SuggestionSerializerFactory.php | 24 ++++++++++ .../Suggestion/ContentSuggestionTest.php | 1 - tests/lib/Model/Suggestion/SuggestionTest.php | 1 - 14 files changed, 225 insertions(+), 77 deletions(-) create mode 100644 src/bundle/Resources/config/services/controllers.yaml create mode 100644 src/bundle/Resources/config/services/normalizers.yaml create mode 100644 src/bundle/Resources/config/services/suggestions.yaml create mode 100644 src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php create mode 100644 src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php create mode 100644 src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php create mode 100644 src/lib/Serializer/SuggestionSerializerFactory.php diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index ec5bebf..85f255b 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -3,6 +3,9 @@ imports: - { resource: twig.yaml } - { resource: sorting_definitions.yaml } - { resource: views.yaml } + - { resource: services/controllers.yaml } + - { resource: services/suggestions.yaml } + - { resource: services/normalizers.yaml } services: _defaults: @@ -10,14 +13,6 @@ services: autowire: true public: false - Ibexa\Bundle\Search\Controller\SearchController: - tags: - - controller.service_arguments - - Ibexa\Bundle\Search\Controller\SuggestionController: - tags: - - controller.service_arguments - Ibexa\Search\Mapper\PagerSearchContentToDataMapper: arguments: $contentTypeService: '@ibexa.api.service.content_type' @@ -27,23 +22,3 @@ services: $languageService: '@ibexa.api.service.language' Ibexa\Search\QueryType\SearchQueryType: ~ - - Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ - - Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ - - Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' - - Ibexa\Search\Service\SuggestionService: ~ - - Ibexa\Bundle\Search\Request\ParamConverter\SuggestionQueryParamConverter: - arguments: - $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' - tags: - - { name: 'request.param_converter', priority: 0 } - - Ibexa\Search\Provider\ParentLocationProvider: ~ - - Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface: '@Ibexa\Search\Provider\ParentLocationProvider' - - Ibexa\Search\Serializer\SuggestionSerializer: ~ diff --git a/src/bundle/Resources/config/services/controllers.yaml b/src/bundle/Resources/config/services/controllers.yaml new file mode 100644 index 0000000..6e61fcd --- /dev/null +++ b/src/bundle/Resources/config/services/controllers.yaml @@ -0,0 +1,13 @@ +services: + _defaults: + autoconfigure: true + autowire: true + public: false + + Ibexa\Bundle\Search\Controller\SearchController: + tags: + - controller.service_arguments + + Ibexa\Bundle\Search\Controller\SuggestionController: + tags: + - controller.service_arguments diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml new file mode 100644 index 0000000..f1cdc5e --- /dev/null +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -0,0 +1,24 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer: + tags: + - { name: 'ibexa.search.serializer.normalizer' } + + Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationCollectionNormalizer: + tags: + - { name: 'ibexa.search.serializer.normalizer' } + + Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationNormalizer: + tags: + - { name: 'ibexa.search.serializer.normalizer' } + + Ibexa\Search\Serializer\SuggestionSerializerFactory: ~ + + Ibexa\Search\Serializer\SuggestionSerializer: + factory: '@Ibexa\Search\Serializer\SuggestionSerializerFactory' + arguments: + $normalizers: !tagged { tag: 'ibexa.search.serializer.normalizer' } diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml new file mode 100644 index 0000000..082234c --- /dev/null +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -0,0 +1,37 @@ +parameters: + ibexa.site_access.config.default.search.suggestion.result_limit: 5 + +services: + _defaults: + autoconfigure: true + autowire: true + public: false + + Ibexa\Bundle\Search\Request\ParamConverter\SuggestionQueryParamConverter: + arguments: + $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' + tags: + - { name: 'request.param_converter', priority: 0 } + + Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ + + Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ + + Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface: '@Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper' + + Ibexa\Search\Service\SuggestionService: ~ + + Ibexa\Contracts\Search\Service\SuggestionServiceInterface: '@Ibexa\Search\Service\SuggestionService' + + Ibexa\Search\Service\Event\SuggestionService: + decorates: Ibexa\Contracts\Search\Service\SuggestionServiceInterface + + +# Ibexa\Taxonomy\Service\Decorator\SearchEngineIndexerTaxonomyEntryAssignmentServiceDecorator: +# decorates: Ibexa\Taxonomy\Service\TaxonomyEntryAssignmentService +# arguments: +# $innerService: '@.inner' + + Ibexa\Search\Provider\ParentLocationProvider: ~ + + Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface: '@Ibexa\Search\Provider\ParentLocationProvider' diff --git a/src/contracts/Model/Suggestion/ContentSuggestion.php b/src/contracts/Model/Suggestion/ContentSuggestion.php index 5e8111b..ac92a8f 100644 --- a/src/contracts/Model/Suggestion/ContentSuggestion.php +++ b/src/contracts/Model/Suggestion/ContentSuggestion.php @@ -48,9 +48,4 @@ public function getContentTypeIdentifier(): string { return $this->contentTypeIdentifier; } - - public function getType(): string - { - return 'content'; - } } diff --git a/src/contracts/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php index 814e8ff..87e0761 100644 --- a/src/contracts/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -57,6 +57,4 @@ public function getParentLocations(): ParentLocationCollection { return $this->parentsLocation; } - - abstract public function getType(): string; } diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index fa8fab8..45844a3 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -58,7 +58,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $content->getContentType()->identifier, $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), - $content->getVersionInfo()->getContentInfo()->getMainLocation()->id, + $content->getVersionInfo()->getContentInfo()->getMainLocation()->id ?? 0, implode('/', $parentsLocation), $parentCollection ); diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php new file mode 100644 index 0000000..a1ff0b4 --- /dev/null +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -0,0 +1,45 @@ +parentLocationCollectionNormalizer = $parentLocationCollectionNormalizer; + } + + /** + * @param \Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion $object + * + * @return array + */ + public function normalize($object, string $format = null, array $context = []): array + { + return [ + 'contentTypeIdentifier' => $object->getContentTypeIdentifier(), + 'name' => $object->getName(), + 'contentId' => $object->getContentId(), + 'locationId' => $object->getLocationId(), + 'pathString' => $object->getPathString(), + 'parentLocations' => $this->parentLocationCollectionNormalizer->normalize($object->getParentLocations()), + 'type' => 'content', + ]; + } + + public function supportsNormalization($data, string $format = null): bool + { + return $data instanceof ContentSuggestion; + } +} diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php new file mode 100644 index 0000000..751086a --- /dev/null +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -0,0 +1,43 @@ +parentLocationNormalizer = $parentLocationNormalizer; + } + + /** + * @param \Ibexa\Search\Model\Suggestion\ParentLocationCollection $object + * + * @return array, array> + */ + public function normalize($object, string $format = null, array $context = []): array + { + $normalizedData = []; + + foreach ($object as $parentLocation) { + $normalizedData[] = $this->parentLocationNormalizer->normalize($parentLocation); + } + + return $normalizedData; + } + + public function supportsNormalization($data, string $format = null): bool + { + return $data instanceof ParentLocationCollection; + } +} diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php new file mode 100644 index 0000000..0d4a413 --- /dev/null +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php @@ -0,0 +1,34 @@ + + */ + public function normalize($object, string $format = null, array $context = []): array + { + return [ + 'contentId' => $object->getContentId(), + 'locationId' => $object->getLocationId(), + 'name' => $object->getName(), + ]; + } + + public function supportsNormalization($data, string $format = null): bool + { + return $data instanceof ParentLocation; + } +} diff --git a/src/lib/Serializer/SuggestionSerializer.php b/src/lib/Serializer/SuggestionSerializer.php index 05251b4..9ec0c62 100644 --- a/src/lib/Serializer/SuggestionSerializer.php +++ b/src/lib/Serializer/SuggestionSerializer.php @@ -8,46 +8,8 @@ namespace Ibexa\Search\Serializer; -use Symfony\Component\Serializer\Encoder\JsonEncoder; -use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; -use Symfony\Component\Serializer\SerializerInterface; -final class SuggestionSerializer implements SerializerInterface +final class SuggestionSerializer extends Serializer { - private SerializerInterface $serializer; - - public function __construct() - { - $encoders = [new JsonEncoder()]; - - $defaultContext = [ - AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => static function ($object): int { - return $object->getId(); - }, - ]; - - $normalizers = [new ObjectNormalizer(null, null, null, null, null, null, $defaultContext)]; - - $this->serializer = new Serializer($normalizers, $encoders); - } - - /** - * @param mixed $data - * @param array $context - */ - public function serialize($data, string $format, array $context = []): string - { - return $this->serializer->serialize($data, $format, $context); - } - - /** - * @param mixed $data - * @param array $context - */ - public function deserialize($data, string $type, string $format, array $context = []) - { - return $this->serializer->deserialize($data, $type, $format, $context); - } } diff --git a/src/lib/Serializer/SuggestionSerializerFactory.php b/src/lib/Serializer/SuggestionSerializerFactory.php new file mode 100644 index 0000000..4296b55 --- /dev/null +++ b/src/lib/Serializer/SuggestionSerializerFactory.php @@ -0,0 +1,24 @@ + $normalizers + */ + public function __invoke(array $normalizers): SuggestionSerializer + { + $encoders = [new JsonEncoder()]; + + return new SuggestionSerializer($normalizers, $encoders); + } +} diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/lib/Model/Suggestion/ContentSuggestionTest.php index 9ada15c..8e10cff 100644 --- a/tests/lib/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/lib/Model/Suggestion/ContentSuggestionTest.php @@ -31,7 +31,6 @@ public function testCreate(): void 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/SuggestionTest.php b/tests/lib/Model/Suggestion/SuggestionTest.php index 02a241b..92ad28d 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/lib/Model/Suggestion/SuggestionTest.php @@ -28,7 +28,6 @@ public function testSuggestionCreate(): void 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()); } From 89a9a39bfc8d23041f732bd8ae8df78881df5bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 10:21:12 +0200 Subject: [PATCH 22/66] Fixed code smells --- src/contracts/Event/AfterSuggestionEvent.php | 2 +- src/contracts/Event/BeforeSuggestionEvent.php | 2 +- src/contracts/Event/SuggestionEvent.php | 2 +- .../Model/Suggestion/ParentLocationCollection.php | 8 ++++---- src/contracts/Model/Suggestion/Suggestion.php | 1 - .../Model/Suggestion/SuggestionCollection.php | 7 ++++--- .../Service/Decorator/SuggestionServiceDecorator.php | 2 +- src/contracts/Service/SuggestionServiceInterface.php | 2 +- src/lib/Mapper/SearchHitToContentSuggestionMapper.php | 4 +--- .../Suggestion/ParentLocationCollectionNormalizer.php | 4 ++-- src/lib/Serializer/SuggestionSerializerFactory.php | 4 +++- src/lib/Service/Event/SuggestionService.php | 2 +- src/lib/Service/SuggestionService.php | 2 +- .../EventDispatcher/Event/SuggestionEventTest.php | 2 +- .../Model/Suggestion/ContentSuggestionTest.php | 4 ++-- .../Model/Suggestion/ParentCollectionTest.php | 4 ++-- .../Model/Suggestion/SuggestionCollectionTest.php | 4 ++-- .../Model/Suggestion/SuggestionTest.php | 2 +- .../Mapper/SearchHitToContentSuggestionMapperTest.php | 10 +++++----- tests/lib/Service/Event/SuggestionServiceTest.php | 10 +++------- tests/lib/Service/SuggestionServiceTest.php | 2 +- 21 files changed, 38 insertions(+), 42 deletions(-) rename src/{lib => contracts}/Model/Suggestion/ParentLocationCollection.php (82%) rename src/{lib => contracts}/Model/Suggestion/SuggestionCollection.php (89%) rename tests/{lib => contracts}/Model/Suggestion/ContentSuggestionTest.php (90%) rename tests/{lib => contracts}/Model/Suggestion/ParentCollectionTest.php (92%) rename tests/{lib => contracts}/Model/Suggestion/SuggestionCollectionTest.php (92%) rename tests/{lib => contracts}/Model/Suggestion/SuggestionTest.php (96%) diff --git a/src/contracts/Event/AfterSuggestionEvent.php b/src/contracts/Event/AfterSuggestionEvent.php index e581c6a..8d7a9aa 100644 --- a/src/contracts/Event/AfterSuggestionEvent.php +++ b/src/contracts/Event/AfterSuggestionEvent.php @@ -9,7 +9,7 @@ namespace Ibexa\Contracts\Search\Event; use Ibexa\Contracts\Core\Repository\Event\AfterEvent; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; final class AfterSuggestionEvent extends AfterEvent diff --git a/src/contracts/Event/BeforeSuggestionEvent.php b/src/contracts/Event/BeforeSuggestionEvent.php index f5610d9..b6edc80 100644 --- a/src/contracts/Event/BeforeSuggestionEvent.php +++ b/src/contracts/Event/BeforeSuggestionEvent.php @@ -9,7 +9,7 @@ namespace Ibexa\Contracts\Search\Event; use Ibexa\Contracts\Core\Repository\Event\BeforeEvent; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; final class BeforeSuggestionEvent extends BeforeEvent diff --git a/src/contracts/Event/SuggestionEvent.php b/src/contracts/Event/SuggestionEvent.php index 1074770..4a8a6da 100644 --- a/src/contracts/Event/SuggestionEvent.php +++ b/src/contracts/Event/SuggestionEvent.php @@ -8,7 +8,7 @@ namespace Ibexa\Contracts\Search\Event; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; final class SuggestionEvent diff --git a/src/lib/Model/Suggestion/ParentLocationCollection.php b/src/contracts/Model/Suggestion/ParentLocationCollection.php similarity index 82% rename from src/lib/Model/Suggestion/ParentLocationCollection.php rename to src/contracts/Model/Suggestion/ParentLocationCollection.php index 4dab861..ddc51c0 100644 --- a/src/lib/Model/Suggestion/ParentLocationCollection.php +++ b/src/contracts/Model/Suggestion/ParentLocationCollection.php @@ -6,15 +6,15 @@ */ declare(strict_types=1); -namespace Ibexa\Search\Model\Suggestion; +namespace Ibexa\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; -use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; /** - * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> + * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList< + * \Ibexa\Contracts\Search\Model\Suggestion\ParentLocation + * > */ final class ParentLocationCollection extends MutableArrayList { diff --git a/src/contracts/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php index 87e0761..58f97b8 100644 --- a/src/contracts/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -9,7 +9,6 @@ namespace Ibexa\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Core\Repository\Values\ValueObject; -use Ibexa\Search\Model\Suggestion\ParentLocationCollection; abstract class Suggestion extends ValueObject { diff --git a/src/lib/Model/Suggestion/SuggestionCollection.php b/src/contracts/Model/Suggestion/SuggestionCollection.php similarity index 89% rename from src/lib/Model/Suggestion/SuggestionCollection.php rename to src/contracts/Model/Suggestion/SuggestionCollection.php index affa113..f92d5e6 100644 --- a/src/lib/Model/Suggestion/SuggestionCollection.php +++ b/src/contracts/Model/Suggestion/SuggestionCollection.php @@ -6,14 +6,15 @@ */ declare(strict_types=1); -namespace Ibexa\Search\Model\Suggestion; +namespace Ibexa\Contracts\Search\Model\Suggestion; 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\Contracts\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/contracts/Service/Decorator/SuggestionServiceDecorator.php b/src/contracts/Service/Decorator/SuggestionServiceDecorator.php index 3dfadd8..9c2e416 100644 --- a/src/contracts/Service/Decorator/SuggestionServiceDecorator.php +++ b/src/contracts/Service/Decorator/SuggestionServiceDecorator.php @@ -8,8 +8,8 @@ namespace Ibexa\Contracts\Search\Service\Decorator; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; abstract class SuggestionServiceDecorator implements SuggestionServiceInterface diff --git a/src/contracts/Service/SuggestionServiceInterface.php b/src/contracts/Service/SuggestionServiceInterface.php index bf57ed5..ec3ebf9 100644 --- a/src/contracts/Service/SuggestionServiceInterface.php +++ b/src/contracts/Service/SuggestionServiceInterface.php @@ -8,7 +8,7 @@ namespace Ibexa\Contracts\Search\Service; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; interface SuggestionServiceInterface diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 45844a3..98298ca 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -53,7 +53,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $parentCollection = $this->parentLocationProvider->provide($parentsLocation); - $suggestion = new ContentSuggestion( + return new ContentSuggestion( $searchHit->score ?? 50, $content->getContentType()->identifier, $content->getName() ?? '', @@ -62,7 +62,5 @@ public function map(SearchHit $searchHit): ?ContentSuggestion implode('/', $parentsLocation), $parentCollection ); - - return $suggestion; } } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php index 751086a..570c3da 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -8,7 +8,7 @@ namespace Ibexa\Search\Serializer\Normalizer\Suggestion; -use Ibexa\Search\Model\Suggestion\ParentLocationCollection; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; final class ParentLocationCollectionNormalizer implements NormalizerInterface @@ -21,7 +21,7 @@ public function __construct(ParentLocationNormalizer $parentLocationNormalizer) } /** - * @param \Ibexa\Search\Model\Suggestion\ParentLocationCollection $object + * @param \Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection $object * * @return array, array> */ diff --git a/src/lib/Serializer/SuggestionSerializerFactory.php b/src/lib/Serializer/SuggestionSerializerFactory.php index 4296b55..3de7fef 100644 --- a/src/lib/Serializer/SuggestionSerializerFactory.php +++ b/src/lib/Serializer/SuggestionSerializerFactory.php @@ -13,7 +13,9 @@ final class SuggestionSerializerFactory { /** - * @param array<\Symfony\Component\Serializer\Normalizer\DenormalizerInterface|\Symfony\Component\Serializer\Normalizer\NormalizerInterface> $normalizers + * @param array< + * \Symfony\Component\Serializer\Normalizer\DenormalizerInterface|\Symfony\Component\Serializer\Normalizer\NormalizerInterface + * > $normalizers */ public function __invoke(array $normalizers): SuggestionSerializer { diff --git a/src/lib/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php index 5006fcf..f7a8d8d 100644 --- a/src/lib/Service/Event/SuggestionService.php +++ b/src/lib/Service/Event/SuggestionService.php @@ -10,9 +10,9 @@ use Ibexa\Contracts\Search\Event\AfterSuggestionEvent; use Ibexa\Contracts\Search\Event\BeforeSuggestionEvent; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\Decorator\SuggestionServiceDecorator; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; diff --git a/src/lib/Service/SuggestionService.php b/src/lib/Service/SuggestionService.php index ffdda95..8620615 100644 --- a/src/lib/Service/SuggestionService.php +++ b/src/lib/Service/SuggestionService.php @@ -9,8 +9,8 @@ namespace Ibexa\Search\Service; use Ibexa\Contracts\Search\Event\SuggestionEvent; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index 4c8b297..e5f878e 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -9,7 +9,7 @@ namespace Ibexa\Tests\Contracts\Search\Event; use Ibexa\Contracts\Search\Event\SuggestionEvent; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; diff --git a/tests/lib/Model/Suggestion/ContentSuggestionTest.php b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php similarity index 90% rename from tests/lib/Model/Suggestion/ContentSuggestionTest.php rename to tests/contracts/Model/Suggestion/ContentSuggestionTest.php index 8e10cff..c10639a 100644 --- a/tests/lib/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php @@ -6,12 +6,12 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\Search\Model\Suggestion; +namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; -use Ibexa\Search\Model\Suggestion\ParentLocationCollection; use Ibexa\Tests\Core\Search\TestCase; final class ContentSuggestionTest extends TestCase diff --git a/tests/lib/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php similarity index 92% rename from tests/lib/Model/Suggestion/ParentCollectionTest.php rename to tests/contracts/Model/Suggestion/ParentCollectionTest.php index cc43abd..6e9a5ad 100644 --- a/tests/lib/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -6,12 +6,12 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\Search\Model\Suggestion; +namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; -use Ibexa\Search\Model\Suggestion\ParentLocationCollection; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use PHPUnit\Framework\TestCase; final class ParentCollectionTest extends TestCase diff --git a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php similarity index 92% rename from tests/lib/Model/Suggestion/SuggestionCollectionTest.php rename to tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index c9d53c5..9e0ad1a 100644 --- a/tests/lib/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -6,11 +6,11 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\Search\Model\Suggestion; +namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use PHPUnit\Framework\TestCase; final class SuggestionCollectionTest extends TestCase diff --git a/tests/lib/Model/Suggestion/SuggestionTest.php b/tests/contracts/Model/Suggestion/SuggestionTest.php similarity index 96% rename from tests/lib/Model/Suggestion/SuggestionTest.php rename to tests/contracts/Model/Suggestion/SuggestionTest.php index 92ad28d..5827470 100644 --- a/tests/lib/Model/Suggestion/SuggestionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionTest.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\Search\Model\Suggestion; +namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index ffc30a7..33e8205 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -13,13 +13,13 @@ use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface 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\ParentLocationCollection; use PHPUnit\Framework\TestCase; final class SearchHitToContentSuggestionMapperTest extends TestCase @@ -62,12 +62,12 @@ public function testMap(): void ); self::assertInstanceOf(ContentSuggestion::class, $result); - self::assertSame($result->getContentId(), 1); - self::assertSame($result->getPathString(), '5/6/7'); + self::assertSame(1, $result->getContentId()); + self::assertSame('5/6/7', $result->getPathString()); self::assertInstanceOf(ParentLocationCollection::class, $result->getParentLocations()); self::assertCount(3, $result->getParentLocations()); - self::assertSame($result->getName(), 'name_eng'); - self::assertSame($result->getScore(), 50.0); + self::assertSame('name_eng', $result->getName()); + self::assertSame(50.0, $result->getScore()); } /** diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 3cc1a06..d58ffd4 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -10,8 +10,8 @@ use Ibexa\Contracts\Search\Event\AfterSuggestionEvent; use Ibexa\Contracts\Search\Event\BeforeSuggestionEvent; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\Event\SuggestionService; use PHPUnit\Framework\TestCase; @@ -76,11 +76,9 @@ static function (BeforeSuggestionEvent $event): BeforeSuggestionEvent { */ private function getSuggestionServiceMock(): SuggestionServiceInterface { - $suggestionServiceMock = $this->getMockBuilder(SuggestionServiceInterface::class) + return $this->getMockBuilder(SuggestionServiceInterface::class) ->disableOriginalConstructor() ->getMock(); - - return $suggestionServiceMock; } /** @@ -88,10 +86,8 @@ private function getSuggestionServiceMock(): SuggestionServiceInterface */ private function getEventDispatcherMock(): EventDispatcherInterface { - $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) + return $this->getMockBuilder(EventDispatcherInterface::class) ->disableOriginalConstructor() ->getMock(); - - return $eventDispatcherMock; } } diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php index 341bc9a..f83a85f 100644 --- a/tests/lib/Service/SuggestionServiceTest.php +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -8,7 +8,7 @@ namespace Ibexa\Tests\Search\Service; -use Ibexa\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\SuggestionService; use PHPUnit\Framework\TestCase; From 429ce34cb57e3da66a9936e1990cda7fc45e3827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 10:38:05 +0200 Subject: [PATCH 23/66] Fixed yaml --- src/bundle/Resources/config/services/suggestions.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 082234c..6a4af36 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -26,12 +26,6 @@ services: Ibexa\Search\Service\Event\SuggestionService: decorates: Ibexa\Contracts\Search\Service\SuggestionServiceInterface - -# Ibexa\Taxonomy\Service\Decorator\SearchEngineIndexerTaxonomyEntryAssignmentServiceDecorator: -# decorates: Ibexa\Taxonomy\Service\TaxonomyEntryAssignmentService -# arguments: -# $innerService: '@.inner' - Ibexa\Search\Provider\ParentLocationProvider: ~ Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface: '@Ibexa\Search\Provider\ParentLocationProvider' From aac1b4f93415a3110be5285ce4b084706f6052db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 10:47:50 +0200 Subject: [PATCH 24/66] Expose route to JS --- src/bundle/Resources/config/routing.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bundle/Resources/config/routing.yaml b/src/bundle/Resources/config/routing.yaml index 1d211c0..4cf7bfa 100644 --- a/src/bundle/Resources/config/routing.yaml +++ b/src/bundle/Resources/config/routing.yaml @@ -1,10 +1,11 @@ ibexa.search: path: /search - methods: ['GET'] - defaults: - _controller: 'Ibexa\Bundle\Search\Controller\SearchController::searchAction' + methods: [GET] + controller: 'Ibexa\Bundle\Search\Controller\SearchController::searchAction' ibexa.search.suggestion: path: /suggestion methods: [GET] controller: 'Ibexa\Bundle\Search\Controller\SuggestionController::suggestAction' + options: + expose: true From ff1728d312b497c7d25441ad68bd2752a20058fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 11:30:41 +0200 Subject: [PATCH 25/66] Fixed sonar cloud allert --- tests/lib/Service/SuggestionServiceTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php index f83a85f..57628f8 100644 --- a/tests/lib/Service/SuggestionServiceTest.php +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -34,10 +34,8 @@ public function testSuggestion(): void */ private function getEventDispatcherMock(): EventDispatcherInterface { - $eventDispatcherMock = $this->getMockBuilder(EventDispatcherInterface::class) + return $this->getMockBuilder(EventDispatcherInterface::class) ->disableOriginalConstructor() ->getMock(); - - return $eventDispatcherMock; } } From c604cdb6e9f30c78c3e7d09298bcc87e8cb6030e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 12:27:51 +0200 Subject: [PATCH 26/66] Fixes --- src/bundle/Resources/config/services/normalizers.yaml | 2 +- src/bundle/Resources/config/services/suggestions.yaml | 1 + .../Suggestion/ContentSuggestionNormalizer.php | 6 +++--- src/lib/Serializer/SuggestionSerializerFactory.php | 11 ++++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index f1cdc5e..b7c4ad9 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -21,4 +21,4 @@ services: Ibexa\Search\Serializer\SuggestionSerializer: factory: '@Ibexa\Search\Serializer\SuggestionSerializerFactory' arguments: - $normalizers: !tagged { tag: 'ibexa.search.serializer.normalizer' } + $normalizers: !tagged_iterator { tag: 'ibexa.search.serializer.normalizer' } diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 6a4af36..6a1380d 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -1,4 +1,5 @@ parameters: + ibexa.site_access.config.default.search.suggestion.min_query_length: 3 ibexa.site_access.config.default.search.suggestion.result_limit: 5 services: diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index a1ff0b4..fe7cc8f 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -28,13 +28,13 @@ public function __construct(ParentLocationCollectionNormalizer $parentLocationCo public function normalize($object, string $format = null, array $context = []): array { return [ - 'contentTypeIdentifier' => $object->getContentTypeIdentifier(), - 'name' => $object->getName(), 'contentId' => $object->getContentId(), 'locationId' => $object->getLocationId(), + 'contentTypeIdentifier' => $object->getContentTypeIdentifier(), + 'name' => $object->getName(), 'pathString' => $object->getPathString(), - 'parentLocations' => $this->parentLocationCollectionNormalizer->normalize($object->getParentLocations()), 'type' => 'content', + 'parentLocations' => $this->parentLocationCollectionNormalizer->normalize($object->getParentLocations()), ]; } diff --git a/src/lib/Serializer/SuggestionSerializerFactory.php b/src/lib/Serializer/SuggestionSerializerFactory.php index 3de7fef..f5d53c5 100644 --- a/src/lib/Serializer/SuggestionSerializerFactory.php +++ b/src/lib/Serializer/SuggestionSerializerFactory.php @@ -13,14 +13,15 @@ final class SuggestionSerializerFactory { /** - * @param array< - * \Symfony\Component\Serializer\Normalizer\DenormalizerInterface|\Symfony\Component\Serializer\Normalizer\NormalizerInterface - * > $normalizers + * @template T of \Symfony\Component\Serializer\Normalizer\DenormalizerInterface + * |\Symfony\Component\Serializer\Normalizer\NormalizerInterface + * @param iterable $normalizers */ - public function __invoke(array $normalizers): SuggestionSerializer + public function __invoke(iterable $normalizers): SuggestionSerializer { $encoders = [new JsonEncoder()]; + $normalizersArray = is_array($normalizers) ? $normalizers : iterator_to_array($normalizers); - return new SuggestionSerializer($normalizers, $encoders); + return new SuggestionSerializer($normalizersArray, $encoders); } } From 609a2c36bde99d65032d83d9a563027aaa568b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 26 Oct 2023 14:25:02 +0200 Subject: [PATCH 27/66] Fixed CS --- src/lib/Serializer/SuggestionSerializerFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/Serializer/SuggestionSerializerFactory.php b/src/lib/Serializer/SuggestionSerializerFactory.php index f5d53c5..e3fa961 100644 --- a/src/lib/Serializer/SuggestionSerializerFactory.php +++ b/src/lib/Serializer/SuggestionSerializerFactory.php @@ -15,6 +15,7 @@ final class SuggestionSerializerFactory /** * @template T of \Symfony\Component\Serializer\Normalizer\DenormalizerInterface * |\Symfony\Component\Serializer\Normalizer\NormalizerInterface + * * @param iterable $normalizers */ public function __invoke(iterable $normalizers): SuggestionSerializer From 3fc20a186a42959fee1c77d0f9ae27712e90464f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 10:05:02 +0200 Subject: [PATCH 28/66] Code review suggestions applied --- .../Parser/SiteAccessAware/SuggestionParser.php | 2 ++ src/bundle/Resources/config/services.yaml | 6 +++++- .../Resources/config/services/controllers.yaml | 13 ------------- .../Mapper/SearchHitToContentSuggestionMapper.php | 4 ++-- .../SearchHitToContentSuggestionMapperTest.php | 4 +--- tests/lib/Service/Event/SuggestionServiceTest.php | 4 ++-- tests/lib/Service/SuggestionServiceTest.php | 3 +-- 7 files changed, 13 insertions(+), 23 deletions(-) delete mode 100644 src/bundle/Resources/config/services/controllers.yaml diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php index fe68827..97da725 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php @@ -86,11 +86,13 @@ private function addSuggestionConfiguration(): ArrayNodeDefinition ->addDefaultsIfNotSet() ->children() ->integerNode('min_query_length') + ->info('The minimum length of the query string needed to trigger suggestions. Minimum value is 3.') ->isRequired() ->defaultValue(3) ->min(3) ->end() ->integerNode('result_limit') + ->info('The maximum number of suggestion results to return. Minimum value is 5.') ->isRequired() ->defaultValue(5) ->min(5) diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 85f255b..4f64027 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -3,7 +3,6 @@ imports: - { resource: twig.yaml } - { resource: sorting_definitions.yaml } - { resource: views.yaml } - - { resource: services/controllers.yaml } - { resource: services/suggestions.yaml } - { resource: services/normalizers.yaml } @@ -13,6 +12,11 @@ services: autowire: true public: false + Ibexa\Bundle\PackageName\Controller\: + resource: './../../Controller' + tags: + - controller.service_arguments + Ibexa\Search\Mapper\PagerSearchContentToDataMapper: arguments: $contentTypeService: '@ibexa.api.service.content_type' diff --git a/src/bundle/Resources/config/services/controllers.yaml b/src/bundle/Resources/config/services/controllers.yaml deleted file mode 100644 index 6e61fcd..0000000 --- a/src/bundle/Resources/config/services/controllers.yaml +++ /dev/null @@ -1,13 +0,0 @@ -services: - _defaults: - autoconfigure: true - autowire: true - public: false - - Ibexa\Bundle\Search\Controller\SearchController: - tags: - - controller.service_arguments - - Ibexa\Bundle\Search\Controller\SuggestionController: - tags: - - controller.service_arguments diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 98298ca..305e049 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -46,7 +46,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion } $parentsLocation = $mainLocation->path; - $position = array_search((string)$rootLocationId, $parentsLocation); + $position = array_search($rootLocationId, $parentsLocation, true); if ($position !== false) { $parentsLocation = array_slice($parentsLocation, (int)$position); } @@ -54,7 +54,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $parentCollection = $this->parentLocationProvider->provide($parentsLocation); return new ContentSuggestion( - $searchHit->score ?? 50, + $searchHit->score ?? 50.0, $content->getContentType()->identifier, $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index 33e8205..abb1f57 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -13,8 +13,7 @@ use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; -use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface as ParentLocationProviderInterface; +use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface; use Ibexa\Core\Repository\Values\Content\Content; use Ibexa\Core\Repository\Values\Content\Location; use Ibexa\Core\Repository\Values\Content\VersionInfo; @@ -64,7 +63,6 @@ public function testMap(): void self::assertInstanceOf(ContentSuggestion::class, $result); self::assertSame(1, $result->getContentId()); self::assertSame('5/6/7', $result->getPathString()); - self::assertInstanceOf(ParentLocationCollection::class, $result->getParentLocations()); self::assertCount(3, $result->getParentLocations()); self::assertSame('name_eng', $result->getName()); self::assertSame(50.0, $result->getScore()); diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index d58ffd4..35f07b4 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -42,7 +42,7 @@ public function testSuggestion(): void $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); - self::assertInstanceOf(SuggestionCollection::class, $result); + self::assertCount(0, $result); } public function testSuggestionStopPropagation(): void @@ -68,7 +68,7 @@ static function (BeforeSuggestionEvent $event): BeforeSuggestionEvent { $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); - self::assertInstanceOf(SuggestionCollection::class, $result); + self::assertCount(0, $result); } /** diff --git a/tests/lib/Service/SuggestionServiceTest.php b/tests/lib/Service/SuggestionServiceTest.php index 57628f8..a978051 100644 --- a/tests/lib/Service/SuggestionServiceTest.php +++ b/tests/lib/Service/SuggestionServiceTest.php @@ -8,7 +8,6 @@ namespace Ibexa\Tests\Search\Service; -use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\SuggestionService; use PHPUnit\Framework\TestCase; @@ -26,7 +25,7 @@ public function testSuggestion(): void $service = new SuggestionService($eventDispatcherMock); $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); - self::assertInstanceOf(SuggestionCollection::class, $result); + self::assertCount(0, $result); } /** From d086898085883523d92b950b0fa29a94b817de67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 10:11:28 +0200 Subject: [PATCH 29/66] Argument Resolver added --- .../SuggestionQueryArgumentResolver.php | 37 ++++++++++++++++ .../SuggestionQueryParamConverter.php | 42 ------------------- src/bundle/Resources/config/services.yaml | 2 +- .../config/services/suggestions.yaml | 4 +- 4 files changed, 40 insertions(+), 45 deletions(-) create mode 100644 src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php delete mode 100644 src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php new file mode 100644 index 0000000..dd2ac6c --- /dev/null +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -0,0 +1,37 @@ +defaultLimit = $defaultLimit; + } + + public function supports(Request $request, ArgumentMetadata $argument): bool + { + return SuggestionQuery::class === $argument->getType(); + } + + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + $query = $request->get('query'); + $limit = $request->query->getInt('limit', $this->defaultLimit); + $language = $request->get('language'); + + yield new SuggestionQuery($query, $limit, $language); + } +} diff --git a/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php b/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php deleted file mode 100644 index 1fb3d80..0000000 --- a/src/bundle/Request/ParamConverter/SuggestionQueryParamConverter.php +++ /dev/null @@ -1,42 +0,0 @@ -defaultLimit = $defaultLimit; - } - - public function apply(Request $request, ParamConverter $configuration): bool - { - $query = $request->get('query'); - $limit = $request->query->getInt('limit', $this->defaultLimit); - $language = $request->get('language'); - - $suggestionQuery = new SuggestionQuery($query, $limit, $language); - - $request->attributes->set($configuration->getName(), $suggestionQuery); - - return true; - } - - 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 4f64027..3c68994 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -12,7 +12,7 @@ services: autowire: true public: false - Ibexa\Bundle\PackageName\Controller\: + Ibexa\Bundle\Search\Controller\: resource: './../../Controller' tags: - controller.service_arguments diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 6a1380d..523d22f 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -8,11 +8,11 @@ services: autowire: true public: false - Ibexa\Bundle\Search\Request\ParamConverter\SuggestionQueryParamConverter: + Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: arguments: $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' tags: - - { name: 'request.param_converter', priority: 0 } + - { name: 'controller.argument_value_resolver', priority: 50 } Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ From ecd2748e9abc8b98a40f355a84f8e806cf4884ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 10:23:16 +0200 Subject: [PATCH 30/66] Updated PHPUnit to v9 --- composer.json | 2 +- .../SuggestionQueryArgumentResolver.php | 1 + .../SuggestionQueryParamConverterTest.php | 93 ------------------- .../Event/SuggestionEventTest.php | 2 +- 4 files changed, 3 insertions(+), 95 deletions(-) delete mode 100644 tests/bundle/Request/ParamConverter/SuggestionQueryParamConverterTest.php diff --git a/composer.json b/composer.json index 236fe58..d6c4054 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "symfony/serializer": "^5.4" }, "require-dev": { - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^9.6.13", "friendsofphp/php-cs-fixer": "^3.0", "ibexa/code-style": "^1.0", "ibexa/doctrine-schema": "~4.6.x-dev", diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index dd2ac6c..eb30a14 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -1,4 +1,5 @@ converter = new SuggestionQueryParamConverter(self::DEFAULT_LIMIT); - } - - /** - * @dataProvider provideSupportsTestData - */ - public function testSupports(string $class, bool $expectedResult): void - { - $configuration = new ParamConverter([]); - $configuration->setClass($class); - - $this->assertSame($expectedResult, $this->converter->supports($configuration)); - } - - /** - * @return array - */ - public function provideSupportsTestData(): array - { - return [ - 'Supports SuggestionQuery' => [SuggestionQuery::class, true], - 'Does not support other classes' => [\stdClass::class, false], - ]; - } - - /** - * @dataProvider provideApplyTestData - * - * @param array{query: string, limit?: int, language?: string|null} $requestData - */ - public function testApply(array $requestData, SuggestionQuery $expectedSuggestionQuery): void - { - $configuration = new ParamConverter([]); - $configuration->setName('suggestion'); - $configuration->setClass(SuggestionQuery::class); - - $request = new Request([], [], [], [], [], []); - $request->query->add($requestData); - - $this->converter->apply($request, $configuration); - - /** @var \Ibexa\Search\Model\SuggestionQuery $suggestionQuery */ - $suggestionQuery = $request->attributes->get('suggestion'); - - $this->assertInstanceOf(SuggestionQuery::class, $suggestionQuery); - $this->assertEquals($expectedSuggestionQuery, $suggestionQuery); - } - - /** - * @return array - */ - public function provideApplyTestData(): array - { - return [ - 'All parameters provided' => [ - ['query' => 'test', 'limit' => 5, 'language' => 'en'], - new SuggestionQuery('test', 5, 'en'), - ], - 'Only query provided' => [ - ['query' => 'test'], - new SuggestionQuery('test', self::DEFAULT_LIMIT, null), - ], - 'Limit falls back to default' => [ - ['query' => 'test', 'language' => 'en'], - new SuggestionQuery('test', self::DEFAULT_LIMIT, 'en'), - ], - ]; - } -} diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index e5f878e..482c0d7 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\Contracts\Search\Event; +namespace Ibexa\Tests\Contracts\Search\EventDispatcher\Event; use Ibexa\Contracts\Search\Event\SuggestionEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; From 23d42e4fa28fcb73afb61bb7e85a28ea7c83f67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 11:09:09 +0200 Subject: [PATCH 31/66] Removed deprecated "withConsecutive" method --- src/bundle/IbexaSearchBundle.php | 1 + .../Service/Event/SuggestionServiceTest.php | 104 +++++++++--------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/bundle/IbexaSearchBundle.php b/src/bundle/IbexaSearchBundle.php index 70f6170..1dbdb31 100644 --- a/src/bundle/IbexaSearchBundle.php +++ b/src/bundle/IbexaSearchBundle.php @@ -4,6 +4,7 @@ * @copyright Copyright (C) Ibexa AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ + namespace Ibexa\Bundle\Search; use Ibexa\Bundle\Search\DependencyInjection\Configuration\Parser\Search; diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 35f07b4..cb67051 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -15,79 +15,75 @@ use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\Event\SuggestionService; use PHPUnit\Framework\TestCase; +use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; final class SuggestionServiceTest extends TestCase { - public function testSuggestion(): void - { - $eventDispatcherMock = $this->getEventDispatcherMock(); - $eventDispatcherMock - ->method('dispatch') - ->withConsecutive( - [ - $this->isInstanceOf(BeforeSuggestionEvent::class), - ], - [ - $this->isInstanceOf(AfterSuggestionEvent::class), - ] - ) - ->willReturnArgument(0); - - $innerServiceMock = $this->getSuggestionServiceMock(); - $innerServiceMock - ->method('suggest') - ->willReturn(new SuggestionCollection()); + /** @var \Ibexa\Contracts\Search\Service\SuggestionServiceInterface|\PHPUnit\Framework\MockObject\MockObject */ + private $innerServiceMock; - $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); + /** @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject */ + private $eventDispatcherMock; - $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); - self::assertCount(0, $result); + protected function setUp(): void + { + $this->innerServiceMock = $this->createMock(SuggestionServiceInterface::class); + $this->eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); } - public function testSuggestionStopPropagation(): void + public function testSuggestWithoutPropagationStop(): void { - $eventDispatcherMock = $this->getEventDispatcherMock(); - $eventDispatcherMock - ->expects(self::once()) + $query = new SuggestionQuery('test', 10, 'eng-GB'); + $suggestionCollection = new SuggestionCollection(); + $callCount = 0; + $this->eventDispatcherMock + ->expects(self::exactly(2)) ->method('dispatch') - ->with(self::isInstanceOf(BeforeSuggestionEvent::class)) - ->willReturnCallback( - static function (BeforeSuggestionEvent $event): BeforeSuggestionEvent { - $event->stopPropagation(); + ->willReturnCallback(static function (Event $event) use (&$callCount, $query, $suggestionCollection): Event { + ++$callCount; + if ($callCount === 1) { + self::assertInstanceOf(BeforeSuggestionEvent::class, $event); - return $event; + return new BeforeSuggestionEvent($query, $suggestionCollection); } - ); - $innerServiceMock = $this->getSuggestionServiceMock(); - $innerServiceMock + self::assertInstanceOf(AfterSuggestionEvent::class, $event); + + return new AfterSuggestionEvent($query, $suggestionCollection); + }); + + $this->innerServiceMock + ->expects($this->once()) ->method('suggest') - ->willReturn(new SuggestionCollection()); + ->with($query) + ->willReturn($suggestionCollection); - $service = new SuggestionService($innerServiceMock, $eventDispatcherMock); + $service = new SuggestionService($this->innerServiceMock, $this->eventDispatcherMock); + $result = $service->suggest($query); - $result = $service->suggest(new SuggestionQuery('query', 10, 'eng-GB')); - self::assertCount(0, $result); + self::assertEquals($suggestionCollection, $result); } - /** - * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Contracts\Search\Service\SuggestionServiceInterface - */ - private function getSuggestionServiceMock(): SuggestionServiceInterface + public function testSuggestWithPropagationStop(): void { - return $this->getMockBuilder(SuggestionServiceInterface::class) - ->disableOriginalConstructor() - ->getMock(); - } + $query = new SuggestionQuery('test', 10, 'eng-GB'); + $suggestionCollection = new SuggestionCollection(); + $beforeEvent = new BeforeSuggestionEvent($query, $suggestionCollection); + $beforeEvent->stopPropagation(); - /** - * @return \PHPUnit\Framework\MockObject\MockObject|\Symfony\Contracts\EventDispatcher\EventDispatcherInterface - */ - private function getEventDispatcherMock(): EventDispatcherInterface - { - return $this->getMockBuilder(EventDispatcherInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatch') + ->willReturn($beforeEvent); + + $this->innerServiceMock + ->expects($this->never()) + ->method('suggest'); + + $service = new SuggestionService($this->innerServiceMock, $this->eventDispatcherMock); + $result = $service->suggest($query); + + self::assertEquals($suggestionCollection, $result); } } From da8c6486052bcaf5717439c8292e6ef5aad79c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 11:09:43 +0200 Subject: [PATCH 32/66] Update src/bundle/Resources/config/services/normalizers.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/bundle/Resources/config/services/normalizers.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index b7c4ad9..61c4dd3 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -5,14 +5,17 @@ services: public: false Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer: + autoconfigure: false tags: - { name: 'ibexa.search.serializer.normalizer' } Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationCollectionNormalizer: + autoconfigure: false tags: - { name: 'ibexa.search.serializer.normalizer' } Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationNormalizer: + autoconfigure: false tags: - { name: 'ibexa.search.serializer.normalizer' } From fa58cef9ae2cafb52b1cda2fe71d32478df02952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 12:44:57 +0200 Subject: [PATCH 33/66] Changed serializer --- .../SuggestionQueryArgumentResolver.php | 3 ++ .../Controller/SuggestionController.php | 8 ------ .../config/services/normalizers.yaml | 16 ++++++----- .../config/services/suggestions.yaml | 4 +++ src/lib/Serializer/SuggestionSerializer.php | 15 ---------- .../SuggestionSerializerFactory.php | 28 ------------------- 6 files changed, 16 insertions(+), 58 deletions(-) delete mode 100644 src/lib/Serializer/SuggestionSerializer.php delete mode 100644 src/lib/Serializer/SuggestionSerializerFactory.php diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index eb30a14..bc9141c 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -27,6 +27,9 @@ public function supports(Request $request, ArgumentMetadata $argument): bool return SuggestionQuery::class === $argument->getType(); } + /** + * @return iterable<\Ibexa\Search\Model\SuggestionQuery> + */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { $query = $request->get('query'); diff --git a/src/bundle/Controller/SuggestionController.php b/src/bundle/Controller/SuggestionController.php index 1da4351..92ab56b 100644 --- a/src/bundle/Controller/SuggestionController.php +++ b/src/bundle/Controller/SuggestionController.php @@ -9,7 +9,6 @@ namespace Ibexa\Bundle\Search\Controller; use Ibexa\Search\Model\SuggestionQuery; -use Ibexa\Search\Serializer\SuggestionSerializer; use Ibexa\Search\Service\SuggestionService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -24,13 +23,6 @@ public function __construct( $this->suggestionService = $suggestionService; } - public static function getSubscribedServices(): array - { - return array_merge(parent::getSubscribedServices(), [ - 'serializer' => SuggestionSerializer::class, - ]); - } - public function suggestAction(SuggestionQuery $suggestionQuery): JsonResponse { $result = $this->suggestionService->suggest($suggestionQuery); diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index 61c4dd3..6aa70f5 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -4,6 +4,15 @@ services: autoconfigure: true public: false + ibexa.search.suggestion.serializer: + class: Symfony\Component\Serializer\Serializer + arguments: + $normalizers: + - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer' + - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationNormalizer' + $encoders: + - '@serializer.encoder.json' + Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer: autoconfigure: false tags: @@ -18,10 +27,3 @@ services: autoconfigure: false tags: - { name: 'ibexa.search.serializer.normalizer' } - - Ibexa\Search\Serializer\SuggestionSerializerFactory: ~ - - Ibexa\Search\Serializer\SuggestionSerializer: - factory: '@Ibexa\Search\Serializer\SuggestionSerializerFactory' - arguments: - $normalizers: !tagged_iterator { tag: 'ibexa.search.serializer.normalizer' } diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 523d22f..4e7d9e4 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -8,6 +8,10 @@ services: autowire: true public: false + Ibexa\Bundle\Search\Controller\SuggestionController: + tags: + - { name: 'container.service_subscriber', key: 'serializer', id: 'ibexa.search.suggestion.serializer' } + Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: arguments: $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' diff --git a/src/lib/Serializer/SuggestionSerializer.php b/src/lib/Serializer/SuggestionSerializer.php deleted file mode 100644 index 9ec0c62..0000000 --- a/src/lib/Serializer/SuggestionSerializer.php +++ /dev/null @@ -1,15 +0,0 @@ - $normalizers - */ - public function __invoke(iterable $normalizers): SuggestionSerializer - { - $encoders = [new JsonEncoder()]; - $normalizersArray = is_array($normalizers) ? $normalizers : iterator_to_array($normalizers); - - return new SuggestionSerializer($normalizersArray, $encoders); - } -} From debf12e2840601d2c767f7979903e9dd74f53c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 12:47:57 +0200 Subject: [PATCH 34/66] Update tests/contracts/EventDispatcher/Event/SuggestionEventTest.php Co-authored-by: Mikolaj Adamczyk --- tests/contracts/EventDispatcher/Event/SuggestionEventTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index 482c0d7..fc5cd55 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -17,7 +17,7 @@ final class SuggestionEventTest extends TestCase { public function testConstruct(): void { - $suggestionQuery = new SuggestionEvent(new SuggestionQuery('test', 3)); + $suggestionEvent = new SuggestionEvent(new SuggestionQuery('test', 3)); self::assertInstanceOf(SuggestionCollection::class, $suggestionQuery->getSuggestionCollection()); self::assertInstanceOf(SuggestionQuery::class, $suggestionQuery->getQuery()); From 58857dd462dea73fe2c56a04b3401dab6745428b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 13:29:10 +0200 Subject: [PATCH 35/66] Additional fixes --- .../EventDispatcher/Event/SuggestionEventTest.php | 8 ++++---- .../contracts/Model/Suggestion/ContentSuggestionTest.php | 4 ---- tests/contracts/Model/Suggestion/ParentCollectionTest.php | 3 ++- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index fc5cd55..1b961eb 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -9,7 +9,6 @@ namespace Ibexa\Tests\Contracts\Search\EventDispatcher\Event; use Ibexa\Contracts\Search\Event\SuggestionEvent; -use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; @@ -17,9 +16,10 @@ final class SuggestionEventTest extends TestCase { public function testConstruct(): void { - $suggestionEvent = new SuggestionEvent(new SuggestionQuery('test', 3)); + $suggestionQuery = new SuggestionQuery('test', 3); + $suggestionEvent = new SuggestionEvent($suggestionQuery); - self::assertInstanceOf(SuggestionCollection::class, $suggestionQuery->getSuggestionCollection()); - self::assertInstanceOf(SuggestionQuery::class, $suggestionQuery->getQuery()); + self::assertCount(0, $suggestionEvent->getSuggestionCollection()); + self::assertSame($suggestionQuery, $suggestionEvent->getQuery()); } } diff --git a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php index c10639a..50c77a4 100644 --- a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php @@ -10,8 +10,6 @@ use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; -use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; use Ibexa\Tests\Core\Search\TestCase; final class ContentSuggestionTest extends TestCase @@ -28,10 +26,8 @@ public function testCreate(): void [0 => new ParentLocation(0, 1, 'text')] ); - self::assertInstanceOf(Suggestion::class, $implementation); self::assertSame(1, $implementation->getContentId()); self::assertSame('content_type_identifier', $implementation->getContentTypeIdentifier()); - self::assertInstanceOf(ParentLocationCollection::class, $implementation->getParentLocations()); self::assertCount(1, $implementation->getParentLocations()); } } diff --git a/tests/contracts/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php index 6e9a5ad..da5fa01 100644 --- a/tests/contracts/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -36,7 +36,8 @@ public function testCollection(): void self::assertInstanceOf(ParentLocation::class, $item); } - self::expectException(InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given'); $collection->append(new \stdClass()); } } From 258575c558efa87bebb2eaa33d8c3c8e8d1b2a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 27 Oct 2023 14:00:08 +0200 Subject: [PATCH 36/66] Fixed removing root location --- src/lib/Mapper/SearchHitToContentSuggestionMapper.php | 2 +- tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 305e049..f401171 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -45,7 +45,7 @@ public function map(SearchHit $searchHit): ?ContentSuggestion return null; } - $parentsLocation = $mainLocation->path; + $parentsLocation = array_map('intval', $mainLocation->path); $position = array_search($rootLocationId, $parentsLocation, true); if ($position !== false) { $parentsLocation = array_slice($parentsLocation, (int)$position); diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index abb1f57..ce20830 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -49,7 +49,7 @@ public function testMap(): void 'contentTypeId' => 1, 'mainLocation' => new Location([ 'id' => 8, - 'path' => [1, 2, 3, 4, 5, 6, 7], + 'path' => ['1', '2', '3', '4', '5', '6', '7'], ]), ]), ]), From 03288c1e15da71d13e92440df38262ffda632027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 31 Oct 2023 10:06:26 +0100 Subject: [PATCH 37/66] Update composer.json Co-authored-by: Mikolaj Adamczyk --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d6c4054..990afad 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "symfony/serializer": "^5.4" }, "require-dev": { - "phpunit/phpunit": "^9.6.13", + "phpunit/phpunit": "^9.6", "friendsofphp/php-cs-fixer": "^3.0", "ibexa/code-style": "^1.0", "ibexa/doctrine-schema": "~4.6.x-dev", From 89b782d76d6d0062026af841a778a0ab9bcda5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 31 Oct 2023 10:07:09 +0100 Subject: [PATCH 38/66] Applied CR suggestions --- .../Model/Suggestion/ParentLocationCollection.php | 2 +- .../Model/Suggestion/SuggestionCollection.php | 2 +- .../EventListener/ContentSuggestionSubscriber.php | 2 +- src/lib/Model/SuggestionQuery.php | 10 +++++----- src/lib/Provider/ParentLocationProvider.php | 2 +- .../Model/Suggestion/ParentCollectionTest.php | 3 ++- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/contracts/Model/Suggestion/ParentLocationCollection.php b/src/contracts/Model/Suggestion/ParentLocationCollection.php index ddc51c0..e7bbe7e 100644 --- a/src/contracts/Model/Suggestion/ParentLocationCollection.php +++ b/src/contracts/Model/Suggestion/ParentLocationCollection.php @@ -30,7 +30,7 @@ public function append($item): void '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) + is_object($item) ? get_class($item) : gettype($item) ) ); } diff --git a/src/contracts/Model/Suggestion/SuggestionCollection.php b/src/contracts/Model/Suggestion/SuggestionCollection.php index f92d5e6..0330772 100644 --- a/src/contracts/Model/Suggestion/SuggestionCollection.php +++ b/src/contracts/Model/Suggestion/SuggestionCollection.php @@ -30,7 +30,7 @@ public function append($item): void '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) + is_object($item) ? get_class($item) : gettype($item) ) ); } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 9fa6b5b..5fa3f60 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -46,7 +46,7 @@ public function onContentSuggestion(SuggestionEvent $event): SuggestionEvent $value = $query->getQuery(); $limit = $query->getLimit(); - $language = $query->getLanguage(); + $language = $query->getLanguageCode(); $query = new Query( [ diff --git a/src/lib/Model/SuggestionQuery.php b/src/lib/Model/SuggestionQuery.php index 1498300..6c6593b 100644 --- a/src/lib/Model/SuggestionQuery.php +++ b/src/lib/Model/SuggestionQuery.php @@ -14,13 +14,13 @@ final class SuggestionQuery private int $limit; - private ?string $language; + private ?string $languageCode; - public function __construct(string $query, int $limit, ?string $language = null) + public function __construct(string $query, int $limit, ?string $languageCode = null) { $this->query = $query; $this->limit = $limit; - $this->language = $language; + $this->languageCode = $languageCode; } public function getQuery(): string @@ -33,8 +33,8 @@ public function getLimit(): int return $this->limit; } - public function getLanguage(): ?string + public function getLanguageCode(): ?string { - return $this->language; + return $this->languageCode; } } diff --git a/src/lib/Provider/ParentLocationProvider.php b/src/lib/Provider/ParentLocationProvider.php index aa29266..5564a8f 100644 --- a/src/lib/Provider/ParentLocationProvider.php +++ b/src/lib/Provider/ParentLocationProvider.php @@ -32,7 +32,7 @@ public function provide(array $parentLocationIds): array $parentLocationMap = []; foreach ($parentLocations as $parentLocation) { $parentLocationMap[] = new ParentLocation( - $parentLocation->getContentInfo()->id, + $parentLocation->getContentInfo()->getId(), $parentLocation->id, $parentLocation->getContentInfo()->name ); diff --git a/tests/contracts/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php index da5fa01..81aa3c6 100644 --- a/tests/contracts/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -13,6 +13,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use PHPUnit\Framework\TestCase; +use stdClass; final class ParentCollectionTest extends TestCase { @@ -38,6 +39,6 @@ public function testCollection(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given'); - $collection->append(new \stdClass()); + $collection->append(new stdClass()); } } From fca194d383dabf87a5416f41b9f41c82e33964db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 31 Oct 2023 10:30:29 +0100 Subject: [PATCH 39/66] Code review suggestions applied --- src/contracts/Event/AfterSuggestionEvent.php | 5 ---- src/contracts/Event/BeforeSuggestionEvent.php | 7 ++--- .../ContentSuggestionNormalizer.php | 22 +++++++++----- .../ParentLocationCollectionNormalizer.php | 30 ++++++++++++------- .../Suggestion/ParentLocationNormalizer.php | 5 ++++ src/lib/Service/Event/SuggestionService.php | 16 ++++++---- .../Service/Event/SuggestionServiceTest.php | 11 +++---- 7 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/contracts/Event/AfterSuggestionEvent.php b/src/contracts/Event/AfterSuggestionEvent.php index 8d7a9aa..db29f96 100644 --- a/src/contracts/Event/AfterSuggestionEvent.php +++ b/src/contracts/Event/AfterSuggestionEvent.php @@ -24,11 +24,6 @@ public function __construct(SuggestionQuery $query, SuggestionCollection $sugges $this->suggestionCollection = $suggestionCollection; } - public function setQuery(SuggestionQuery $query): void - { - $this->query = $query; - } - public function getQuery(): SuggestionQuery { return $this->query; diff --git a/src/contracts/Event/BeforeSuggestionEvent.php b/src/contracts/Event/BeforeSuggestionEvent.php index b6edc80..6e40fc6 100644 --- a/src/contracts/Event/BeforeSuggestionEvent.php +++ b/src/contracts/Event/BeforeSuggestionEvent.php @@ -16,12 +16,11 @@ final class BeforeSuggestionEvent extends BeforeEvent { private SuggestionQuery $query; - private SuggestionCollection $suggestionCollection; + private ?SuggestionCollection $suggestionCollection = null; - public function __construct(SuggestionQuery $query, SuggestionCollection $suggestionCollection) + public function __construct(SuggestionQuery $query) { $this->query = $query; - $this->suggestionCollection = $suggestionCollection; } public function setQuery(SuggestionQuery $query): void @@ -34,7 +33,7 @@ public function getQuery(): SuggestionQuery return $this->query; } - public function getSuggestionCollection(): SuggestionCollection + public function getSuggestionCollection(): ?SuggestionCollection { return $this->suggestionCollection; } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index fe7cc8f..3739404 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -9,16 +9,17 @@ namespace Ibexa\Search\Serializer\Normalizer\Suggestion; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -final class ContentSuggestionNormalizer implements NormalizerInterface +final class ContentSuggestionNormalizer implements + NormalizerInterface, + NormalizerAwareInterface, + CacheableSupportsMethodInterface { - private ParentLocationCollectionNormalizer $parentLocationCollectionNormalizer; - - public function __construct(ParentLocationCollectionNormalizer $parentLocationCollectionNormalizer) - { - $this->parentLocationCollectionNormalizer = $parentLocationCollectionNormalizer; - } + use NormalizerAwareTrait; /** * @param \Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion $object @@ -34,7 +35,7 @@ public function normalize($object, string $format = null, array $context = []): 'name' => $object->getName(), 'pathString' => $object->getPathString(), 'type' => 'content', - 'parentLocations' => $this->parentLocationCollectionNormalizer->normalize($object->getParentLocations()), + 'parentLocations' => $this->normalizer->normalize($object->getParentLocations()), ]; } @@ -42,4 +43,9 @@ public function supportsNormalization($data, string $format = null): bool { return $data instanceof ContentSuggestion; } + + public function hasCacheableSupportsMethod(): bool + { + return __CLASS__ === static::class; + } } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php index 570c3da..c167459 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -8,36 +8,44 @@ namespace Ibexa\Search\Serializer\Normalizer\Suggestion; +use ArrayObject; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -final class ParentLocationCollectionNormalizer implements NormalizerInterface +final class ParentLocationCollectionNormalizer implements + NormalizerInterface, + NormalizerAwareInterface, + CacheableSupportsMethodInterface { - private ParentLocationNormalizer $parentLocationNormalizer; - - public function __construct(ParentLocationNormalizer $parentLocationNormalizer) - { - $this->parentLocationNormalizer = $parentLocationNormalizer; - } + use NormalizerAwareTrait; /** * @param \Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection $object + * @param array $context * - * @return array, array> + * @return ArrayObject. */ - public function normalize($object, string $format = null, array $context = []): array + public function normalize($object, string $format = null, array $context = []): ArrayObject { $normalizedData = []; foreach ($object as $parentLocation) { - $normalizedData[] = $this->parentLocationNormalizer->normalize($parentLocation); + $normalizedData[] = $this->normalizer->normalize($parentLocation); } - return $normalizedData; + return new ArrayObject($normalizedData); } public function supportsNormalization($data, string $format = null): bool { return $data instanceof ParentLocationCollection; } + + public function hasCacheableSupportsMethod(): bool + { + return __CLASS__ === static::class; + } } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php index 0d4a413..7236739 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php @@ -31,4 +31,9 @@ public function supportsNormalization($data, string $format = null): bool { return $data instanceof ParentLocation; } + + public function hasCacheableSupportsMethod(): bool + { + return __CLASS__ === static::class; + } } diff --git a/src/lib/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php index f7a8d8d..93b4e5d 100644 --- a/src/lib/Service/Event/SuggestionService.php +++ b/src/lib/Service/Event/SuggestionService.php @@ -14,6 +14,7 @@ use Ibexa\Contracts\Search\Service\Decorator\SuggestionServiceDecorator; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\SuggestionQuery; +use LogicException; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; final class SuggestionService extends SuggestionServiceDecorator @@ -32,18 +33,21 @@ public function __construct( public function suggest(SuggestionQuery $query): SuggestionCollection { $beforeEvent = $this->eventDispatcher->dispatch( - new BeforeSuggestionEvent( - $query, - new SuggestionCollection() - ) + new BeforeSuggestionEvent($query) ); if ($beforeEvent->isPropagationStopped()) { - return $beforeEvent->getSuggestionCollection(); + $suggestionCollection = $beforeEvent->getSuggestionCollection(); + if ($suggestionCollection === null) { + throw new LogicException( + 'The suggestion collection must be set when the propagation is stopped.' + ); + } + + return $suggestionCollection; } $result = $this->innerService->suggest($beforeEvent->getQuery()); - $afterEvent = $this->eventDispatcher->dispatch( new AfterSuggestionEvent( $query, diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index cb67051..a44df4b 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -14,6 +14,7 @@ use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\SuggestionQuery; use Ibexa\Search\Service\Event\SuggestionService; +use LogicException; use PHPUnit\Framework\TestCase; use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -45,7 +46,7 @@ public function testSuggestWithoutPropagationStop(): void if ($callCount === 1) { self::assertInstanceOf(BeforeSuggestionEvent::class, $event); - return new BeforeSuggestionEvent($query, $suggestionCollection); + return new BeforeSuggestionEvent($query); } self::assertInstanceOf(AfterSuggestionEvent::class, $event); @@ -68,8 +69,7 @@ public function testSuggestWithoutPropagationStop(): void public function testSuggestWithPropagationStop(): void { $query = new SuggestionQuery('test', 10, 'eng-GB'); - $suggestionCollection = new SuggestionCollection(); - $beforeEvent = new BeforeSuggestionEvent($query, $suggestionCollection); + $beforeEvent = new BeforeSuggestionEvent($query); $beforeEvent->stopPropagation(); $this->eventDispatcherMock @@ -82,8 +82,9 @@ public function testSuggestWithPropagationStop(): void ->method('suggest'); $service = new SuggestionService($this->innerServiceMock, $this->eventDispatcherMock); - $result = $service->suggest($query); - self::assertEquals($suggestionCollection, $result); + self::expectException(LogicException::class); + self::expectExceptionMessage('The suggestion collection must be set when the propagation is stopped.'); + $service->suggest($query); } } From 21aa94138ee4e6bd360de0bf05e4157a3237fe78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 31 Oct 2023 11:31:42 +0100 Subject: [PATCH 40/66] Code review suggestions applied --- phpstan-baseline.neon | 3 +++ .../ArgumentResolver/SuggestionQueryArgumentResolver.php | 5 +++-- src/bundle/Resources/config/services/suggestions.yaml | 4 +--- .../EventListener/ContentSuggestionSubscriber.php | 2 +- tests/contracts/Model/Suggestion/SuggestionTest.php | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ba9018e..1769ec6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,8 @@ parameters: ignoreErrors: + - + message: "#^Cannot call method (log|debug|info|notice|warning|error|critical|alert|emergency)\\(\\) on Psr\\\\Log\\\\LoggerInterface\\|null\\.$#" + - message: "#^Method Ibexa\\\\Bundle\\\\Search\\\\DependencyInjection\\\\Configuration\\\\Parser\\\\Search\\:\\:addSemanticConfig\\(\\) has no return type specified\\.$#" count: 1 diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index bc9141c..27f7347 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -8,6 +8,7 @@ namespace Ibexa\Bundle\Search\ArgumentResolver; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Search\Model\SuggestionQuery; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; @@ -17,9 +18,9 @@ final class SuggestionQueryArgumentResolver implements ArgumentValueResolverInte { private int $defaultLimit; - public function __construct(int $defaultLimit) + public function __construct(ConfigResolverInterface $configResolver) { - $this->defaultLimit = $defaultLimit; + $this->defaultLimit = $configResolver->getParameter('search.suggestion.result_limit'); } public function supports(Request $request, ArgumentMetadata $argument): bool diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 4e7d9e4..24e78ed 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -13,10 +13,8 @@ services: - { name: 'container.service_subscriber', key: 'serializer', id: 'ibexa.search.suggestion.serializer' } Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: - arguments: - $defaultLimit: '%ibexa.site_access.config.default.search.suggestion.result_limit%' tags: - - { name: 'controller.argument_value_resolver', priority: 50 } + - { name: 'controller.argument_value_resolver' } Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 5fa3f60..6932e06 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -67,7 +67,7 @@ public function onContentSuggestion(SuggestionEvent $event): SuggestionEvent $suggestionCollection->append($contentSuggestion); } } catch (InvalidArgumentException $e) { - $this->logger ? $this->logger->error($e) : null; + $this->logger->error($e); } return $event; diff --git a/tests/contracts/Model/Suggestion/SuggestionTest.php b/tests/contracts/Model/Suggestion/SuggestionTest.php index 5827470..0e2e0e3 100644 --- a/tests/contracts/Model/Suggestion/SuggestionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionTest.php @@ -16,7 +16,7 @@ final class SuggestionTest extends TestCase { public function testSuggestionCreate(): void { - $implementation = self::createSuggestion( + $implementation = $this->createSuggestion( 0, 'name', '2/4/5', From 5d130e67f504bfdf020daee85349d5a4a3f3e50c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 2 Nov 2023 09:07:23 +0100 Subject: [PATCH 41/66] Code review suggestions applied --- .../ArgumentResolver/SuggestionQueryArgumentResolver.php | 4 ++-- src/bundle/Resources/config/services/normalizers.yaml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index 27f7347..87354b6 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -33,9 +33,9 @@ public function supports(Request $request, ArgumentMetadata $argument): bool */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { - $query = $request->get('query'); + $query = $request->query->get('query'); $limit = $request->query->getInt('limit', $this->defaultLimit); - $language = $request->get('language'); + $language = $request->query->get('language'); yield new SuggestionQuery($query, $limit, $language); } diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index 6aa70f5..84a95f7 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -6,6 +6,7 @@ services: ibexa.search.suggestion.serializer: class: Symfony\Component\Serializer\Serializer + autoconfigure: false arguments: $normalizers: - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer' From 49709865538e8b8f54e9559b7ee4f0882c252943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 2 Nov 2023 12:19:33 +0100 Subject: [PATCH 42/66] Code review suggestions applied --- .../ArgumentResolver/SuggestionQueryArgumentResolver.php | 7 +++++++ src/contracts/Model/Suggestion/ContentSuggestion.php | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index 87354b6..cb678b2 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; final class SuggestionQueryArgumentResolver implements ArgumentValueResolverInterface { @@ -30,6 +31,8 @@ public function supports(Request $request, ArgumentMetadata $argument): bool /** * @return iterable<\Ibexa\Search\Model\SuggestionQuery> + * + * @throw \Symfony\Component\HttpKernel\Exception\BadRequestHttpException */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { @@ -37,6 +40,10 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable $limit = $request->query->getInt('limit', $this->defaultLimit); $language = $request->query->get('language'); + if ($query === null) { + throw new BadRequestHttpException('Missing query parameter'); + } + yield new SuggestionQuery($query, $limit, $language); } } diff --git a/src/contracts/Model/Suggestion/ContentSuggestion.php b/src/contracts/Model/Suggestion/ContentSuggestion.php index ac92a8f..884ec76 100644 --- a/src/contracts/Model/Suggestion/ContentSuggestion.php +++ b/src/contracts/Model/Suggestion/ContentSuggestion.php @@ -12,7 +12,7 @@ final class ContentSuggestion extends Suggestion { private int $contentId; - private int $locationId; + private ?int $locationId; private string $contentTypeIdentifier; @@ -24,7 +24,7 @@ public function __construct( string $contentTypeIdentifier, string $name, int $contentId, - int $locationId, + ?int $locationId = null, string $pathString = '', array $parentLocations = [] ) { @@ -39,7 +39,7 @@ public function getContentId(): int return $this->contentId; } - public function getLocationId(): int + public function getLocationId(): ?int { return $this->locationId; } From df7e476cc6542217be00b7aaf0c39df8e74967a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 3 Nov 2023 09:37:50 +0100 Subject: [PATCH 43/66] Code review suggestions applied --- .../Normalizer/Suggestion/ContentSuggestionNormalizer.php | 2 +- .../Suggestion/ParentLocationCollectionNormalizer.php | 2 +- .../Normalizer/Suggestion/ParentLocationNormalizer.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index 3739404..11cbb5b 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -46,6 +46,6 @@ public function supportsNormalization($data, string $format = null): bool public function hasCacheableSupportsMethod(): bool { - return __CLASS__ === static::class; + return true; } } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php index c167459..2702f8a 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -46,6 +46,6 @@ public function supportsNormalization($data, string $format = null): bool public function hasCacheableSupportsMethod(): bool { - return __CLASS__ === static::class; + return true; } } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php index 7236739..477ec96 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php @@ -11,7 +11,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -class ParentLocationNormalizer implements NormalizerInterface +final class ParentLocationNormalizer implements NormalizerInterface { /** * @param \Ibexa\Contracts\Search\Model\Suggestion\ParentLocation $object @@ -34,6 +34,6 @@ public function supportsNormalization($data, string $format = null): bool public function hasCacheableSupportsMethod(): bool { - return __CLASS__ === static::class; + return true; } } From ac106c0e0c7a6ac7ad76fe1c49c9112650b0dd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 3 Nov 2023 12:28:47 +0100 Subject: [PATCH 44/66] Code review suggestions applied --- ...estionEvent.php => BeforeSuggestEvent.php} | 2 +- ...php => BuildSuggestionCollectionEvent.php} | 2 +- ...erSuggestionEvent.php => SuggestEvent.php} | 7 +---- .../Model/Suggestion/ContentSuggestion.php | 30 +++++++++++++++---- .../Model/Suggestion/ParentLocation.php | 10 +++---- src/contracts/Model/Suggestion/Suggestion.php | 23 +------------- .../ContentSuggestionSubscriber.php | 6 ++-- .../SearchHitToContentSuggestionMapper.php | 4 +-- .../ContentSuggestionNormalizer.php | 2 +- .../Suggestion/ParentLocationNormalizer.php | 2 +- src/lib/Service/Event/SuggestionService.php | 8 ++--- src/lib/Service/SuggestionService.php | 6 ++-- .../Event/SuggestionEventTest.php | 4 +-- .../Suggestion/ContentSuggestionTest.php | 6 ++-- .../Suggestion/SuggestionCollectionTest.php | 17 ++++++----- .../Model/Suggestion/SuggestionTest.php | 18 ++--------- .../ContentSuggestionSubscriberTest.php | 11 +++---- .../Service/Event/SuggestionServiceTest.php | 14 ++++----- 18 files changed, 79 insertions(+), 93 deletions(-) rename src/contracts/Event/{BeforeSuggestionEvent.php => BeforeSuggestEvent.php} (95%) rename src/contracts/Event/{SuggestionEvent.php => BuildSuggestionCollectionEvent.php} (95%) rename src/contracts/Event/{AfterSuggestionEvent.php => SuggestEvent.php} (80%) diff --git a/src/contracts/Event/BeforeSuggestionEvent.php b/src/contracts/Event/BeforeSuggestEvent.php similarity index 95% rename from src/contracts/Event/BeforeSuggestionEvent.php rename to src/contracts/Event/BeforeSuggestEvent.php index 6e40fc6..7acf697 100644 --- a/src/contracts/Event/BeforeSuggestionEvent.php +++ b/src/contracts/Event/BeforeSuggestEvent.php @@ -12,7 +12,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; -final class BeforeSuggestionEvent extends BeforeEvent +final class BeforeSuggestEvent extends BeforeEvent { private SuggestionQuery $query; diff --git a/src/contracts/Event/SuggestionEvent.php b/src/contracts/Event/BuildSuggestionCollectionEvent.php similarity index 95% rename from src/contracts/Event/SuggestionEvent.php rename to src/contracts/Event/BuildSuggestionCollectionEvent.php index 4a8a6da..0ed3533 100644 --- a/src/contracts/Event/SuggestionEvent.php +++ b/src/contracts/Event/BuildSuggestionCollectionEvent.php @@ -11,7 +11,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; -final class SuggestionEvent +final class BuildSuggestionCollectionEvent { private SuggestionCollection $suggestionCollection; diff --git a/src/contracts/Event/AfterSuggestionEvent.php b/src/contracts/Event/SuggestEvent.php similarity index 80% rename from src/contracts/Event/AfterSuggestionEvent.php rename to src/contracts/Event/SuggestEvent.php index db29f96..ae96afa 100644 --- a/src/contracts/Event/AfterSuggestionEvent.php +++ b/src/contracts/Event/SuggestEvent.php @@ -12,7 +12,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Search\Model\SuggestionQuery; -final class AfterSuggestionEvent extends AfterEvent +final class SuggestEvent extends AfterEvent { private SuggestionQuery $query; @@ -29,11 +29,6 @@ public function getQuery(): SuggestionQuery return $this->query; } - public function setSuggestionCollection(SuggestionCollection $suggestionCollection): void - { - $this->suggestionCollection = $suggestionCollection; - } - public function getSuggestionCollection(): SuggestionCollection { return $this->suggestionCollection; diff --git a/src/contracts/Model/Suggestion/ContentSuggestion.php b/src/contracts/Model/Suggestion/ContentSuggestion.php index 884ec76..8347111 100644 --- a/src/contracts/Model/Suggestion/ContentSuggestion.php +++ b/src/contracts/Model/Suggestion/ContentSuggestion.php @@ -8,30 +8,38 @@ namespace Ibexa\Contracts\Search\Model\Suggestion; +use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; + final class ContentSuggestion extends Suggestion { private int $contentId; private ?int $locationId; - private string $contentTypeIdentifier; + private ContentType $contentType; + + private string $pathString; + + private ParentLocationCollection $parentsLocation; /** * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations */ public function __construct( float $score, - string $contentTypeIdentifier, + ContentType $contentType, string $name, int $contentId, ?int $locationId = null, string $pathString = '', array $parentLocations = [] ) { - parent::__construct($score, $name, $pathString, $parentLocations); + parent::__construct($score, $name); $this->contentId = $contentId; - $this->contentTypeIdentifier = $contentTypeIdentifier; + $this->contentType = $contentType; $this->locationId = $locationId; + $this->pathString = $pathString; + $this->parentsLocation = new ParentLocationCollection($parentLocations); } public function getContentId(): int @@ -44,8 +52,18 @@ public function getLocationId(): ?int return $this->locationId; } - public function getContentTypeIdentifier(): string + public function getContentType(): ContentType + { + return $this->contentType; + } + + public function getPathString(): string + { + return $this->pathString; + } + + public function getParentLocations(): ParentLocationCollection { - return $this->contentTypeIdentifier; + return $this->parentsLocation; } } diff --git a/src/contracts/Model/Suggestion/ParentLocation.php b/src/contracts/Model/Suggestion/ParentLocation.php index d3776ab..e4e5cba 100644 --- a/src/contracts/Model/Suggestion/ParentLocation.php +++ b/src/contracts/Model/Suggestion/ParentLocation.php @@ -10,22 +10,22 @@ final class ParentLocation { - private int $contentId; + private int $id; private int $locationId; private string $name; - public function __construct(int $contentId, int $locationId, string $name) + public function __construct(int $id, int $locationId, string $name) { - $this->contentId = $contentId; + $this->id = $id; $this->locationId = $locationId; $this->name = $name; } - public function getContentId(): int + public function getId(): int { - return $this->contentId; + return $this->id; } public function getLocationId(): int diff --git a/src/contracts/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php index 58f97b8..8c2cc74 100644 --- a/src/contracts/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -16,23 +16,12 @@ abstract class Suggestion extends ValueObject private string $name; - private string $pathString; - - private ParentLocationCollection $parentsLocation; - - /** - * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations - */ public function __construct( float $score, - string $name, - string $pathString = '', - array $parentLocations = [] + string $name ) { $this->score = $score; $this->name = $name; - $this->pathString = $pathString; - $this->parentsLocation = new ParentLocationCollection($parentLocations); parent::__construct(); } @@ -46,14 +35,4 @@ public function getName(): string { return $this->name; } - - public function getPathString(): string - { - return $this->pathString; - } - - public function getParentLocations(): ParentLocationCollection - { - return $this->parentsLocation; - } } diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 6932e06..5f578d9 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -10,7 +10,7 @@ use Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException; use Ibexa\Contracts\Core\Repository\Values\Content\Query; -use Ibexa\Contracts\Search\Event\SuggestionEvent; +use Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent; use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; use Ibexa\Core\Repository\SiteAccessAware\SearchService; use Psr\Log\LoggerAwareInterface; @@ -36,11 +36,11 @@ public function __construct( public static function getSubscribedEvents(): array { return [ - SuggestionEvent::class => 'onContentSuggestion', + BuildSuggestionCollectionEvent::class => 'onBuildSuggestionCollectionEvent', ]; } - public function onContentSuggestion(SuggestionEvent $event): SuggestionEvent + public function onBuildSuggestionCollectionEvent(BuildSuggestionCollectionEvent $event): BuildSuggestionCollectionEvent { $query = $event->getQuery(); diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index f401171..64d3f28 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -55,10 +55,10 @@ public function map(SearchHit $searchHit): ?ContentSuggestion return new ContentSuggestion( $searchHit->score ?? 50.0, - $content->getContentType()->identifier, + $content->getContentType(), $content->getName() ?? '', $content->getVersionInfo()->getContentInfo()->getId(), - $content->getVersionInfo()->getContentInfo()->getMainLocation()->id ?? 0, + $content->getVersionInfo()->getContentInfo()->getMainLocation()->id ?? null, implode('/', $parentsLocation), $parentCollection ); diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index 11cbb5b..40eb871 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -31,7 +31,7 @@ public function normalize($object, string $format = null, array $context = []): return [ 'contentId' => $object->getContentId(), 'locationId' => $object->getLocationId(), - 'contentTypeIdentifier' => $object->getContentTypeIdentifier(), + 'contentTypeIdentifier' => $object->getContentType(), 'name' => $object->getName(), 'pathString' => $object->getPathString(), 'type' => 'content', diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php index 477ec96..9a90b7d 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php @@ -21,7 +21,7 @@ final class ParentLocationNormalizer implements NormalizerInterface public function normalize($object, string $format = null, array $context = []): array { return [ - 'contentId' => $object->getContentId(), + 'contentId' => $object->getId(), 'locationId' => $object->getLocationId(), 'name' => $object->getName(), ]; diff --git a/src/lib/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php index 93b4e5d..7ade7d5 100644 --- a/src/lib/Service/Event/SuggestionService.php +++ b/src/lib/Service/Event/SuggestionService.php @@ -8,8 +8,8 @@ namespace Ibexa\Search\Service\Event; -use Ibexa\Contracts\Search\Event\AfterSuggestionEvent; -use Ibexa\Contracts\Search\Event\BeforeSuggestionEvent; +use Ibexa\Contracts\Search\Event\BeforeSuggestEvent; +use Ibexa\Contracts\Search\Event\SuggestEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\Decorator\SuggestionServiceDecorator; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; @@ -33,7 +33,7 @@ public function __construct( public function suggest(SuggestionQuery $query): SuggestionCollection { $beforeEvent = $this->eventDispatcher->dispatch( - new BeforeSuggestionEvent($query) + new BeforeSuggestEvent($query) ); if ($beforeEvent->isPropagationStopped()) { @@ -49,7 +49,7 @@ public function suggest(SuggestionQuery $query): SuggestionCollection $result = $this->innerService->suggest($beforeEvent->getQuery()); $afterEvent = $this->eventDispatcher->dispatch( - new AfterSuggestionEvent( + new SuggestEvent( $query, $result ) diff --git a/src/lib/Service/SuggestionService.php b/src/lib/Service/SuggestionService.php index 8620615..f674f7c 100644 --- a/src/lib/Service/SuggestionService.php +++ b/src/lib/Service/SuggestionService.php @@ -8,7 +8,7 @@ namespace Ibexa\Search\Service; -use Ibexa\Contracts\Search\Event\SuggestionEvent; +use Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\SuggestionQuery; @@ -25,9 +25,9 @@ public function __construct(EventDispatcherInterface $eventDispatcher) public function suggest(SuggestionQuery $query): SuggestionCollection { - /** @var \Ibexa\Contracts\Search\Event\SuggestionEvent $event */ + /** @var \Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent $event */ $event = $this->eventDispatcher->dispatch( - new SuggestionEvent( + new BuildSuggestionCollectionEvent( $query ) ); diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php index 1b961eb..e81504b 100644 --- a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php @@ -8,7 +8,7 @@ namespace Ibexa\Tests\Contracts\Search\EventDispatcher\Event; -use Ibexa\Contracts\Search\Event\SuggestionEvent; +use Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent; use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; @@ -17,7 +17,7 @@ final class SuggestionEventTest extends TestCase public function testConstruct(): void { $suggestionQuery = new SuggestionQuery('test', 3); - $suggestionEvent = new SuggestionEvent($suggestionQuery); + $suggestionEvent = new BuildSuggestionCollectionEvent($suggestionQuery); self::assertCount(0, $suggestionEvent->getSuggestionCollection()); self::assertSame($suggestionQuery, $suggestionEvent->getQuery()); diff --git a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php index 50c77a4..7fe5e53 100644 --- a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php @@ -10,6 +10,7 @@ use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Core\Repository\Values\ContentType\ContentType; use Ibexa\Tests\Core\Search\TestCase; final class ContentSuggestionTest extends TestCase @@ -18,7 +19,7 @@ public function testCreate(): void { $implementation = new ContentSuggestion( 1, - 'content_type_identifier', + $this->createMock(ContentType::class), 'name', 1, 2, @@ -27,7 +28,8 @@ public function testCreate(): void ); self::assertSame(1, $implementation->getContentId()); - self::assertSame('content_type_identifier', $implementation->getContentTypeIdentifier()); + self::assertCount(1, $implementation->getParentLocations()); + self::assertSame('2/4/5', $implementation->getPathString()); self::assertCount(1, $implementation->getParentLocations()); } } diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index 9e0ad1a..8ce6164 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -11,6 +11,7 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Core\Repository\Values\ContentType\ContentType; use PHPUnit\Framework\TestCase; final class SuggestionCollectionTest extends TestCase @@ -21,13 +22,15 @@ public function testCollection(): void self::assertInstanceOf(MutableArrayList::class, $collection); self::assertInstanceOf(SuggestionCollection::class, $collection); - $collection->append(new ContentSuggestion(10, 'article', 'test', 1, 2)); - $collection->append(new ContentSuggestion(20, 'article', 'test2', 1, 2)); - $collection->append(new ContentSuggestion(30, 'article', 'test3', 1, 2)); - $collection->append(new ContentSuggestion(10, 'article', 'test4', 1, 2)); - $collection->append(new ContentSuggestion(50, 'article', 'test5', 1, 2)); - $collection->append(new ContentSuggestion(60, 'article', 'test6', 1, 2)); - $collection->append(new ContentSuggestion(70, 'article', 'test7', 1, 2)); + $contentTypeMock = $this->createMock(ContentType::class); + + $collection->append(new ContentSuggestion(10, $contentTypeMock, 'test', 1, 2)); + $collection->append(new ContentSuggestion(20, $contentTypeMock, 'test2', 1, 2)); + $collection->append(new ContentSuggestion(30, $contentTypeMock, 'test3', 1, 2)); + $collection->append(new ContentSuggestion(10, $contentTypeMock, 'test4', 1, 2)); + $collection->append(new ContentSuggestion(50, $contentTypeMock, 'test5', 1, 2)); + $collection->append(new ContentSuggestion(60, $contentTypeMock, 'test6', 1, 2)); + $collection->append(new ContentSuggestion(70, $contentTypeMock, 'test7', 1, 2)); self::assertCount(7, $collection); diff --git a/tests/contracts/Model/Suggestion/SuggestionTest.php b/tests/contracts/Model/Suggestion/SuggestionTest.php index 0e2e0e3..2da2619 100644 --- a/tests/contracts/Model/Suggestion/SuggestionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionTest.php @@ -8,7 +8,6 @@ namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Model\Suggestion\Suggestion; use PHPUnit\Framework\TestCase; @@ -18,29 +17,18 @@ public function testSuggestionCreate(): void { $implementation = $this->createSuggestion( 0, - 'name', - '2/4/5', - [ - new ParentLocation(10, 1, 'text_1'), - ] + 'name' ); self::assertInstanceOf(Suggestion::class, $implementation); self::assertSame('name', $implementation->getName()); - self::assertSame('2/4/5', $implementation->getPathString()); - self::assertCount(1, $implementation->getParentLocations()); } - /** - * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations - */ private function createSuggestion( int $score, - string $name, - string $pathString = '', - array $parentLocations = [] + string $name ): Suggestion { - return new class($score, $name, $pathString, $parentLocations) extends Suggestion { + return new class($score, $name) extends Suggestion { public function getType(): string { return 'test_implementation'; diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php index 1b1164a..b63eff5 100644 --- a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -10,7 +10,8 @@ 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\Core\Repository\Values\ContentType\ContentType; +use Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent; use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion as ContentSuggestionModel; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; @@ -24,7 +25,7 @@ final class ContentSuggestionSubscriberTest extends TestCase public function testSubscribedEvents(): void { $this->assertSame( - [SuggestionEvent::class => 'onContentSuggestion'], + [BuildSuggestionCollectionEvent::class => 'onBuildSuggestionCollectionEvent'], ContentSuggestionSubscriber::getSubscribedEvents() ); } @@ -37,8 +38,8 @@ public function testOnContentSuggestion(): void $subscriber = new ContentSuggestionSubscriber($searchService, $mapper); - $event = new SuggestionEvent($query); - $subscriber->onContentSuggestion($event); + $event = new BuildSuggestionCollectionEvent($query); + $subscriber->onBuildSuggestionCollectionEvent($event); $collection = $event->getSuggestionCollection(); @@ -73,7 +74,7 @@ private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContent $searchHitToContentSuggestionMapperMock->method('map')->willReturn( new ContentSuggestionModel( 10.0, - 'test', + $this->createMock(ContentType::class), 'test', 1, 2, diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index a44df4b..849f12a 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -8,8 +8,8 @@ namespace Ibexa\Tests\Search\Service\Event; -use Ibexa\Contracts\Search\Event\AfterSuggestionEvent; -use Ibexa\Contracts\Search\Event\BeforeSuggestionEvent; +use Ibexa\Contracts\Search\Event\BeforeSuggestEvent; +use Ibexa\Contracts\Search\Event\SuggestEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\SuggestionQuery; @@ -44,14 +44,14 @@ public function testSuggestWithoutPropagationStop(): void ->willReturnCallback(static function (Event $event) use (&$callCount, $query, $suggestionCollection): Event { ++$callCount; if ($callCount === 1) { - self::assertInstanceOf(BeforeSuggestionEvent::class, $event); + self::assertInstanceOf(BeforeSuggestEvent::class, $event); - return new BeforeSuggestionEvent($query); + return new BeforeSuggestEvent($query); } - self::assertInstanceOf(AfterSuggestionEvent::class, $event); + self::assertInstanceOf(SuggestEvent::class, $event); - return new AfterSuggestionEvent($query, $suggestionCollection); + return new SuggestEvent($query, $suggestionCollection); }); $this->innerServiceMock @@ -69,7 +69,7 @@ public function testSuggestWithoutPropagationStop(): void public function testSuggestWithPropagationStop(): void { $query = new SuggestionQuery('test', 10, 'eng-GB'); - $beforeEvent = new BeforeSuggestionEvent($query); + $beforeEvent = new BeforeSuggestEvent($query); $beforeEvent->stopPropagation(); $this->eventDispatcherMock From 68a5e848779a90f2159e24ac927b6546fe868542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 3 Nov 2023 13:33:55 +0100 Subject: [PATCH 45/66] Code review suggestions applied --- .../Normalizer/Suggestion/ContentSuggestionNormalizer.php | 2 +- .../Normalizer/Suggestion/ParentLocationNormalizer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index 40eb871..819709f 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -31,7 +31,7 @@ public function normalize($object, string $format = null, array $context = []): return [ 'contentId' => $object->getContentId(), 'locationId' => $object->getLocationId(), - 'contentTypeIdentifier' => $object->getContentType(), + 'contentTypeIdentifier' => $object->getContentType()->id, 'name' => $object->getName(), 'pathString' => $object->getPathString(), 'type' => 'content', diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php index 9a90b7d..fd234ee 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php @@ -21,7 +21,7 @@ final class ParentLocationNormalizer implements NormalizerInterface public function normalize($object, string $format = null, array $context = []): array { return [ - 'contentId' => $object->getId(), + 'id' => $object->getId(), 'locationId' => $object->getLocationId(), 'name' => $object->getName(), ]; From a5f395c2e03bb67aa805c11673bbfbb9113a825d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 10:10:23 +0100 Subject: [PATCH 46/66] Added container.service_subscriber for serializer --- src/bundle/Resources/config/services.yaml | 8 ++++++++ src/bundle/Resources/config/services/suggestions.yaml | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 3c68994..25c49eb 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -17,6 +17,14 @@ services: tags: - controller.service_arguments + Ibexa\Bundle\Search\Controller\SuggestionController: + tags: + - { name: 'container.service_subscriber', key: 'serializer', id: 'ibexa.search.suggestion.serializer' } + + Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: + tags: + - { name: 'controller.argument_value_resolver' } + Ibexa\Search\Mapper\PagerSearchContentToDataMapper: arguments: $contentTypeService: '@ibexa.api.service.content_type' diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 24e78ed..df564db 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -8,14 +8,6 @@ services: autowire: true public: false - Ibexa\Bundle\Search\Controller\SuggestionController: - tags: - - { name: 'container.service_subscriber', key: 'serializer', id: 'ibexa.search.suggestion.serializer' } - - Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: - tags: - - { name: 'controller.argument_value_resolver' } - Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ From c360c2aa96d1eec5b9ee9727101faf831bb2646e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 08:56:17 +0100 Subject: [PATCH 47/66] Fixed phpstan.neon --- phpstan-baseline.neon | 3 --- phpstan.neon | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1769ec6..ba9018e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,8 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Cannot call method (log|debug|info|notice|warning|error|critical|alert|emergency)\\(\\) on Psr\\\\Log\\\\LoggerInterface\\|null\\.$#" - - message: "#^Method Ibexa\\\\Bundle\\\\Search\\\\DependencyInjection\\\\Configuration\\\\Parser\\\\Search\\:\\:addSemanticConfig\\(\\) has no return type specified\\.$#" count: 1 diff --git a/phpstan.neon b/phpstan.neon index 129755d..d080f65 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,3 +8,6 @@ parameters: paths: - src - tests + + ignoreErrors: + - message: "#^Cannot call method (log|debug|info|notice|warning|error|critical|alert|emergency)\\(\\) on Psr\\\\Log\\\\LoggerInterface\\|null\\.$#" From 739ff5643b2dc231f7e15dcd62d9fe631d8514c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 10:13:46 +0100 Subject: [PATCH 48/66] Fixed ContentType serialization --- src/bundle/Resources/config/services.yaml | 4 ---- src/bundle/Resources/config/services/suggestions.yaml | 4 ++++ .../Normalizer/Suggestion/ContentSuggestionNormalizer.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bundle/Resources/config/services.yaml b/src/bundle/Resources/config/services.yaml index 25c49eb..5becd8c 100644 --- a/src/bundle/Resources/config/services.yaml +++ b/src/bundle/Resources/config/services.yaml @@ -21,10 +21,6 @@ services: tags: - { name: 'container.service_subscriber', key: 'serializer', id: 'ibexa.search.suggestion.serializer' } - Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: - tags: - - { name: 'controller.argument_value_resolver' } - Ibexa\Search\Mapper\PagerSearchContentToDataMapper: arguments: $contentTypeService: '@ibexa.api.service.content_type' diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index df564db..10356e3 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -8,6 +8,10 @@ services: autowire: true public: false + Ibexa\Bundle\Search\ArgumentResolver\SuggestionQueryArgumentResolver: + tags: + - { name: 'controller.argument_value_resolver' } + Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber: ~ Ibexa\Search\Mapper\SearchHitToContentSuggestionMapper: ~ diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index 819709f..d4aff49 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -31,7 +31,7 @@ public function normalize($object, string $format = null, array $context = []): return [ 'contentId' => $object->getContentId(), 'locationId' => $object->getLocationId(), - 'contentTypeIdentifier' => $object->getContentType()->id, + 'contentTypeIdentifier' => $object->getContentType()->identifier, 'name' => $object->getName(), 'pathString' => $object->getPathString(), 'type' => 'content', From 319359f5127542899c5b44befe3b54b659708b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:01:24 +0100 Subject: [PATCH 49/66] Update src/contracts/Model/Suggestion/SuggestionCollection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/contracts/Model/Suggestion/SuggestionCollection.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/contracts/Model/Suggestion/SuggestionCollection.php b/src/contracts/Model/Suggestion/SuggestionCollection.php index 0330772..5ac56ee 100644 --- a/src/contracts/Model/Suggestion/SuggestionCollection.php +++ b/src/contracts/Model/Suggestion/SuggestionCollection.php @@ -40,9 +40,7 @@ public function append($item): void public function sortByScore(): void { - usort($this->items, static function ($a, $b): int { - return $b->getScore() <=> $a->getScore(); - }); + usort($this->items, static fn ($a, $b): int => $b->getScore() <=> $a->getScore()); } public function truncate(int $count): void From 248cede26abb77b5185a8ad4ca32cdfbd39043a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:03:15 +0100 Subject: [PATCH 50/66] Update src/contracts/Model/Suggestion/ParentLocationCollection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/contracts/Model/Suggestion/ParentLocationCollection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/contracts/Model/Suggestion/ParentLocationCollection.php b/src/contracts/Model/Suggestion/ParentLocationCollection.php index e7bbe7e..55291d0 100644 --- a/src/contracts/Model/Suggestion/ParentLocationCollection.php +++ b/src/contracts/Model/Suggestion/ParentLocationCollection.php @@ -27,8 +27,8 @@ public function append($item): void throw new InvalidArgumentException( '$item', sprintf( - 'Argument 1 passed to %s::append() must be an instance of %s, %s given', - __CLASS__, + 'Argument 1 passed to %s() must be an instance of %s, %s given', + __METHOD__, Suggestion::class, is_object($item) ? get_class($item) : gettype($item) ) From 746eeaac12fac2ddfc508a5621e618e8720193fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:03:30 +0100 Subject: [PATCH 51/66] Update src/contracts/Model/Suggestion/SuggestionCollection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/contracts/Model/Suggestion/SuggestionCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/Model/Suggestion/SuggestionCollection.php b/src/contracts/Model/Suggestion/SuggestionCollection.php index 5ac56ee..6789253 100644 --- a/src/contracts/Model/Suggestion/SuggestionCollection.php +++ b/src/contracts/Model/Suggestion/SuggestionCollection.php @@ -30,7 +30,7 @@ public function append($item): void '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) + get_debug_type($item), ) ); } From 308cc467e0dd978cc7598ecf20227ada79e3bfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:04:21 +0100 Subject: [PATCH 52/66] Update src/contracts/Model/Suggestion/SuggestionCollection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/contracts/Model/Suggestion/SuggestionCollection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/contracts/Model/Suggestion/SuggestionCollection.php b/src/contracts/Model/Suggestion/SuggestionCollection.php index 6789253..5fad4e5 100644 --- a/src/contracts/Model/Suggestion/SuggestionCollection.php +++ b/src/contracts/Model/Suggestion/SuggestionCollection.php @@ -27,8 +27,8 @@ public function append($item): void throw new InvalidArgumentException( '$item', sprintf( - 'Argument 1 passed to %s::append() must be an instance of %s, %s given', - __CLASS__, + 'Argument 1 passed to %s() must be an instance of %s, %s given', + __METHOD__, Suggestion::class, get_debug_type($item), ) From 1cb0968ac2b3cdb913a98adc97143090d8d6bba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:04:39 +0100 Subject: [PATCH 53/66] Update src/contracts/Model/Suggestion/ParentLocationCollection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Niedzielski --- src/contracts/Model/Suggestion/ParentLocationCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/Model/Suggestion/ParentLocationCollection.php b/src/contracts/Model/Suggestion/ParentLocationCollection.php index 55291d0..d7dfb34 100644 --- a/src/contracts/Model/Suggestion/ParentLocationCollection.php +++ b/src/contracts/Model/Suggestion/ParentLocationCollection.php @@ -30,7 +30,7 @@ public function append($item): void 'Argument 1 passed to %s() must be an instance of %s, %s given', __METHOD__, Suggestion::class, - is_object($item) ? get_class($item) : gettype($item) + get_debug_type($item), ) ); } From 28d94e73cb3660792984bc97caace31c413d8ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 14:27:31 +0100 Subject: [PATCH 54/66] Made changes in ContentSuggestion - Complete object provided --- .../config/services/normalizers.yaml | 10 +---- .../Model/Suggestion/ContentSuggestion.php | 27 +++++-------- .../Model/Suggestion/ParentLocation.php | 40 ------------------- .../Suggestion/ParentLocationCollection.php | 7 ++-- src/contracts/Model/Suggestion/Suggestion.php | 6 +-- .../ParentLocationProviderInterface.php | 2 +- .../SearchHitToContentSuggestionMapper.php | 8 ++-- src/lib/Provider/ParentLocationProvider.php | 9 +---- .../ContentSuggestionNormalizer.php | 8 ++-- ...nNormalizer.php => LocationNormalizer.php} | 14 +++---- .../Suggestion/ContentSuggestionTest.php | 34 +++++++++++----- .../Model/Suggestion/ParentCollectionTest.php | 30 +++++++++----- .../Suggestion/SuggestionCollectionTest.php | 17 ++++---- .../ContentSuggestionSubscriberTest.php | 11 +++-- ...SearchHitToContentSuggestionMapperTest.php | 21 +++++----- 15 files changed, 107 insertions(+), 137 deletions(-) delete mode 100644 src/contracts/Model/Suggestion/ParentLocation.php rename src/lib/Serializer/Normalizer/Suggestion/{ParentLocationNormalizer.php => LocationNormalizer.php} (63%) diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index 84a95f7..c1e87b2 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -10,21 +10,15 @@ services: arguments: $normalizers: - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer' - - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationNormalizer' + - '@Ibexa\Search\Serializer\Normalizer\Suggestion\LocationNormalizer' $encoders: - '@serializer.encoder.json' Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer: autoconfigure: false - tags: - - { name: 'ibexa.search.serializer.normalizer' } Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationCollectionNormalizer: autoconfigure: false - tags: - - { name: 'ibexa.search.serializer.normalizer' } - Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationNormalizer: + Ibexa\Search\Serializer\Normalizer\Suggestion\LocationNormalizer: autoconfigure: false - tags: - - { name: 'ibexa.search.serializer.normalizer' } diff --git a/src/contracts/Model/Suggestion/ContentSuggestion.php b/src/contracts/Model/Suggestion/ContentSuggestion.php index 8347111..92cf661 100644 --- a/src/contracts/Model/Suggestion/ContentSuggestion.php +++ b/src/contracts/Model/Suggestion/ContentSuggestion.php @@ -8,13 +8,12 @@ namespace Ibexa\Contracts\Search\Model\Suggestion; +use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; final class ContentSuggestion extends Suggestion { - private int $contentId; - - private ?int $locationId; + private Content $content; private ContentType $contentType; @@ -23,33 +22,25 @@ final class ContentSuggestion extends Suggestion private ParentLocationCollection $parentsLocation; /** - * @param array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> $parentLocations + * @param array<\Ibexa\Contracts\Core\Repository\Values\Content\Location> $parentLocations */ public function __construct( float $score, + Content $content, ContentType $contentType, - string $name, - int $contentId, - ?int $locationId = null, string $pathString = '', array $parentLocations = [] ) { - parent::__construct($score, $name); - $this->contentId = $contentId; + parent::__construct($score, $content->getName()); + $this->content = $content; $this->contentType = $contentType; - $this->locationId = $locationId; $this->pathString = $pathString; $this->parentsLocation = new ParentLocationCollection($parentLocations); } - public function getContentId(): int - { - return $this->contentId; - } - - public function getLocationId(): ?int + public function getContent(): Content { - return $this->locationId; + return $this->content; } public function getContentType(): ContentType @@ -62,7 +53,7 @@ public function getPathString(): string return $this->pathString; } - public function getParentLocations(): ParentLocationCollection + public function getParentsLocation(): ParentLocationCollection { return $this->parentsLocation; } diff --git a/src/contracts/Model/Suggestion/ParentLocation.php b/src/contracts/Model/Suggestion/ParentLocation.php deleted file mode 100644 index e4e5cba..0000000 --- a/src/contracts/Model/Suggestion/ParentLocation.php +++ /dev/null @@ -1,40 +0,0 @@ -id = $id; - $this->locationId = $locationId; - $this->name = $name; - } - - public function getId(): int - { - return $this->id; - } - - public function getLocationId(): int - { - return $this->locationId; - } - - public function getName(): string - { - return $this->name; - } -} diff --git a/src/contracts/Model/Suggestion/ParentLocationCollection.php b/src/contracts/Model/Suggestion/ParentLocationCollection.php index d7dfb34..06aaeda 100644 --- a/src/contracts/Model/Suggestion/ParentLocationCollection.php +++ b/src/contracts/Model/Suggestion/ParentLocationCollection.php @@ -10,10 +10,11 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; +use Ibexa\Contracts\Core\Repository\Values\Content\Location; /** * @template-extends \Ibexa\Contracts\Core\Collection\MutableArrayList< - * \Ibexa\Contracts\Search\Model\Suggestion\ParentLocation + * \Ibexa\Contracts\Core\Repository\Values\Content\Location * > */ final class ParentLocationCollection extends MutableArrayList @@ -23,13 +24,13 @@ final class ParentLocationCollection extends MutableArrayList */ public function append($item): void { - if (!$item instanceof ParentLocation) { + if (!$item instanceof Location) { throw new InvalidArgumentException( '$item', sprintf( 'Argument 1 passed to %s() must be an instance of %s, %s given', __METHOD__, - Suggestion::class, + Location::class, get_debug_type($item), ) ); diff --git a/src/contracts/Model/Suggestion/Suggestion.php b/src/contracts/Model/Suggestion/Suggestion.php index 8c2cc74..cd88f3d 100644 --- a/src/contracts/Model/Suggestion/Suggestion.php +++ b/src/contracts/Model/Suggestion/Suggestion.php @@ -14,11 +14,11 @@ abstract class Suggestion extends ValueObject { private float $score; - private string $name; + private ?string $name; public function __construct( float $score, - string $name + string $name = null ) { $this->score = $score; $this->name = $name; @@ -31,7 +31,7 @@ public function getScore(): float return $this->score; } - public function getName(): string + public function getName(): ?string { return $this->name; } diff --git a/src/contracts/Provider/ParentLocationProviderInterface.php b/src/contracts/Provider/ParentLocationProviderInterface.php index 68bd611..bb81245 100644 --- a/src/contracts/Provider/ParentLocationProviderInterface.php +++ b/src/contracts/Provider/ParentLocationProviderInterface.php @@ -13,7 +13,7 @@ interface ParentLocationProviderInterface /** * @param array $parentLocationIds * - * @return array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> + * @return array<\Ibexa\Contracts\Core\Repository\Values\Content\Location> */ public function provide(array $parentLocationIds): array; } diff --git a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php index 64d3f28..1ad70fb 100644 --- a/src/lib/Mapper/SearchHitToContentSuggestionMapper.php +++ b/src/lib/Mapper/SearchHitToContentSuggestionMapper.php @@ -51,16 +51,14 @@ public function map(SearchHit $searchHit): ?ContentSuggestion $parentsLocation = array_slice($parentsLocation, (int)$position); } - $parentCollection = $this->parentLocationProvider->provide($parentsLocation); + $parentLocations = $this->parentLocationProvider->provide($parentsLocation); return new ContentSuggestion( $searchHit->score ?? 50.0, + $content, $content->getContentType(), - $content->getName() ?? '', - $content->getVersionInfo()->getContentInfo()->getId(), - $content->getVersionInfo()->getContentInfo()->getMainLocation()->id ?? null, implode('/', $parentsLocation), - $parentCollection + $parentLocations ); } } diff --git a/src/lib/Provider/ParentLocationProvider.php b/src/lib/Provider/ParentLocationProvider.php index 5564a8f..bd8e0c1 100644 --- a/src/lib/Provider/ParentLocationProvider.php +++ b/src/lib/Provider/ParentLocationProvider.php @@ -9,7 +9,6 @@ namespace Ibexa\Search\Provider; use Ibexa\Contracts\Core\Repository\LocationService; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface; final class ParentLocationProvider implements ParentLocationProviderInterface @@ -24,18 +23,14 @@ public function __construct(LocationService $locationService) /** * @param array $parentLocationIds * - * @return array<\Ibexa\Contracts\Search\Model\Suggestion\ParentLocation> + * @return array<\Ibexa\Contracts\Core\Repository\Values\Content\Location> */ public function provide(array $parentLocationIds): array { $parentLocations = $this->locationService->loadLocationList($parentLocationIds); $parentLocationMap = []; foreach ($parentLocations as $parentLocation) { - $parentLocationMap[] = new ParentLocation( - $parentLocation->getContentInfo()->getId(), - $parentLocation->id, - $parentLocation->getContentInfo()->name - ); + $parentLocationMap[] = $parentLocation; } return $parentLocationMap; diff --git a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php index d4aff49..cba0d07 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ContentSuggestionNormalizer.php @@ -28,14 +28,16 @@ final class ContentSuggestionNormalizer implements */ public function normalize($object, string $format = null, array $context = []): array { + $content = $object->getContent(); + return [ - 'contentId' => $object->getContentId(), - 'locationId' => $object->getLocationId(), + 'contentId' => $content->id, + 'locationId' => $content->getVersionInfo()->getContentInfo()->getMainLocation()->id ?? null, 'contentTypeIdentifier' => $object->getContentType()->identifier, 'name' => $object->getName(), 'pathString' => $object->getPathString(), 'type' => 'content', - 'parentLocations' => $this->normalizer->normalize($object->getParentLocations()), + 'parentLocations' => $this->normalizer->normalize($object->getParentsLocation()), ]; } diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/LocationNormalizer.php similarity index 63% rename from src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php rename to src/lib/Serializer/Normalizer/Suggestion/LocationNormalizer.php index fd234ee..f30960f 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/LocationNormalizer.php @@ -8,28 +8,28 @@ namespace Ibexa\Search\Serializer\Normalizer\Suggestion; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Core\Repository\Values\Content\Location; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -final class ParentLocationNormalizer implements NormalizerInterface +final class LocationNormalizer implements NormalizerInterface { /** - * @param \Ibexa\Contracts\Search\Model\Suggestion\ParentLocation $object + * @param \Ibexa\Contracts\Core\Repository\Values\Content\Location $object * * @return array */ public function normalize($object, string $format = null, array $context = []): array { return [ - 'id' => $object->getId(), - 'locationId' => $object->getLocationId(), - 'name' => $object->getName(), + 'id' => $object->getContentInfo()->getId(), + 'locationId' => $object->id, + 'name' => $object->getContent()->getName(), ]; } public function supportsNormalization($data, string $format = null): bool { - return $data instanceof ParentLocation; + return $data instanceof Location; } public function hasCacheableSupportsMethod(): bool diff --git a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php index 7fe5e53..08f8508 100644 --- a/tests/contracts/Model/Suggestion/ContentSuggestionTest.php +++ b/tests/contracts/Model/Suggestion/ContentSuggestionTest.php @@ -9,7 +9,9 @@ namespace Ibexa\Tests\Contracts\Search\Model\Suggestion; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +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\Tests\Core\Search\TestCase; @@ -17,19 +19,31 @@ final class ContentSuggestionTest extends TestCase { public function testCreate(): void { + $contentType = new ContentType(); + $content = new Content([ + 'versionInfo' => new VersionInfo([ + 'names' => ['eng-GB' => 'Test'], + 'initialLanguageCode' => 'eng-GB', + 'contentInfo' => [ + 'id' => 1, + ], + ]), + ]); + $implementation = new ContentSuggestion( 1, - $this->createMock(ContentType::class), - 'name', - 1, - 2, - 'text', - [0 => new ParentLocation(0, 1, 'text')] + $content, + $contentType, + '2/4/5', + [new Location([ + 'id' => 1, + 'path' => [2, 4, 5], + ])] ); - self::assertSame(1, $implementation->getContentId()); - self::assertCount(1, $implementation->getParentLocations()); + self::assertSame($content, $implementation->getContent()); + self::assertCount(1, $implementation->getParentsLocation()); self::assertSame('2/4/5', $implementation->getPathString()); - self::assertCount(1, $implementation->getParentLocations()); + self::assertSame($contentType, $implementation->getContentType()); } } diff --git a/tests/contracts/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php index 81aa3c6..5b6323c 100644 --- a/tests/contracts/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -10,7 +10,8 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Core\Exception\InvalidArgumentException; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; +use Ibexa\Contracts\Core\Persistence\Content\ContentInfo; +use Ibexa\Contracts\Core\Persistence\Content\Location; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use PHPUnit\Framework\TestCase; use stdClass; @@ -23,22 +24,33 @@ public function testCollection(): void self::assertInstanceOf(MutableArrayList::class, $collection); self::assertInstanceOf(ParentLocationCollection::class, $collection); - $collection->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')); + $collection->append($this->getLocation(10)); + $collection->append($this->getLocation(10)); + $collection->append($this->getLocation(10)); + $collection->append($this->getLocation(40)); + $collection->append($this->getLocation(50)); + $collection->append($this->getLocation(60)); + $collection->append($this->getLocation(70)); self::assertCount(7, $collection); foreach ($collection as $item) { - self::assertInstanceOf(ParentLocation::class, $item); + self::assertInstanceOf(Location::class, $item); } $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given'); $collection->append(new stdClass()); } + + private function getLocation(int $locationId): Location + { + return new Location([ + 'id' => $locationId, + 'contentInfo' => new ContentInfo([ + 'id' => $locationId, + 'name' => 'name_' . $locationId, + ]), + ]); + } } diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index 8ce6164..144d47e 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -11,6 +11,8 @@ use Ibexa\Contracts\Core\Collection\MutableArrayList; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; +use Ibexa\Core\Repository\Values\Content\Content; +use Ibexa\Core\Repository\Values\Content\Location; use Ibexa\Core\Repository\Values\ContentType\ContentType; use PHPUnit\Framework\TestCase; @@ -22,15 +24,16 @@ public function testCollection(): void self::assertInstanceOf(MutableArrayList::class, $collection); self::assertInstanceOf(SuggestionCollection::class, $collection); + $contentMock = $this->createMock(Content::class); $contentTypeMock = $this->createMock(ContentType::class); - $collection->append(new ContentSuggestion(10, $contentTypeMock, 'test', 1, 2)); - $collection->append(new ContentSuggestion(20, $contentTypeMock, 'test2', 1, 2)); - $collection->append(new ContentSuggestion(30, $contentTypeMock, 'test3', 1, 2)); - $collection->append(new ContentSuggestion(10, $contentTypeMock, 'test4', 1, 2)); - $collection->append(new ContentSuggestion(50, $contentTypeMock, 'test5', 1, 2)); - $collection->append(new ContentSuggestion(60, $contentTypeMock, 'test6', 1, 2)); - $collection->append(new ContentSuggestion(70, $contentTypeMock, 'test7', 1, 2)); + $collection->append(new ContentSuggestion(10, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(20, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(30, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(10, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(50, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(60, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(70, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); self::assertCount(7, $collection); diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php index b63eff5..87212e6 100644 --- a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -8,14 +8,15 @@ namespace Ibexa\Tests\Search\EventDispatcher\EventListener; +use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchResult; use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; use Ibexa\Contracts\Search\Event\BuildSuggestionCollectionEvent; use Ibexa\Contracts\Search\Mapper\SearchHitToContentSuggestionMapperInterface; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion as ContentSuggestionModel; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Core\Repository\SiteAccessAware\SearchService; +use Ibexa\Core\Repository\Values\Content\Location; use Ibexa\Search\EventDispatcher\EventListener\ContentSuggestionSubscriber; use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; @@ -74,13 +75,11 @@ private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContent $searchHitToContentSuggestionMapperMock->method('map')->willReturn( new ContentSuggestionModel( 10.0, + $this->createMock(Content::class), $this->createMock(ContentType::class), - 'test', - 1, - 2, - 'test', + '1/2/3', [ - new ParentLocation(1, 2, 'test'), + new Location(['id' => 1, 'path' => [1, 2, 3]]), ] ) ); diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index ce20830..efb86d2 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -8,11 +8,10 @@ namespace Ibexa\Tests\Search\Mapper; -use Ibexa\Contracts\Core\Persistence\Content\ContentInfo; +use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo; use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchHit; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Contracts\Search\Model\Suggestion\ContentSuggestion; -use Ibexa\Contracts\Search\Model\Suggestion\ParentLocation; use Ibexa\Contracts\Search\Provider\ParentLocationProviderInterface; use Ibexa\Core\Repository\Values\Content\Content; use Ibexa\Core\Repository\Values\Content\Location; @@ -30,9 +29,7 @@ public function testMap(): void $this->getConfigResolverMock() ); - $result = $mapper->map( - new SearchHit([ - 'valueObject' => new Content([ + $content = new Content([ 'id' => 1, 'contentInfo' => new ContentInfo([ 'name' => 'name', @@ -43,7 +40,7 @@ public function testMap(): void 'versionInfo' => new VersionInfo([ 'initialLanguageCode' => 'eng-GB', 'names' => ['eng-GB' => 'name_eng'], - 'contentInfo' => new \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo([ + 'contentInfo' => new ContentInfo([ 'id' => 1, 'mainLanguageCode' => 'eng-GB', 'contentTypeId' => 1, @@ -56,14 +53,18 @@ public function testMap(): void 'contentType' => new ContentType([ 'identifier' => 'content_type_identifier', ]), - ]), + ]); + + $result = $mapper->map( + new SearchHit([ + 'valueObject' => $content, ]) ); self::assertInstanceOf(ContentSuggestion::class, $result); - self::assertSame(1, $result->getContentId()); + self::assertSame($content, $result->getContent()); self::assertSame('5/6/7', $result->getPathString()); - self::assertCount(3, $result->getParentLocations()); + self::assertCount(3, $result->getParentsLocation()); self::assertSame('name_eng', $result->getName()); self::assertSame(50.0, $result->getScore()); } @@ -89,7 +90,7 @@ private function getParentLocationProviderMock(): ParentLocationProviderInterfac $locations = []; foreach ($locationIds as $locationId) { - $locations[] = new ParentLocation(10 + $locationId, $locationId, 'parent_' . $locationId); + $locations[] = new Location(['id' => $locationId]); } return $locations; From 2336f022550a5dea8cdce425fbefd7787d60741f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 7 Nov 2023 15:25:08 +0100 Subject: [PATCH 55/66] BeforeSuggestioEvent and SuggestionEvent moved to Service namespace --- src/contracts/Event/{ => Service}/BeforeSuggestEvent.php | 2 +- src/contracts/Event/{ => Service}/SuggestEvent.php | 2 +- src/lib/Service/Event/SuggestionService.php | 4 ++-- tests/lib/Service/Event/SuggestionServiceTest.php | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/contracts/Event/{ => Service}/BeforeSuggestEvent.php (95%) rename src/contracts/Event/{ => Service}/SuggestEvent.php (95%) diff --git a/src/contracts/Event/BeforeSuggestEvent.php b/src/contracts/Event/Service/BeforeSuggestEvent.php similarity index 95% rename from src/contracts/Event/BeforeSuggestEvent.php rename to src/contracts/Event/Service/BeforeSuggestEvent.php index 7acf697..0ab575b 100644 --- a/src/contracts/Event/BeforeSuggestEvent.php +++ b/src/contracts/Event/Service/BeforeSuggestEvent.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Contracts\Search\Event; +namespace Ibexa\Contracts\Search\Event\Service; use Ibexa\Contracts\Core\Repository\Event\BeforeEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; diff --git a/src/contracts/Event/SuggestEvent.php b/src/contracts/Event/Service/SuggestEvent.php similarity index 95% rename from src/contracts/Event/SuggestEvent.php rename to src/contracts/Event/Service/SuggestEvent.php index ae96afa..4094661 100644 --- a/src/contracts/Event/SuggestEvent.php +++ b/src/contracts/Event/Service/SuggestEvent.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Contracts\Search\Event; +namespace Ibexa\Contracts\Search\Event\Service; use Ibexa\Contracts\Core\Repository\Event\AfterEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; diff --git a/src/lib/Service/Event/SuggestionService.php b/src/lib/Service/Event/SuggestionService.php index 7ade7d5..83e8a9c 100644 --- a/src/lib/Service/Event/SuggestionService.php +++ b/src/lib/Service/Event/SuggestionService.php @@ -8,8 +8,8 @@ namespace Ibexa\Search\Service\Event; -use Ibexa\Contracts\Search\Event\BeforeSuggestEvent; -use Ibexa\Contracts\Search\Event\SuggestEvent; +use Ibexa\Contracts\Search\Event\Service\BeforeSuggestEvent; +use Ibexa\Contracts\Search\Event\Service\SuggestEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\Decorator\SuggestionServiceDecorator; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 849f12a..74d07df 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -8,8 +8,8 @@ namespace Ibexa\Tests\Search\Service\Event; -use Ibexa\Contracts\Search\Event\BeforeSuggestEvent; -use Ibexa\Contracts\Search\Event\SuggestEvent; +use Ibexa\Contracts\Search\Event\Service\BeforeSuggestEvent; +use Ibexa\Contracts\Search\Event\Service\SuggestEvent; use Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection; use Ibexa\Contracts\Search\Service\SuggestionServiceInterface; use Ibexa\Search\Model\SuggestionQuery; From 280f8ce392e809faeae7098e604b52d961ba9016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:39:04 +0100 Subject: [PATCH 56/66] Tests improvements --- .../contracts/Model/Suggestion/SuggestionCollectionTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index 144d47e..b6f4db2 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -36,10 +36,7 @@ public function testCollection(): void $collection->append(new ContentSuggestion(70, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); self::assertCount(7, $collection); - - foreach ($collection as $item) { - self::assertInstanceOf(ContentSuggestion::class, $item); - } + self::assertContainsOnlyInstancesOf(ContentSuggestion::class, $collection); $collection->sortByScore(); self::assertSame(70.0, $collection->first()->getScore()); From 05513c9042bd0d538b1cc052dc864de4456cd75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:42:38 +0100 Subject: [PATCH 57/66] Moved config resolving --- .../ArgumentResolver/SuggestionQueryArgumentResolver.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php index cb678b2..002d09a 100644 --- a/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php +++ b/src/bundle/ArgumentResolver/SuggestionQueryArgumentResolver.php @@ -17,11 +17,11 @@ final class SuggestionQueryArgumentResolver implements ArgumentValueResolverInterface { - private int $defaultLimit; + private ConfigResolverInterface $configResolver; public function __construct(ConfigResolverInterface $configResolver) { - $this->defaultLimit = $configResolver->getParameter('search.suggestion.result_limit'); + $this->configResolver = $configResolver; } public function supports(Request $request, ArgumentMetadata $argument): bool @@ -36,8 +36,9 @@ public function supports(Request $request, ArgumentMetadata $argument): bool */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { + $defaultLimit = $this->configResolver->getParameter('search.suggestion.result_limit'); $query = $request->query->get('query'); - $limit = $request->query->getInt('limit', $this->defaultLimit); + $limit = $request->query->getInt('limit', $defaultLimit); $language = $request->query->get('language'); if ($query === null) { From 132f0d9fdfc86b785259bc6d2bee12be6d8ce911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:50:24 +0100 Subject: [PATCH 58/66] Fixed sonar cloud --- .../ContentSuggestionSubscriber.php | 5 +++-- .../Model/Suggestion/ParentCollectionTest.php | 7 ++++++- .../Suggestion/SuggestionCollectionTest.php | 12 +++++------ .../ContentSuggestionSubscriberTest.php | 4 +++- .../Service/Event/SuggestionServiceTest.php | 20 ++++++++++--------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php index 5f578d9..859d973 100644 --- a/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php +++ b/src/lib/EventDispatcher/EventListener/ContentSuggestionSubscriber.php @@ -40,8 +40,9 @@ public static function getSubscribedEvents(): array ]; } - public function onBuildSuggestionCollectionEvent(BuildSuggestionCollectionEvent $event): BuildSuggestionCollectionEvent - { + public function onBuildSuggestionCollectionEvent( + BuildSuggestionCollectionEvent $event + ): BuildSuggestionCollectionEvent { $query = $event->getQuery(); $value = $query->getQuery(); diff --git a/tests/contracts/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php index 5b6323c..fcc0027 100644 --- a/tests/contracts/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -39,7 +39,12 @@ public function testCollection(): void } $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given'); + $this->expectExceptionMessage( + <<<'EOD' +Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() +must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given +EOD + ); $collection->append(new stdClass()); } diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index b6f4db2..50f6bb7 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -28,12 +28,12 @@ public function testCollection(): void $contentTypeMock = $this->createMock(ContentType::class); $collection->append(new ContentSuggestion(10, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(20, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(30, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(10, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(50, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(60, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); - $collection->append(new ContentSuggestion(70, $contentMock, $contentTypeMock, '1/2/3', [new Location()])); + $collection->append(new ContentSuggestion(20, $contentMock, $contentTypeMock, '1/3/5', [new Location()])); + $collection->append(new ContentSuggestion(30, $contentMock, $contentTypeMock, '1/2/6', [new Location()])); + $collection->append(new ContentSuggestion(10, $contentMock, $contentTypeMock, '1/3/4', [new Location()])); + $collection->append(new ContentSuggestion(50, $contentMock, $contentTypeMock, '5/7/10', [new Location()])); + $collection->append(new ContentSuggestion(60, $contentMock, $contentTypeMock, '5/2/1', [new Location()])); + $collection->append(new ContentSuggestion(70, $contentMock, $contentTypeMock, '8/2/10', [new Location()])); self::assertCount(7, $collection); self::assertContainsOnlyInstancesOf(ContentSuggestion::class, $collection); diff --git a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php index 87212e6..de1da1b 100644 --- a/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php +++ b/tests/lib/EventDispatcher/EventListener/ContentSuggestionSubscriberTest.php @@ -71,7 +71,9 @@ private function getSearchServiceMock(): SearchService */ private function getSearchHitToContentSuggestionMapperMock(): SearchHitToContentSuggestionMapperInterface { - $searchHitToContentSuggestionMapperMock = $this->createMock(SearchHitToContentSuggestionMapperInterface::class); + $searchHitToContentSuggestionMapperMock = $this->createMock( + SearchHitToContentSuggestionMapperInterface::class + ); $searchHitToContentSuggestionMapperMock->method('map')->willReturn( new ContentSuggestionModel( 10.0, diff --git a/tests/lib/Service/Event/SuggestionServiceTest.php b/tests/lib/Service/Event/SuggestionServiceTest.php index 74d07df..78ceb7d 100644 --- a/tests/lib/Service/Event/SuggestionServiceTest.php +++ b/tests/lib/Service/Event/SuggestionServiceTest.php @@ -41,18 +41,20 @@ public function testSuggestWithoutPropagationStop(): void $this->eventDispatcherMock ->expects(self::exactly(2)) ->method('dispatch') - ->willReturnCallback(static function (Event $event) use (&$callCount, $query, $suggestionCollection): Event { - ++$callCount; - if ($callCount === 1) { - self::assertInstanceOf(BeforeSuggestEvent::class, $event); + ->willReturnCallback( + static function (Event $event) use (&$callCount, $query, $suggestionCollection): Event { + ++$callCount; + if ($callCount === 1) { + self::assertInstanceOf(BeforeSuggestEvent::class, $event); - return new BeforeSuggestEvent($query); - } + return new BeforeSuggestEvent($query); + } - self::assertInstanceOf(SuggestEvent::class, $event); + self::assertInstanceOf(SuggestEvent::class, $event); - return new SuggestEvent($query, $suggestionCollection); - }); + return new SuggestEvent($query, $suggestionCollection); + } + ); $this->innerServiceMock ->expects($this->once()) From aa28f898d15b691897368c4c63c44b6ab08268b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:52:37 +0100 Subject: [PATCH 59/66] Fixed tests --- .../Model/Suggestion/ParentCollectionTest.php | 2 +- .../Model/Suggestion/SuggestionCollectionTest.php | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/contracts/Model/Suggestion/ParentCollectionTest.php b/tests/contracts/Model/Suggestion/ParentCollectionTest.php index fcc0027..cb49909 100644 --- a/tests/contracts/Model/Suggestion/ParentCollectionTest.php +++ b/tests/contracts/Model/Suggestion/ParentCollectionTest.php @@ -42,7 +42,7 @@ public function testCollection(): void $this->expectExceptionMessage( <<<'EOD' Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() -must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given +must be an instance of Ibexa\Contracts\Core\Repository\Values\Content\Location, stdClass given EOD ); $collection->append(new stdClass()); diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index 50f6bb7..36e34e3 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -14,7 +14,9 @@ use Ibexa\Core\Repository\Values\Content\Content; use Ibexa\Core\Repository\Values\Content\Location; use Ibexa\Core\Repository\Values\ContentType\ContentType; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use stdClass; final class SuggestionCollectionTest extends TestCase { @@ -43,5 +45,14 @@ public function testCollection(): void $collection->truncate(5); self::assertCount(5, $collection); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + <<<'EOD' +Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() +must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given +EOD + ); + $collection->append(new stdClass()); } } From db57d92881375d2ca0150529b394f550bfbb30e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:53:48 +0100 Subject: [PATCH 60/66] Fixed indent --- ...SearchHitToContentSuggestionMapperTest.php | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php index efb86d2..76fc9d2 100644 --- a/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php +++ b/tests/lib/Mapper/SearchHitToContentSuggestionMapperTest.php @@ -30,30 +30,30 @@ public function testMap(): void ); $content = new Content([ + 'id' => 1, + 'contentInfo' => new ContentInfo([ + 'name' => 'name', + 'mainLanguageCode' => 'eng-GB', + 'mainLocationId' => 1, + 'contentTypeId' => 1, + ]), + 'versionInfo' => new VersionInfo([ + 'initialLanguageCode' => 'eng-GB', + 'names' => ['eng-GB' => 'name_eng'], + 'contentInfo' => new ContentInfo([ 'id' => 1, - 'contentInfo' => new ContentInfo([ - 'name' => 'name', - 'mainLanguageCode' => 'eng-GB', - 'mainLocationId' => 1, - 'contentTypeId' => 1, + 'mainLanguageCode' => 'eng-GB', + 'contentTypeId' => 1, + 'mainLocation' => new Location([ + 'id' => 8, + 'path' => ['1', '2', '3', '4', '5', '6', '7'], ]), - 'versionInfo' => new VersionInfo([ - 'initialLanguageCode' => 'eng-GB', - 'names' => ['eng-GB' => 'name_eng'], - 'contentInfo' => new ContentInfo([ - 'id' => 1, - 'mainLanguageCode' => 'eng-GB', - 'contentTypeId' => 1, - 'mainLocation' => new Location([ - 'id' => 8, - 'path' => ['1', '2', '3', '4', '5', '6', '7'], - ]), - ]), - ]), - 'contentType' => new ContentType([ - 'identifier' => 'content_type_identifier', - ]), - ]); + ]), + ]), + 'contentType' => new ContentType([ + 'identifier' => 'content_type_identifier', + ]), + ]); $result = $mapper->map( new SearchHit([ From 9d9d9c5b974304b6c91437aa70368ec5aaee634b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 8 Nov 2023 13:55:07 +0100 Subject: [PATCH 61/66] Fixed test --- tests/contracts/Model/Suggestion/SuggestionCollectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php index 36e34e3..cded242 100644 --- a/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php +++ b/tests/contracts/Model/Suggestion/SuggestionCollectionTest.php @@ -49,7 +49,7 @@ public function testCollection(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( <<<'EOD' -Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection::append() +Argument 1 passed to Ibexa\Contracts\Search\Model\Suggestion\SuggestionCollection::append() must be an instance of Ibexa\Contracts\Search\Model\Suggestion\Suggestion, stdClass given EOD ); From 9f110c944ee9895b77b0496967e643888cc068c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Tue, 14 Nov 2023 10:45:58 +0100 Subject: [PATCH 62/66] Fixed issue with normalizer --- src/bundle/Resources/config/services/normalizers.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bundle/Resources/config/services/normalizers.yaml b/src/bundle/Resources/config/services/normalizers.yaml index c1e87b2..02c86f5 100644 --- a/src/bundle/Resources/config/services/normalizers.yaml +++ b/src/bundle/Resources/config/services/normalizers.yaml @@ -11,6 +11,7 @@ services: $normalizers: - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ContentSuggestionNormalizer' - '@Ibexa\Search\Serializer\Normalizer\Suggestion\LocationNormalizer' + - '@Ibexa\Search\Serializer\Normalizer\Suggestion\ParentLocationCollectionNormalizer' $encoders: - '@serializer.encoder.json' From 40f2473c69e65749d7b7c506f1c6b93267cba098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Wed, 15 Nov 2023 09:43:11 +0100 Subject: [PATCH 63/66] Fixed issue with normalizer --- .../Suggestion/ParentLocationCollectionNormalizer.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php index 2702f8a..27096b5 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -8,7 +8,6 @@ namespace Ibexa\Search\Serializer\Normalizer\Suggestion; -use ArrayObject; use Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection; use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; @@ -26,9 +25,9 @@ final class ParentLocationCollectionNormalizer implements * @param \Ibexa\Contracts\Search\Model\Suggestion\ParentLocationCollection $object * @param array $context * - * @return ArrayObject. + * @return array. */ - public function normalize($object, string $format = null, array $context = []): ArrayObject + public function normalize($object, string $format = null, array $context = []): array { $normalizedData = []; @@ -36,7 +35,7 @@ public function normalize($object, string $format = null, array $context = []): $normalizedData[] = $this->normalizer->normalize($parentLocation); } - return new ArrayObject($normalizedData); + return $normalizedData; } public function supportsNormalization($data, string $format = null): bool From 0ecc81712c307b6b01a76cd64881d76bffa65d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 16 Nov 2023 13:29:58 +0100 Subject: [PATCH 64/66] Fixed issue with normalizer --- ...estionEventTest.php => BuildSuggestionCollectionEventTest.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/contracts/EventDispatcher/Event/{SuggestionEventTest.php => BuildSuggestionCollectionEventTest.php} (100%) diff --git a/tests/contracts/EventDispatcher/Event/SuggestionEventTest.php b/tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php similarity index 100% rename from tests/contracts/EventDispatcher/Event/SuggestionEventTest.php rename to tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php From 61bd3cec40029f284e8e085be89f9691f829fd6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Thu, 16 Nov 2023 13:30:34 +0100 Subject: [PATCH 65/66] Code review improvements --- .../Suggestion/ParentLocationCollectionNormalizer.php | 2 +- .../Event/BuildSuggestionCollectionEventTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php index 27096b5..8e2a975 100644 --- a/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php +++ b/src/lib/Serializer/Normalizer/Suggestion/ParentLocationCollectionNormalizer.php @@ -32,7 +32,7 @@ public function normalize($object, string $format = null, array $context = []): $normalizedData = []; foreach ($object as $parentLocation) { - $normalizedData[] = $this->normalizer->normalize($parentLocation); + $normalizedData[] = $this->normalizer->normalize($parentLocation, $format, $context); } return $normalizedData; diff --git a/tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php b/tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php index e81504b..833d9b7 100644 --- a/tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php +++ b/tests/contracts/EventDispatcher/Event/BuildSuggestionCollectionEventTest.php @@ -12,7 +12,7 @@ use Ibexa\Search\Model\SuggestionQuery; use PHPUnit\Framework\TestCase; -final class SuggestionEventTest extends TestCase +final class BuildSuggestionCollectionEventTest extends TestCase { public function testConstruct(): void { From bd48916ee0b1bb3ce76e9cac0edf2764aae6b3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20S=C5=82omka?= Date: Fri, 17 Nov 2023 12:55:26 +0100 Subject: [PATCH 66/66] Fixed default values --- .../Configuration/Parser/SiteAccessAware/SuggestionParser.php | 2 +- src/bundle/Resources/config/default_settings.yaml | 2 ++ src/bundle/Resources/config/services/suggestions.yaml | 4 ---- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php index 97da725..bdab0ad 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SiteAccessAware/SuggestionParser.php @@ -66,6 +66,7 @@ private function addSuggestionParameters( 'min_query_length', 'result_limit', ]; + foreach ($names as $name) { if (isset($settings['suggestion'][$name])) { $contextualizer->setContextualParameter( @@ -83,7 +84,6 @@ private function addSuggestionConfiguration(): ArrayNodeDefinition $node = $treeBuilder->getRootNode(); $node - ->addDefaultsIfNotSet() ->children() ->integerNode('min_query_length') ->info('The minimum length of the query string needed to trigger suggestions. Minimum value is 3.') diff --git a/src/bundle/Resources/config/default_settings.yaml b/src/bundle/Resources/config/default_settings.yaml index 03e3e14..8b8a293 100644 --- a/src/bundle/Resources/config/default_settings.yaml +++ b/src/bundle/Resources/config/default_settings.yaml @@ -1,5 +1,7 @@ parameters: ibexa.site_access.config.default.search.pagination.limit: 10 + ibexa.site_access.config.default.search.suggestion.min_query_length: 3 + ibexa.site_access.config.default.search.suggestion.result_limit: 5 ibexa.site_access.config.site_group.search_view: full: diff --git a/src/bundle/Resources/config/services/suggestions.yaml b/src/bundle/Resources/config/services/suggestions.yaml index 10356e3..8e05637 100644 --- a/src/bundle/Resources/config/services/suggestions.yaml +++ b/src/bundle/Resources/config/services/suggestions.yaml @@ -1,7 +1,3 @@ -parameters: - ibexa.site_access.config.default.search.suggestion.min_query_length: 3 - ibexa.site_access.config.default.search.suggestion.result_limit: 5 - services: _defaults: autoconfigure: true