createInSeasonWindowQueryBuilder()->getQuery()->getDQL(); // both bounds on dateFrom: a placement running past the last day of the season still // belongs to that season, so dateTo must not be part of the test $this->assertStringContainsString('season_assignment.dateFrom >= :windowStart', $dql); $this->assertStringContainsString('season_assignment.dateFrom <= :windowEnd', $dql); $this->assertStringNotContainsString('dateTo', $dql); } /** * The period is the assignment's own, so there is no second row left to join - and none that * could be soft-deleted underneath a live placement. */ public function testTheSeasonWindowQueryNeedsNoJoin(): void { $dql = $this->createInSeasonWindowQueryBuilder()->getQuery()->getDQL(); $this->assertStringContainsString('season_assignment.deletedAt IS NULL', $dql); $this->assertStringNotContainsString('destination', $dql); } public function testTheSeasonWindowQueryOnlyExcludesARowWhenEditingOne(): void { $this->assertStringNotContainsString( 'season_assignment.id <> :excludeId', $this->createInSeasonWindowQueryBuilder()->getQuery()->getDQL() ); $this->assertStringContainsString( 'season_assignment.id <> :excludeId', $this->createInSeasonWindowQueryBuilder(42)->getQuery()->getDQL() ); } /** * Upcoming means "not ended yet", like the dispositions it is listed with - a running season * is still shown - and a deleted placement is not. */ public function testTheUpcomingQueryKeepsRunningAssignmentsAndDropsDeletedOnes(): void { /** @var EntityManagerInterface $entityManager */ $entityManager = static::getContainer()->get(EntityManagerInterface::class); /** @var SeasonAssignmentRepository $repository */ $repository = $entityManager->getRepository(SeasonAssignment::class); $dql = $repository->createUpcomingByTeamerQueryBuilder(new Teamer())->getQuery()->getDQL(); $this->assertStringContainsString('season_assignment.dateTo >= :today', $dql); $this->assertStringContainsString('season_assignment.deletedAt IS NULL', $dql); $this->assertStringNotContainsString('season_assignment.dateFrom >=', $dql); } private function createInSeasonWindowQueryBuilder(?int $excludeId = null): \Doctrine\ORM\QueryBuilder { /** @var EntityManagerInterface $entityManager */ $entityManager = static::getContainer()->get(EntityManagerInterface::class); /** @var SeasonAssignmentRepository $repository */ $repository = $entityManager->getRepository(SeasonAssignment::class); return $repository->createInSeasonWindowQueryBuilder( new Teamer(), new \DateTimeImmutable('2026-11-01'), new \DateTimeImmutable('2027-04-01'), $excludeId ); } }