Add Meilisearch event indexing with 3 indexes: global, admin, per-account

- Create EventIndexService with indexEvent() and removeEvent()
- event_global: online events where isSecret=false (public search)
- event_admin: all events regardless of status (admin search)
- event_{accountId}: all events per organizer (account search)
- Integrate indexing in create/edit/delete event controllers
- Try/catch for Meilisearch unavailability (graceful degradation)
- Add 5 unit tests for EventIndexService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-20 17:18:45 +01:00
parent 3cd40f30c0
commit e6213ca66f
3 changed files with 216 additions and 3 deletions

View File

@@ -0,0 +1,125 @@
<?php
namespace App\Tests\Service;
use App\Entity\Event;
use App\Entity\User;
use App\Service\EventIndexService;
use App\Service\MeilisearchService;
use PHPUnit\Framework\TestCase;
class EventIndexServiceTest extends TestCase
{
private MeilisearchService $meilisearch;
private EventIndexService $service;
protected function setUp(): void
{
$this->meilisearch = $this->createMock(MeilisearchService::class);
$this->service = new EventIndexService($this->meilisearch);
}
private function createEvent(bool $online = true, bool $secret = false): Event
{
$user = $this->createMock(User::class);
$user->method('getId')->willReturn(42);
$user->method('getCompanyName')->willReturn('Asso Test');
$user->method('getFirstName')->willReturn('Test');
$user->method('getLastName')->willReturn('User');
$event = $this->createMock(Event::class);
$event->method('getId')->willReturn(1);
$event->method('getTitle')->willReturn('Brocante');
$event->method('getDescription')->willReturn('Description');
$event->method('getAddress')->willReturn('12 rue');
$event->method('getZipcode')->willReturn('75001');
$event->method('getCity')->willReturn('Paris');
$event->method('getStartAt')->willReturn(new \DateTimeImmutable('2026-07-01 10:00'));
$event->method('getEndAt')->willReturn(new \DateTimeImmutable('2026-07-01 18:00'));
$event->method('isOnline')->willReturn($online);
$event->method('isSecret')->willReturn($secret);
$event->method('getAccount')->willReturn($user);
return $event;
}
public function testIndexEventOnlineNotSecret(): void
{
$event = $this->createEvent(true, false);
$this->meilisearch->expects(self::exactly(3))
->method('createIndexIfNotExists');
$this->meilisearch->expects(self::exactly(3))
->method('addDocuments');
$this->service->indexEvent($event);
}
public function testIndexEventOfflineRemovesFromGlobal(): void
{
$event = $this->createEvent(false, false);
$this->meilisearch->expects(self::exactly(2))
->method('createIndexIfNotExists');
$this->meilisearch->expects(self::exactly(2))
->method('addDocuments');
$this->meilisearch->expects(self::once())
->method('indexExists')
->with('event_global')
->willReturn(true);
$this->meilisearch->expects(self::once())
->method('deleteDocument')
->with('event_global', 1);
$this->service->indexEvent($event);
}
public function testIndexEventSecretRemovesFromGlobal(): void
{
$event = $this->createEvent(true, true);
$this->meilisearch->expects(self::once())
->method('indexExists')
->with('event_global')
->willReturn(false);
$this->meilisearch->expects(self::never())
->method('deleteDocument');
$this->service->indexEvent($event);
}
public function testRemoveEvent(): void
{
$event = $this->createEvent();
$this->meilisearch->expects(self::exactly(3))
->method('deleteDocument');
$this->meilisearch->expects(self::once())
->method('indexExists')
->with('event_global')
->willReturn(true);
$this->service->removeEvent($event);
}
public function testRemoveEventGlobalIndexNotExists(): void
{
$event = $this->createEvent();
$this->meilisearch->expects(self::once())
->method('indexExists')
->with('event_global')
->willReturn(false);
$this->meilisearch->expects(self::exactly(2))
->method('deleteDocument');
$this->service->removeEvent($event);
}
}