Skip to content

Commit a832398

Browse files
Merge #335
335: Update settings once per index r=norkunas a=norkunas # Pull Request ## Related issue Fixes #255 ## What does this PR do? - When running index create/import commands, it will only update settings once per index; - Adds `meilisearch:update-settings` command; - Splits commands tests into multiple files; - Enables parallel config for cs fixer; - Adds settings name to output message: `Settings updated of "posts"` -> `Setting "filterableAttributes" updated of "posts".` ## PR checklist Please check if your PR fulfills the following requirements: - [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)? - [x] Have you read the contributing guidelines? - [x] Have you made sure that the title is accurate and descriptive of the changes? Co-authored-by: Tomas <[email protected]>
2 parents 82e2943 + f96307c commit a832398

13 files changed

+555
-272
lines changed

.php-cs-fixer.dist.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
->append([__FILE__]);
99

1010
return (new PhpCsFixer\Config())
11+
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
1112
->setRiskyAllowed(true)
1213
->setFinder($finder)
1314
->setRules([

config/services.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@
7878
<tag name="console.command" />
7979
</service>
8080

81+
<service id="Meilisearch\Bundle\Command\MeilisearchUpdateSettingsCommand">
82+
<argument type="service" id="meilisearch.service" />
83+
<argument type="service" id="meilisearch.settings_updater" />
84+
<argument type="service" id="event_dispatcher" />
85+
<tag name="console.command" />
86+
</service>
87+
8188
<service id="Meilisearch\Bundle\Services\UnixTimestampNormalizer">
8289
<tag name="serializer.normalizer" />
8390
</service>

src/Command/MeilisearchImportCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
141141
);
142142
}
143143

144-
if ($updateSettings) {
145-
$this->settingsUpdater->update($index['prefixed_name'], $responseTimeout);
146-
}
147-
148144
++$page;
149145
} while (count($entities) >= $batchSize);
150146

151147
$manager->clear();
148+
149+
if ($updateSettings) {
150+
$this->settingsUpdater->update($index['prefixed_name'], $responseTimeout);
151+
}
152152
}
153153

154154
$output->writeln('<info>Done!</info>');
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Command;
6+
7+
use Meilisearch\Bundle\Collection;
8+
use Meilisearch\Bundle\EventListener\ConsoleOutputSubscriber;
9+
use Meilisearch\Bundle\Model\Aggregator;
10+
use Meilisearch\Bundle\SearchService;
11+
use Meilisearch\Bundle\Services\SettingsUpdater;
12+
use Symfony\Component\Console\Input\InputInterface;
13+
use Symfony\Component\Console\Input\InputOption;
14+
use Symfony\Component\Console\Output\OutputInterface;
15+
use Symfony\Component\Console\Style\SymfonyStyle;
16+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17+
18+
final class MeilisearchUpdateSettingsCommand extends IndexCommand
19+
{
20+
private SettingsUpdater $settingsUpdater;
21+
private EventDispatcherInterface $eventDispatcher;
22+
23+
public function __construct(SearchService $searchService, SettingsUpdater $settingsUpdater, EventDispatcherInterface $eventDispatcher)
24+
{
25+
parent::__construct($searchService);
26+
27+
$this->settingsUpdater = $settingsUpdater;
28+
$this->eventDispatcher = $eventDispatcher;
29+
}
30+
31+
public static function getDefaultName(): string
32+
{
33+
return 'meilisearch:update-settings';
34+
}
35+
36+
public static function getDefaultDescription(): string
37+
{
38+
return 'Push settings to meilisearch';
39+
}
40+
41+
protected function configure(): void
42+
{
43+
$this
44+
->setDescription(self::getDefaultDescription())
45+
->addOption('indices', 'i', InputOption::VALUE_OPTIONAL, 'Comma-separated list of index names')
46+
->addOption(
47+
'response-timeout',
48+
't',
49+
InputOption::VALUE_REQUIRED,
50+
'Timeout (in ms) to get response from the search engine',
51+
self::DEFAULT_RESPONSE_TIMEOUT
52+
)
53+
;
54+
}
55+
56+
protected function execute(InputInterface $input, OutputInterface $output): int
57+
{
58+
$this->eventDispatcher->addSubscriber(new ConsoleOutputSubscriber(new SymfonyStyle($input, $output)));
59+
60+
$indexes = $this->getEntitiesFromArgs($input, $output);
61+
$entitiesToIndex = $this->entitiesToIndex($indexes);
62+
$responseTimeout = ((int) $input->getOption('response-timeout')) ?: self::DEFAULT_RESPONSE_TIMEOUT;
63+
64+
/** @var array $index */
65+
foreach ($entitiesToIndex as $index) {
66+
$entityClassName = $index['class'];
67+
68+
if (!$this->searchService->isSearchable($entityClassName)) {
69+
continue;
70+
}
71+
72+
$this->settingsUpdater->update($index['prefixed_name'], $responseTimeout);
73+
}
74+
75+
$output->writeln('<info>Done!</info>');
76+
77+
return 0;
78+
}
79+
80+
private function entitiesToIndex($indexes): array
81+
{
82+
foreach ($indexes as $key => $index) {
83+
$entityClassName = $index['class'];
84+
85+
if (!is_subclass_of($entityClassName, Aggregator::class)) {
86+
continue;
87+
}
88+
89+
$indexes->forget($key);
90+
91+
$indexes = new Collection(array_merge(
92+
$indexes->all(),
93+
array_map(
94+
static fn ($entity) => ['name' => $index['name'], 'prefixed_name' => $index['prefixed_name'], 'class' => $entity],
95+
$entityClassName::getEntities()
96+
)
97+
));
98+
}
99+
100+
return array_unique($indexes->all(), SORT_REGULAR);
101+
}
102+
}

