cmsDataProvider = $this->createStub(CmsDataProvider::class); $this->accommodationRepository = $this->createStub(AccommodationRepository::class); $this->calendarHotelRepository = $this->createStub(CalendarHotelRepository::class); $this->entityManager = $this->createStub(EntityManagerInterface::class); } public function testRefreshAddsRenamesAndRemovesStoredHotels(): void { $this->entityManager = $this->createMock(EntityManagerInterface::class); $renamed = (new CalendarHotel())->setCode('DKI')->setName('Schwendi'); $dropped = (new CalendarHotel())->setCode('ASB')->setName('Sportclub Bader'); $this->calendarHotelRepository->method('findAllIndexedByCode')->willReturn(['DKI' => $renamed, 'ASB' => $dropped]); $this->cmsDataProvider->method('fetchCalendarHotels')->willReturn([ new CmsCalendarHotel('DKI', 'Sportclub Schwendi'), new CmsCalendarHotel('DWW', 'Sportclub Weissfluh'), ]); $this->entityManager->expects(self::once())->method('persist') ->with(self::callback(static fn (CalendarHotel $hotel) => 'DWW' === $hotel->getCode() && 'Sportclub Weissfluh' === $hotel->getName())); $this->entityManager->expects(self::once())->method('remove')->with($dropped); $this->entityManager->expects(self::once())->method('flush'); self::assertTrue($this->directory()->refresh()); self::assertSame('Sportclub Schwendi', $renamed->getName()); } public function testRefreshKeepsTheStoredListWhenTypo3IsUnavailable(): void { $this->assertKeepsStoredList(null); } public function testRefreshKeepsTheStoredListWhenTypo3ReturnsNoHotels(): void { $this->assertKeepsStoredList([]); } public function testRefreshIgnoresCodesTheApiCouldNotBeAskedFor(): void { $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->calendarHotelRepository->method('findAllIndexedByCode')->willReturn([]); $this->cmsDataProvider->method('fetchCalendarHotels')->willReturn([ new CmsCalendarHotel('DKI', 'Sportclub Schwendi'), new CmsCalendarHotel('ABCDEFGHIJKLMNOPQ', 'Too long'), new CmsCalendarHotel('A B', 'Space'), ]); $this->entityManager->expects(self::once())->method('persist') ->with(self::callback(static fn (CalendarHotel $hotel) => 'DKI' === $hotel->getCode())); $this->directory()->refresh(); } public function testAllIsTheUnionOfAccommodationsAndTypo3Hotels(): void { $this->accommodationRepository->method('findAllWithCalendarCode')->willReturn([ (new Accommodation())->setCalendarCode('DGS'), (new Accommodation())->setCalendarCode('SERASCSO'), ]); $this->calendarHotelRepository->method('findAllIndexedByCode')->willReturn([ 'ASCGR' => (new CalendarHotel())->setCode('ASCGR')->setName('Christiler'), 'DGS' => (new CalendarHotel())->setCode('DGS')->setName('Spinabad'), ]); $hotels = $this->directory()->all(); self::assertSame(['ASCGR', 'DGS', 'SERASCSO'], array_keys($hotels)); self::assertSame([ContingentHotelSource::Typo3], $hotels['ASCGR']->sources()); self::assertSame([ContingentHotelSource::Accommodation, ContingentHotelSource::Typo3], $hotels['DGS']->sources()); self::assertSame([ContingentHotelSource::Accommodation], $hotels['SERASCSO']->sources()); } public function testFindKnowsATypo3OnlyHotel(): void { $this->accommodationRepository->method('findOneByCalendarCode')->willReturn(null); $this->calendarHotelRepository->method('findOneBy')->willReturn((new CalendarHotel())->setCode('DKI')->setName('Schwendi')); self::assertSame('DKI', $this->directory()->find('DKI')?->code); } public function testFindReturnsNullForAnUnknownCode(): void { $this->accommodationRepository->method('findOneByCalendarCode')->willReturn(null); $this->calendarHotelRepository->method('findOneBy')->willReturn(null); self::assertNull($this->directory()->find('NOPE')); } /** * @param list|null $fetched */ private function assertKeepsStoredList(?array $fetched): void { $this->entityManager = $this->createMock(EntityManagerInterface::class); $logger = $this->createMock(LoggerInterface::class); $this->calendarHotelRepository->method('findAllIndexedByCode')->willReturn([ 'DKI' => (new CalendarHotel())->setCode('DKI')->setName('Sportclub Schwendi'), ]); $this->cmsDataProvider->method('fetchCalendarHotels')->willReturn($fetched); $this->entityManager->expects(self::never())->method('remove'); $this->entityManager->expects(self::never())->method('flush'); $logger->expects(self::once())->method('warning'); self::assertFalse($this->directory($logger)->refresh()); } private function directory(?LoggerInterface $logger = null): ContingentHotelDirectory { return new ContingentHotelDirectory( $this->cmsDataProvider, $this->accommodationRepository, $this->calendarHotelRepository, $this->entityManager, $logger ?? $this->createStub(LoggerInterface::class), ); } }