Skip to content

Commit a1b36da

Browse files
committed
Add data collector
1 parent f30e146 commit a1b36da

File tree

11 files changed

+210
-2
lines changed

11 files changed

+210
-2
lines changed

composer-dependency-analyser.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
return (new Configuration())
66
->addPathToExclude(__DIR__ . '/tests')
7+
->ignoreErrorsOnPackage('symfony/http-client', [\ShipMonk\ComposerDependencyAnalyser\Config\ErrorType::UNUSED_DEPENDENCY]) // We use the Symfony HTTP client to inject into the Meilisearch client
78
;

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
"dragon-code/size-sorter": "^1.5",
1919
"knplabs/knp-menu": "^3.4",
2020
"liip/imagine-bundle": "^2.10",
21-
"meilisearch/meilisearch-php": "^1.8",
21+
"meilisearch/meilisearch-php": "^1.14",
2222
"ocramius/doctrine-batch-utils": "^2.4",
2323
"psr/cache": "^1.0 || ^2.0 || ^3.0",
2424
"psr/container": "^1.0 || ^2.0",
2525
"psr/event-dispatcher": "^1.0",
26+
"psr/http-client": "^1.0",
2627
"setono/composite-compiler-pass": "^1.2",
2728
"setono/doctrine-orm-trait": "^1.1",
2829
"sylius/attribute": "^1.0",
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\DataCollector;
6+
7+
use Meilisearch\Client;
8+
use Meilisearch\Contracts\SearchQuery;
9+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Client\TraceableClient;
10+
use Symfony\Component\HttpFoundation\Request;
11+
use Symfony\Component\HttpFoundation\Response;
12+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
13+
use Webmozart\Assert\Assert;
14+
15+
final class MeilisearchDataCollector extends DataCollector
16+
{
17+
public function __construct(private readonly Client $client)
18+
{
19+
}
20+
21+
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
22+
{
23+
if (!$this->client instanceof TraceableClient) {
24+
return;
25+
}
26+
27+
$this->data['multiSearchRequests'] = [];
28+
29+
foreach ($this->client->getMultiSearchRequests() as $multiSearchRequest) {
30+
/** @psalm-suppress MixedArrayAssignment */
31+
$this->data['multiSearchRequests'][] = [
32+
'queries' => array_map(fn (SearchQuery $query) => $this->cloneVar($query->toArray()), $multiSearchRequest['queries']),
33+
'results' => array_map(fn (mixed $result) => $this->cloneVar($result), $multiSearchRequest['results']),
34+
];
35+
}
36+
}
37+
38+
public function getName(): string
39+
{
40+
return 'meilisearch';
41+
}
42+
43+
public function getMultiSearchRequests(): array
44+
{
45+
$multiSearchRequests = $this->data['multiSearchRequests'] ?? [];
46+
Assert::isArray($multiSearchRequests);
47+
48+
return $multiSearchRequests;
49+
}
50+
51+
public function hasMultiSearchRequests(): bool
52+
{
53+
return [] !== $this->getMultiSearchRequests();
54+
}
55+
56+
public function reset(): void
57+
{
58+
// Remove this when dropping support for SF5.4
59+
$this->data = [];
60+
}
61+
}