src/Event/SettingsUpdatedEvent.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@ final class SettingsUpdatedEvent extends Event
1818
*/
1919
private string $index;
2020

21+
/**
22+
* @var non-empty-string
23+
*/
24+
private string $setting;
25+
2126
/**
2227
* @param class-string $class
2328
* @param non-empty-string $index
29+
* @param non-empty-string $setting
2430
*/
25-
public function __construct(string $class, string $index)
31+
public function __construct(string $class, string $index, string $setting)
2632
{
2733
$this->index = $index;
2834
$this->class = $class;
35+
$this->setting = $setting;
2936
}
3037

3138
/**
@@ -43,4 +50,12 @@ public function getIndex(): string
4350
{
4451
return $this->index;
4552
}
53+
54+
/**
55+
* @return non-empty-string
56+
*/
57+
public function getSetting(): string
58+
{
59+
return $this->setting;
60+
}
4661
}

src/EventListener/ConsoleOutputSubscriber.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function __construct(OutputStyle $io)
1919

2020
public function afterSettingsUpdate(SettingsUpdatedEvent $event): void
2121
{
22-
$this->io->writeln('<info>Settings updated of "'.$event->getIndex().'".</info>');
22+
$this->io->writeln('<info>Setting "'.$event->getSetting().'" updated of "'.$event->getIndex().'".</info>');
2323
}
2424

2525
public static function getSubscribedEvents(): array

src/Services/SettingsUpdater.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function update(string $indice, ?int $responseTimeout = null): void
7373
throw new TaskException($task['error']);
7474
}
7575

76-
$this->eventDispatcher->dispatch(new SettingsUpdatedEvent($index['class'], $indexName));
76+
$this->eventDispatcher->dispatch(new SettingsUpdatedEvent($index['class'], $indexName, $variable));
7777
}
7878
}
7979
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Tests\Integration\Command;
6+
7+
use Meilisearch\Bundle\Tests\BaseKernelTestCase;
8+
use Symfony\Bundle\FrameworkBundle\Console\Application;
9+
use Symfony\Component\Console\Tester\CommandTester;
10+
11+
final class MeilisearchClearCommandTest extends BaseKernelTestCase
12+
{
13+
protected Application $application;
14+
15+
protected function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
$this->application = new Application(self::createKernel());
20+
}
21+
22+
public function testClear(): void
23+
{
24+
$command = $this->application->find('meilisearch:clear');
25+
$commandTester = new CommandTester($command);
26+
$commandTester->execute([]);
27+
28+
$this->assertSame(<<<'EOD'
29+
Cleared sf_phpunit__posts index of Meilisearch\Bundle\Tests\Entity\Post
30+
Cleared sf_phpunit__comments index of Meilisearch\Bundle\Tests\Entity\Comment
31+
Cleared sf_phpunit__aggregated index of Meilisearch\Bundle\Tests\Entity\ContentAggregator
32+
Cleared sf_phpunit__tags index of Meilisearch\Bundle\Tests\Entity\Tag
33+
Cleared sf_phpunit__tags index of Meilisearch\Bundle\Tests\Entity\Link
34+
Cleared sf_phpunit__discriminator_map index of Meilisearch\Bundle\Tests\Entity\ContentItem
35+
Cleared sf_phpunit__pages index of Meilisearch\Bundle\Tests\Entity\Page
36+
Cleared sf_phpunit__self_normalizable index of Meilisearch\Bundle\Tests\Entity\SelfNormalizable
37+
Cleared sf_phpunit__dummy_custom_groups index of Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
38+
Cleared sf_phpunit__dynamic_settings index of Meilisearch\Bundle\Tests\Entity\DynamicSettings
39+
Done!
40+
41+
EOD, $commandTester->getDisplay());
42+
}
43+
44+
public function testClearWithIndice(): void
45+
{
46+
$command = $this->application->find('meilisearch:clear');
47+
$commandTester = new CommandTester($command);
48+
$commandTester->execute(['--indices' => 'posts']);
49+
50+
$this->assertSame(<<<'EOD'
51+
Cleared sf_phpunit__posts index of Meilisearch\Bundle\Tests\Entity\Post
52+
Done!
53+
54+
EOD, $commandTester->getDisplay());
55+
}
56+
57+
public function testClearUnknownIndex(): void
58+
{
59+
$command = $this->application->find('meilisearch:clear');
60+
$commandTester = new CommandTester($command);
61+
62+
$commandTester->execute([
63+
'--indices' => 'test',
64+
]);
65+
66+
$this->assertStringContainsString('Cannot clear index. Not found.', $commandTester->getDisplay());
67+
}
68+
69+
public function testAlias(): void
70+
{
71+
$command = $this->application->find('meilisearch:clear');
72+
73+
self::assertSame(['meili:clear'], $command->getAliases());
74+
}
75+
}

0 commit comments

Comments
 (0)