From 86eff35c875a8316e9ccd80e776835bab12def06 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 25 Jul 2023 16:29:21 +0200 Subject: [PATCH 01/31] Rename product box dist file template --- .../Search/{product => Product}/_box.html.twig | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/{product => Product}/_box.html.twig (100%) diff --git a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/product/_box.html.twig b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Product/_box.html.twig similarity index 100% rename from dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/product/_box.html.twig rename to dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Product/_box.html.twig From a89c61f88b9f66fa7184ef9c94d8a78196d12fcd Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 25 Jul 2023 16:30:31 +0200 Subject: [PATCH 02/31] Add stuffs for test app to index taxons --- dist/src/Resources/config/config.yaml | 1 + .../elasticsearch/app_taxon_mapping.yaml | 51 +++++++++ dist/src/Resources/config/search/taxons.yaml | 22 ++++ .../Automapper/TaxonMapperConfiguration.php | 104 ++++++++++++++++++ .../Model/Datasource/TaxonDatasource.php | 57 ++++++++++ dist/src/Search/Model/Taxon/TaxonDTO.php | 20 ++++ .../Instant/Taxon/_box.html.twig | 7 ++ .../Search/Taxon/_box.html.twig | 7 ++ 8 files changed, 269 insertions(+) create mode 100644 dist/src/Resources/config/elasticsearch/app_taxon_mapping.yaml create mode 100644 dist/src/Resources/config/search/taxons.yaml create mode 100644 dist/src/Search/Automapper/TaxonMapperConfiguration.php create mode 100644 dist/src/Search/Model/Datasource/TaxonDatasource.php create mode 100644 dist/src/Search/Model/Taxon/TaxonDTO.php create mode 100644 dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig create mode 100644 dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig diff --git a/dist/src/Resources/config/config.yaml b/dist/src/Resources/config/config.yaml index c430b5e3..650833cb 100644 --- a/dist/src/Resources/config/config.yaml +++ b/dist/src/Resources/config/config.yaml @@ -3,3 +3,4 @@ parameters: imports: - { resource: "services.yaml" } + - { resource: "search/taxons.yaml" } diff --git a/dist/src/Resources/config/elasticsearch/app_taxon_mapping.yaml b/dist/src/Resources/config/elasticsearch/app_taxon_mapping.yaml new file mode 100644 index 00000000..a506015c --- /dev/null +++ b/dist/src/Resources/config/elasticsearch/app_taxon_mapping.yaml @@ -0,0 +1,51 @@ +mappings: + dynamic: false + properties: + code: + type: keyword + enabled: + type: boolean + name: + type: text + fields: + keyword: + type: keyword + autocomplete: + type: text + analyzer: search_autocomplete + search_analyzer: standard + description: + type: text + created_at: + type: date + format: yyyy-MM-dd HH:mm:ss||strict_date_optional_time||epoch_second + position: + type: integer + level: + type: integer + left: + type: integer + right: + type: integer + parent_taxon: + type: nested + properties: + code: + type: keyword + enabled: + type: boolean + name: + type: keyword + description: + type: text + created_at: + type: date + format: yyyy-MM-dd HH:mm:ss||strict_date_optional_time||epoch_second + position: + type: integer + level: + type: integer + left: + type: integer + right: + type: integer diff --git a/dist/src/Resources/config/search/taxons.yaml b/dist/src/Resources/config/search/taxons.yaml new file mode 100644 index 00000000..99d12a5d --- /dev/null +++ b/dist/src/Resources/config/search/taxons.yaml @@ -0,0 +1,22 @@ +monsieurbiz_sylius_search: + documents: + app_taxon: + #prefix: '…' # define a custom index prefix on index names and aliases + #document_class: '…' # by default MonsieurBiz\SyliusSearchPlugin\Model\Documentable\Documentable + instant_search_enabled: true # by default false + limits: + search: [9, 18, 27] + taxon: [9, 18, 27] + instant_search: [5] + source: 'Sylius\Component\Core\Model\TaxonInterface' + target: 'App\Search\Model\Taxon\TaxonDTO' + templates: + item: '@MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig' + instant: '@MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig' + #mapping_provider: '...' # by default monsieurbiz.search.mapper_provider + datasource: 'App\Search\Model\Datasource\TaxonDatasource' # by default MonsieurBiz\SyliusSearchPlugin\Model\Datasource\RepositoryDatasource + automapper_classes: + sources: + taxon: '%sylius.model.taxon.class%' + targets: + app_taxon: 'App\Search\Model\Taxon\TaxonDTO' diff --git a/dist/src/Search/Automapper/TaxonMapperConfiguration.php b/dist/src/Search/Automapper/TaxonMapperConfiguration.php new file mode 100644 index 00000000..b25c6597 --- /dev/null +++ b/dist/src/Search/Automapper/TaxonMapperConfiguration.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Automapper; + +use DateTimeInterface; +use Jane\Bundle\AutoMapperBundle\Configuration\MapperConfigurationInterface; +use Jane\Component\AutoMapper\AutoMapperInterface; +use Jane\Component\AutoMapper\MapperGeneratorMetadataInterface; +use Jane\Component\AutoMapper\MapperMetadata; +use MonsieurBiz\SyliusSearchPlugin\AutoMapper\ConfigurationInterface; +use Sylius\Component\Core\Model\TaxonInterface; + +final class TaxonMapperConfiguration implements MapperConfigurationInterface +{ + private ConfigurationInterface $configuration; + + private AutoMapperInterface $autoMapper; + + public function __construct( + ConfigurationInterface $configuration, + AutoMapperInterface $autoMapper, + ) { + $this->configuration = $configuration; + $this->autoMapper = $autoMapper; + } + + public function process(MapperGeneratorMetadataInterface $metadata): void + { + if (!$metadata instanceof MapperMetadata) { + return; + } + + $metadata->forMember('id', function (TaxonInterface $taxon): int { + return $taxon->getId(); + }); + + $metadata->forMember('code', function (TaxonInterface $taxon): ?string { + return $taxon->getCode(); + }); + + $metadata->forMember('enabled', function (TaxonInterface $taxon): bool { + return $taxon->isEnabled(); + }); + + $metadata->forMember('slug', function (TaxonInterface $taxon): ?string { + return $taxon->getSlug(); + }); + + $metadata->forMember('name', function (TaxonInterface $taxon): ?string { + return $taxon->getName(); + }); + + $metadata->forMember('description', function (TaxonInterface $taxon): ?string { + return $taxon->getDescription(); + }); + + $metadata->forMember('created_at', function (TaxonInterface $taxon): ?DateTimeInterface { + return $taxon->getCreatedAt(); + }); + + $metadata->forMember('position', function (TaxonInterface $taxon): ?DateTimeInterface { + return $taxon->getPosition(); + }); + + $metadata->forMember('level', function (TaxonInterface $taxon): ?DateTimeInterface { + return $taxon->getLevel(); + }); + + $metadata->forMember('left', function (TaxonInterface $taxon): ?DateTimeInterface { + return $taxon->getLeft(); + }); + + $metadata->forMember('right', function (TaxonInterface $taxon): ?DateTimeInterface { + return $taxon->getRight(); + }); + + $metadata->forMember('parent_taxon', function (TaxonInterface $taxon) { + return null !== $taxon->getParent() + ? $this->autoMapper->map($taxon->getParent(), $this->configuration->getTargetClass('app_taxon')) + : null; + }); + } + + public function getSource(): string + { + return $this->configuration->getSourceClass('taxon'); + } + + public function getTarget(): string + { + return $this->configuration->getTargetClass('app_taxon'); + } +} diff --git a/dist/src/Search/Model/Datasource/TaxonDatasource.php b/dist/src/Search/Model/Datasource/TaxonDatasource.php new file mode 100644 index 00000000..ca4c0ada --- /dev/null +++ b/dist/src/Search/Model/Datasource/TaxonDatasource.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Model\Datasource; + +use Doctrine\ORM\EntityManagerInterface; +use MonsieurBiz\SyliusSearchPlugin\Model\Datasource\DatasourceInterface; +use Pagerfanta\Doctrine\ORM\QueryAdapter; +use Pagerfanta\Pagerfanta; +use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface; +use Webmozart\Assert\Assert; + +class TaxonDatasource implements DatasourceInterface +{ + private EntityManagerInterface $entityManager; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->entityManager = $entityManager; + } + + public function getItems(string $sourceClass): iterable + { + $repository = $this->entityManager->getRepository($sourceClass); + /** @var TaxonRepositoryInterface $repository */ + Assert::isInstanceOf($repository, TaxonRepositoryInterface::class); + + $queryBuilder = $repository->createQueryBuilder('o') + ->andWhere('o.enabled = :enabled') + ->setParameter('enabled', true) + ; + + $paginator = new Pagerfanta(new QueryAdapter($queryBuilder, false, false)); + $paginator->setMaxPerPage(self::DEFAULT_MAX_PER_PAGE); + $page = 1; + do { + $paginator->setCurrentPage($page); + + foreach ($paginator->getIterator() as $item) { + yield $item; + } + $page = $paginator->hasNextPage() ? $paginator->getNextPage() : 1; + } while ($paginator->hasNextPage()); + + return null; + } +} diff --git a/dist/src/Search/Model/Taxon/TaxonDTO.php b/dist/src/Search/Model/Taxon/TaxonDTO.php new file mode 100644 index 00000000..d1d8fc7d --- /dev/null +++ b/dist/src/Search/Model/Taxon/TaxonDTO.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Model\Taxon; + +use Jacquesbh\Eater\Eater; + +class TaxonDTO extends Eater +{ +} diff --git a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig new file mode 100644 index 00000000..3024e4e6 --- /dev/null +++ b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig @@ -0,0 +1,7 @@ +{% import "@SyliusShop/Common/Macro/money.html.twig" as money %} + + diff --git a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig new file mode 100644 index 00000000..d4c4816b --- /dev/null +++ b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig @@ -0,0 +1,7 @@ +{% import "@SyliusShop/Common/Macro/money.html.twig" as money %} + + From c1368d2aebdebf030c88d9e25b9a5cb5132b679e Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 25 Jul 2023 16:30:41 +0200 Subject: [PATCH 03/31] Add lines in documentation links --- docs/add_custom_values.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/add_custom_values.md b/docs/add_custom_values.md index 6b500c02..c152ba61 100644 --- a/docs/add_custom_values.md +++ b/docs/add_custom_values.md @@ -6,7 +6,7 @@ In our example we will add the `short_description` product field to the indexed - [Add your elasticsearch config path in `monsieurbiz_sylius_search.elastically_configuration_paths`](../dist/config/packages/monsieurbiz_sylius_search_plugin.yaml#L9) - [Extends the product mapping to add the field](../dist/src/Resources/config/elasticsearch/monsieurbiz_product_mapping.yaml) -- [Add a decorator for ProductMapperConfiguration](../dist/src/Resources/config/services.yaml) +- [Add a decorator for ProductMapperConfiguration](../dist/src/Resources/config/services.yaml#L20) - [Create DecorateProductMapperConfiguration class](../dist/src/Search/Automapper/DecorateProductMapperConfiguration.php) You will have the `item.short_description` variable available in your templates. @@ -18,4 +18,4 @@ You have to redeclare `monsieurbiz.search.request.query_filter.product_search.se and `monsieurbiz.search.request.query_filter.product_instant_search.search_term_filter` services to add the `short_description` fields. -- [Add `short_description` in search term filter](../dist/src/Resources/config/services.yaml) +- [Add `short_description` in search term filter](../dist/src/Resources/config/services.yaml#L34) From aa1fb7c256f4da7a65d0a8ae97a9bc1337952829 Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Tue, 25 Jul 2023 17:53:09 +0200 Subject: [PATCH 04/31] fix: find the global analyzers in all config directories --- UPGRADE-2.0.md | 2 +- src/Factory/YamlProviderFactory.php | 25 ------------------ src/Mapping/YamlWithLocaleProvider.php | 35 +++++++++++++++----------- 3 files changed, 21 insertions(+), 41 deletions(-) delete mode 100644 src/Factory/YamlProviderFactory.php diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index 8b4b0ba3..92b71c74 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -6,7 +6,7 @@ - Remove `MonsieurBiz\SyliusSearchPlugin\Search\Request\PostFilter\ProductTaxonRegistry` service to use an iterator of services tagged `monsieurbiz.search.request.product_post_filter` - Remove `MonsieurBiz\SyliusSearchPlugin\Search\Request\Sorting\ProductSorterRegistry` service to use an iterator of services tagged `monsieurbiz.search.request.product_sorter` - Remove `\MonsieurBiz\SyliusSearchPlugin\Search\Request\FunctionScore\ProductFunctionScoreRegistry` service to use an iterator of services tagged `monsieurbiz.search.request.product_function_score` -- The `MonsieurBiz\SyliusSearchPlugin\Mapping\YamlWithLocaleProvider` is no longer a decorator. Some constructor parameters are removed : `$decorated`, `$configurationDirectory` and `$attributeRepository`, and we have `$yamlProviderFactory`, `$fileLocator` and `$configurationDirectories`. +- The `MonsieurBiz\SyliusSearchPlugin\Mapping\YamlWithLocaleProvider` is no longer a decorator. Some constructor parameters are removed : `$decorated`, `$configurationDirectory` and `$attributeRepository`, and we add `$fileLocator` and `$configurationDirectories`. - New setting `monsieurbiz_sylius_search.elastically_configuration_paths` to define paths of elasticsearch mapping files. By default it's `['@MonsieurBizSyliusSearchPlugin/Resources/config/elasticsearch']`. - New method `deleteByDocumentIds` in the `MonsieurBiz\SyliusSearchPlugin\Index\IndexerInterface` interface - Deprecated the method `deleteByDocuments` in the `MonsieurBiz\SyliusSearchPlugin\Index\IndexerInterface` interface. Use `deleteByDocumentIds` instead. diff --git a/src/Factory/YamlProviderFactory.php b/src/Factory/YamlProviderFactory.php deleted file mode 100644 index d8b6219b..00000000 --- a/src/Factory/YamlProviderFactory.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace MonsieurBiz\SyliusSearchPlugin\Factory; - -use JoliCode\Elastically\Mapping\YamlProvider; -use Symfony\Component\Yaml\Parser; - -class YamlProviderFactory -{ - public function create(string $configurationDirectory, Parser $parser): YamlProvider - { - return new YamlProvider($configurationDirectory, $parser); - } -} diff --git a/src/Mapping/YamlWithLocaleProvider.php b/src/Mapping/YamlWithLocaleProvider.php index ecf2d412..3ef19b85 100644 --- a/src/Mapping/YamlWithLocaleProvider.php +++ b/src/Mapping/YamlWithLocaleProvider.php @@ -17,7 +17,6 @@ use Elastica\Exception\InvalidException; use JoliCode\Elastically\Mapping\MappingProviderInterface; use MonsieurBiz\SyliusSearchPlugin\Event\MappingProviderEvent; -use MonsieurBiz\SyliusSearchPlugin\Factory\YamlProviderFactory; use Symfony\Component\Config\FileLocatorInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Yaml\Exception\ParseException; @@ -27,7 +26,6 @@ class YamlWithLocaleProvider implements MappingProviderInterface { private EventDispatcherInterface $eventDispatcher; - private YamlProviderFactory $yamlProviderFactory; private FileLocatorInterface $fileLocator; @@ -40,13 +38,11 @@ class YamlWithLocaleProvider implements MappingProviderInterface public function __construct( EventDispatcherInterface $eventDispatcher, - YamlProviderFactory $yamlProviderFactory, FileLocatorInterface $fileLocator, iterable $configurationDirectories = [], ?Parser $parser = null ) { $this->eventDispatcher = $eventDispatcher; - $this->yamlProviderFactory = $yamlProviderFactory; $this->fileLocator = $fileLocator; $this->configurationDirectories = $configurationDirectories; $this->parser = $parser ?? new Parser(); @@ -81,11 +77,13 @@ public function provideMapping(string $indexName, array $context = []): ?array private function appendMapping(string $configurationDirectory, array $mapping, string $indexName, array $context): array { - $yamlProvider = $this->yamlProviderFactory->create($configurationDirectory, $this->parser); - try { - $mapping = array_merge_recursive($mapping, $yamlProvider->provideMapping($context['index_code'] ?? $indexName, $context) ?? []); - } catch (InvalidException $exception) { + $indexName = $context['index_code'] ?? $indexName; + $fileName = $context['filename'] ?? ($indexName . '_mapping.yaml'); + $mappingFilePath = $configurationDirectory . \DIRECTORY_SEPARATOR . $fileName; + + $mapping = array_merge_recursive($mapping, $this->parser->parseFile($mappingFilePath)); + } catch (ParseException $exception) { // the mapping yaml file does not exist. } @@ -98,15 +96,22 @@ private function appendLocaleAnalyzers(string $configurationDirectory, array $ma return $mapping; } + $mapping = $this->appendAnalyzers($configurationDirectory . DIRECTORY_SEPARATOR . 'analyzers.yaml', $mapping); + foreach ($this->getLocaleCode($locale) as $localeCode) { - $analyzerFilePath = $configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers_' . $localeCode . '.yaml'; + $mapping = $this->appendAnalyzers($configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers_' . $localeCode . '.yaml', $mapping); + } - try { - $analyzer = $this->parser->parseFile($analyzerFilePath) ?? []; - $mapping['settings']['analysis'] = array_merge_recursive($mapping['settings']['analysis'] ?? [], $analyzer); - } catch (ParseException $exception) { - // the yaml file does not exist or does not exist. - } + return $mapping; + } + + private function appendAnalyzers(string $analyzerFilePath, array $mapping): array + { + try { + $analyzer = $this->parser->parseFile($analyzerFilePath) ?? []; + $mapping['settings']['analysis'] = array_merge_recursive($mapping['settings']['analysis'] ?? [], $analyzer); + } catch (ParseException $exception) { + // the yaml file does not exist or does not exist. } return $mapping; From 3e2da15e8c72099cf95ca2dee9d5a690852375c4 Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Tue, 25 Jul 2023 18:01:07 +0200 Subject: [PATCH 05/31] fix: replace type for taxon dto mapper --- .../Search/Automapper/TaxonMapperConfiguration.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dist/src/Search/Automapper/TaxonMapperConfiguration.php b/dist/src/Search/Automapper/TaxonMapperConfiguration.php index b25c6597..fe1dd2c6 100644 --- a/dist/src/Search/Automapper/TaxonMapperConfiguration.php +++ b/dist/src/Search/Automapper/TaxonMapperConfiguration.php @@ -13,6 +13,7 @@ namespace App\Search\Automapper; +use App\Search\Model\Taxon\TaxonDTO; use DateTimeInterface; use Jane\Bundle\AutoMapperBundle\Configuration\MapperConfigurationInterface; use Jane\Component\AutoMapper\AutoMapperInterface; @@ -69,23 +70,23 @@ public function process(MapperGeneratorMetadataInterface $metadata): void return $taxon->getCreatedAt(); }); - $metadata->forMember('position', function (TaxonInterface $taxon): ?DateTimeInterface { + $metadata->forMember('position', function (TaxonInterface $taxon): ?int { return $taxon->getPosition(); }); - $metadata->forMember('level', function (TaxonInterface $taxon): ?DateTimeInterface { + $metadata->forMember('level', function (TaxonInterface $taxon): ?int { return $taxon->getLevel(); }); - $metadata->forMember('left', function (TaxonInterface $taxon): ?DateTimeInterface { + $metadata->forMember('left', function (TaxonInterface $taxon): ?int { return $taxon->getLeft(); }); - $metadata->forMember('right', function (TaxonInterface $taxon): ?DateTimeInterface { + $metadata->forMember('right', function (TaxonInterface $taxon): ?int { return $taxon->getRight(); }); - $metadata->forMember('parent_taxon', function (TaxonInterface $taxon) { + $metadata->forMember('parent_taxon', function (TaxonInterface $taxon): ?TaxonDTO { return null !== $taxon->getParent() ? $this->autoMapper->map($taxon->getParent(), $this->configuration->getTargetClass('app_taxon')) : null; From 3fea7bfeed345ca0a0796e8d4cea5240a72ed42c Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Wed, 26 Jul 2023 08:53:54 +0200 Subject: [PATCH 06/31] Fix PHP CS --- src/Mapping/YamlWithLocaleProvider.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mapping/YamlWithLocaleProvider.php b/src/Mapping/YamlWithLocaleProvider.php index 3ef19b85..dfdee2a8 100644 --- a/src/Mapping/YamlWithLocaleProvider.php +++ b/src/Mapping/YamlWithLocaleProvider.php @@ -26,7 +26,6 @@ class YamlWithLocaleProvider implements MappingProviderInterface { private EventDispatcherInterface $eventDispatcher; - private FileLocatorInterface $fileLocator; /** @@ -96,7 +95,7 @@ private function appendLocaleAnalyzers(string $configurationDirectory, array $ma return $mapping; } - $mapping = $this->appendAnalyzers($configurationDirectory . DIRECTORY_SEPARATOR . 'analyzers.yaml', $mapping); + $mapping = $this->appendAnalyzers($configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers.yaml', $mapping); foreach ($this->getLocaleCode($locale) as $localeCode) { $mapping = $this->appendAnalyzers($configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers_' . $localeCode . '.yaml', $mapping); From f0664ed73df17f517cacba2fa8b28038582d2926 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Wed, 26 Jul 2023 08:56:13 +0200 Subject: [PATCH 07/31] Make taxons appears in instant search --- dist/src/Resources/config/services.yaml | 18 +++ .../QueryFilter/Taxon/SearchTermFilter.php | 58 ++++++++++ .../Request/TaxonRequest/InstantSearch.php | 103 ++++++++++++++++++ dist/translations/messages.en.yaml | 4 + 4 files changed, 183 insertions(+) create mode 100644 dist/src/Search/Request/QueryFilter/Taxon/SearchTermFilter.php create mode 100644 dist/src/Search/Request/TaxonRequest/InstantSearch.php diff --git a/dist/src/Resources/config/services.yaml b/dist/src/Resources/config/services.yaml index 1d621a2f..8c0f2e59 100644 --- a/dist/src/Resources/config/services.yaml +++ b/dist/src/Resources/config/services.yaml @@ -3,6 +3,8 @@ services: autowire: true autoconfigure: true public: false + bind: + $documentableRegistry: '@monsieurbiz.search.registry.documentable' # Makes classes in src/ available to be used as services; # this creates a service per class whose id is the fully-qualified class name @@ -53,3 +55,19 @@ services: App\Search\Request\FunctionScore\Product\BoostExpensiveProductFunction: tags: - { name: monsieurbiz.search.request.product_function_score } + + # Define the taxon queries + App\Search\Request\TaxonRequest\InstantSearch: + arguments: + $queryFilters: !tagged_iterator { tag: 'app.search.request.taxon_instant_search_filter' } + $functionScores: !tagged_iterator { tag: 'app.search.request.taxon_function_score' } + + # Define the taxon query filters + App\Search\Request\QueryFilter\Taxon\SearchTermFilter: + arguments: + $fieldsToSearch: + - 'name^5' + - 'description' + - 'name.autocomplete' + tags: + - { name: app.search.request.taxon_instant_search_filter } diff --git a/dist/src/Search/Request/QueryFilter/Taxon/SearchTermFilter.php b/dist/src/Search/Request/QueryFilter/Taxon/SearchTermFilter.php new file mode 100644 index 00000000..cf2a5441 --- /dev/null +++ b/dist/src/Search/Request/QueryFilter/Taxon/SearchTermFilter.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Request\QueryFilter\Taxon; + +use Elastica\Query\BoolQuery; +use Elastica\Query\MultiMatch; +use Elastica\QueryBuilder; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\QueryFilter\QueryFilterInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\RequestConfiguration; + +final class SearchTermFilter implements QueryFilterInterface +{ + private array $fieldsToSearch; + + public function __construct( + array $fieldsToSearch + ) { + $this->fieldsToSearch = $fieldsToSearch; + } + + public function apply(BoolQuery $boolQuery, RequestConfiguration $requestConfiguration): void + { + $qb = new QueryBuilder(); + + $searchCode = $qb->query()->term(['code' => $requestConfiguration->getQueryText()]); + + $searchQuery = $qb->query()->bool(); + $searchQuery->addShould($searchCode); + $this->addFieldsToSearchCondition($searchQuery, $requestConfiguration); + + $boolQuery->addMust($searchQuery); + } + + private function addFieldsToSearchCondition(BoolQuery $searchQuery, RequestConfiguration $requestConfiguration): void + { + if (0 === \count($this->fieldsToSearch)) { + return; + } + $qb = new QueryBuilder(); + $nameAndDescriptionQuery = $qb->query()->multi_match(); + $nameAndDescriptionQuery->setFields($this->fieldsToSearch); + $nameAndDescriptionQuery->setQuery($requestConfiguration->getQueryText()); + $nameAndDescriptionQuery->setType(MultiMatch::TYPE_MOST_FIELDS); + $nameAndDescriptionQuery->setFuzziness(MultiMatch::FUZZINESS_AUTO); + $searchQuery->addShould($nameAndDescriptionQuery); + } +} diff --git a/dist/src/Search/Request/TaxonRequest/InstantSearch.php b/dist/src/Search/Request/TaxonRequest/InstantSearch.php new file mode 100644 index 00000000..bb2e7440 --- /dev/null +++ b/dist/src/Search/Request/TaxonRequest/InstantSearch.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Request\TaxonRequest; + +use Elastica\Query; +use Elastica\QueryBuilder; +use MonsieurBiz\SyliusSearchPlugin\Model\Documentable\DocumentableInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\FunctionScore\FunctionScoreInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\QueryFilter\QueryFilterInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\RequestConfiguration; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\RequestInterface; +use RuntimeException; +use Sylius\Component\Registry\ServiceRegistryInterface; + +final class InstantSearch implements RequestInterface +{ + private DocumentableInterface $documentable; + + private ?RequestConfiguration $configuration; + + /** + * @var iterable + */ + private iterable $queryFilters; + + /** + * @var iterable + */ + private iterable $functionScores; + + public function __construct( + ServiceRegistryInterface $documentableRegistry, + iterable $queryFilters, + iterable $functionScores + ) { + /** @var DocumentableInterface $documentable */ + $documentable = $documentableRegistry->get('search.documentable.app_taxon'); + $this->documentable = $documentable; + $this->queryFilters = $queryFilters; + $this->functionScores = $functionScores; + } + + public function getType(): string + { + return RequestInterface::INSTANT_TYPE; + } + + public function getDocumentable(): DocumentableInterface + { + return $this->documentable; + } + + public function getQuery(): Query + { + if (null === $this->configuration) { + throw new RuntimeException('missing configuration'); + } + + $qb = new QueryBuilder(); + $boolQuery = $qb->query()->bool(); + foreach ($this->queryFilters as $queryFilter) { + $queryFilter->apply($boolQuery, $this->configuration); + } + + $query = Query::create($boolQuery); + + /** @var Query\AbstractQuery $queryObject */ + $queryObject = $query->getQuery(); + $functionScore = $qb->query()->function_score() + ->setQuery($queryObject) + ->setBoostMode(Query\FunctionScore::BOOST_MODE_MULTIPLY) + ->setScoreMode(Query\FunctionScore::SCORE_MODE_MULTIPLY) + ; + foreach ($this->functionScores as $functionScoreClass) { + $functionScoreClass->addFunctionScore($functionScore, $this->configuration); + } + + $query->setQuery($functionScore); + + return $query; + } + + public function supports(string $type, string $documentableCode): bool + { + return RequestInterface::INSTANT_TYPE == $type && $this->getDocumentable()->getIndexCode() == $documentableCode; + } + + public function setConfiguration(RequestConfiguration $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/dist/translations/messages.en.yaml b/dist/translations/messages.en.yaml index 7cfd41ab..6cb3b389 100644 --- a/dist/translations/messages.en.yaml +++ b/dist/translations/messages.en.yaml @@ -2,3 +2,7 @@ app: ui: short_desc_a_to_z_path: From short description A to Z short_desc_z_to_a_path: From short description Z to A +monsieurbiz_searchplugin: + instant: + result: + app_taxon: Taxons From f886d9eee8b3953d20f03b8fa4c84fccbb8821cf Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Wed, 26 Jul 2023 08:56:26 +0200 Subject: [PATCH 08/31] Display taxon name same as product name in search result in test app --- .../MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig | 2 +- .../MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig index 3024e4e6..7f28ac1e 100644 --- a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig +++ b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig @@ -2,6 +2,6 @@ diff --git a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig index d4c4816b..77478d3a 100644 --- a/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig +++ b/dist/templates/bundles/MonsieurBizSyliusSearchPlugin/Search/Taxon/_box.html.twig @@ -2,6 +2,6 @@ From 4e945e05c62992d0cb381c0941dab2ffcf388cc8 Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Wed, 26 Jul 2023 10:34:08 +0200 Subject: [PATCH 09/31] fix: should index parent taxon data --- .../Automapper/TaxonMapperConfiguration.php | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/dist/src/Search/Automapper/TaxonMapperConfiguration.php b/dist/src/Search/Automapper/TaxonMapperConfiguration.php index fe1dd2c6..a9647679 100644 --- a/dist/src/Search/Automapper/TaxonMapperConfiguration.php +++ b/dist/src/Search/Automapper/TaxonMapperConfiguration.php @@ -15,6 +15,9 @@ use App\Search\Model\Taxon\TaxonDTO; use DateTimeInterface; +use Doctrine\Common\Proxy\Proxy; +use Doctrine\Common\Util\ClassUtils; +use Doctrine\ORM\EntityManagerInterface; use Jane\Bundle\AutoMapperBundle\Configuration\MapperConfigurationInterface; use Jane\Component\AutoMapper\AutoMapperInterface; use Jane\Component\AutoMapper\MapperGeneratorMetadataInterface; @@ -31,6 +34,7 @@ final class TaxonMapperConfiguration implements MapperConfigurationInterface public function __construct( ConfigurationInterface $configuration, AutoMapperInterface $autoMapper, + private EntityManagerInterface $entityManager ) { $this->configuration = $configuration; $this->autoMapper = $autoMapper; @@ -86,10 +90,12 @@ public function process(MapperGeneratorMetadataInterface $metadata): void return $taxon->getRight(); }); + /** @phpstan-ignore-next-line */ $metadata->forMember('parent_taxon', function (TaxonInterface $taxon): ?TaxonDTO { - return null !== $taxon->getParent() - ? $this->autoMapper->map($taxon->getParent(), $this->configuration->getTargetClass('app_taxon')) - : null; + return ($parent = $taxon->getParent()) ? $this->autoMapper->map( + $this->getRealTaxonEntity($parent), + $this->configuration->getTargetClass('app_taxon') + ) : null; }); } @@ -102,4 +108,19 @@ public function getTarget(): string { return $this->configuration->getTargetClass('app_taxon'); } + + private function getRealTaxonEntity(TaxonInterface $taxon): TaxonInterface + { + if ($taxon instanceof Proxy) { + // Clear the entity manager to detach the proxy object + $this->entityManager->clear(\get_class($taxon)); + // Retrieve the original class name + $entityClassName = ClassUtils::getRealClass(\get_class($taxon)); + // Find the object in repository from the ID + /** @var ?TaxonInterface $taxon */ + $taxon = $this->entityManager->find($entityClassName, $taxon->getId()); + } + + return $taxon; + } } From d2120c1d9c371f870822393b6501129162372219 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Thu, 27 Jul 2023 10:15:12 +0200 Subject: [PATCH 10/31] Be able to search on many entities displayed by tabs --- dist/src/Resources/config/services.yaml | 19 ++- .../Search/Request/TaxonRequest/Search.php | 145 ++++++++++++++++++ src/Controller/SearchController.php | 21 ++- src/Resources/config/routing/shop.yaml | 1 + src/Resources/views/Search/_filters.html.twig | 3 +- src/Resources/views/Search/_tabs.html.twig | 19 +++ src/Resources/views/Search/result.html.twig | 2 + 7 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 dist/src/Search/Request/TaxonRequest/Search.php create mode 100644 src/Resources/views/Search/_tabs.html.twig diff --git a/dist/src/Resources/config/services.yaml b/dist/src/Resources/config/services.yaml index 8c0f2e59..8c16795f 100644 --- a/dist/src/Resources/config/services.yaml +++ b/dist/src/Resources/config/services.yaml @@ -62,8 +62,16 @@ services: $queryFilters: !tagged_iterator { tag: 'app.search.request.taxon_instant_search_filter' } $functionScores: !tagged_iterator { tag: 'app.search.request.taxon_function_score' } + App\Search\Request\TaxonRequest\Search: + arguments: + $queryFilters: !tagged_iterator { tag: 'app.search.request.taxon_search_filter' } + $postFilters: !tagged_iterator { tag: 'app.search.request.taxon_post_filter' } + $sorters: !tagged_iterator { tag: 'app.search.request.taxon_sorter' } + $functionScores: !tagged_iterator { tag: 'app.search.request.taxon_function_score' } + # Define the taxon query filters - App\Search\Request\QueryFilter\Taxon\SearchTermFilter: + app.search.request.query_filter.taxon_instant_search.search_term_filter: + class: App\Search\Request\QueryFilter\Taxon\SearchTermFilter arguments: $fieldsToSearch: - 'name^5' @@ -71,3 +79,12 @@ services: - 'name.autocomplete' tags: - { name: app.search.request.taxon_instant_search_filter } + + app.search.request.query_filter.taxon_search.search_term_filter: + class: App\Search\Request\QueryFilter\Taxon\SearchTermFilter + arguments: + $fieldsToSearch: + - 'name^5' + - 'description' + tags: + - { name: app.search.request.taxon_search_filter } diff --git a/dist/src/Search/Request/TaxonRequest/Search.php b/dist/src/Search/Request/TaxonRequest/Search.php new file mode 100644 index 00000000..e4424000 --- /dev/null +++ b/dist/src/Search/Request/TaxonRequest/Search.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Search\Request\TaxonRequest; + +use Elastica\Query; +use Elastica\QueryBuilder; +use MonsieurBiz\SyliusSearchPlugin\Model\Documentable\DocumentableInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\AggregationBuilder; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\FunctionScore\FunctionScoreInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\PostFilter\PostFilterInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\QueryFilter\QueryFilterInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\RequestConfiguration; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\RequestInterface; +use MonsieurBiz\SyliusSearchPlugin\Search\Request\Sorting\SorterInterface; +use Sylius\Component\Registry\ServiceRegistryInterface; + +final class Search implements RequestInterface +{ + private DocumentableInterface $documentable; + + private RequestConfiguration $configuration; + + private AggregationBuilder $aggregationBuilder; + + /** + * @var iterable + */ + private iterable $queryFilters; + + /** + * @var iterable + */ + private iterable $postFilters; + + /** + * @var iterable + */ + private iterable $sorters; + + /** + * @var iterable + */ + private iterable $functionScores; + + public function __construct( + ServiceRegistryInterface $documentableRegistry, + AggregationBuilder $aggregationBuilder, + iterable $queryFilters, + iterable $postFilters, + iterable $sorters, + iterable $functionScores + ) { + /** @var DocumentableInterface $documentable */ + $documentable = $documentableRegistry->get('search.documentable.app_taxon'); + $this->documentable = $documentable; + $this->aggregationBuilder = $aggregationBuilder; + $this->queryFilters = $queryFilters; + $this->postFilters = $postFilters; + $this->sorters = $sorters; + $this->functionScores = $functionScores; + } + + public function getType(): string + { + return RequestInterface::SEARCH_TYPE; + } + + public function getDocumentable(): DocumentableInterface + { + return $this->documentable; + } + + public function setConfiguration(RequestConfiguration $configuration): void + { + $this->configuration = $configuration; + } + + public function getQuery(): Query + { + $qb = new QueryBuilder(); + + $boolQuery = $qb->query()->bool(); + foreach ($this->queryFilters as $queryFilter) { + $queryFilter->apply($boolQuery, $this->configuration); + } + + $query = Query::create($boolQuery); + $postFilter = new Query\BoolQuery(); + foreach ($this->postFilters as $postFilterApplier) { + $postFilterApplier->apply($postFilter, $this->configuration); + } + $query->setPostFilter($postFilter); + + // $this->addAggregations($query, $postFilter); + + foreach ($this->sorters as $sorter) { + $sorter->apply($query, $this->configuration); + } + + /** @var Query\AbstractQuery $queryObject */ + $queryObject = $query->getQuery(); + $functionScore = $qb->query()->function_score() + ->setQuery($queryObject) + ->setBoostMode(Query\FunctionScore::BOOST_MODE_MULTIPLY) + ->setScoreMode(Query\FunctionScore::SCORE_MODE_MULTIPLY) + ; + foreach ($this->functionScores as $functionScoreClass) { + $functionScoreClass->addFunctionScore($functionScore, $this->configuration); + } + + $query->setQuery($functionScore); + + return $query; + } + + public function supports(string $type, string $documentableCode): bool + { + return $type == $this->getType() && $this->getDocumentable()->getIndexCode() == $documentableCode; + } + + private function addAggregations(Query $query, Query\BoolQuery $postFilter): void + { + $aggregations = $this->aggregationBuilder->buildAggregations( + [ + 'parent_taxon', + ], + $postFilter->hasParam('must') ? $postFilter->getParam('must') : [] + ); + + foreach ($aggregations as $aggregation) { + $query->addAggregation($aggregation); + } + } +} diff --git a/src/Controller/SearchController.php b/src/Controller/SearchController.php index 2ea42b7e..40d24c4b 100644 --- a/src/Controller/SearchController.php +++ b/src/Controller/SearchController.php @@ -24,11 +24,13 @@ use Sylius\Component\Channel\Context\ChannelContextInterface; use Sylius\Component\Currency\Context\CurrencyContextInterface; use Sylius\Component\Locale\Context\LocaleContextInterface; +use Sylius\Component\Registry\NonExistingServiceException; use Sylius\Component\Registry\ServiceRegistryInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Intl\Currencies; class SearchController extends AbstractController @@ -65,11 +67,19 @@ public function __construct( $this->parametersParser = $parametersParser; } - // TODO add an optional parameter $documentType (nullable => get the default document type) - public function searchAction(Request $request, string $query): Response - { + public function searchAction( + Request $request, + string $query, + string $documentType, + ): Response { + $documentType = $request->query->get('documentType', null) ?? $documentType; /** @var DocumentableInterface $documentable */ - $documentable = $this->documentableRegistry->get('search.documentable.monsieurbiz_product'); + try { + $documentable = $this->documentableRegistry->get('search.documentable.' . $documentType); + } catch (NonExistingServiceException $exception) { + throw new NotFoundHttpException(sprintf('Documentable "%s" not found', $documentType)); + } + $requestConfiguration = new RequestConfiguration( $request, RequestInterface::SEARCH_TYPE, @@ -80,6 +90,7 @@ public function searchAction(Request $request, string $query): Response $result = $this->search->search($requestConfiguration); return $this->render('@MonsieurBizSyliusSearchPlugin/Search/result.html.twig', [ + 'documentableRegistries' => $this->documentableRegistry->all(), 'documentable' => $result->getDocumentable(), 'requestConfiguration' => $requestConfiguration, 'query' => urldecode($query), @@ -126,7 +137,7 @@ public function instantAction(Request $request): Response ); try { - $results[] = $this->search->search($requestConfiguration); + $results[$documentable->getIndexCode()] = $this->search->search($requestConfiguration); } catch (UnknownRequestTypeException $e) { continue; } diff --git a/src/Resources/config/routing/shop.yaml b/src/Resources/config/routing/shop.yaml index 89cc7123..e2053753 100644 --- a/src/Resources/config/routing/shop.yaml +++ b/src/Resources/config/routing/shop.yaml @@ -3,6 +3,7 @@ monsieurbiz_search_search: methods: [GET] defaults: _controller: MonsieurBiz\SyliusSearchPlugin\Controller\SearchController::searchAction + documentType: monsieurbiz_product requirements: query: .+ diff --git a/src/Resources/views/Search/_filters.html.twig b/src/Resources/views/Search/_filters.html.twig index 8fa35cf0..3a25f575 100644 --- a/src/Resources/views/Search/_filters.html.twig +++ b/src/Resources/views/Search/_filters.html.twig @@ -8,7 +8,8 @@ {{ 'monsieurbiz_searchplugin.filters.no_filter'|trans }} {% else %} - {% set path = path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge(app.request.query.all)) %} + {% set encodedQuery = app.request.attributes.get('_route_params').query|default('')|url_encode %} + {% set path = path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge(app.request.query.all)|merge({query: encodedQuery})) %}
{% for filter in result.filters %} diff --git a/src/Resources/views/Search/_tabs.html.twig b/src/Resources/views/Search/_tabs.html.twig new file mode 100644 index 00000000..5dba3ac2 --- /dev/null +++ b/src/Resources/views/Search/_tabs.html.twig @@ -0,0 +1,19 @@ +{% if documentableRegistries|length > 1%} + +{% endif %} diff --git a/src/Resources/views/Search/result.html.twig b/src/Resources/views/Search/result.html.twig index b9d802f9..f887a4d5 100644 --- a/src/Resources/views/Search/result.html.twig +++ b/src/Resources/views/Search/result.html.twig @@ -4,6 +4,8 @@ {% block content %} {% include '@MonsieurBizSyliusSearchPlugin/Search/_header.html.twig' %} + {% include '@MonsieurBizSyliusSearchPlugin/Search/_tabs.html.twig' %} +
From e76d68e886788d10717b9412cc73c5ff25216014 Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Thu, 27 Jul 2023 10:23:21 +0200 Subject: [PATCH 11/31] feat: add position on documentables to change the order --- src/DependencyInjection/Configuration.php | 3 +++ src/DependencyInjection/DocumentableRegistryPass.php | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index a4edd50d..241dc546 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -59,6 +59,9 @@ public function getConfigTreeBuilder(): TreeBuilder ->prototype('scalar')->end() ->end() ->end() + + // Position + ->integerNode('position')->defaultValue(0)->end() ->end() ->end() ->end() diff --git a/src/DependencyInjection/DocumentableRegistryPass.php b/src/DependencyInjection/DocumentableRegistryPass.php index d00a8de0..cbf2e52c 100644 --- a/src/DependencyInjection/DocumentableRegistryPass.php +++ b/src/DependencyInjection/DocumentableRegistryPass.php @@ -39,6 +39,11 @@ public function process(ContainerBuilder $container): void $searchSettings = $container->getParameter('monsieurbiz.settings.config.plugins'); } + // Sort documentables by position + uasort($documentables, function ($documentableA, $documentableB) { + return $documentableA['position'] <=> $documentableB['position']; + }); + foreach ($documentables as $indexCode => $documentableConfiguration) { $documentableServiceId = 'search.documentable.' . $indexCode; $documentableClass = $documentableConfiguration['document_class']; From 155832d26bc3547052e1c08f9ee377126b71083e Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Thu, 27 Jul 2023 10:23:54 +0200 Subject: [PATCH 12/31] test: change position of app_taxon to display first --- dist/src/Resources/config/search/taxons.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/src/Resources/config/search/taxons.yaml b/dist/src/Resources/config/search/taxons.yaml index 99d12a5d..d4e44060 100644 --- a/dist/src/Resources/config/search/taxons.yaml +++ b/dist/src/Resources/config/search/taxons.yaml @@ -15,6 +15,7 @@ monsieurbiz_sylius_search: instant: '@MonsieurBizSyliusSearchPlugin/Instant/Taxon/_box.html.twig' #mapping_provider: '...' # by default monsieurbiz.search.mapper_provider datasource: 'App\Search\Model\Datasource\TaxonDatasource' # by default MonsieurBiz\SyliusSearchPlugin\Model\Datasource\RepositoryDatasource + position: -1 automapper_classes: sources: taxon: '%sylius.model.taxon.class%' From b79b209843eb5f463cc402ae517268adafb5d1e9 Mon Sep 17 00:00:00 2001 From: Maxime Leclercq Date: Thu, 27 Jul 2023 10:34:46 +0200 Subject: [PATCH 13/31] feat: use the first documentable as default --- src/Controller/SearchController.php | 29 ++++++++++++++-------- src/Resources/config/routing/shop.yaml | 1 - src/Resources/views/Search/_tabs.html.twig | 5 ++-- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Controller/SearchController.php b/src/Controller/SearchController.php index 40d24c4b..dfedc274 100644 --- a/src/Controller/SearchController.php +++ b/src/Controller/SearchController.php @@ -69,17 +69,9 @@ public function __construct( public function searchAction( Request $request, - string $query, - string $documentType, + string $query ): Response { - $documentType = $request->query->get('documentType', null) ?? $documentType; - /** @var DocumentableInterface $documentable */ - try { - $documentable = $this->documentableRegistry->get('search.documentable.' . $documentType); - } catch (NonExistingServiceException $exception) { - throw new NotFoundHttpException(sprintf('Documentable "%s" not found', $documentType)); - } - + $documentable = $this->getDocumentable($request->query->get('documentType', null)); $requestConfiguration = new RequestConfiguration( $request, RequestInterface::SEARCH_TYPE, @@ -151,7 +143,7 @@ public function instantAction(Request $request): Response public function taxonAction(Request $request): Response { /** @var DocumentableInterface $documentable */ - $documentable = $this->documentableRegistry->get('search.documentable.monsieurbiz_product'); + $documentable = $this->getDocumentable('monsieurbiz_product'); $requestConfiguration = new RequestConfiguration( $request, RequestInterface::TAXON_TYPE, @@ -168,4 +160,19 @@ public function taxonAction(Request $request): Response 'currencySymbol' => Currencies::getSymbol($this->currencyContext->getCurrencyCode(), $this->localeContext->getLocaleCode()), ]); } + + private function getDocumentable(?string $documentType): DocumentableInterface + { + if (null === $documentType) { + $documentables = $this->documentableRegistry->all(); + + return reset($documentables); + } + + try { + return $this->documentableRegistry->get('search.documentable.' . $documentType); + } catch (NonExistingServiceException $exception) { + throw new NotFoundHttpException(sprintf('Documentable "%s" not found', $documentType)); + } + } } diff --git a/src/Resources/config/routing/shop.yaml b/src/Resources/config/routing/shop.yaml index e2053753..89cc7123 100644 --- a/src/Resources/config/routing/shop.yaml +++ b/src/Resources/config/routing/shop.yaml @@ -3,7 +3,6 @@ monsieurbiz_search_search: methods: [GET] defaults: _controller: MonsieurBiz\SyliusSearchPlugin\Controller\SearchController::searchAction - documentType: monsieurbiz_product requirements: query: .+ diff --git a/src/Resources/views/Search/_tabs.html.twig b/src/Resources/views/Search/_tabs.html.twig index 5dba3ac2..0f07e0c5 100644 --- a/src/Resources/views/Search/_tabs.html.twig +++ b/src/Resources/views/Search/_tabs.html.twig @@ -1,14 +1,15 @@ {% if documentableRegistries|length > 1%}