fix(demo): invalidate paginated caches after seeding
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled

Invalidate tenant read-model caches after generating demo data so seeded users, classes and assignments appear immediately in the UI.
This commit is contained in:
2026-03-10 22:58:06 +01:00
parent ee62beea8c
commit 0f3e57c6e6
2 changed files with 74 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ namespace App\Administration\Infrastructure\Service;
use App\Administration\Application\Port\OfficialCalendarProvider; use App\Administration\Application\Port\OfficialCalendarProvider;
use App\Administration\Application\Port\PasswordHasher; use App\Administration\Application\Port\PasswordHasher;
use App\Administration\Application\Service\Cache\PaginatedQueryCache;
use App\Administration\Domain\Model\AcademicYear\DefaultPeriods; use App\Administration\Domain\Model\AcademicYear\DefaultPeriods;
use App\Administration\Domain\Model\AcademicYear\PeriodType; use App\Administration\Domain\Model\AcademicYear\PeriodType;
use App\Administration\Domain\Model\ClassAssignment\ClassAssignment; use App\Administration\Domain\Model\ClassAssignment\ClassAssignment;
@@ -69,6 +70,7 @@ final readonly class DemoDataGenerator
private \App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository $schoolCalendarRepository, private \App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository $schoolCalendarRepository,
private GradingConfigurationRepository $gradingConfigurationRepository, private GradingConfigurationRepository $gradingConfigurationRepository,
private PasswordHasher $passwordHasher, private PasswordHasher $passwordHasher,
private PaginatedQueryCache $paginatedQueryCache,
private Clock $clock, private Clock $clock,
private TenantContext $tenantContext, private TenantContext $tenantContext,
private CurrentAcademicYearResolver $currentAcademicYearResolver, private CurrentAcademicYearResolver $currentAcademicYearResolver,
@@ -114,6 +116,7 @@ final readonly class DemoDataGenerator
$this->seedTeacherAssignments($tenantId, $academicYearId, $users, $classes, $subjects, $now, $result); $this->seedTeacherAssignments($tenantId, $academicYearId, $users, $classes, $subjects, $now, $result);
$this->seedStudentGuardianLinks($tenantId, $users, $now, $result); $this->seedStudentGuardianLinks($tenantId, $users, $now, $result);
$this->seedScheduleSlots($tenantId, $classes, $subjects, $users, $academicYearStartYear, $now, $result); $this->seedScheduleSlots($tenantId, $classes, $subjects, $users, $academicYearStartYear, $now, $result);
$this->invalidateReadModelCaches((string) $tenantId);
return $result; return $result;
} finally { } finally {
@@ -667,6 +670,20 @@ final readonly class DemoDataGenerator
return $startYear; return $startYear;
} }
private function invalidateReadModelCaches(string $tenantId): void
{
foreach ([
'users',
'classes',
'subjects',
'assignments',
'parent_invitations',
'students_image_rights',
] as $entityType) {
$this->paginatedQueryCache->invalidate($entityType, $tenantId);
}
}
private function emailFor(string $emailSlug, string $subdomain): string private function emailFor(string $emailSlug, string $subdomain): string
{ {
return sprintf('%s.%s@classeo.test', strtolower($emailSlug), strtolower($subdomain)); return sprintf('%s.%s@classeo.test', strtolower($emailSlug), strtolower($subdomain));

View File

@@ -4,8 +4,10 @@ declare(strict_types=1);
namespace App\Tests\Unit\Administration\Infrastructure\Service; namespace App\Tests\Unit\Administration\Infrastructure\Service;
use App\Administration\Application\Dto\PaginatedResult;
use App\Administration\Application\Port\OfficialCalendarProvider; use App\Administration\Application\Port\OfficialCalendarProvider;
use App\Administration\Application\Port\PasswordHasher; use App\Administration\Application\Port\PasswordHasher;
use App\Administration\Application\Service\Cache\PaginatedQueryCache;
use App\Administration\Domain\Model\AcademicYear\PeriodType; use App\Administration\Domain\Model\AcademicYear\PeriodType;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry; use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId; use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
@@ -34,6 +36,8 @@ use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException; use RuntimeException;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
final class DemoDataGeneratorTest extends TestCase final class DemoDataGeneratorTest extends TestCase
{ {
@@ -50,6 +54,7 @@ final class DemoDataGeneratorTest extends TestCase
private InMemoryPeriodConfigurationRepository $periodConfigurationRepository; private InMemoryPeriodConfigurationRepository $periodConfigurationRepository;
private InMemorySchoolCalendarRepository $schoolCalendarRepository; private InMemorySchoolCalendarRepository $schoolCalendarRepository;
private GradingConfigurationRepository $gradingConfigurationRepository; private GradingConfigurationRepository $gradingConfigurationRepository;
private PaginatedQueryCache $paginatedQueryCache;
private DemoDataGenerator $generator; private DemoDataGenerator $generator;
private TenantConfig $tenantConfig; private TenantConfig $tenantConfig;
@@ -65,6 +70,7 @@ final class DemoDataGeneratorTest extends TestCase
$this->periodConfigurationRepository = new InMemoryPeriodConfigurationRepository(); $this->periodConfigurationRepository = new InMemoryPeriodConfigurationRepository();
$this->schoolCalendarRepository = new InMemorySchoolCalendarRepository(); $this->schoolCalendarRepository = new InMemorySchoolCalendarRepository();
$this->gradingConfigurationRepository = new InMemoryGradingConfigurationRepository(); $this->gradingConfigurationRepository = new InMemoryGradingConfigurationRepository();
$this->paginatedQueryCache = new PaginatedQueryCache(new TagAwareAdapter(new ArrayAdapter()));
$clock = new class implements Clock { $clock = new class implements Clock {
public function now(): DateTimeImmutable public function now(): DateTimeImmutable
@@ -136,6 +142,7 @@ final class DemoDataGeneratorTest extends TestCase
schoolCalendarRepository: $this->schoolCalendarRepository, schoolCalendarRepository: $this->schoolCalendarRepository,
gradingConfigurationRepository: $this->gradingConfigurationRepository, gradingConfigurationRepository: $this->gradingConfigurationRepository,
passwordHasher: $passwordHasher, passwordHasher: $passwordHasher,
paginatedQueryCache: $this->paginatedQueryCache,
clock: $clock, clock: $clock,
tenantContext: $tenantContext, tenantContext: $tenantContext,
currentAcademicYearResolver: $currentAcademicYearResolver, currentAcademicYearResolver: $currentAcademicYearResolver,
@@ -255,6 +262,56 @@ final class DemoDataGeneratorTest extends TestCase
self::assertCount(30, $result->accounts); self::assertCount(30, $result->accounts);
} }
#[Test]
public function itInvalidatesPaginatedReadModelCacheAfterGeneration(): void
{
$loadCount = 0;
$this->paginatedQueryCache->getOrLoad(
'users',
self::TENANT_ID,
['page' => 1, 'limit' => 30, 'role' => null, 'statut' => null, 'search' => null],
static function () use (&$loadCount): PaginatedResult {
++$loadCount;
return new PaginatedResult(
items: [],
total: 0,
page: 1,
limit: 30,
);
},
);
self::assertSame(1, $loadCount);
$this->generator->generate(
tenantConfig: $this->tenantConfig,
password: 'DemoPassword123!',
schoolName: 'Établissement Démo',
zone: SchoolZone::B,
periodType: PeriodType::TRIMESTER,
);
$this->paginatedQueryCache->getOrLoad(
'users',
self::TENANT_ID,
['page' => 1, 'limit' => 30, 'role' => null, 'statut' => null, 'search' => null],
static function () use (&$loadCount): PaginatedResult {
++$loadCount;
return new PaginatedResult(
items: [],
total: 30,
page: 1,
limit: 30,
);
},
);
self::assertSame(2, $loadCount);
}
private function resolveCurrentAcademicYearId(): \App\Administration\Domain\Model\SchoolClass\AcademicYearId private function resolveCurrentAcademicYearId(): \App\Administration\Domain\Model\SchoolClass\AcademicYearId
{ {
$tenantContext = new TenantContext(); $tenantContext = new TenantContext();