diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index 79344e18..286cda1b 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -5,6 +5,8 @@ - Remove `MonsieurBiz\SyliusSearchPlugin\Search\Request\QueryFilter\ProductTaxonRegistry` service to use an iterator of services tagged `monsieurbiz.search.request.product_taxon_filter` - 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` +- 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`. +- New setting `monsieurbiz_sylius_search.elastically_configuration_paths` to define paths of elasticsearch mapping files. By default it's `['@MonsieurBizSyliusSearchPlugin/Resources/config/elasticsearch']`. # UPGRADE FROM v1.X.X TO v2.0.x diff --git a/dist/config/packages/monsieurbiz_sylius_search_plugin.yaml b/dist/config/packages/monsieurbiz_sylius_search_plugin.yaml index 3ed34db6..f66f0d72 100644 --- a/dist/config/packages/monsieurbiz_sylius_search_plugin.yaml +++ b/dist/config/packages/monsieurbiz_sylius_search_plugin.yaml @@ -5,3 +5,6 @@ monsieurbiz_sylius_search: documents: monsieurbiz_product: prefix: 'myprefix' # define a custom index prefix + + elastically_configuration_paths: + - '%kernel.project_dir%/src/Resources/config/elasticsearch' diff --git a/dist/src/Resources/config/elasticsearch/monsieurbiz_product_mapping.yaml b/dist/src/Resources/config/elasticsearch/monsieurbiz_product_mapping.yaml new file mode 100644 index 00000000..e02f0df4 --- /dev/null +++ b/dist/src/Resources/config/elasticsearch/monsieurbiz_product_mapping.yaml @@ -0,0 +1,4 @@ +mappings: + properties: + short_description: + type: text diff --git a/dist/src/Search/EventListener/AppendProductMappingSubscriber.php b/dist/src/Search/EventListener/AppendProductMappingSubscriber.php deleted file mode 100644 index 05f1ef54..00000000 --- a/dist/src/Search/EventListener/AppendProductMappingSubscriber.php +++ /dev/null @@ -1,44 +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 App\Search\EventListener; - -use MonsieurBiz\SyliusSearchPlugin\Event\MappingProviderEvent; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -final class AppendProductMappingSubscriber implements EventSubscriberInterface -{ - public static function getSubscribedEvents(): array - { - return [ - MappingProviderEvent::EVENT_NAME => 'onMappingProvider', - ]; - } - - public function onMappingProvider(MappingProviderEvent $event): void - { - // We only change product mapping - if ('monsieurbiz_product' !== $event->getIndexCode()) { - return; - } - - $mapping = $event->getMapping(); - $mappings = $mapping->offsetGet('mappings') ?? []; - - $mappings['properties']['short_description'] = [ - 'type' => 'text', - ]; - - $mapping->offsetSet('mappings', $mappings); - } -} diff --git a/docs/add_custom_values.md b/docs/add_custom_values.md index d3b81c9c..6b500c02 100644 --- a/docs/add_custom_values.md +++ b/docs/add_custom_values.md @@ -4,7 +4,8 @@ In our example we will add the `short_description` product field to the indexed content. -- [Use event listener to change the product mapping](../dist/src/Search/EventListener/AppendProductMappingSubscriber.php) +- [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) - [Create DecorateProductMapperConfiguration class](../dist/src/Search/Automapper/DecorateProductMapperConfiguration.php) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 6c5229ba..a4edd50d 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -76,6 +76,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() + ->arrayNode('elastically_configuration_paths') + ->defaultValue([]) + ->prototype('scalar')->end() + ->end() ->end() ; diff --git a/src/Factory/YamlProviderFactory.php b/src/Factory/YamlProviderFactory.php new file mode 100644 index 00000000..d8b6219b --- /dev/null +++ b/src/Factory/YamlProviderFactory.php @@ -0,0 +1,25 @@ + + * + * 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 7d51bfde..ecf2d412 100644 --- a/src/Mapping/YamlWithLocaleProvider.php +++ b/src/Mapping/YamlWithLocaleProvider.php @@ -14,47 +14,55 @@ namespace MonsieurBiz\SyliusSearchPlugin\Mapping; use ArrayObject; +use Elastica\Exception\InvalidException; use JoliCode\Elastically\Mapping\MappingProviderInterface; -use JoliCode\Elastically\Mapping\YamlProvider; use MonsieurBiz\SyliusSearchPlugin\Event\MappingProviderEvent; -use MonsieurBiz\SyliusSearchPlugin\Repository\ProductAttributeRepositoryInterface; +use MonsieurBiz\SyliusSearchPlugin\Factory\YamlProviderFactory; +use Symfony\Component\Config\FileLocatorInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Parser; class YamlWithLocaleProvider implements MappingProviderInterface { - private YamlProvider $decorated; + private EventDispatcherInterface $eventDispatcher; - private string $configurationDirectory; + private YamlProviderFactory $yamlProviderFactory; - private Parser $parser; + private FileLocatorInterface $fileLocator; - private ProductAttributeRepositoryInterface $attributeRepository; + /** + * @var array + */ + private iterable $configurationDirectories; - private EventDispatcherInterface $eventDispatcher; + private Parser $parser; public function __construct( - YamlProvider $decorated, - string $configurationDirectory, EventDispatcherInterface $eventDispatcher, - ProductAttributeRepositoryInterface $attributeRepository, + YamlProviderFactory $yamlProviderFactory, + FileLocatorInterface $fileLocator, + iterable $configurationDirectories = [], ?Parser $parser = null ) { - $this->decorated = $decorated; - $this->configurationDirectory = $configurationDirectory; - $this->parser = $parser ?? new Parser(); - $this->attributeRepository = $attributeRepository; $this->eventDispatcher = $eventDispatcher; + $this->yamlProviderFactory = $yamlProviderFactory; + $this->fileLocator = $fileLocator; + $this->configurationDirectories = $configurationDirectories; + $this->parser = $parser ?? new Parser(); } public function provideMapping(string $indexName, array $context = []): ?array { - $mapping = $this->decorated->provideMapping($context['index_code'] ?? $indexName, $context) ?? []; - + $mapping = []; $locale = $context['locale'] ?? null; - if (null !== $locale) { - $mapping = $this->appendLocaleAnalyzers($mapping, $locale); + foreach ($this->configurationDirectories as $configurationDirectory) { + $configurationDirectory = $this->fileLocator->locate($configurationDirectory); + if (!\is_string($configurationDirectory)) { + continue; + } + $mapping = $this->appendMapping($configurationDirectory, $mapping, $indexName, $context); + $mapping = $this->appendLocaleAnalyzers($configurationDirectory, $mapping, $locale); } $mappingProviderEvent = new MappingProviderEvent($context['index_code'] ?? $indexName, new ArrayObject($mapping)); @@ -63,13 +71,35 @@ public function provideMapping(string $indexName, array $context = []): ?array MappingProviderEvent::EVENT_NAME ); - return (array) $mappingProviderEvent->getMapping(); + $mapping = (array) $mappingProviderEvent->getMapping(); + if (empty($mapping['mappings'] ?? [])) { + throw new InvalidException(sprintf('Mapping no found for "%s" not found. Please check your configuration.', $indexName)); + } + + return $mapping; + } + + 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) { + // the mapping yaml file does not exist. + } + + return $mapping; } - private function appendLocaleAnalyzers(array $mapping, string $locale): array + private function appendLocaleAnalyzers(string $configurationDirectory, array $mapping, ?string $locale): array { + if (null === $locale) { + return $mapping; + } + foreach ($this->getLocaleCode($locale) as $localeCode) { - $analyzerFilePath = $this->configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers_' . $localeCode . '.yaml'; + $analyzerFilePath = $configurationDirectory . \DIRECTORY_SEPARATOR . 'analyzers_' . $localeCode . '.yaml'; try { $analyzer = $this->parser->parseFile($analyzerFilePath) ?? []; diff --git a/src/Resources/config/monsieurbiz_search.yaml b/src/Resources/config/monsieurbiz_search.yaml index a036d519..abdbde9e 100644 --- a/src/Resources/config/monsieurbiz_search.yaml +++ b/src/Resources/config/monsieurbiz_search.yaml @@ -30,3 +30,5 @@ monsieurbiz_sylius_search: product_variant: 'MonsieurBiz\SyliusSearchPlugin\Model\Product\VariantDTO' pricing: 'MonsieurBiz\SyliusSearchPlugin\Generated\Model\PricingDTO' + elastically_configuration_paths: + - '@MonsieurBizSyliusSearchPlugin/Resources/config/elasticsearch' diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 95ed627e..f0eb0b6b 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -55,13 +55,10 @@ services: $attributeRepository: '@sylius.repository.product_attribute' # Define our mapping provider - JoliCode\Elastically\Mapping\YamlProvider: - arguments: - $configurationDirectory: '@=service("file_locator").locate("@MonsieurBizSyliusSearchPlugin/Resources/config/elasticsearch")' MonsieurBiz\SyliusSearchPlugin\Mapping\YamlWithLocaleProvider: - decorates: JoliCode\Elastically\Mapping\YamlProvider arguments: - $decorated: '@.inner' + $fileLocator: '@file_locator' + $configurationDirectories: '%monsieurbiz.search.config.elastically_configuration_paths%' # Automapper configuration MonsieurBiz\SyliusSearchPlugin\AutoMapper\Configuration: