Skip to content

Commit e284b5f

Browse files
committed
Allow to use services for settings
1 parent 1b16382 commit e284b5f

12 files changed

+254
-11
lines changed

src/Command/MeilisearchCreateCommand.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Meilisearch\Bundle\Exception\TaskException;
1010
use Meilisearch\Bundle\Model\Aggregator;
1111
use Meilisearch\Bundle\SearchService;
12+
use Meilisearch\Bundle\SettingsProvider;
1213
use Meilisearch\Client;
1314
use Symfony\Component\Console\Input\InputInterface;
1415
use Symfony\Component\Console\Input\InputOption;
@@ -42,7 +43,7 @@ protected function configure(): void
4243
->addOption('indices', 'i', InputOption::VALUE_OPTIONAL, 'Comma-separated list of index names');
4344
}
4445

45-
private function entitiesToIndex($indexes)
46+
private function entitiesToIndex($indexes): array
4647
{
4748
foreach ($indexes as $key => $index) {
4849
$entityClassName = $index['class'];
@@ -85,16 +86,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8586
foreach ($index['settings'] as $variable => $value) {
8687
$method = sprintf('update%s', ucfirst($variable));
8788

88-
if (false === method_exists($indexInstance, $method)) {
89+
if (!method_exists($indexInstance, $method)) {
8990
throw new InvalidSettingName(sprintf('Invalid setting name: "%s"', $variable));
9091
}
9192

93+
if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) {
94+
$value = $value['_service']();
95+
}
96+
9297
$task = $indexInstance->{$method}($value);
93-
$task = $indexInstance->getTask($task['taskUid']);
98+
$indexInstance->waitForTask($task['taskUid']);
9499

95100
if ('failed' === $task['status']) {
96101
throw new TaskException($task['error']);
97102
}
103+
104+
$output->writeln('<info>Settings updated of "'.$index['name'].'".</info>');
98105
}
99106
}
100107
}

src/Command/MeilisearchImportCommand.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
use Meilisearch\Bundle\Exception\TaskException;
1111
use Meilisearch\Bundle\Model\Aggregator;
1212
use Meilisearch\Bundle\SearchService;
13+
use Meilisearch\Bundle\SettingsProvider;
1314
use Meilisearch\Client;
15+
use Meilisearch\Exceptions\TimeOutException;
1416
use Symfony\Component\Console\Input\InputInterface;
1517
use Symfony\Component\Console\Input\InputOption;
1618
use Symfony\Component\Console\Output\OutputInterface;
@@ -155,10 +157,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
155157
$indexInstance = $this->searchClient->index($index['name']);
156158
foreach ($index['settings'] as $variable => $value) {
157159
$method = sprintf('update%s', ucfirst($variable));
158-
if (false === method_exists($indexInstance, $method)) {
160+
161+
if (!method_exists($indexInstance, $method)) {
159162
throw new InvalidSettingName(sprintf('Invalid setting name: "%s"', $variable));
160163
}
161164

165+
if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) {
166+
$value = $value['_service']();
167+
}
168+
162169
// Update
163170
$task = $indexInstance->{$method}($value);
164171

@@ -168,9 +175,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
168175

169176
if ('failed' === $task['status']) {
170177
throw new TaskException($task['error']);
171-
} else {
172-
$output->writeln('<info>Settings updated.</info>');
173178
}
179+
180+
$output->writeln('<info>Settings updated of "'.$index['name'].'".</info>');
174181
}
175182
}
176183

@@ -185,7 +192,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
185192
return 0;
186193
}
187194

188-
/*
195+
/**
189196
* @throws TimeOutException
190197
*/
191198
private function formatIndexingResponse(array $batch, int $responseTimeout): array

src/DependencyInjection/MeilisearchExtension.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public function load(array $configs, ContainerBuilder $container): void
3131
$config['prefix'] = $container->getParameter('kernel.environment').'_';
3232
}
3333

34+
foreach ($config['indices'] as $index => $indice) {
35+
$config['indices'][$index]['settings'] = $this->findReferences($config['indices'][$index]['settings']);
36+
}
37+
3438
$container->setParameter('meili_url', $config['url'] ?? null);
3539
$container->setParameter('meili_api_key', $config['api_key'] ?? null);
3640
$container->setParameter('meili_symfony_version', MeilisearchBundle::qualifiedVersion());
@@ -55,4 +59,22 @@ public function load(array $configs, ContainerBuilder $container): void
5559

5660
$container->setDefinition('search.service', $searchDefinition->setPublic(true));
5761
}
62+
63+
/**
64+
* @param array<mixed, mixed> $settings
65+
*
66+
* @return array<mixed, mixed>
67+
*/
68+
private function findReferences(array $settings): array
69+
{
70+
foreach ($settings as $key => $value) {
71+
if (is_array($value)) {
72+
$settings[$key] = $this->findReferences($value);
73+
} elseif ('_service' === substr((string) $key, -8) || str_starts_with((string) $value, '@') || 'service' === $key) {
74+
$settings[$key] = new Reference(ltrim($value, '@'));
75+
}
76+
}
77+
78+
return $settings;
79+
}
5880
}

src/SettingsProvider.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle;
6+
7+
interface SettingsProvider
8+
{
9+
/**
10+
* @return array<mixed>
11+
*/
12+
public function __invoke(): array;
13+
}

tests/Entity/DynamicSettings.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Entity;
6+
7+
use Doctrine\DBAL\Types\Types;
8+
use Doctrine\ORM\Mapping as ORM;
9+
10+
/**
11+
* @ORM\Entity
12+
*/
13+
#[ORM\Entity]
14+
class DynamicSettings
15+
{
16+
/**
17+
* @ORM\Id
18+
*
19+
* @ORM\Column(type="integer")
20+
*/
21+
#[ORM\Id]
22+
#[ORM\Column(type: Types::INTEGER)]
23+
private int $id;
24+
25+
/**
26+
* @ORM\Column(type="string")
27+
*/
28+
#[ORM\Column(type: Types::STRING)]
29+
private string $name;
30+
31+
public function __construct(int $id, string $name)
32+
{
33+
$this->id = $id;
34+
$this->name = $name;
35+
}
36+
37+
public function getId(): int
38+
{
39+
return $this->id;
40+
}
41+
42+
public function getName(): string
43+
{
44+
return $this->name;
45+
}
46+
}

tests/Integration/CommandsTest.php

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Meilisearch\Bundle\Tests\BaseKernelTestCase;
88
use Meilisearch\Bundle\Tests\Entity\DummyCustomGroups;
9+
use Meilisearch\Bundle\Tests\Entity\DynamicSettings;
910
use Meilisearch\Bundle\Tests\Entity\SelfNormalizable;
1011
use Meilisearch\Client;
1112
use Meilisearch\Endpoints\Indexes;
@@ -77,9 +78,9 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
7778
Importing for index Meilisearch\Bundle\Tests\Entity\Post
7879
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index (6 indexed since start)
7980
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index (6 indexed since start)
80-
Settings updated.
81-
Settings updated.
82-
Settings updated.
81+
Settings updated of "sf_phpunit__posts".
82+
Settings updated of "sf_phpunit__posts".
83+
Settings updated of "sf_phpunit__posts".
8384
Importing for index Meilisearch\Bundle\Tests\Entity\Comment
8485
Importing for index Meilisearch\Bundle\Tests\Entity\Tag
8586
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index (6 indexed since start)
@@ -89,6 +90,11 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
8990
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (6 indexed since start)
9091
Importing for index Meilisearch\Bundle\Tests\Entity\SelfNormalizable
9192
Importing for index Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
93+
Importing for index Meilisearch\Bundle\Tests\Entity\DynamicSettings
94+
Settings updated of "sf_phpunit__dynamic_settings".
95+
Settings updated of "sf_phpunit__dynamic_settings".
96+
Settings updated of "sf_phpunit__dynamic_settings".
97+
Settings updated of "sf_phpunit__dynamic_settings".
9298
Importing for index Meilisearch\Bundle\Tests\Entity\Post
9399
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index (6 indexed since start)
94100
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index (6 indexed since start)
@@ -114,6 +120,7 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
114120
Cleared sf_phpunit__pages index of Meilisearch\Bundle\Tests\Entity\Page
115121
Cleared sf_phpunit__self_normalizable index of Meilisearch\Bundle\Tests\Entity\SelfNormalizable
116122
Cleared sf_phpunit__dummy_custom_groups index of Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
123+
Cleared sf_phpunit__dynamic_settings index of Meilisearch\Bundle\Tests\Entity\DynamicSettings
117124
Done!
118125

119126
EOD, $clearOutput);
@@ -132,6 +139,7 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
132139
Deleted sf_phpunit__pages
133140
Deleted sf_phpunit__self_normalizable
134141
Deleted sf_phpunit__dummy_custom_groups
142+
Deleted sf_phpunit__dynamic_settings
135143
Done!
136144

137145
EOD, $clearOutput);
@@ -325,12 +333,20 @@ public function testSearchCreateWithoutIndices(): void
325333

326334
$this->assertSame(<<<'EOD'
327335
Creating index sf_phpunit__posts for Meilisearch\Bundle\Tests\Entity\Post
336+
Settings updated of "sf_phpunit__posts".
337+
Settings updated of "sf_phpunit__posts".
338+
Settings updated of "sf_phpunit__posts".
328339
Creating index sf_phpunit__comments for Meilisearch\Bundle\Tests\Entity\Comment
329340
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Tag
330341
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Link
331342
Creating index sf_phpunit__pages for Meilisearch\Bundle\Tests\Entity\Page
332343
Creating index sf_phpunit__self_normalizable for Meilisearch\Bundle\Tests\Entity\SelfNormalizable
333344
Creating index sf_phpunit__dummy_custom_groups for Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
345+
Creating index sf_phpunit__dynamic_settings for Meilisearch\Bundle\Tests\Entity\DynamicSettings
346+
Settings updated of "sf_phpunit__dynamic_settings".
347+
Settings updated of "sf_phpunit__dynamic_settings".
348+
Settings updated of "sf_phpunit__dynamic_settings".
349+
Settings updated of "sf_phpunit__dynamic_settings".
334350
Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Post
335351
Creating index sf_phpunit__aggregated for Meilisearch\Bundle\Tests\Entity\Tag
336352
Done!
@@ -350,6 +366,9 @@ public function testSearchCreateWithIndices(): void
350366

351367
$this->assertSame(<<<'EOD'
352368
Creating index sf_phpunit__posts for Meilisearch\Bundle\Tests\Entity\Post
369+
Settings updated of "sf_phpunit__posts".
370+
Settings updated of "sf_phpunit__posts".
371+
Settings updated of "sf_phpunit__posts".
353372
Done!
354373

355374
EOD, $createOutput);
@@ -437,4 +456,55 @@ public function testImportsDummyWithCustomGroups(): void
437456
],
438457
], $this->client->index('sf_phpunit__dummy_custom_groups')->getDocuments()->getResults());
439458
}
459+
460+
/**
461+
* @testWith ["meili:create"]
462+
* ["meili:import"]
463+
*/
464+
public function testImportWithDynamicSettings(string $command): void
465+
{
466+
for ($i = 0; $i <= 5; ++$i) {
467+
$this->entityManager->persist(new DynamicSettings($i, "Dynamic $i"));
468+
}
469+
470+
$this->entityManager->flush();
471+
472+
$importCommand = $this->application->find($command);
473+
$importCommandTester = new CommandTester($importCommand);
474+
$importCommandTester->execute(['--indices' => 'dynamic_settings']);
475+
476+
$importOutput = $importCommandTester->getDisplay();
477+
478+
if ('meili:import' === $command) {
479+
$this->assertSame(<<<'EOD'
480+
Importing for index Meilisearch\Bundle\Tests\Entity\DynamicSettings
481+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\DynamicSettings entities into sf_phpunit__dynamic_settings index (6 indexed since start)
482+
Settings updated of "sf_phpunit__dynamic_settings".
483+
Settings updated of "sf_phpunit__dynamic_settings".
484+
Settings updated of "sf_phpunit__dynamic_settings".
485+
Settings updated of "sf_phpunit__dynamic_settings".
486+
Done!
487+
488+
EOD, $importOutput);
489+
} else {
490+
$this->assertSame(<<<'EOD'
491+
Creating index sf_phpunit__dynamic_settings for Meilisearch\Bundle\Tests\Entity\DynamicSettings
492+
Settings updated of "sf_phpunit__dynamic_settings".
493+
Settings updated of "sf_phpunit__dynamic_settings".
494+
Settings updated of "sf_phpunit__dynamic_settings".
495+
Settings updated of "sf_phpunit__dynamic_settings".
496+
Done!
497+
498+
EOD, $importOutput);
499+
}
500+
501+
$settings = $this->get('search.client')->index('sf_phpunit__dynamic_settings')->getSettings();
502+
503+
$getSetting = static fn ($value) => $value instanceof \IteratorAggregate ? iterator_to_array($value) : $value;
504+
505+
self::assertSame(['publishedAt', 'title'], $getSetting($settings['filterableAttributes']));
506+
self::assertSame(['title'], $getSetting($settings['searchableAttributes']));
507+
self::assertSame(['a', 'n', 'the'], $getSetting($settings['stopWords']));
508+
self::assertSame(['fantastic' => ['great'], 'great' => ['fantastic']], $getSetting($settings['synonyms']));
509+
}
440510
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Integration\Fixtures;
6+
7+
use Meilisearch\Bundle\SettingsProvider;
8+
9+
class FilterableAttributes implements SettingsProvider
10+
{
11+
public function __invoke(): array
12+
{
13+
return ['title', 'publishedAt'];
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Integration\Fixtures;
6+
7+
use Meilisearch\Bundle\SettingsProvider;
8+
9+
class SearchableAttributes implements SettingsProvider
10+
{
11+
public function __invoke(): array
12+
{
13+
return ['title'];
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Integration\Fixtures;
6+
7+
use Meilisearch\Bundle\SettingsProvider;
8+
9+
class StopWords implements SettingsProvider
10+
{
11+
public function __invoke(): array
12+
{
13+
return ['the', 'a', 'n'];
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Integration\Fixtures;
6+
7+
use Meilisearch\Bundle\SettingsProvider;
8+
9+
class Synonyms implements SettingsProvider
10+
{
11+
public function __invoke(): array
12+
{
13+
return [
14+
'great' => ['fantastic'],
15+
'fantastic' => ['great'],
16+
];
17+
}
18+
}

tests/Integration/SettingsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function testUpdateSettings(): void
5555
$settings = $this->client->index($index)->getSettings();
5656

5757
$output = $commandTester->getDisplay();
58-
$this->assertStringContainsString('Settings updated.', $output);
58+
$this->assertStringContainsString('Settings updated of "sf_phpunit__posts".', $output);
5959
$this->assertNotEmpty($settings['stopWords']);
6060
$this->assertEquals(['a', 'an', 'the'], $settings['stopWords']);
6161

0 commit comments

Comments
 (0)