From fc4a0fe09ac3a68ff0a2dd09647076a5f3df692c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Garcia?= Date: Fri, 9 Aug 2024 16:11:35 +0200 Subject: [PATCH 1/3] added a custom repository method for indexation with "meilisearch:import" command --- src/Command/MeilisearchImportCommand.php | 40 +++++++--- src/DependencyInjection/Configuration.php | 4 + src/SearchService.php | 5 ++ src/Services/MeilisearchService.php | 18 +++++ tests/BaseKernelTestCase.php | 13 ++++ tests/Entity/RepositoryMethod.php | 75 +++++++++++++++++++ .../Command/MeilisearchClearCommandTest.php | 1 + .../Command/MeilisearchCreateCommandTest.php | 2 + .../Command/MeilisearchDeleteCommandTest.php | 1 + .../Command/MeilisearchImportCommandTest.php | 29 +++++++ .../Repository/RepositoryMethodRepository.php | 21 ++++++ tests/Unit/ConfigurationTest.php | 55 +++++++++++++- tests/config/meilisearch.yaml | 3 + 13 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 tests/Entity/RepositoryMethod.php create mode 100644 tests/Repository/RepositoryMethodRepository.php diff --git a/src/Command/MeilisearchImportCommand.php b/src/Command/MeilisearchImportCommand.php index 30f8d342..135fd94d 100644 --- a/src/Command/MeilisearchImportCommand.php +++ b/src/Command/MeilisearchImportCommand.php @@ -99,10 +99,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $totalIndexed = 0; $manager = $this->managerRegistry->getManagerForClass($entityClassName); - $repository = $manager->getRepository($entityClassName); - $classMetadata = $manager->getClassMetadata($entityClassName); - $entityIdentifiers = $classMetadata->getIdentifierFieldNames(); - $sortByAttrs = array_combine($entityIdentifiers, array_fill(0, \count($entityIdentifiers), 'ASC')); $output->writeln('Importing for index '.$entityClassName.''); @@ -119,12 +115,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } do { - $entities = $repository->findBy( - [], - $sortByAttrs, - $batchSize, - $batchSize * $page - ); + $entities = $this->getEntities($entityClassName, $batchSize, $page); $responses = $this->formatIndexingResponse($this->searchService->index($manager, $entities), $responseTimeout); $totalIndexed += \count($entities); @@ -208,4 +199,33 @@ private function entitiesToIndex($indexes): array return array_unique($indexes->all(), SORT_REGULAR); } + + /** + * @param string $entityClassName + * @param int $batchSize + * @param int $page + * + * @return array + */ + private function getEntities($entityClassName, $batchSize, $page): array + { + $manager = $this->managerRegistry->getManagerForClass($entityClassName); + $classMetadata = $manager->getClassMetadata($entityClassName); + $entityIdentifiers = $classMetadata->getIdentifierFieldNames(); + $repository = $manager->getRepository($entityClassName); + $sortByAttrs = array_combine($entityIdentifiers, array_fill(0, \count($entityIdentifiers), 'ASC')); + + $repositoryMethod = $this->searchService->getRepositoryMethod($entityClassName); + + if (null === $repositoryMethod) { + return $repository->findBy( + [], + $sortByAttrs, + $batchSize, + $batchSize * $page + ); + } + + return $repository->$repositoryMethod($batchSize, $batchSize * $page); + } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index c3edcff7..a50012f8 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -59,6 +59,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Property accessor path (like method or property name) used to decide if an entry should be indexed.') ->defaultNull() ->end() + ->scalarNode('repository_method') + ->info('Method of the entity repository called when the meilisearch:import command is invoked.') + ->defaultNull() + ->end() ->arrayNode('settings') ->info('Configure indices settings, see: https://www.meilisearch.com/docs/reference/api/settings') ->beforeNormalization() diff --git a/src/SearchService.php b/src/SearchService.php index 9fbdcfef..1e9ce5a7 100644 --- a/src/SearchService.php +++ b/src/SearchService.php @@ -79,4 +79,9 @@ public function rawSearch( * @return int<0, max> */ public function count(string $className, string $query = '', array $searchParams = []): int; + + /** + * @param class-string $className + */ + public function getRepositoryMethod(string $className): ?string; } diff --git a/src/Services/MeilisearchService.php b/src/Services/MeilisearchService.php index a001fee2..e8d85582 100644 --- a/src/Services/MeilisearchService.php +++ b/src/Services/MeilisearchService.php @@ -42,6 +42,7 @@ final class MeilisearchService implements SearchService */ private array $classToSerializerGroup; private array $indexIfMapping; + private array $repositoryMethodMapping; public function __construct(NormalizerInterface $normalizer, Engine $engine, array $configuration, ?PropertyAccessorInterface $propertyAccessor = null) { @@ -54,6 +55,7 @@ public function __construct(NormalizerInterface $normalizer, Engine $engine, arr $this->setAggregatorsAndEntitiesAggregators(); $this->setClassToSerializerGroup(); $this->setIndexIfMapping(); + $this->setRepositoryMethodMapping(); } public function isSearchable($className): bool @@ -223,6 +225,11 @@ public function shouldBeIndexed(object $entity): bool return true; } + public function getRepositoryMethod(string $className): ?string + { + return $this->repositoryMethodMapping[$className] ?? null; + } + /** * @param object|class-string $objectOrClass * @@ -295,6 +302,17 @@ private function setIndexIfMapping(): void $this->indexIfMapping = $mapping; } + private function setRepositoryMethodMapping(): void + { + $mapping = []; + + /** @var array $indexDetails */ + foreach ($this->configuration->get('indices') as $indexDetails) { + $mapping[$indexDetails['class']] = $indexDetails['repository_method']; + } + $this->repositoryMethodMapping = $mapping; + } + /** * Returns the aggregators instances of the provided entities. * diff --git a/tests/BaseKernelTestCase.php b/tests/BaseKernelTestCase.php index 8137a37b..e88ef041 100644 --- a/tests/BaseKernelTestCase.php +++ b/tests/BaseKernelTestCase.php @@ -17,6 +17,7 @@ use Meilisearch\Bundle\Tests\Entity\Page; use Meilisearch\Bundle\Tests\Entity\Podcast; use Meilisearch\Bundle\Tests\Entity\Post; +use Meilisearch\Bundle\Tests\Entity\RepositoryMethod; use Meilisearch\Bundle\Tests\Entity\Tag; use Meilisearch\Client; use Meilisearch\Exceptions\ApiException; @@ -194,6 +195,18 @@ protected function createLink(array $properties = []): Link return $link; } + protected function createRepositoryMethod(bool $isFiltered): RepositoryMethod + { + $repositoryMethod = new RepositoryMethod(); + $repositoryMethod->setName('Test'); + $repositoryMethod->setIsFiltered($isFiltered); + + $this->entityManager->persist($repositoryMethod); + $this->entityManager->flush(); + + return $repositoryMethod; + } + protected function getPrefix(): string { return $this->searchService->getConfiguration()->get('prefix'); diff --git a/tests/Entity/RepositoryMethod.php b/tests/Entity/RepositoryMethod.php new file mode 100644 index 00000000..32e9fbd6 --- /dev/null +++ b/tests/Entity/RepositoryMethod.php @@ -0,0 +1,75 @@ + false])] + private bool $isFiltered = false; + + public function getId() + { + return $this->id; + } + + public function setId($id): self + { + $this->id = $id; + + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function isFiltered(): bool + { + return $this->isFiltered; + } + + public function setIsFiltered(bool $isFiltered): void + { + $this->isFiltered = $isFiltered; + } +} diff --git a/tests/Integration/Command/MeilisearchClearCommandTest.php b/tests/Integration/Command/MeilisearchClearCommandTest.php index 19c4b64c..e454f166 100644 --- a/tests/Integration/Command/MeilisearchClearCommandTest.php +++ b/tests/Integration/Command/MeilisearchClearCommandTest.php @@ -36,6 +36,7 @@ public function testClear(): void Cleared sf_phpunit__self_normalizable index of Meilisearch\Bundle\Tests\Entity\SelfNormalizable Cleared sf_phpunit__dummy_custom_groups index of Meilisearch\Bundle\Tests\Entity\DummyCustomGroups Cleared sf_phpunit__dynamic_settings index of Meilisearch\Bundle\Tests\Entity\DynamicSettings +Cleared sf_phpunit__repository_methods index of Meilisearch\Bundle\Tests\Entity\RepositoryMethod Done! EOD, $commandTester->getDisplay()); diff --git a/tests/Integration/Command/MeilisearchCreateCommandTest.php b/tests/Integration/Command/MeilisearchCreateCommandTest.php index 2f2398f9..a1a2ecc8 100644 --- a/tests/Integration/Command/MeilisearchCreateCommandTest.php +++ b/tests/Integration/Command/MeilisearchCreateCommandTest.php @@ -60,6 +60,7 @@ public function testWithoutIndices(bool $updateSettings): void Setting "searchableAttributes" updated of "sf_phpunit__dynamic_settings". Setting "stopWords" updated of "sf_phpunit__dynamic_settings". Setting "synonyms" updated of "sf_phpunit__dynamic_settings". +Creating index sf_phpunit__repository_methods for Meilisearch\Bundle\Tests\Entity\RepositoryMethod Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Post Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Tag Done! @@ -76,6 +77,7 @@ public function testWithoutIndices(bool $updateSettings): void Creating index sf_phpunit__self_normalizable for Meilisearch\Bundle\Tests\Entity\SelfNormalizable Creating index sf_phpunit__dummy_custom_groups for Meilisearch\Bundle\Tests\Entity\DummyCustomGroups Creating index sf_phpunit__dynamic_settings for Meilisearch\Bundle\Tests\Entity\DynamicSettings +Creating index sf_phpunit__repository_methods for Meilisearch\Bundle\Tests\Entity\RepositoryMethod Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Post Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Tag Done! diff --git a/tests/Integration/Command/MeilisearchDeleteCommandTest.php b/tests/Integration/Command/MeilisearchDeleteCommandTest.php index 94c00276..caf1963b 100644 --- a/tests/Integration/Command/MeilisearchDeleteCommandTest.php +++ b/tests/Integration/Command/MeilisearchDeleteCommandTest.php @@ -37,6 +37,7 @@ public function testDeleteWithoutIndices(): void Deleted sf_phpunit__self_normalizable Deleted sf_phpunit__dummy_custom_groups Deleted sf_phpunit__dynamic_settings +Deleted sf_phpunit__repository_methods Done! EOD, $clearOutput); diff --git a/tests/Integration/Command/MeilisearchImportCommandTest.php b/tests/Integration/Command/MeilisearchImportCommandTest.php index 781a6d5f..9f073c12 100644 --- a/tests/Integration/Command/MeilisearchImportCommandTest.php +++ b/tests/Integration/Command/MeilisearchImportCommandTest.php @@ -391,4 +391,33 @@ public function testAlias(): void self::assertSame(['meili:import'], $command->getAliases()); } + + public function testImportCustomRepositoryMethod(): void + { + $this->createRepositoryMethod(true); + $this->createRepositoryMethod(false); + + $importCommand = $this->application->find('meilisearch:clear'); + $importCommandTester = new CommandTester($importCommand); + $importCommandTester->execute(['--indices' => 'repository_methods']); + + $importCommand = $this->application->find('meilisearch:import'); + $importCommandTester = new CommandTester($importCommand); + $importCommandTester->execute(['--indices' => 'repository_methods']); + + $importOutput = $importCommandTester->getDisplay(); + + $this->assertSame(<<<'EOD' +Importing for index Meilisearch\Bundle\Tests\Entity\RepositoryMethod +Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\RepositoryMethod entities into sf_phpunit__repository_methods index (1 indexed since start) +Done! + +EOD, $importOutput); + + /** @var SearchResult $searchResult */ + $searchResult = $this->client->index($this->getPrefix().'repository_methods')->search(null); + + $this->assertEquals(1, $searchResult->getHitsCount()); + $this->assertTrue($searchResult->getHit(0)['filtered']); + } } diff --git a/tests/Repository/RepositoryMethodRepository.php b/tests/Repository/RepositoryMethodRepository.php new file mode 100644 index 00000000..53c7df24 --- /dev/null +++ b/tests/Repository/RepositoryMethodRepository.php @@ -0,0 +1,21 @@ +createQueryBuilder('r') + ->where('r.isFiltered = :filtered') + ->setParameter('filtered', true) + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult(); + } +} diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php index fca71a73..09f7575d 100644 --- a/tests/Unit/ConfigurationTest.php +++ b/tests/Unit/ConfigurationTest.php @@ -62,12 +62,18 @@ public function dataTestConfigurationTree(): array [ 'prefix' => 'sf_', 'indices' => [ - ['name' => 'posts', 'class' => 'App\Entity\Post', 'index_if' => null], + [ + 'name' => 'posts', + 'class' => 'App\Entity\Post', + 'index_if' => null, + 'repository_method' => null, + ], [ 'name' => 'tags', 'class' => 'App\Entity\Tag', 'enable_serializer_groups' => true, 'index_if' => null, + 'repository_method' => null, ], ], ], @@ -86,6 +92,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], 1 => [ 'name' => 'tags', @@ -94,6 +101,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], ], ], @@ -108,6 +116,7 @@ public function dataTestConfigurationTree(): array 'enable_serializer_groups' => false, 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], [ 'name' => 'items', @@ -115,6 +124,7 @@ public function dataTestConfigurationTree(): array 'enable_serializer_groups' => false, 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], ], 'nbResults' => 20, @@ -131,7 +141,9 @@ public function dataTestConfigurationTree(): array 'class' => 'App\Entity\Post', 'enable_serializer_groups' => false, 'serializer_groups' => ['searchable'], - 'index_if' => null, 'settings' => [], + 'index_if' => null, + 'settings' => [], + 'repository_method' => null, ], [ 'name' => 'items', @@ -140,6 +152,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], ], 'nbResults' => 20, @@ -159,6 +172,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['post.public', 'post.private'], 'index_if' => null, 'settings' => [], + 'repository_method' => null, ], ], ], @@ -171,7 +185,9 @@ public function dataTestConfigurationTree(): array 'class' => 'App\Entity\Post', 'enable_serializer_groups' => true, 'serializer_groups' => ['post.public', 'post.private'], - 'index_if' => null, 'settings' => [], + 'index_if' => null, + 'settings' => [], + 'repository_method' => null, ], ], 'nbResults' => 20, @@ -206,6 +222,7 @@ public function dataTestConfigurationTree(): array 'settings' => [ 'distinctAttribute' => ['product_id'], ], + 'repository_method' => null, ], ], 'nbResults' => 20, @@ -240,6 +257,38 @@ public function dataTestConfigurationTree(): array 'settings' => [ 'proximityPrecision' => ['byWord'], ], + 'repository_method' => null, + ], + ], + 'nbResults' => 20, + 'batchSize' => 500, + 'serializer' => 'serializer', + 'doctrineSubscribedEvents' => ['postPersist', 'postUpdate', 'preRemove'], + ], + ], + 'custom repository method' => [ + [ + 'prefix' => 'sf_', + 'indices' => [ + [ + 'name' => 'items', + 'class' => 'App\Entity\Post', + 'repository_method' => 'myCustomRepositoryMethod', + ], + ], + ], + [ + 'url' => 'http://localhost:7700', + 'prefix' => 'sf_', + 'indices' => [ + [ + 'name' => 'items', + 'class' => 'App\Entity\Post', + 'enable_serializer_groups' => false, + 'serializer_groups' => ['searchable'], + 'index_if' => null, + 'settings' => [], + 'repository_method' => 'myCustomRepositoryMethod', ], ], 'nbResults' => 20, diff --git a/tests/config/meilisearch.yaml b/tests/config/meilisearch.yaml index 50a06b90..a7f13166 100644 --- a/tests/config/meilisearch.yaml +++ b/tests/config/meilisearch.yaml @@ -54,6 +54,9 @@ meilisearch: _service: '@Meilisearch\Bundle\Tests\Integration\Fixtures\StopWords' synonyms: _service: '@Meilisearch\Bundle\Tests\Integration\Fixtures\Synonyms' + - name: repository_methods + class: 'Meilisearch\Bundle\Tests\Entity\RepositoryMethod' + repository_method: customRepositoryMethod services: Meilisearch\Bundle\Tests\Integration\Fixtures\: From 91f6da087b70e3b98603adaa5e23f5ead8c02c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Garcia?= Date: Fri, 16 Aug 2024 10:16:55 +0200 Subject: [PATCH 2/3] added a "data_provider" option in indices settings --- src/Command/IndexCommand.php | 5 ++ src/Command/MeilisearchImportCommand.php | 28 +++---- src/DataProvider/DataProvider.php | 18 ++++ src/DataProvider/DoctrineOrmDataProvider.php | 43 ++++++++++ src/DependencyInjection/Configuration.php | 2 +- .../MeilisearchExtension.php | 4 + src/SearchService.php | 6 +- src/Services/MeilisearchService.php | 15 ++-- tests/BaseKernelTestCase.php | 12 ++- tests/DataProvider/TicketDataProvider.php | 32 +++++++ tests/Entity/RepositoryMethod.php | 75 ----------------- tests/Entity/Ticket.php | 84 +++++++++++++++++++ .../Command/MeilisearchClearCommandTest.php | 2 +- .../Command/MeilisearchCreateCommandTest.php | 4 +- .../Command/MeilisearchDeleteCommandTest.php | 2 +- .../Command/MeilisearchImportCommandTest.php | 19 +++-- .../Repository/RepositoryMethodRepository.php | 21 ----- tests/Unit/ConfigurationTest.php | 30 +++---- tests/config/config.yaml | 4 + tests/config/config_php7.yaml | 4 + tests/config/meilisearch.yaml | 6 +- 21 files changed, 252 insertions(+), 164 deletions(-) create mode 100644 src/DataProvider/DataProvider.php create mode 100644 src/DataProvider/DoctrineOrmDataProvider.php create mode 100644 tests/DataProvider/TicketDataProvider.php delete mode 100644 tests/Entity/RepositoryMethod.php create mode 100644 tests/Entity/Ticket.php delete mode 100644 tests/Repository/RepositoryMethodRepository.php diff --git a/src/Command/IndexCommand.php b/src/Command/IndexCommand.php index ff0c7778..8c055ca6 100644 --- a/src/Command/IndexCommand.php +++ b/src/Command/IndexCommand.php @@ -36,6 +36,11 @@ protected function getIndices(): Collection }); } + protected function getIndexNameWithoutPrefix(string $prefixedIndexName): string + { + return preg_replace(\sprintf('/^%s/', preg_quote($this->prefix)), '', $prefixedIndexName) ?? $prefixedIndexName; + } + protected function getEntitiesFromArgs(InputInterface $input, OutputInterface $output): Collection { $indices = $this->getIndices(); diff --git a/src/Command/MeilisearchImportCommand.php b/src/Command/MeilisearchImportCommand.php index 135fd94d..a32d3578 100644 --- a/src/Command/MeilisearchImportCommand.php +++ b/src/Command/MeilisearchImportCommand.php @@ -6,6 +6,7 @@ use Doctrine\Persistence\ManagerRegistry; use Meilisearch\Bundle\Collection; +use Meilisearch\Bundle\DataProvider\DoctrineOrmDataProvider; use Meilisearch\Bundle\EventListener\ConsoleOutputSubscriber; use Meilisearch\Bundle\Exception\TaskException; use Meilisearch\Bundle\Model\Aggregator; @@ -115,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } do { - $entities = $this->getEntities($entityClassName, $batchSize, $page); + $entities = $this->getEntities($index['name'], $entityClassName, $batchSize, $page); $responses = $this->formatIndexingResponse($this->searchService->index($manager, $entities), $responseTimeout); $totalIndexed += \count($entities); @@ -201,31 +202,22 @@ private function entitiesToIndex($indexes): array } /** + * @param string $prefixedIndexName * @param string $entityClassName * @param int $batchSize * @param int $page * * @return array */ - private function getEntities($entityClassName, $batchSize, $page): array + private function getEntities($prefixedIndexName, $entityClassName, $batchSize, $page): array { - $manager = $this->managerRegistry->getManagerForClass($entityClassName); - $classMetadata = $manager->getClassMetadata($entityClassName); - $entityIdentifiers = $classMetadata->getIdentifierFieldNames(); - $repository = $manager->getRepository($entityClassName); - $sortByAttrs = array_combine($entityIdentifiers, array_fill(0, \count($entityIdentifiers), 'ASC')); - - $repositoryMethod = $this->searchService->getRepositoryMethod($entityClassName); - - if (null === $repositoryMethod) { - return $repository->findBy( - [], - $sortByAttrs, - $batchSize, - $batchSize * $page - ); + $dataProvider = $this->searchService->getDataProvider($this->getIndexNameWithoutPrefix($prefixedIndexName)); + + if (null === $dataProvider) { + $dataProvider = new DoctrineOrmDataProvider($this->managerRegistry); + $dataProvider->setEntityClassName($entityClassName); } - return $repository->$repositoryMethod($batchSize, $batchSize * $page); + return $dataProvider->getAll($batchSize, $batchSize * $page); } } diff --git a/src/DataProvider/DataProvider.php b/src/DataProvider/DataProvider.php new file mode 100644 index 00000000..7f5228bc --- /dev/null +++ b/src/DataProvider/DataProvider.php @@ -0,0 +1,18 @@ +managerRegistry = $managerRegistry; + } + + public function setEntityClassName(string $entityClassName): void + { + $this->entityClassName = $entityClassName; + } + + public function getAll(int $limit = 100, int $offset = 0): array + { + if (empty($this->entityClassName)) { + throw new \Exception('No entity class name set on data provider.'); + } + + $manager = $this->managerRegistry->getManagerForClass($this->entityClassName); + $classMetadata = $manager->getClassMetadata($this->entityClassName); + $entityIdentifiers = $classMetadata->getIdentifierFieldNames(); + $repository = $manager->getRepository($this->entityClassName); + $sortByAttrs = array_combine($entityIdentifiers, array_fill(0, \count($entityIdentifiers), 'ASC')); + + return $repository->findBy( + [], + $sortByAttrs, + $limit, + $offset + ); + } +} diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index a50012f8..af98287e 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -59,7 +59,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Property accessor path (like method or property name) used to decide if an entry should be indexed.') ->defaultNull() ->end() - ->scalarNode('repository_method') + ->scalarNode('data_provider') ->info('Method of the entity repository called when the meilisearch:import command is invoked.') ->defaultNull() ->end() diff --git a/src/DependencyInjection/MeilisearchExtension.php b/src/DependencyInjection/MeilisearchExtension.php index e6692bb5..ce640473 100644 --- a/src/DependencyInjection/MeilisearchExtension.php +++ b/src/DependencyInjection/MeilisearchExtension.php @@ -30,6 +30,10 @@ public function load(array $configs, ContainerBuilder $container): void foreach ($config['indices'] as $index => $indice) { $config['indices'][$index]['prefixed_name'] = $config['prefix'].$indice['name']; $config['indices'][$index]['settings'] = $this->findReferences($config['indices'][$index]['settings']); + + if (null !== $config['indices'][$index]['data_provider']) { + $config['indices'][$index]['data_provider'] = new Reference($config['indices'][$index]['data_provider']); + } } $container->setParameter('meili_url', $config['url'] ?? null); diff --git a/src/SearchService.php b/src/SearchService.php index 1e9ce5a7..e77d027e 100644 --- a/src/SearchService.php +++ b/src/SearchService.php @@ -5,6 +5,7 @@ namespace Meilisearch\Bundle; use Doctrine\Persistence\ObjectManager; +use Meilisearch\Bundle\DataProvider\DataProvider; interface SearchService { @@ -80,8 +81,5 @@ public function rawSearch( */ public function count(string $className, string $query = '', array $searchParams = []): int; - /** - * @param class-string $className - */ - public function getRepositoryMethod(string $className): ?string; + public function getDataProvider(string $indexName): ?DataProvider; } diff --git a/src/Services/MeilisearchService.php b/src/Services/MeilisearchService.php index e8d85582..0efd8655 100644 --- a/src/Services/MeilisearchService.php +++ b/src/Services/MeilisearchService.php @@ -8,6 +8,7 @@ use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver; use Doctrine\Persistence\ObjectManager; use Meilisearch\Bundle\Collection; +use Meilisearch\Bundle\DataProvider\DataProvider; use Meilisearch\Bundle\Engine; use Meilisearch\Bundle\Entity\Aggregator; use Meilisearch\Bundle\Exception\ObjectIdNotFoundException; @@ -42,7 +43,7 @@ final class MeilisearchService implements SearchService */ private array $classToSerializerGroup; private array $indexIfMapping; - private array $repositoryMethodMapping; + private array $dataProviderMapping; public function __construct(NormalizerInterface $normalizer, Engine $engine, array $configuration, ?PropertyAccessorInterface $propertyAccessor = null) { @@ -55,7 +56,7 @@ public function __construct(NormalizerInterface $normalizer, Engine $engine, arr $this->setAggregatorsAndEntitiesAggregators(); $this->setClassToSerializerGroup(); $this->setIndexIfMapping(); - $this->setRepositoryMethodMapping(); + $this->setDataProviderMapping(); } public function isSearchable($className): bool @@ -225,9 +226,9 @@ public function shouldBeIndexed(object $entity): bool return true; } - public function getRepositoryMethod(string $className): ?string + public function getDataProvider(string $indexName): ?DataProvider { - return $this->repositoryMethodMapping[$className] ?? null; + return $this->dataProviderMapping[$indexName] ?? null; } /** @@ -302,15 +303,15 @@ private function setIndexIfMapping(): void $this->indexIfMapping = $mapping; } - private function setRepositoryMethodMapping(): void + private function setDataProviderMapping(): void { $mapping = []; /** @var array $indexDetails */ foreach ($this->configuration->get('indices') as $indexDetails) { - $mapping[$indexDetails['class']] = $indexDetails['repository_method']; + $mapping[$indexDetails['name']] = $indexDetails['data_provider']; } - $this->repositoryMethodMapping = $mapping; + $this->dataProviderMapping = $mapping; } /** diff --git a/tests/BaseKernelTestCase.php b/tests/BaseKernelTestCase.php index e88ef041..6704ea20 100644 --- a/tests/BaseKernelTestCase.php +++ b/tests/BaseKernelTestCase.php @@ -17,8 +17,8 @@ use Meilisearch\Bundle\Tests\Entity\Page; use Meilisearch\Bundle\Tests\Entity\Podcast; use Meilisearch\Bundle\Tests\Entity\Post; -use Meilisearch\Bundle\Tests\Entity\RepositoryMethod; use Meilisearch\Bundle\Tests\Entity\Tag; +use Meilisearch\Bundle\Tests\Entity\Ticket; use Meilisearch\Client; use Meilisearch\Exceptions\ApiException; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; @@ -195,16 +195,14 @@ protected function createLink(array $properties = []): Link return $link; } - protected function createRepositoryMethod(bool $isFiltered): RepositoryMethod + protected function createTicket(int $id, bool $sold): Ticket { - $repositoryMethod = new RepositoryMethod(); - $repositoryMethod->setName('Test'); - $repositoryMethod->setIsFiltered($isFiltered); + $ticket = new Ticket($id, str_pad((string) random_int(0, 1000000), 6, '0', STR_PAD_LEFT), $sold); - $this->entityManager->persist($repositoryMethod); + $this->entityManager->persist($ticket); $this->entityManager->flush(); - return $repositoryMethod; + return $ticket; } protected function getPrefix(): string diff --git a/tests/DataProvider/TicketDataProvider.php b/tests/DataProvider/TicketDataProvider.php new file mode 100644 index 00000000..d76b5b5e --- /dev/null +++ b/tests/DataProvider/TicketDataProvider.php @@ -0,0 +1,32 @@ +managerRegistry = $managerRegistry; + } + + public function getAll(int $limit = 100, int $offset = 0): array + { + $manager = $this->managerRegistry->getManagerForClass(Ticket::class); + $repository = $manager->getRepository(Ticket::class); + + return $repository->findBy( + ['sold' => false], + ['id' => 'ASC'], + $limit, + $offset + ); + } +} diff --git a/tests/Entity/RepositoryMethod.php b/tests/Entity/RepositoryMethod.php deleted file mode 100644 index 32e9fbd6..00000000 --- a/tests/Entity/RepositoryMethod.php +++ /dev/null @@ -1,75 +0,0 @@ - false])] - private bool $isFiltered = false; - - public function getId() - { - return $this->id; - } - - public function setId($id): self - { - $this->id = $id; - - return $this; - } - - public function getName(): string - { - return $this->name; - } - - public function setName(string $name): void - { - $this->name = $name; - } - - public function isFiltered(): bool - { - return $this->isFiltered; - } - - public function setIsFiltered(bool $isFiltered): void - { - $this->isFiltered = $isFiltered; - } -} diff --git a/tests/Entity/Ticket.php b/tests/Entity/Ticket.php new file mode 100644 index 00000000..e1d17cac --- /dev/null +++ b/tests/Entity/Ticket.php @@ -0,0 +1,84 @@ + false])] + private bool $sold; + + /** + * @param int $id + * @param string $barcode + * @param bool $sold + */ + public function __construct(int $id, string $barcode, bool $sold) + { + $this->id = $id; + $this->barcode = $barcode; + $this->sold = $sold; + } + + public function getId(): int + { + return $this->id; + } + + public function setId(int $id): Ticket + { + $this->id = $id; + + return $this; + } + + public function getBarcode(): string + { + return $this->barcode; + } + + public function setBarcode(string $barcode): Ticket + { + $this->barcode = $barcode; + + return $this; + } + + public function isSold(): bool + { + return $this->sold; + } + + public function setSold(bool $sold): Ticket + { + $this->sold = $sold; + + return $this; + } +} diff --git a/tests/Integration/Command/MeilisearchClearCommandTest.php b/tests/Integration/Command/MeilisearchClearCommandTest.php index e454f166..bac92f2f 100644 --- a/tests/Integration/Command/MeilisearchClearCommandTest.php +++ b/tests/Integration/Command/MeilisearchClearCommandTest.php @@ -36,7 +36,7 @@ public function testClear(): void Cleared sf_phpunit__self_normalizable index of Meilisearch\Bundle\Tests\Entity\SelfNormalizable Cleared sf_phpunit__dummy_custom_groups index of Meilisearch\Bundle\Tests\Entity\DummyCustomGroups Cleared sf_phpunit__dynamic_settings index of Meilisearch\Bundle\Tests\Entity\DynamicSettings -Cleared sf_phpunit__repository_methods index of Meilisearch\Bundle\Tests\Entity\RepositoryMethod +Cleared sf_phpunit__tickets index of Meilisearch\Bundle\Tests\Entity\Ticket Done! EOD, $commandTester->getDisplay()); diff --git a/tests/Integration/Command/MeilisearchCreateCommandTest.php b/tests/Integration/Command/MeilisearchCreateCommandTest.php index a1a2ecc8..c0c1bb5c 100644 --- a/tests/Integration/Command/MeilisearchCreateCommandTest.php +++ b/tests/Integration/Command/MeilisearchCreateCommandTest.php @@ -60,7 +60,7 @@ public function testWithoutIndices(bool $updateSettings): void Setting "searchableAttributes" updated of "sf_phpunit__dynamic_settings". Setting "stopWords" updated of "sf_phpunit__dynamic_settings". Setting "synonyms" updated of "sf_phpunit__dynamic_settings". -Creating index sf_phpunit__repository_methods for Meilisearch\Bundle\Tests\Entity\RepositoryMethod +Creating index sf_phpunit__tickets for Meilisearch\Bundle\Tests\Entity\Ticket Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Post Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Tag Done! @@ -77,7 +77,7 @@ public function testWithoutIndices(bool $updateSettings): void Creating index sf_phpunit__self_normalizable for Meilisearch\Bundle\Tests\Entity\SelfNormalizable Creating index sf_phpunit__dummy_custom_groups for Meilisearch\Bundle\Tests\Entity\DummyCustomGroups Creating index sf_phpunit__dynamic_settings for Meilisearch\Bundle\Tests\Entity\DynamicSettings -Creating index sf_phpunit__repository_methods for Meilisearch\Bundle\Tests\Entity\RepositoryMethod +Creating index sf_phpunit__tickets for Meilisearch\Bundle\Tests\Entity\Ticket Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Post Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Tag Done! diff --git a/tests/Integration/Command/MeilisearchDeleteCommandTest.php b/tests/Integration/Command/MeilisearchDeleteCommandTest.php index caf1963b..6666c6f9 100644 --- a/tests/Integration/Command/MeilisearchDeleteCommandTest.php +++ b/tests/Integration/Command/MeilisearchDeleteCommandTest.php @@ -37,7 +37,7 @@ public function testDeleteWithoutIndices(): void Deleted sf_phpunit__self_normalizable Deleted sf_phpunit__dummy_custom_groups Deleted sf_phpunit__dynamic_settings -Deleted sf_phpunit__repository_methods +Deleted sf_phpunit__tickets Done! EOD, $clearOutput); diff --git a/tests/Integration/Command/MeilisearchImportCommandTest.php b/tests/Integration/Command/MeilisearchImportCommandTest.php index 9f073c12..63a270b6 100644 --- a/tests/Integration/Command/MeilisearchImportCommandTest.php +++ b/tests/Integration/Command/MeilisearchImportCommandTest.php @@ -392,32 +392,33 @@ public function testAlias(): void self::assertSame(['meili:import'], $command->getAliases()); } - public function testImportCustomRepositoryMethod(): void + public function testImportDataProvider(): void { - $this->createRepositoryMethod(true); - $this->createRepositoryMethod(false); + $this->createTicket(1, true); + $this->createTicket(2, false); $importCommand = $this->application->find('meilisearch:clear'); $importCommandTester = new CommandTester($importCommand); - $importCommandTester->execute(['--indices' => 'repository_methods']); + $importCommandTester->execute(['--indices' => 'tickets']); $importCommand = $this->application->find('meilisearch:import'); $importCommandTester = new CommandTester($importCommand); - $importCommandTester->execute(['--indices' => 'repository_methods']); + $importCommandTester->execute(['--indices' => 'tickets']); $importOutput = $importCommandTester->getDisplay(); $this->assertSame(<<<'EOD' -Importing for index Meilisearch\Bundle\Tests\Entity\RepositoryMethod -Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\RepositoryMethod entities into sf_phpunit__repository_methods index (1 indexed since start) +Importing for index Meilisearch\Bundle\Tests\Entity\Ticket +Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\Ticket entities into sf_phpunit__tickets index (1 indexed since start) Done! EOD, $importOutput); /** @var SearchResult $searchResult */ - $searchResult = $this->client->index($this->getPrefix().'repository_methods')->search(null); + $searchResult = $this->client->index($this->getPrefix().'tickets')->search(null); $this->assertEquals(1, $searchResult->getHitsCount()); - $this->assertTrue($searchResult->getHit(0)['filtered']); + $this->assertEquals(2, $searchResult->getHit(0)['id']); + $this->assertFalse($searchResult->getHit(0)['sold']); } } diff --git a/tests/Repository/RepositoryMethodRepository.php b/tests/Repository/RepositoryMethodRepository.php deleted file mode 100644 index 53c7df24..00000000 --- a/tests/Repository/RepositoryMethodRepository.php +++ /dev/null @@ -1,21 +0,0 @@ -createQueryBuilder('r') - ->where('r.isFiltered = :filtered') - ->setParameter('filtered', true) - ->setMaxResults($limit) - ->setFirstResult($offset) - ->getQuery() - ->getResult(); - } -} diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php index 09f7575d..fc7511cd 100644 --- a/tests/Unit/ConfigurationTest.php +++ b/tests/Unit/ConfigurationTest.php @@ -66,14 +66,14 @@ public function dataTestConfigurationTree(): array 'name' => 'posts', 'class' => 'App\Entity\Post', 'index_if' => null, - 'repository_method' => null, + 'data_provider' => null, ], [ 'name' => 'tags', 'class' => 'App\Entity\Tag', 'enable_serializer_groups' => true, 'index_if' => null, - 'repository_method' => null, + 'data_provider' => null, ], ], ], @@ -92,7 +92,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], 1 => [ 'name' => 'tags', @@ -101,7 +101,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], ], ], @@ -116,7 +116,7 @@ public function dataTestConfigurationTree(): array 'enable_serializer_groups' => false, 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], [ 'name' => 'items', @@ -124,7 +124,7 @@ public function dataTestConfigurationTree(): array 'enable_serializer_groups' => false, 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], ], 'nbResults' => 20, @@ -143,7 +143,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], [ 'name' => 'items', @@ -152,7 +152,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], ], 'nbResults' => 20, @@ -172,7 +172,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['post.public', 'post.private'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], ], ], @@ -187,7 +187,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['post.public', 'post.private'], 'index_if' => null, 'settings' => [], - 'repository_method' => null, + 'data_provider' => null, ], ], 'nbResults' => 20, @@ -222,7 +222,7 @@ public function dataTestConfigurationTree(): array 'settings' => [ 'distinctAttribute' => ['product_id'], ], - 'repository_method' => null, + 'data_provider' => null, ], ], 'nbResults' => 20, @@ -257,7 +257,7 @@ public function dataTestConfigurationTree(): array 'settings' => [ 'proximityPrecision' => ['byWord'], ], - 'repository_method' => null, + 'data_provider' => null, ], ], 'nbResults' => 20, @@ -266,14 +266,14 @@ public function dataTestConfigurationTree(): array 'doctrineSubscribedEvents' => ['postPersist', 'postUpdate', 'preRemove'], ], ], - 'custom repository method' => [ + 'custom data provider' => [ [ 'prefix' => 'sf_', 'indices' => [ [ 'name' => 'items', 'class' => 'App\Entity\Post', - 'repository_method' => 'myCustomRepositoryMethod', + 'data_provider' => 'Meilisearch\Bundle\Tests\DataProvider\TicketDataProvider', ], ], ], @@ -288,7 +288,7 @@ public function dataTestConfigurationTree(): array 'serializer_groups' => ['searchable'], 'index_if' => null, 'settings' => [], - 'repository_method' => 'myCustomRepositoryMethod', + 'data_provider' => 'Meilisearch\Bundle\Tests\DataProvider\TicketDataProvider', ], ], 'nbResults' => 20, diff --git a/tests/config/config.yaml b/tests/config/config.yaml index 87de9ee1..e876a310 100644 --- a/tests/config/config.yaml +++ b/tests/config/config.yaml @@ -24,3 +24,7 @@ doctrine: dir: '%kernel.project_dir%/tests/Entity' prefix: 'Meilisearch\Bundle\Tests\Entity' alias: App + +services: + Meilisearch\Bundle\Tests\DataProvider\TicketDataProvider: + arguments: [ '@doctrine' ] diff --git a/tests/config/config_php7.yaml b/tests/config/config_php7.yaml index 7f690a23..b8d68c4b 100644 --- a/tests/config/config_php7.yaml +++ b/tests/config/config_php7.yaml @@ -28,3 +28,7 @@ doctrine: dir: '%kernel.project_dir%/tests/Entity' prefix: 'Meilisearch\Bundle\Tests\Entity' alias: App + +services: + Meilisearch\Bundle\Tests\DataProvider\TicketDataProvider: + arguments: [ '@doctrine' ] diff --git a/tests/config/meilisearch.yaml b/tests/config/meilisearch.yaml index a7f13166..25e0c922 100644 --- a/tests/config/meilisearch.yaml +++ b/tests/config/meilisearch.yaml @@ -54,9 +54,9 @@ meilisearch: _service: '@Meilisearch\Bundle\Tests\Integration\Fixtures\StopWords' synonyms: _service: '@Meilisearch\Bundle\Tests\Integration\Fixtures\Synonyms' - - name: repository_methods - class: 'Meilisearch\Bundle\Tests\Entity\RepositoryMethod' - repository_method: customRepositoryMethod + - name: tickets + class: 'Meilisearch\Bundle\Tests\Entity\Ticket' + data_provider: 'Meilisearch\Bundle\Tests\DataProvider\TicketDataProvider' services: Meilisearch\Bundle\Tests\Integration\Fixtures\: From e9863b880d17d42302390bf4deb2c197fa6ddf3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Garcia?= Date: Fri, 16 Aug 2024 10:27:10 +0200 Subject: [PATCH 3/3] tests for default data provider --- .../DoctrineOrmDataProviderTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/Unit/DataProvider/DoctrineOrmDataProviderTest.php diff --git a/tests/Unit/DataProvider/DoctrineOrmDataProviderTest.php b/tests/Unit/DataProvider/DoctrineOrmDataProviderTest.php new file mode 100644 index 00000000..614f3e8e --- /dev/null +++ b/tests/Unit/DataProvider/DoctrineOrmDataProviderTest.php @@ -0,0 +1,24 @@ +get('doctrine')); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No entity class name set on data provider.'); + + $dataProvider->getAll(); + } +}