diff --git a/config/services.xml b/config/services.xml index 7691418b..cf25ac1e 100644 --- a/config/services.xml +++ b/config/services.xml @@ -4,17 +4,20 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - + + + + The "%alias_id%" service alias is deprecated. Use "meilisearch.search_indexer_subscriber" instead. - + %meili_url% %meili_api_key% @@ -22,8 +25,14 @@ %meili_symfony_version% + + The "%alias_id%" service alias is deprecated. Use "meilisearch.client" instead. + - - + + + The "%alias_id%" service alias is deprecated. Use "meilisearch.client" instead. + + diff --git a/src/DataCollector/MeilisearchDataCollector.php b/src/DataCollector/MeilisearchDataCollector.php new file mode 100644 index 00000000..73c8fb3f --- /dev/null +++ b/src/DataCollector/MeilisearchDataCollector.php @@ -0,0 +1,40 @@ + + */ +final class MeilisearchDataCollector extends AbstractDataCollector +{ + private TraceableMeilisearchService $meilisearchService; + + public function __construct(TraceableMeilisearchService $meilisearchService) + { + $this->meilisearchService = $meilisearchService; + } + public function collect(Request $request, Response $response, \Throwable $exception = null): void + { + $data = $this->meilisearchService->getData(); + + $this->data[$this->getName()] = !empty($data) ? $this->cloneVar($data) : null; + } + + public function getName(): string + { + return 'meilisearch'; + } + + /** @internal used in the DataCollector view template */ + public function getMeilisearch(): mixed + { + return $this->data[$this->getName()] ?? null; + } +} diff --git a/src/Debug/TraceableMeilisearchService.php b/src/Debug/TraceableMeilisearchService.php new file mode 100644 index 00000000..f23875b2 --- /dev/null +++ b/src/Debug/TraceableMeilisearchService.php @@ -0,0 +1,110 @@ + + */ +final class TraceableMeilisearchService implements SearchService +{ + private SearchService $searchService; + private Stopwatch $stopwatch; + private array $data = []; + + public function __construct(SearchService $searchService, Stopwatch $stopwatch) + { + $this->searchService = $searchService; + $this->stopwatch = $stopwatch; + } + + public function index(ObjectManager $objectManager, $searchable): array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function remove(ObjectManager $objectManager, $searchable): array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function clear(string $className): array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function deleteByIndexName(string $indexName): ?array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function delete(string $className): ?array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function search(ObjectManager $objectManager, string $className, string $query = '', array $searchParams = []): array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function rawSearch(string $className, string $query = '', array $searchParams = []): array + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function count(string $className, string $query = '', array $searchParams = []): int + { + return $this->innerSearchService(__FUNCTION__, \func_get_args()); + } + + public function isSearchable($className): bool + { + return $this->searchService->isSearchable($className); + } + + public function getSearchable(): array + { + return $this->searchService->getSearchable(); + } + + public function getConfiguration(): Collection + { + return $this->searchService->getConfiguration(); + } + + public function searchableAs(string $className): string + { + return $this->searchService->searchableAs($className); + } + + /** @internal used in the DataCollector class */ + public function getData(): array + { + return $this->data; + } + + private function innerSearchService(string $function, array $args): mixed + { + $this->stopwatch->start($function); + + $result = $this->searchService->{$function}(...$args); + + $event = $this->stopwatch->stop($function); + + $this->data[$function] = [ + '_params' => $args, + '_results' => $result, + '_duration' => $event->getDuration(), + '_memory' => $event->getMemory(), + ]; + + return $result; + } +} diff --git a/src/DependencyInjection/MeilisearchExtension.php b/src/DependencyInjection/MeilisearchExtension.php index 6bf53c94..3e5c8f7f 100644 --- a/src/DependencyInjection/MeilisearchExtension.php +++ b/src/DependencyInjection/MeilisearchExtension.php @@ -4,8 +4,11 @@ namespace Meilisearch\Bundle\DependencyInjection; +use Meilisearch\Bundle\DataCollector\MeilisearchDataCollector; +use Meilisearch\Bundle\Debug\TraceableMeilisearchService; use Meilisearch\Bundle\Engine; use Meilisearch\Bundle\MeilisearchBundle; +use Meilisearch\Bundle\SearchService; use Meilisearch\Bundle\Services\MeilisearchService; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -40,24 +43,39 @@ public function load(array $configs, ContainerBuilder $container): void $container->setParameter('meili_symfony_version', MeilisearchBundle::qualifiedVersion()); if (\count($doctrineEvents = $config['doctrineSubscribedEvents']) > 0) { - $subscriber = $container->getDefinition('search.search_indexer_subscriber'); + $subscriber = $container->getDefinition('meilisearch.search_indexer_subscriber'); foreach ($doctrineEvents as $event) { $subscriber->addTag('doctrine.event_listener', ['event' => $event]); $subscriber->addTag('doctrine_mongodb.odm.event_listener', ['event' => $event]); } } else { - $container->removeDefinition('search.search_indexer_subscriber'); + $container->removeDefinition('meilisearch.search_indexer_subscriber'); } - $engineDefinition = new Definition(Engine::class, [new Reference('search.client')]); + $engineDefinition = new Definition(Engine::class, [new Reference('meilisearch.client')]); $searchDefinition = (new Definition( MeilisearchService::class, [new Reference($config['serializer']), $engineDefinition, $config] )); - $container->setDefinition('search.service', $searchDefinition->setPublic(true)); + $container->setDefinition('meilisearch.service', $searchDefinition->setPublic(true)); + $container->setAlias('search.service', 'meilisearch.service')->setPublic(true); + + if ($container->getParameter('kernel.debug')) { + $container->register('debug.meilisearch.service', TraceableMeilisearchService::class) + ->setDecoratedService(SearchService::class) + ->addArgument(new Reference('debug.meilisearch.service.inner')) + ->addArgument(new Reference('debug.stopwatch')) + ; + $container->register('data_collector.meilisearch', MeilisearchDataCollector::class) + ->addArgument(new Reference('debug.meilisearch.service')) + ->addTag('data_collector', [ + 'id' => 'meilisearch', + 'template' => '@Meilisearch/DataCollector/meilisearch.html.twig', + ]); + } } /** diff --git a/templates/DataCollector/meilisearch.html.twig b/templates/DataCollector/meilisearch.html.twig new file mode 100644 index 00000000..1bbd111b --- /dev/null +++ b/templates/DataCollector/meilisearch.html.twig @@ -0,0 +1,80 @@ +{% extends '@WebProfiler/Profiler/layout.html.twig' %} + +{% block toolbar %} + {% set _data = collector.meilisearch %} + {% if _data is not null %} + {% set icon %} + {{ include('@Meilisearch/DataCollector/meilisearch.svg') }} + Meilisearch + {% endset %} + {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: 'meilisearch' }) }} + {% endif %} +{% endblock %} + +{% block menu %} + {% set _data = collector.meilisearch %} + + + {{ include('@Meilisearch/DataCollector/meilisearch.svg') }} + + Meilisearch + +{% endblock %} + +{% block panel %} +

Meilisearch

+ {% set _data = collector.meilisearch %} + {% if _data is not null %} +
+ {% for _name, _d in _data %} +
+

{{ _name|title }}

+
+
+
+ {{ '%.0f'|format(_d._duration) }} ms + Total execution time +
+
+ {{ '%.2f'|format(_d._memory / 1024 / 1024) }} MB + Peak memory usage +
+
+

Params

+ + {% for _pk, _pv in _d._params %} + + + + + {% endfor %} +
{{ _pk }}{{ profiler_dump(_pv) }}
+

Result

+ + {% for _rk, _rv in _d._results %} + + + + + {% endfor %} +
{{ _rk }}{{ profiler_dump(_rv) }}
+
+
+ {% endfor %} +
+

+ You can also see the HTTP Client & Performance{% if constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') >= '6.1.0' %} & Serializer{% endif %} tabs to learn more. +

+ {% else %} +
+

No Meilisearch data collected.

+
+ {% endif %} +

+ Read Meilisearch documentation +
+ Read Meilisearch PHP SDK documentation +
+ Read Meilisearch Symfony bundle documentation +

+{% endblock %} diff --git a/templates/DataCollector/meilisearch.svg b/templates/DataCollector/meilisearch.svg new file mode 100644 index 00000000..564dd22f --- /dev/null +++ b/templates/DataCollector/meilisearch.svg @@ -0,0 +1,23 @@ + + + Meilisearch + + + + + + + + + + + + + + + + + + + + diff --git a/tests/BaseKernelTestCase.php b/tests/BaseKernelTestCase.php index a1021b37..be12e70c 100644 --- a/tests/BaseKernelTestCase.php +++ b/tests/BaseKernelTestCase.php @@ -29,7 +29,7 @@ protected function setUp(): void self::bootKernel(); $this->entityManager = $this->get('doctrine.orm.entity_manager'); - $this->searchService = $this->get('search.service'); + $this->searchService = $this->get('meilisearch.service'); $metaData = $this->entityManager->getMetadataFactory()->getAllMetadata(); $tool = new SchemaTool($this->entityManager); diff --git a/tests/Integration/CommandsTest.php b/tests/Integration/CommandsTest.php index 405a5750..3f24a1c3 100644 --- a/tests/Integration/CommandsTest.php +++ b/tests/Integration/CommandsTest.php @@ -34,7 +34,7 @@ protected function setUp(): void { parent::setUp(); - $this->client = $this->get('search.client'); + $this->client = $this->get('meilisearch.client'); $this->index = $this->client->index($this->getPrefix().self::$indexName); $this->application = new Application(self::createKernel()); } @@ -498,7 +498,7 @@ public function testImportWithDynamicSettings(string $command): void EOD, $importOutput); } - $settings = $this->get('search.client')->index('sf_phpunit__dynamic_settings')->getSettings(); + $settings = $this->get('meilisearch.client')->index('sf_phpunit__dynamic_settings')->getSettings(); $getSetting = static fn ($value) => $value instanceof \IteratorAggregate ? iterator_to_array($value) : $value; diff --git a/tests/Integration/DependencyInjectionTest.php b/tests/Integration/DependencyInjectionTest.php index d5588cec..c16d09af 100644 --- a/tests/Integration/DependencyInjectionTest.php +++ b/tests/Integration/DependencyInjectionTest.php @@ -19,7 +19,7 @@ public function testHasMeilisearchVersionDefinitionAfterLoad(): void { $this->load(); - $this->assertContainerBuilderHasServiceDefinitionWithArgument('search.client', '$clientAgents', ['%meili_symfony_version%']); + $this->assertContainerBuilderHasServiceDefinitionWithArgument('meilisearch.client', '$clientAgents', ['%meili_symfony_version%']); } public function testHasMeilisearchVersionFromConstantAfterLoad(): void diff --git a/tests/Integration/EngineTest.php b/tests/Integration/EngineTest.php index ca0b36a0..b2e7a676 100644 --- a/tests/Integration/EngineTest.php +++ b/tests/Integration/EngineTest.php @@ -19,7 +19,7 @@ public function setUp(): void { parent::setUp(); - $this->engine = new Engine($this->get('search.client')); + $this->engine = new Engine($this->get('meilisearch.client')); } /** diff --git a/tests/Integration/EventListener/DoctrineEventSubscriberTest.php b/tests/Integration/EventListener/DoctrineEventSubscriberTest.php index ad0b099e..47f45eb2 100644 --- a/tests/Integration/EventListener/DoctrineEventSubscriberTest.php +++ b/tests/Integration/EventListener/DoctrineEventSubscriberTest.php @@ -22,7 +22,7 @@ public function setUp(): void { parent::setUp(); - $this->client = $this->get('search.client'); + $this->client = $this->get('meilisearch.client'); } /** diff --git a/tests/Integration/SearchTest.php b/tests/Integration/SearchTest.php index fcd808ab..33da6b75 100644 --- a/tests/Integration/SearchTest.php +++ b/tests/Integration/SearchTest.php @@ -36,7 +36,7 @@ protected function setUp(): void { parent::setUp(); - $this->client = $this->get('search.client'); + $this->client = $this->get('meilisearch.client'); $this->objectManager = $this->get('doctrine')->getManager(); $this->index = $this->client->index($this->getPrefix().self::$indexName); $this->application = new Application(self::createKernel()); diff --git a/tests/Integration/SettingsTest.php b/tests/Integration/SettingsTest.php index fa230771..1781c2fc 100644 --- a/tests/Integration/SettingsTest.php +++ b/tests/Integration/SettingsTest.php @@ -37,7 +37,7 @@ public function setUp(): void { parent::setUp(); - $this->client = $this->get('search.client'); + $this->client = $this->get('meilisearch.client'); $this->application = new Application(self::$kernel); }