src/DependencyInjection/SetonoSyliusMeilisearchExtension.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public function prepend(ContainerBuilder $container): void
107107
],
108108
],
109109
],
110+
'http_client' => [
111+
'scoped_clients' => [
112+
'http_client.setono_sylius_meilisearch' => [
113+
'scope' => '%env(MEILISEARCH_URL)%',
114+
],
115+
],
116+
],
110117
'messenger' => [
111118
'buses' => [
112119
'setono_sylius_meilisearch.command_bus' => null,

src/Meilisearch/Client/ClientFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@ public function __construct(
1313
private readonly string $url,
1414
private readonly string $apiKey,
1515
private readonly ClientInterface $httpClient,
16+
private readonly bool $debug = false,
1617
) {
1718
}
1819

1920
public function create(): Client
2021
{
22+
if ($this->debug) {
23+
return new TraceableClient($this->url, $this->apiKey, $this->httpClient);
24+
}
25+
2126
return new Client($this->url, $this->apiKey, $this->httpClient);
2227
}
2328
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Meilisearch\Client;
6+
7+
use Meilisearch\Client;
8+
use Meilisearch\Contracts\MultiSearchFederation;
9+
use Meilisearch\Contracts\SearchQuery;
10+
use Webmozart\Assert\Assert;
11+
12+
final class TraceableClient extends Client
13+
{
14+
/** @var list<array{queries: list<SearchQuery>, results: array}> */
15+
private array $multiSearchRequests = [];
16+
17+
public function multiSearch(array $queries = [], ?MultiSearchFederation $federation = null): array
18+
{
19+
$results = parent::multiSearch($queries, $federation);
20+
Assert::isArray($results);
21+
22+
$this->multiSearchRequests[] = [
23+
'queries' => $queries,
24+
'results' => isset($results['results']) && is_array($results['results']) ? $results['results'] : [],
25+
];
26+
27+
return $results;
28+
}
29+
30+
/**
31+
* @return list<array{queries: list<SearchQuery>, results: array}>
32+
*/
33+
public function getMultiSearchRequests(): array
34+
{
35+
return $this->multiSearchRequests;
36+
}
37+
}

src/Resources/config/services.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<imports>
55
<import resource="services/command.xml"/>
66
<import resource="services/config.xml"/>
7+
<import resource="services/data_collector.xml"/>
78
<import resource="services/data_mapper.xml"/>
89
<import resource="services/data_provider.xml"/>
910
<import resource="services/document.xml"/>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://symfony.com/schema/dic/services"
3+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
4+
<services>
5+
<service id="Setono\SyliusMeilisearchPlugin\DataCollector\MeilisearchDataCollector">
6+
<argument type="service" id="Meilisearch\Client"/>
7+
8+
<tag name="data_collector" template="@SetonoSyliusMeilisearchPlugin/data_collector/meilisearch.html.twig" id="meilisearch"/>
9+
</service>
10+
</services>
11+
</container>

src/Resources/config/services/meilisearch.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
<service id="Setono\SyliusMeilisearchPlugin\Meilisearch\Client\ClientFactory">
3434
<argument>%setono_sylius_meilisearch.server.url%</argument>
3535
<argument>%setono_sylius_meilisearch.server.master_key%</argument>
36-
<argument type="service" id="psr18.http_client"/>
36+
<argument type="service" id="psr18.http_client.setono_sylius_meilisearch"/>
37+
<argument>%kernel.debug%</argument>
3738
</service>
3839

3940
<service id="Meilisearch\Client" class="Meilisearch\Client">
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{# @var collector \Setono\SyliusMeilisearchPlugin\DataCollector\MeilisearchDataCollector #}
2+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
3+
4+
{% block toolbar %}
5+
{% set multiSearchRequestCount = collector.multiSearchRequests|length %}
6+
7+
{% set icon %}
8+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m6.505 18.998l4.434-11.345a4.17 4.17 0 0 1 3.882-2.651h2.674l-4.434 11.345a4.17 4.17 0 0 1-3.883 2.651zm6.505 0l4.434-11.345a4.17 4.17 0 0 1 3.883-2.651H24l-4.434 11.345a4.17 4.17 0 0 1-3.882 2.651zm-13.01 0L4.434 7.653a4.17 4.17 0 0 1 3.882-2.651h2.674L6.556 16.347a4.17 4.17 0 0 1-3.883 2.651z"/></svg>
9+
<span class="sf-toolbar-value">{{ multiSearchRequestCount }}</span>
10+
{% endset %}
11+
12+
{% set text %}
13+
<div class="sf-toolbar-info-piece">
14+
<b>Multi Search Requests</b>
15+
<span class="sf-toolbar-status">{{ multiSearchRequestCount }}</span>
16+
</div>
17+
{% endset %}
18+
19+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
20+
{% endblock %}
21+
22+
{% block head %}
23+
{{ parent() }}
24+
25+
<style>
26+
.sf-profiler-meilisearch-request-response {
27+
display: flex;
28+
border-radius: 5px;
29+
border: 1px solid var(--gray-200);
30+
padding: 10px;
31+
gap: 30px;
32+
}
33+
34+
.sf-profiler-meilisearch-request-response h4 {
35+
border-bottom: 1px solid var(--gray-200);
36+
padding-bottom: 10px;
37+
margin: 0 0 10px 0;
38+
}
39+
</style>
40+
{% endblock %}
41+
42+
{% block menu %}
43+
{# This left-hand menu appears when using the full-screen profiler. #}
44+
<span class="label{{ collector.hasMultiSearchRequests ? '' : ' disabled' }}">
45+
<span class="icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m6.505 18.998l4.434-11.345a4.17 4.17 0 0 1 3.882-2.651h2.674l-4.434 11.345a4.17 4.17 0 0 1-3.883 2.651zm6.505 0l4.434-11.345a4.17 4.17 0 0 1 3.883-2.651H24l-4.434 11.345a4.17 4.17 0 0 1-3.882 2.651zm-13.01 0L4.434 7.653a4.17 4.17 0 0 1 3.882-2.651h2.674L6.556 16.347a4.17 4.17 0 0 1-3.883 2.651z"/></svg></span>
46+
<strong>Meilisearch</strong>
47+
{% if collector.hasMultiSearchRequests %}
48+
<span class="count">
49+
<span>{{ collector.multiSearchRequests|length }}</span>
50+
</span>
51+
{% endif %}
52+
</span>
53+
{% endblock %}
54+
55+
{% block panel %}
56+
<h2>Multi Search Requests</h2>
57+
58+
{% if collector.hasMultiSearchRequests %}
59+
{% for multiSearchRequest in collector.multiSearchRequests %}
60+
{% for query in multiSearchRequest.queries %}
61+
<h3>Request/response #{{ loop.index }}</h3>
62+
<div class="sf-profiler-meilisearch-request-response">
63+
<div class="sf-profiler-meilisearch-request">
64+
<h4>Request</h4>
65+
{{ profiler_dump(query, maxDepth=1) }}
66+
</div>
67+
68+
{% if multiSearchRequest.results is not empty and multiSearchRequest.results[loop.index0] is defined %}
69+
<div class="sf-profiler-meilisearch-response">
70+
<h4>Response</h4>
71+
{{ profiler_dump(multiSearchRequest.results[loop.index0], maxDepth=1) }}
72+
</div>
73+
{% endif %}
74+
</div>
75+
{% endfor %}
76+
{% endfor %}
77+
{% else %}
78+
<div class="empty empty-panel">
79+
<p>No multi search requests.</p>
80+
</div>
81+
{% endif %}
82+
{% endblock %}

0 commit comments

Comments
 (0)