chore: initial import for test contour

This commit is contained in:
sova-bootstrap
2026-05-27 19:36:32 +03:00
commit 166cdb148e
282 changed files with 84872 additions and 0 deletions
@@ -0,0 +1,208 @@
<?php
namespace App\Service\ScheduleCache;
use App\Entity\Schedule;
use App\Repository\ScheduleRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
class ScheduleCacheService
{
private const CACHE_TTL_MINUTES = 5;
public function __construct(
private ScheduleRepository $scheduleRepository,
private EntityManagerInterface $entityManager,
private LoggerInterface $logger
) {
$this->logger = $logger->withName('infoclinica-cache');
}
public function getCachedSchedule(string $queryString, bool $isOnlineMode): ?array
{
try {
$cacheTime = new \DateTime(sprintf('-%d minutes', self::CACHE_TTL_MINUTES));
$recentSchedules = $this->scheduleRepository->findByQueryModeAndTime(
$queryString,
$isOnlineMode,
$cacheTime
);
if (empty($recentSchedules)) {
return null;
}
return $this->reconstructFromDatabase($recentSchedules, $isOnlineMode);
} catch (\Exception $e) {
$this->logger->error('Error reading from cache', [
'error' => $e->getMessage(),
'query' => $queryString,
'onlineMode' => $isOnlineMode
]);
return null;
}
}
public function saveSchedule(array $scheduleData, string $queryString, bool $isOnlineMode): int
{
try {
// Удаляем старые записи для этого запроса и типа расписания
$this->scheduleRepository->removeByQueryStringAndMode($queryString, $isOnlineMode);
$savedCount = 0;
$now = new \DateTime();
foreach ($scheduleData['schedule'] ?? [] as $department => $dates) {
foreach ($dates as $dateString => $daySchedule) {
$savedCount += $this->saveDaySchedule(
$department,
$dateString,
$daySchedule,
$queryString,
$isOnlineMode,
$now
);
}
}
$this->entityManager->flush();
$this->logger->info('Successfully saved schedule to cache', [
'query' => $queryString,
'onlineMode' => $isOnlineMode,
'saved_records' => $savedCount
]);
return $savedCount;
} catch (\Exception $e) {
$this->logger->error('Error saving to cache', [
'error' => $e->getMessage(),
'query' => $queryString,
'onlineMode' => $isOnlineMode
]);
throw $e;
}
}
private function saveDaySchedule(
string $department,
string $dateString,
array $daySchedule,
string $queryString,
bool $isOnlineMode,
\DateTime $createdAt
): int {
$count = 0;
foreach ($daySchedule['intervals'] ?? [] as $interval) {
$schedule = new Schedule();
$workDate = \DateTime::createFromFormat('Ymd', $dateString);
if ($workDate === false) {
$workDate = new \DateTime();
}
// Базовые поля
$schedule
->setDcode((string)($daySchedule['dcode'] ?? ''))
->setDepartment((string)$department)
->setFilial((int)($daySchedule['filial'] ?? 0))
->setSchedident((string)($daySchedule['schedident'] ?? ''))
->setWorkdate($workDate)
->setRnum((string)($daySchedule['rnum'] ?? ''))
->setTime((string)($interval['time'] ?? ''))
->setIsFree((bool)($daySchedule['isFree'] ?? false))
->setOnlineMode($isOnlineMode)
->setIntervalIsFree((bool)($interval['isFree'] ?? false))
->setQueryString($queryString)
->setCreatedAt($createdAt);
// Поля только для офлайн расписания
if (!$isOnlineMode) {
$schedule
->setRfloor($daySchedule['rfloor'] ?? null)
->setRbuilding($daySchedule['rbuilding'] ?? null);
}
// Поле priceInfo только для онлайн расписания
if ($isOnlineMode && isset($daySchedule['priceInfo'])) {
$schedule->setPriceInfo($daySchedule['priceInfo']);
}
$this->entityManager->persist($schedule);
$count++;
}
return $count;
}
private function reconstructFromDatabase(array $schedules, bool $isOnlineMode): array
{
$result = [
'schedule' => [],
'nearestDate' => []
];
foreach ($schedules as $schedule) {
$department = $schedule->getDepartment();
$workDate = $schedule->getWorkdate()->format('Ymd');
if (!isset($result['schedule'][$department][$workDate])) {
$dayData = [
'schedident' => $schedule->getSchedident(),
'rnum' => $schedule->getRnum(),
'dcode' => $schedule->getDcode(),
'filial' => $schedule->getFilial(),
'intervals' => [],
'depnum' => $department,
'isFree' => $schedule->isFree()
];
// Добавляем поля в зависимости от типа расписания
if (!$isOnlineMode) {
$dayData['rfloor'] = $schedule->getRfloor();
$dayData['rbuilding'] = $schedule->getRbuilding();
}
if ($isOnlineMode && $schedule->getPriceInfo()) {
$dayData['priceInfo'] = $schedule->getPriceInfo();
}
$result['schedule'][$department][$workDate] = $dayData;
// Сохраняем nearestDate
if (!isset($result['nearestDate'][$department])) {
$result['nearestDate'][$department] = (int)$workDate;
}
}
$result['schedule'][$department][$workDate]['intervals'][] = [
'time' => $schedule->getTime(),
'isFree' => $schedule->isIntervalIsFree()
];
}
return $result;
}
public function clearOldCache(\DateTimeInterface $olderThan): int
{
try {
return $this->scheduleRepository->removeOlderThan($olderThan);
} catch (\Exception $e) {
$this->logger->error('Error clearing old cache', [
'error' => $e->getMessage()
]);
throw $e;
}
}
public function getCacheStats(): array
{
return $this->scheduleRepository->getCacheStatistics();
}
}