namespace App\Controller; use App\Entity\CalendarEvent; use App\Entity\Candidate; use App\Entity\Person; use App\Entity\Student; use App\Enum\CalendarEvent\Type; use App\Enum\Candidate\RegistrationType; use App\Enum\Student\Status; use App\Exception\Student\StudentToSubscriberStatusException; use App\Form\PersonType; use App\Form\StudentType; use App\Library\PyTg\PyTgUtils; use App\Library\TdLib\TdLibObject\Model\Message\Message; use App\Library\Utils\ApiHandler; use App\Library\Utils\Other\Other; use App\Service\CalendarEvent\CalendarEventService; use App\Service\Candidate\CandidateService; use App\Service\City\CityService; use App\Service\FileService; use App\Service\Image\ImageService; use App\Service\Job\JobService; use App\Service\Person\PersonService; use App\Service\Queue\ErrorLogCreateQueueService; use App\Service\RouteService; use App\Service\ServiceRetriever; use App\Service\Student\StudentService; use App\Service\StudentLevel\StudentLevelService; use App\Service\User\UserService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\Validator\ValidatorInterface; class StudentController extends BaseAbstractController { /** * @var PersonService */ private $personService; /** * @var CalendarEventService */ private $calendarEventService; /** * @var CandidateService */ private $candidateService; /** * @var UserService */ private $userService; /** * @var JobService */ private $jobService; /** * @var CityService */ private $cityService; /** * @var StudentLevelService */ private $studentLevelService; private ApiHandler\DefaultApiHandler $defaultApiHandler; public function __construct(Security $security, RequestStack $requestStack, ValidatorInterface $validator, RouteService $routeService, RouterInterface $router, SessionInterface $session, EntityManagerInterface $em, FileService $fileService, ServiceRetriever $serviceRetriever, PersonService $personService, CalendarEventService $calendarEventService, CandidateService $candidateService, UserService $userService, JobService $jobService, CityService $cityService, StudentLevelService $studentLevelService, ApiHandler\DefaultApiHandler $defaultApiHandler, ImageService $imageService = null, ErrorLogCreateQueueService $errorLogCreateQueueService = null) { parent::__construct($security, $requestStack, $validator, $routeService, $router, $session, $em, $fileService, $serviceRetriever, $imageService, $errorLogCreateQueueService); $this->personService = $personService; $this->calendarEventService = $calendarEventService; $this->candidateService = $candidateService; $this->userService = $userService; $this->jobService = $jobService; $this->cityService = $cityService; $this->studentLevelService = $studentLevelService; $this->defaultApiHandler = $defaultApiHandler; } public function campaignsSubscription(Request $request, PersonService $personService): JsonResponse { $personId = $request->get('subscriberId'); $status = $request->get('status'); /** @var Person|null $person */ $person = $personService->getBaseService()->get($personId); if (!$person) { return new JsonResponse([], 400); } if ($status) { if (!in_array($status, ["subscribed", "unsubscribed"])) { return new JsonResponse([], 400); } $unsubscribed = $status == "unsubscribed"; $person->setIsUnsubscribed($unsubscribed); $isSubscriberAnyStatus = in_array($person->getStudentStatus(), Status::getSubscriberStatuses()); if ($isSubscriberAnyStatus) { //пока только для подписчиков $isNew = !$person->getStudent(); if (!$person->getStudent() || !$unsubscribed) { $this->changeLearnerData($person, $person->getStudent(), Status::STATUS_SUBSCRIBER_LISTENER, $isNew, null, true); } elseif ($unsubscribed) { $this->changeLearnerData($person, $person->getStudent(), Status::STATUS_SUBSCRIBER_NON_ACTIVE, $isNew, null, true); } } $person->setCanSendTelegramCampaigns(!$unsubscribed); $this->em->flush(); return new JsonResponse([], 200); } else { return new JsonResponse([], $person->isIsUnsubscribed() ? 404 : 200); } } public function list(Request $request, CandidateService $candidateService, StudentService $studentService, CalendarEventService $calendarEventService): Response { $students = $studentService->getBaseService()->getAll(); $persons = array_map(function (Student $student) { return $student->getPerson(); }, $students); $candidatesByStudentAndCalendarEvent = $candidateService->getCandidatesGroupedByPersonsAndCalendarEvents(); $calendarEvents = $calendarEventService->getAll(); $calendarEvents = Other::getIdIndexedEntityArray($calendarEvents); $earnLevelCandidates = $candidateService ->getPersonsLastCandidateWithEarnLevelCalendarEvent($persons); return $this->render('admin/student/students.html.twig', [ 'students' => $students, "candidatesByStudentAndCalendarEvent" => $candidatesByStudentAndCalendarEvent, "calendarEvents" => $calendarEvents, "earnLevelCandidates" => $earnLevelCandidates, ]); } public function learners(Request $request, CandidateService $candidateService, StudentService $studentService, CalendarEventService $calendarEventService, PersonService $personService): Response { $items = $personService->getLearners(); $candidatesByPersonsAndCalendarEvent = $candidateService->getCandidatesGroupedByPersonsAndCalendarEvents(); $calendarEvents = $calendarEventService->getAll(); $calendarEvents = Other::getIdIndexedEntityArray($calendarEvents); $earnLevelCandidates = $candidateService ->getPersonsLastCandidateWithEarnLevelCalendarEvent($items); $itemsByStatusCount = []; foreach (Status::getAsArray() as $status) { $itemsByStatusCount[$status] = [ "status" => $status, "statusText" => Status::getText($status), "count" => 0, ]; } $itemsByStatusCount["subscriber_virtual_status"] = [ "status" => "subscriber_virtual_status", "statusText" => "Подписчик", "count" => 0, ]; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : "subscriber_virtual_status"; $itemsByStatusCount[$status]["count"]++; } $itemsByStudentLevelCount = []; for ($i = 0; $i <= 6; $i++) { $itemsByStudentLevelCount[$i] = [ "level" => $i, "count" => 0, ]; } foreach ($items as $item) { if ($item->isIsStudent() && Status::isActiveStatus($item->getStudent()->getStatus())) { $level = $item->getStudent()->getLevel(); //redo if ($level === null) { continue; } if ($level !== null) { if ($level < 0) { dd($item); } $itemsByStudentLevelCount[$level]["count"]++; } } } //sort by key, Status::canSendCampaignStatuses(), and rest statuses $sorted = []; foreach (Status::getCanSendCampaignStatuses() as $status) { if (isset($itemsByStatusCount[$status])) { $sorted[$status] = $itemsByStatusCount[$status]; } } foreach ($itemsByStatusCount as $status => $itemByStatusCount) { if (!isset($sorted[$status])) { $sorted[$status] = $itemByStatusCount; } } $itemsByStatusCount = $sorted; $itemsWithCanSendCampaignStatusCount = 0; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : null; if ($status && Status::isStudentStatus($status)) { $itemsWithCanSendCampaignStatusCount++; } } $allLeavedStudentsCount = 0; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : null; if ($status && Status::isLeavedStatus($status)) { $allLeavedStudentsCount++; } } $allStudentsCount = 0; foreach ($items as $item) { if ($item->isIsStudent()) { $allStudentsCount++; } } return $this->render('admin/student/learners.html.twig', [ 'items' => $items, "candidatesByPersonsAndCalendarEvent" => $candidatesByPersonsAndCalendarEvent, "calendarEvents" => $calendarEvents, "earnLevelCandidates" => $earnLevelCandidates, "itemsByStatusCount" => $itemsByStatusCount, "itemsWithCanSendCampaignStatusCount" => $itemsWithCanSendCampaignStatusCount, "allStudentsCount" => $allStudentsCount, "allLeavedStudentsCount" => $allLeavedStudentsCount, "itemsByStudentLevelCount" => $itemsByStudentLevelCount, ]); } // public function edit(Request $request, StudentService $studentService): Response // { // $id = $request->get('id'); // /** // * @var Student $item // */ // $item = $id ? $studentService->getBaseService()->get($id) : null; // $person = $item ? $item->getPerson() : null; // // $isNew = false; // if (!$item) { // $person = new Person(); // $item = (new Student()); // $isNew = true; // } // // $form = $this->createForm(StudentType::class, $item); // $form->handleRequest($request); // // $personForm = $this->createForm(PersonType::class, $person); // $personForm->handleRequest($request); // // if ($form->isSubmitted() && $form->isValid()) { // $this->em->persist($person); // $this->em->flush(); // // $item->setPerson($person); // $this->em->persist($item); // $this->em->flush(); // // return $this->redirectToRoute('moderator_students'); // } // // return $this->render('admin/student/student_edit.html.twig', [ // 'form' => $form->createView(), // 'personForm' => $personForm->createView(), // 'item' => $item, // ]); // } private function changeLearnerData(Person $person, $student = null, $virtualStatus, bool &$isNew = null, Request $request = null, bool $isFormDataValid = null) { if (!$student) { $student = (new Student()); $isNew = true; } $oldPhone = $person->getPhone(); $student->setStatus($virtualStatus); if ($isFormDataValid) { //todo redo if ($request) { $newJobName = $request->get("newJobName"); $jobId = (int)($request->get("person")['job'] ?? null); $addNewJob = $jobId === -100; if ($addNewJob) { if (!$newJobName) { throw new \Exception('Название новой деятельности не может быть пустым.'); } $job = $this->jobService->createOrGetDefault(["name" => $newJobName]); } else { $job = $this->jobService->getBaseService()->get($jobId); } $person->setJob($job); $newCityName = $request->get("newCityName"); $cityId = (int)($request->get("person")['city'] ?? null); $addNewCity = $cityId === -100; if ($addNewCity) { if (!$newCityName) { throw new \Exception('Название нового города не может быть пустым.'); } $city = $this->cityService->createOrGetDefault(["name" => $newCityName]); } else { $city = $this->cityService->getBaseService()->get($cityId); } $person->setCity($city); } if ($this->personService->hasSameDefault($person)) { throw new \Exception('Учащийся с такими данными уже существует.'); } $this->em->persist($person); $this->em->flush(); if ($oldPhone && $oldPhone != $person->getPhone()) { $person->setTelegramUserId(null); } if ($person->isIsStudent()) { $student->setPerson($person); $this->em->persist($student); $this->em->flush(); } } } public function learnerEdit(Request $request, PersonService $personService, StudentLevelService $studentLevelService, JobService $jobService, CityService $cityService): Response { $id = $request->get('id'); /** * @var Person $person */ $person = $id ? $personService->getBaseService()->get($id) : null; /** * @var Student $student */ $student = $person ? $person->getStudent() : null; $isNew = false; if (!$person) { $person = new Person(); $isNew = true; } if (!$student) { $student = (new Student()); $isNew = true; } $form = $this->createForm(StudentType::class, $student); $form->handleRequest($request); $personForm = $this->createForm(PersonType::class, $person); $personForm->handleRequest($request); try { if ($form->isSubmitted()) { $virtualStatus = $request->get("person")['studentStatus'] ?? null; $isFormDataValid = $form->isValid() && $personForm->isValid(); $this->changeLearnerData($person, $student, $virtualStatus, $isNew, $request, $isFormDataValid); if ($isFormDataValid) { return $this->redirectToRoute('moderator_learners'); } } } catch (\Throwable $e) { $this->addExceptionFlash($e); } // if (!$form->isSubmitted()) { // $pyTgUtils->setTechAdminAccount(); // } return $this->render('admin/student/learner_edit.html.twig', [ 'form' => $form->createView(), 'personForm' => $personForm->createView(), 'item' => $student, 'person' => $person, ]); } public function delete(Request $request, StudentService $studentService, PersonService $personService): RedirectResponse { $id = $request->get('id'); if (!$id) { $this->addFlash('errors', 'Не указан идентификатор учащегося.'); return $this->redirectToRoute('moderator_learners'); } /** @var Person|null $item */ $item = $personService->getBaseService()->get($id); if (!$item) { $this->addFlash('errors', 'Учащийся не найден.'); return $this->redirectToRoute('moderator_learners'); } try { $item->setStatus(Status::STATUS_DELETED); if ($item->getStudent()) { $item->getStudent()->setStatus(Status::STATUS_DELETED); } $this->em->flush(); $studentName = $item->getName(); $this->addFlash('success', 'Учащийся ' . $studentName . ' помечен как удалённый.'); } catch (\Throwable $e) { $this->addExceptionFlash($e, null, 'Ошибка при удалении учащегося. '); } return $this->redirectToRoute('moderator_learners'); } public function registration(Request $request, PersonService $personService, CalendarEventService $calendarEventService, CandidateService $candidateService): Response { $calendarEventId = $request->query->get('calendarEventId'); $selectedCalendarEvent = null; $persons = []; // Get all calendar events without review requirement $allCalendarEvents = $calendarEventService->getCalendarEventsForMakeCandidates( Type::getForRegisterWithoutReviewTypes() ); $calendarEvents = array_filter($allCalendarEvents, function($event) { return !$event->isIsCandidateReviewRequired(); }); if ($calendarEventId) { /** @var CalendarEvent $selectedCalendarEvent */ $selectedCalendarEvent = $calendarEventService->getBaseService()->get($calendarEventId); if ($selectedCalendarEvent) { // Get existing candidates for this event $existingCandidates = $candidateService->getDefault([ 'calendarEvent' => $selectedCalendarEvent, 'status' => [ \App\Enum\Candidate\Status::STATUS_NEW, \App\Enum\Candidate\Status::STATUS_APPROVED, \App\Enum\Candidate\Status::STATUS_DRAFT, ] ]); $candidatesByPerson = []; foreach ($existingCandidates as $candidate) { if ($candidate->getPerson()) { $candidatesByPerson[$candidate->getPerson()->getId()] = $candidate; } } // Get students with matching level $fromLevel = $selectedCalendarEvent->getFromLevel(); $allPersons = $personService->getLearners(); $persons = array_filter($allPersons, function(Person $person) use ($fromLevel, $selectedCalendarEvent, $candidatesByPerson) { if (isset($candidatesByPerson[$person->getId()])) { return true; } if (!Status::isCanSendCampaignStatus($person->getStudentStatus())) { return false; } //redo $isRequiredStatusSubscriber = $selectedCalendarEvent->getRequireStudentStatus() == Status::STATUS_SUBSCRIBER_LISTENER; $isSubscriberAnyStatus = in_array($person->getStudentStatus(), Status::getSubscriberActiveStatuses()); if ($selectedCalendarEvent->getRequireStudentStatus() && !($isRequiredStatusSubscriber && $isSubscriberAnyStatus ? true : $person->getStudentStatus() == $selectedCalendarEvent->getRequireStudentStatus())) { return false; } if ($selectedCalendarEvent->getFromLevel() === null) { return true; } if ($person->isIsStudent() && $person->getStudent()) { $level = $person->getStudent()->getLevel(); return $level !== null && $level >= $fromLevel && ($selectedCalendarEvent->getToLevel() === null || $level <= $selectedCalendarEvent->getToLevel()) && $person->isCalendarEventStatusAllowed($selectedCalendarEvent); } return false; }); } } // Prepare dropdown data for calendar events $routeParamDropdownsData = [ 'calendarEvent' => array_map(function($event) { return [ 'listItemId' => $event->getId(), 'text' => $event->getText(['quotes' => true]) ]; }, array_values($calendarEvents)) ]; return $this->render('admin/student/registration.html.twig', [ 'persons' => $persons, 'calendarEvents' => $calendarEvents, 'selectedCalendarEvent' => $selectedCalendarEvent, 'routeParamDropdownsData' => $routeParamDropdownsData, 'candidatesByPerson' => $candidatesByPerson ?? [] ]); } public function toggleRegistration(Request $request, CandidateService $candidateService, PersonService $personService, CalendarEventService $calendarEventService, UserService $userService): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $candidateService, $personService, $calendarEventService, $userService ) { $personId = $content['person_id'] ?? null; $calendarEventId = $content['calendar_event_id'] ?? null; /** @var Person $person */ $person = $this->personService->getBaseService()->get($personId); /** @var CalendarEvent $calendarEvent */ $calendarEvent = $this->calendarEventService->getBaseService()->get($calendarEventId); return $this->doToggleRegistration($person, $calendarEvent, $responseCode); }, true, ['person_id', 'calendar_event_id']); } public function toggleRegistrationByStudent(Request $request, CandidateService $candidateService, PersonService $personService, CalendarEventService $calendarEventService, UserService $userService): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $candidateService, $personService, $calendarEventService, $userService, $request ) { $personId = $request->get("registrantId"); $calendarEventId = $request->get("eventId"); $status = $request->get("status"); $create = $status == "registered"; /** @var Person $person */ $person = $this->personService->getBaseService()->get($personId); /** @var CalendarEvent $calendarEvent */ $calendarEvent = $this->calendarEventService->getBaseService()->get($calendarEventId); if ($status) { return $this->doToggleRegistration($person, $calendarEvent, $responseCode, $create, RegistrationType::REGISTRATION_TYPE_LEARNER); } else { /** @var Candidate|null $existingCandidate */ $existingCandidate = null; try { $existingCandidate = $this->getExistingCandidate($person, $calendarEvent, $existsWithStatusIsNotNew); if ($existingCandidate) { $responseCode = 200; return []; } else { $responseCode = 404; return []; } } catch (\Throwable $exception) { if ($existsWithStatusIsNotNew) { $responseCode = 200; return []; } $responseCode = 400; return ['error' => $exception->getMessage()]; } } }, false, []); } private function doToggleRegistration(?Person $person, ?CalendarEvent $calendarEvent, &$responseCode, bool $create = null, $registrationType = null): array { if (!$person || !$calendarEvent) { $responseCode = 404; return ['error' => 'Person or CalendarEvent not found']; } if ($calendarEvent->isIsCandidateReviewRequired()) { throw new \Exception("Candidate review is required"); } // Check if candidate already exists /** @var Candidate|null $existingCandidate */ $existingCandidate = null; try { $existingCandidate = $this->getExistingCandidate($person, $calendarEvent); } catch (\Throwable $exception) { $responseCode = 400; return ['error' => $exception->getMessage()]; } if ($existingCandidate && ($create === null || !$create)) { // Delete candidate $this->candidateService->removeCandidate($existingCandidate); $responseCode = 200; return ['action' => 'deleted', 'candidateId' => null]; } elseif ($create === null || $create) { // Create new candidate $params = [ "person" => $person, "calendarEvent" => $calendarEvent, "status" => \App\Enum\Candidate\Status::STATUS_APPROVED, ]; if ($registrationType) { $params['registrationType'] = $registrationType; } /** @var Candidate $candidate */ $candidate = $this->candidateService->createOrGetDefault($params); if (!$candidate->getAuthor() && $this->getUser()) { $candidate->setAuthor($this->getUser()); } if (!$candidate->getCurator() && $this->userService->getStarCurator()) { $candidate->setCurator($this->userService->getStarCurator()); } $this->em->flush(); $responseCode = 200; return ['action' => 'created', 'candidateId' => $candidate->getId()]; } else { $responseCode = 200; return []; } } private function getExistingCandidate($person, $calendarEvent, bool &$existsWithStatusIsNotNew = null): ?Candidate { $existingCandidates = $this->candidateService->getDefault([ 'person' => $person, 'calendarEvent' => $calendarEvent, ]); $existingCandidates = array_filter($existingCandidates, function (Candidate $candidate) { return $candidate->getStatus() != \App\Enum\Candidate\Status::STATUS_DELETED; }); /** @var Candidate $existingCandidate */ $existingCandidate = count($existingCandidates) > 0 ? current($existingCandidates) : null; $existsWithStatusIsNotNew = $existingCandidate && $existingCandidate->getStatus() !== \App\Enum\Candidate\Status::STATUS_NEW; if ($existsWithStatusIsNotNew && $calendarEvent->isIsCandidateReviewRequired()) { throw new \Exception('Статус кандидата: ' . $existingCandidate->getStatusText()); } return $existingCandidate; } public function loadTelegramHistory(Request $request, PersonService $personService, PyTgUtils $pyTgUtils): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $personService, $pyTgUtils ) { $personId = $content['person_id'] ?? null; if (!$personId) { $responseCode = 400; return ['error' => 'Missing person_id']; } /** @var Person $person */ $person = $personService->getBaseService()->get($personId); if (!$person) { $responseCode = 404; return ['error' => 'Person not found']; } $telegramUserId = $person->getTelegramUserId(); if (!$telegramUserId) { $responseCode = 400; return ['error' => 'Telegram user ID not set']; } try { // Устанавливаем технический аккаунт администратора $pyTgUtils->setTechAdminAccount(); // Создаем приватный чат $chat = $pyTgUtils->pyTg->createPrivateChat($telegramUserId); $chatId = $chat['id']; // Получаем последние 5 сообщений $messages = $pyTgUtils->pyTg->getChatHistory($chatId, 10); $messages = array_map(function (Message $message) { return $message->getData(); }, $messages); // Обрабатываем сообщения $processedMessages = []; $debugInfo = []; foreach ($messages as $messageIndex => $message) { $processedMessage = [ 'id' => $message['id'] ?? null, 'date' => $message['date'] ?? null, 'is_outgoing' => $message['is_outgoing'] ?? false, 'text' => '', 'images' => [], 'debug' => [] // Отладочная информация (будет удалена перед отправкой) ]; $messageDebug = [ 'message_index' => $messageIndex, 'message_id' => $message['id'] ?? null, 'content_type' => $message['content']['@type'] ?? 'unknown', ]; // Получаем текст сообщения if (isset($message['content'])) { if (isset($message['content']['text']) && isset($message['content']['text']['text'])) { $processedMessage['text'] = $message['content']['text']['text']; } elseif (isset($message['content']['caption']) && isset($message['content']['caption']['text'])) { $processedMessage['text'] = $message['content']['caption']['text']; } // Обрабатываем фото if (isset($message['content']['@type']) && $message['content']['@type'] === 'messagePhoto') { $messageDebug['has_photo'] = true; if (isset($message['content']['photo']['sizes'])) { $sizes = $message['content']['photo']['sizes']; $messageDebug['sizes_count'] = count($sizes); // Берем изображение среднего размера (для оптимизации) // Если размеров меньше 3, берем последнее $photoIndex = count($sizes) > 2 ? count($sizes) - 2 : count($sizes) - 1; $selectedPhoto = $sizes[$photoIndex]; $messageDebug['selected_photo_index'] = $photoIndex; $messageDebug['selected_photo_type'] = $selectedPhoto['type'] ?? 'unknown'; $imageLoaded = false; $imagePath = null; // Проверяем, есть ли локальный путь к файлу if (isset($selectedPhoto['photo']['local']['path']) && file_exists($selectedPhoto['photo']['local']['path'])) { $imagePath = $selectedPhoto['photo']['local']['path']; $messageDebug['source'] = 'local_path'; $messageDebug['path'] = $imagePath; $imageLoaded = true; } elseif (isset($selectedPhoto['photo']['id'])) { // Если файл не загружен локально, загружаем через API $messageDebug['source'] = 'api_download'; $messageDebug['file_id'] = $selectedPhoto['photo']['id']; try { // downloadFile возвращает base64 данные напрямую $base64Data = $pyTgUtils->pyTg->downloadFile($selectedPhoto['photo']['id']); $messageDebug['download_response'] = [ 'is_string' => is_string($base64Data), 'data_length' => is_string($base64Data) ? strlen($base64Data) : 0, ]; if (is_string($base64Data) && !empty($base64Data)) { // Данные уже в base64, используем их напрямую $processedMessage['images'][] = "data:image/jpeg;base64," . $base64Data; $messageDebug['base64_length'] = strlen($base64Data); $messageDebug['success'] = true; $imageLoaded = true; // Помечаем, что изображение загружено } else { $messageDebug['error'] = 'Invalid base64 data received'; } } catch (\Exception $e) { $messageDebug['error'] = 'Download failed: ' . $e->getMessage(); } } // Конвертируем изображение в base64 (только для локальных файлов) if ($imageLoaded && $imagePath) { try { $fileSize = filesize($imagePath); $messageDebug['file_size'] = $fileSize; // Ограничение размера файла (5 МБ) if ($fileSize > 5 * 1024 * 1024) { $messageDebug['error'] = 'File too large: ' . $fileSize . ' bytes'; } else { $imageData = file_get_contents($imagePath); if ($imageData !== false) { $base64 = base64_encode($imageData); $mimeType = mime_content_type($imagePath); $processedMessage['images'][] = "data:$mimeType;base64,$base64"; $messageDebug['mime_type'] = $mimeType; $messageDebug['base64_length'] = strlen($base64); $messageDebug['success'] = true; } else { $messageDebug['error'] = 'Failed to read file contents'; } } } catch (\Exception $e) { $messageDebug['error'] = 'Base64 conversion failed: ' . $e->getMessage(); } } } else { $messageDebug['error'] = 'No photo sizes found'; } } } $debugInfo[] = $messageDebug; // Удаляем debug перед добавлением в результат unset($processedMessage['debug']); $processedMessages[] = $processedMessage; } // Сортируем сообщения по дате (от старых к новым) usort($processedMessages, function($a, $b) { return ($a['date'] ?? 0) - ($b['date'] ?? 0); }); $responseCode = 200; return [ 'success' => true, 'messages' => $processedMessages, 'person_name' => $person->getName(), 'debug' => $debugInfo, // Отладочная информация 'total_messages' => count($processedMessages), 'messages_with_images' => count(array_filter($processedMessages, function($m) { return !empty($m['images']); })) ]; } catch (\Exception $e) { $responseCode = 500; return ['error' => 'Failed to load Telegram history: ' . $e->getMessage()]; } }, true, ['person_id']); } } namespace App\Controller; use App\Entity\CalendarEvent; use App\Entity\Candidate; use App\Entity\Person; use App\Entity\Student; use App\Enum\CalendarEvent\Type; use App\Enum\Candidate\RegistrationType; use App\Enum\Student\Status; use App\Exception\Student\StudentToSubscriberStatusException; use App\Form\PersonType; use App\Form\StudentType; use App\Library\PyTg\PyTgUtils; use App\Library\TdLib\TdLibObject\Model\Message\Message; use App\Library\Utils\ApiHandler; use App\Library\Utils\Other\Other; use App\Service\CalendarEvent\CalendarEventService; use App\Service\Candidate\CandidateService; use App\Service\City\CityService; use App\Service\FileService; use App\Service\Image\ImageService; use App\Service\Job\JobService; use App\Service\Person\PersonService; use App\Service\Queue\ErrorLogCreateQueueService; use App\Service\RouteService; use App\Service\ServiceRetriever; use App\Service\Student\StudentService; use App\Service\StudentLevel\StudentLevelService; use App\Service\User\UserService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\Validator\ValidatorInterface; class StudentController extends BaseAbstractController { /** * @var PersonService */ private $personService; /** * @var CalendarEventService */ private $calendarEventService; /** * @var CandidateService */ private $candidateService; /** * @var UserService */ private $userService; /** * @var JobService */ private $jobService; /** * @var CityService */ private $cityService; /** * @var StudentLevelService */ private $studentLevelService; private ApiHandler\DefaultApiHandler $defaultApiHandler; public function __construct(Security $security, RequestStack $requestStack, ValidatorInterface $validator, RouteService $routeService, RouterInterface $router, SessionInterface $session, EntityManagerInterface $em, FileService $fileService, ServiceRetriever $serviceRetriever, PersonService $personService, CalendarEventService $calendarEventService, CandidateService $candidateService, UserService $userService, JobService $jobService, CityService $cityService, StudentLevelService $studentLevelService, ApiHandler\DefaultApiHandler $defaultApiHandler, ImageService $imageService = null, ErrorLogCreateQueueService $errorLogCreateQueueService = null) { parent::__construct($security, $requestStack, $validator, $routeService, $router, $session, $em, $fileService, $serviceRetriever, $imageService, $errorLogCreateQueueService); $this->personService = $personService; $this->calendarEventService = $calendarEventService; $this->candidateService = $candidateService; $this->userService = $userService; $this->jobService = $jobService; $this->cityService = $cityService; $this->studentLevelService = $studentLevelService; $this->defaultApiHandler = $defaultApiHandler; } public function campaignsSubscription(Request $request, PersonService $personService): JsonResponse { $personId = $request->get('subscriberId'); $status = $request->get('status'); /** @var Person|null $person */ $person = $personService->getBaseService()->get($personId); if (!$person) { return new JsonResponse([], 400); } if ($status) { if (!in_array($status, ["subscribed", "unsubscribed"])) { return new JsonResponse([], 400); } $unsubscribed = $status == "unsubscribed"; $person->setIsUnsubscribed($unsubscribed); $isSubscriberAnyStatus = in_array($person->getStudentStatus(), Status::getSubscriberStatuses()); if ($isSubscriberAnyStatus) { //пока только для подписчиков $isNew = !$person->getStudent(); if (!$person->getStudent() || !$unsubscribed) { $this->changeLearnerData($person, $person->getStudent(), Status::STATUS_SUBSCRIBER_LISTENER, $isNew, null, true); } elseif ($unsubscribed) { $this->changeLearnerData($person, $person->getStudent(), Status::STATUS_SUBSCRIBER_NON_ACTIVE, $isNew, null, true); } } $person->setCanSendTelegramCampaigns(!$unsubscribed); $this->em->flush(); return new JsonResponse([], 200); } else { return new JsonResponse([], $person->isIsUnsubscribed() ? 404 : 200); } } public function list(Request $request, CandidateService $candidateService, StudentService $studentService, CalendarEventService $calendarEventService): Response { $students = $studentService->getBaseService()->getAll(); $persons = array_map(function (Student $student) { return $student->getPerson(); }, $students); $candidatesByStudentAndCalendarEvent = $candidateService->getCandidatesGroupedByPersonsAndCalendarEvents(); $calendarEvents = $calendarEventService->getAll(); $calendarEvents = Other::getIdIndexedEntityArray($calendarEvents); $earnLevelCandidates = $candidateService ->getPersonsLastCandidateWithEarnLevelCalendarEvent($persons); return $this->render('admin/student/students.html.twig', [ 'students' => $students, "candidatesByStudentAndCalendarEvent" => $candidatesByStudentAndCalendarEvent, "calendarEvents" => $calendarEvents, "earnLevelCandidates" => $earnLevelCandidates, ]); } public function learners(Request $request, CandidateService $candidateService, StudentService $studentService, CalendarEventService $calendarEventService, PersonService $personService): Response { $items = $personService->getLearners(); $candidatesByPersonsAndCalendarEvent = $candidateService->getCandidatesGroupedByPersonsAndCalendarEvents(); $calendarEvents = $calendarEventService->getAll(); $calendarEvents = Other::getIdIndexedEntityArray($calendarEvents); $earnLevelCandidates = $candidateService ->getPersonsLastCandidateWithEarnLevelCalendarEvent($items); $itemsByStatusCount = []; foreach (Status::getAsArray() as $status) { $itemsByStatusCount[$status] = [ "status" => $status, "statusText" => Status::getText($status), "count" => 0, ]; } $itemsByStatusCount["subscriber_virtual_status"] = [ "status" => "subscriber_virtual_status", "statusText" => "Подписчик", "count" => 0, ]; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : "subscriber_virtual_status"; $itemsByStatusCount[$status]["count"]++; } $itemsByStudentLevelCount = []; for ($i = 0; $i <= 6; $i++) { $itemsByStudentLevelCount[$i] = [ "level" => $i, "count" => 0, ]; } foreach ($items as $item) { if ($item->isIsStudent() && Status::isActiveStatus($item->getStudent()->getStatus())) { $level = $item->getStudent()->getLevel(); //redo if ($level === null) { continue; } if ($level !== null) { if ($level < 0) { dd($item); } $itemsByStudentLevelCount[$level]["count"]++; } } } //sort by key, Status::canSendCampaignStatuses(), and rest statuses $sorted = []; foreach (Status::getCanSendCampaignStatuses() as $status) { if (isset($itemsByStatusCount[$status])) { $sorted[$status] = $itemsByStatusCount[$status]; } } foreach ($itemsByStatusCount as $status => $itemByStatusCount) { if (!isset($sorted[$status])) { $sorted[$status] = $itemByStatusCount; } } $itemsByStatusCount = $sorted; $itemsWithCanSendCampaignStatusCount = 0; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : null; if ($status && Status::isStudentStatus($status)) { $itemsWithCanSendCampaignStatusCount++; } } $allLeavedStudentsCount = 0; foreach ($items as $item) { $status = $item->isIsStudent() ? $item->getStudent()->getStatus() : null; if ($status && Status::isLeavedStatus($status)) { $allLeavedStudentsCount++; } } $allStudentsCount = 0; foreach ($items as $item) { if ($item->isIsStudent()) { $allStudentsCount++; } } return $this->render('admin/student/learners.html.twig', [ 'items' => $items, "candidatesByPersonsAndCalendarEvent" => $candidatesByPersonsAndCalendarEvent, "calendarEvents" => $calendarEvents, "earnLevelCandidates" => $earnLevelCandidates, "itemsByStatusCount" => $itemsByStatusCount, "itemsWithCanSendCampaignStatusCount" => $itemsWithCanSendCampaignStatusCount, "allStudentsCount" => $allStudentsCount, "allLeavedStudentsCount" => $allLeavedStudentsCount, "itemsByStudentLevelCount" => $itemsByStudentLevelCount, ]); } // public function edit(Request $request, StudentService $studentService): Response // { // $id = $request->get('id'); // /** // * @var Student $item // */ // $item = $id ? $studentService->getBaseService()->get($id) : null; // $person = $item ? $item->getPerson() : null; // // $isNew = false; // if (!$item) { // $person = new Person(); // $item = (new Student()); // $isNew = true; // } // // $form = $this->createForm(StudentType::class, $item); // $form->handleRequest($request); // // $personForm = $this->createForm(PersonType::class, $person); // $personForm->handleRequest($request); // // if ($form->isSubmitted() && $form->isValid()) { // $this->em->persist($person); // $this->em->flush(); // // $item->setPerson($person); // $this->em->persist($item); // $this->em->flush(); // // return $this->redirectToRoute('moderator_students'); // } // // return $this->render('admin/student/student_edit.html.twig', [ // 'form' => $form->createView(), // 'personForm' => $personForm->createView(), // 'item' => $item, // ]); // } private function changeLearnerData(Person $person, $student = null, $virtualStatus, bool &$isNew = null, Request $request = null, bool $isFormDataValid = null) { if (!$student) { $student = (new Student()); $isNew = true; } $oldPhone = $person->getPhone(); $student->setStatus($virtualStatus); if ($isFormDataValid) { //todo redo if ($request) { $newJobName = $request->get("newJobName"); $jobId = (int)($request->get("person")['job'] ?? null); $addNewJob = $jobId === -100; if ($addNewJob) { if (!$newJobName) { throw new \Exception('Название новой деятельности не может быть пустым.'); } $job = $this->jobService->createOrGetDefault(["name" => $newJobName]); } else { $job = $this->jobService->getBaseService()->get($jobId); } $person->setJob($job); $newCityName = $request->get("newCityName"); $cityId = (int)($request->get("person")['city'] ?? null); $addNewCity = $cityId === -100; if ($addNewCity) { if (!$newCityName) { throw new \Exception('Название нового города не может быть пустым.'); } $city = $this->cityService->createOrGetDefault(["name" => $newCityName]); } else { $city = $this->cityService->getBaseService()->get($cityId); } $person->setCity($city); } if ($this->personService->hasSameDefault($person)) { throw new \Exception('Учащийся с такими данными уже существует.'); } $this->em->persist($person); $this->em->flush(); if ($oldPhone && $oldPhone != $person->getPhone()) { $person->setTelegramUserId(null); } if ($person->isIsStudent()) { $student->setPerson($person); $this->em->persist($student); $this->em->flush(); } } } public function learnerEdit(Request $request, PersonService $personService, StudentLevelService $studentLevelService, JobService $jobService, CityService $cityService): Response { $id = $request->get('id'); /** * @var Person $person */ $person = $id ? $personService->getBaseService()->get($id) : null; /** * @var Student $student */ $student = $person ? $person->getStudent() : null; $isNew = false; if (!$person) { $person = new Person(); $isNew = true; } if (!$student) { $student = (new Student()); $isNew = true; } $form = $this->createForm(StudentType::class, $student); $form->handleRequest($request); $personForm = $this->createForm(PersonType::class, $person); $personForm->handleRequest($request); try { if ($form->isSubmitted()) { $virtualStatus = $request->get("person")['studentStatus'] ?? null; $isFormDataValid = $form->isValid() && $personForm->isValid(); $this->changeLearnerData($person, $student, $virtualStatus, $isNew, $request, $isFormDataValid); if ($isFormDataValid) { return $this->redirectToRoute('moderator_learners'); } } } catch (\Throwable $e) { $this->addExceptionFlash($e); } // if (!$form->isSubmitted()) { // $pyTgUtils->setTechAdminAccount(); // } return $this->render('admin/student/learner_edit.html.twig', [ 'form' => $form->createView(), 'personForm' => $personForm->createView(), 'item' => $student, 'person' => $person, ]); } public function delete(Request $request, StudentService $studentService, PersonService $personService): RedirectResponse { $id = $request->get('id'); if (!$id) { $this->addFlash('errors', 'Не указан идентификатор учащегося.'); return $this->redirectToRoute('moderator_learners'); } /** @var Person|null $item */ $item = $personService->getBaseService()->get($id); if (!$item) { $this->addFlash('errors', 'Учащийся не найден.'); return $this->redirectToRoute('moderator_learners'); } try { $item->setStatus(Status::STATUS_DELETED); if ($item->getStudent()) { $item->getStudent()->setStatus(Status::STATUS_DELETED); } $this->em->flush(); $studentName = $item->getName(); $this->addFlash('success', 'Учащийся ' . $studentName . ' помечен как удалённый.'); } catch (\Throwable $e) { $this->addExceptionFlash($e, null, 'Ошибка при удалении учащегося. '); } return $this->redirectToRoute('moderator_learners'); } public function registration(Request $request, PersonService $personService, CalendarEventService $calendarEventService, CandidateService $candidateService): Response { $calendarEventId = $request->query->get('calendarEventId'); $selectedCalendarEvent = null; $persons = []; // Get all calendar events without review requirement $allCalendarEvents = $calendarEventService->getCalendarEventsForMakeCandidates( Type::getForRegisterWithoutReviewTypes() ); $calendarEvents = array_filter($allCalendarEvents, function($event) { return !$event->isIsCandidateReviewRequired(); }); if ($calendarEventId) { /** @var CalendarEvent $selectedCalendarEvent */ $selectedCalendarEvent = $calendarEventService->getBaseService()->get($calendarEventId); if ($selectedCalendarEvent) { // Get existing candidates for this event $existingCandidates = $candidateService->getDefault([ 'calendarEvent' => $selectedCalendarEvent, 'status' => [ \App\Enum\Candidate\Status::STATUS_NEW, \App\Enum\Candidate\Status::STATUS_APPROVED, \App\Enum\Candidate\Status::STATUS_DRAFT, ] ]); $candidatesByPerson = []; foreach ($existingCandidates as $candidate) { if ($candidate->getPerson()) { $candidatesByPerson[$candidate->getPerson()->getId()] = $candidate; } } // Get students with matching level $fromLevel = $selectedCalendarEvent->getFromLevel(); $allPersons = $personService->getLearners(); $persons = array_filter($allPersons, function(Person $person) use ($fromLevel, $selectedCalendarEvent, $candidatesByPerson) { if (isset($candidatesByPerson[$person->getId()])) { return true; } if (!Status::isCanSendCampaignStatus($person->getStudentStatus())) { return false; } //redo $isRequiredStatusSubscriber = $selectedCalendarEvent->getRequireStudentStatus() == Status::STATUS_SUBSCRIBER_LISTENER; $isSubscriberAnyStatus = in_array($person->getStudentStatus(), Status::getSubscriberActiveStatuses()); if ($selectedCalendarEvent->getRequireStudentStatus() && !($isRequiredStatusSubscriber && $isSubscriberAnyStatus ? true : $person->getStudentStatus() == $selectedCalendarEvent->getRequireStudentStatus())) { return false; } if ($selectedCalendarEvent->getFromLevel() === null) { return true; } if ($person->isIsStudent() && $person->getStudent()) { $level = $person->getStudent()->getLevel(); return $level !== null && $level >= $fromLevel && ($selectedCalendarEvent->getToLevel() === null || $level <= $selectedCalendarEvent->getToLevel()) && $person->isCalendarEventStatusAllowed($selectedCalendarEvent); } return false; }); } } // Prepare dropdown data for calendar events $routeParamDropdownsData = [ 'calendarEvent' => array_map(function($event) { return [ 'listItemId' => $event->getId(), 'text' => $event->getText(['quotes' => true]) ]; }, array_values($calendarEvents)) ]; return $this->render('admin/student/registration.html.twig', [ 'persons' => $persons, 'calendarEvents' => $calendarEvents, 'selectedCalendarEvent' => $selectedCalendarEvent, 'routeParamDropdownsData' => $routeParamDropdownsData, 'candidatesByPerson' => $candidatesByPerson ?? [] ]); } public function toggleRegistration(Request $request, CandidateService $candidateService, PersonService $personService, CalendarEventService $calendarEventService, UserService $userService): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $candidateService, $personService, $calendarEventService, $userService ) { $personId = $content['person_id'] ?? null; $calendarEventId = $content['calendar_event_id'] ?? null; /** @var Person $person */ $person = $this->personService->getBaseService()->get($personId); /** @var CalendarEvent $calendarEvent */ $calendarEvent = $this->calendarEventService->getBaseService()->get($calendarEventId); return $this->doToggleRegistration($person, $calendarEvent, $responseCode); }, true, ['person_id', 'calendar_event_id']); } public function toggleRegistrationByStudent(Request $request, CandidateService $candidateService, PersonService $personService, CalendarEventService $calendarEventService, UserService $userService): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $candidateService, $personService, $calendarEventService, $userService, $request ) { $personId = $request->get("registrantId"); $calendarEventId = $request->get("eventId"); $status = $request->get("status"); $create = $status == "registered"; /** @var Person $person */ $person = $this->personService->getBaseService()->get($personId); /** @var CalendarEvent $calendarEvent */ $calendarEvent = $this->calendarEventService->getBaseService()->get($calendarEventId); if ($status) { return $this->doToggleRegistration($person, $calendarEvent, $responseCode, $create, RegistrationType::REGISTRATION_TYPE_LEARNER); } else { /** @var Candidate|null $existingCandidate */ $existingCandidate = null; try { $existingCandidate = $this->getExistingCandidate($person, $calendarEvent, $existsWithStatusIsNotNew); if ($existingCandidate) { $responseCode = 200; return []; } else { $responseCode = 404; return []; } } catch (\Throwable $exception) { if ($existsWithStatusIsNotNew) { $responseCode = 200; return []; } $responseCode = 400; return ['error' => $exception->getMessage()]; } } }, false, []); } private function doToggleRegistration(?Person $person, ?CalendarEvent $calendarEvent, &$responseCode, bool $create = null, $registrationType = null): array { if (!$person || !$calendarEvent) { $responseCode = 404; return ['error' => 'Person or CalendarEvent not found']; } if ($calendarEvent->isIsCandidateReviewRequired()) { throw new \Exception("Candidate review is required"); } // Check if candidate already exists /** @var Candidate|null $existingCandidate */ $existingCandidate = null; try { $existingCandidate = $this->getExistingCandidate($person, $calendarEvent); } catch (\Throwable $exception) { $responseCode = 400; return ['error' => $exception->getMessage()]; } if ($existingCandidate && ($create === null || !$create)) { // Delete candidate $this->candidateService->removeCandidate($existingCandidate); $responseCode = 200; return ['action' => 'deleted', 'candidateId' => null]; } elseif ($create === null || $create) { // Create new candidate $params = [ "person" => $person, "calendarEvent" => $calendarEvent, "status" => \App\Enum\Candidate\Status::STATUS_APPROVED, ]; if ($registrationType) { $params['registrationType'] = $registrationType; } /** @var Candidate $candidate */ $candidate = $this->candidateService->createOrGetDefault($params); if (!$candidate->getAuthor() && $this->getUser()) { $candidate->setAuthor($this->getUser()); } if (!$candidate->getCurator() && $this->userService->getStarCurator()) { $candidate->setCurator($this->userService->getStarCurator()); } $this->em->flush(); $responseCode = 200; return ['action' => 'created', 'candidateId' => $candidate->getId()]; } else { $responseCode = 200; return []; } } private function getExistingCandidate($person, $calendarEvent, bool &$existsWithStatusIsNotNew = null): ?Candidate { $existingCandidates = $this->candidateService->getDefault([ 'person' => $person, 'calendarEvent' => $calendarEvent, ]); $existingCandidates = array_filter($existingCandidates, function (Candidate $candidate) { return $candidate->getStatus() != \App\Enum\Candidate\Status::STATUS_DELETED; }); /** @var Candidate $existingCandidate */ $existingCandidate = count($existingCandidates) > 0 ? current($existingCandidates) : null; $existsWithStatusIsNotNew = $existingCandidate && $existingCandidate->getStatus() !== \App\Enum\Candidate\Status::STATUS_NEW; if ($existsWithStatusIsNotNew && $calendarEvent->isIsCandidateReviewRequired()) { throw new \Exception('Статус кандидата: ' . $existingCandidate->getStatusText()); } return $existingCandidate; } public function loadTelegramHistory(Request $request, PersonService $personService, PyTgUtils $pyTgUtils): JsonResponse { return $this->defaultApiHandler->handleApiRequest($request, function (&$responseCode, $content) use ( $personService, $pyTgUtils ) { $personId = $content['person_id'] ?? null; if (!$personId) { $responseCode = 400; return ['error' => 'Missing person_id']; } /** @var Person $person */ $person = $personService->getBaseService()->get($personId); if (!$person) { $responseCode = 404; return ['error' => 'Person not found']; } $telegramUserId = $person->getTelegramUserId(); if (!$telegramUserId) { $responseCode = 400; return ['error' => 'Telegram user ID not set']; } try { // Устанавливаем технический аккаунт администратора $pyTgUtils->setTechAdminAccount(); // Создаем приватный чат $chat = $pyTgUtils->pyTg->createPrivateChat($telegramUserId); $chatId = $chat['id']; // Получаем последние 5 сообщений $messages = $pyTgUtils->pyTg->getChatHistory($chatId, 10); $messages = array_map(function (Message $message) { return $message->getData(); }, $messages); // Обрабатываем сообщения $processedMessages = []; $debugInfo = []; foreach ($messages as $messageIndex => $message) { $processedMessage = [ 'id' => $message['id'] ?? null, 'date' => $message['date'] ?? null, 'is_outgoing' => $message['is_outgoing'] ?? false, 'text' => '', 'images' => [], 'debug' => [] // Отладочная информация (будет удалена перед отправкой) ]; $messageDebug = [ 'message_index' => $messageIndex, 'message_id' => $message['id'] ?? null, 'content_type' => $message['content']['@type'] ?? 'unknown', ]; // Получаем текст сообщения if (isset($message['content'])) { if (isset($message['content']['text']) && isset($message['content']['text']['text'])) { $processedMessage['text'] = $message['content']['text']['text']; } elseif (isset($message['content']['caption']) && isset($message['content']['caption']['text'])) { $processedMessage['text'] = $message['content']['caption']['text']; } // Обрабатываем фото if (isset($message['content']['@type']) && $message['content']['@type'] === 'messagePhoto') { $messageDebug['has_photo'] = true; if (isset($message['content']['photo']['sizes'])) { $sizes = $message['content']['photo']['sizes']; $messageDebug['sizes_count'] = count($sizes); // Берем изображение среднего размера (для оптимизации) // Если размеров меньше 3, берем последнее $photoIndex = count($sizes) > 2 ? count($sizes) - 2 : count($sizes) - 1; $selectedPhoto = $sizes[$photoIndex]; $messageDebug['selected_photo_index'] = $photoIndex; $messageDebug['selected_photo_type'] = $selectedPhoto['type'] ?? 'unknown'; $imageLoaded = false; $imagePath = null; // Проверяем, есть ли локальный путь к файлу if (isset($selectedPhoto['photo']['local']['path']) && file_exists($selectedPhoto['photo']['local']['path'])) { $imagePath = $selectedPhoto['photo']['local']['path']; $messageDebug['source'] = 'local_path'; $messageDebug['path'] = $imagePath; $imageLoaded = true; } elseif (isset($selectedPhoto['photo']['id'])) { // Если файл не загружен локально, загружаем через API $messageDebug['source'] = 'api_download'; $messageDebug['file_id'] = $selectedPhoto['photo']['id']; try { // downloadFile возвращает base64 данные напрямую $base64Data = $pyTgUtils->pyTg->downloadFile($selectedPhoto['photo']['id']); $messageDebug['download_response'] = [ 'is_string' => is_string($base64Data), 'data_length' => is_string($base64Data) ? strlen($base64Data) : 0, ]; if (is_string($base64Data) && !empty($base64Data)) { // Данные уже в base64, используем их напрямую $processedMessage['images'][] = "data:image/jpeg;base64," . $base64Data; $messageDebug['base64_length'] = strlen($base64Data); $messageDebug['success'] = true; $imageLoaded = true; // Помечаем, что изображение загружено } else { $messageDebug['error'] = 'Invalid base64 data received'; } } catch (\Exception $e) { $messageDebug['error'] = 'Download failed: ' . $e->getMessage(); } } // Конвертируем изображение в base64 (только для локальных файлов) if ($imageLoaded && $imagePath) { try { $fileSize = filesize($imagePath); $messageDebug['file_size'] = $fileSize; // Ограничение размера файла (5 МБ) if ($fileSize > 5 * 1024 * 1024) { $messageDebug['error'] = 'File too large: ' . $fileSize . ' bytes'; } else { $imageData = file_get_contents($imagePath); if ($imageData !== false) { $base64 = base64_encode($imageData); $mimeType = mime_content_type($imagePath); $processedMessage['images'][] = "data:$mimeType;base64,$base64"; $messageDebug['mime_type'] = $mimeType; $messageDebug['base64_length'] = strlen($base64); $messageDebug['success'] = true; } else { $messageDebug['error'] = 'Failed to read file contents'; } } } catch (\Exception $e) { $messageDebug['error'] = 'Base64 conversion failed: ' . $e->getMessage(); } } } else { $messageDebug['error'] = 'No photo sizes found'; } } } $debugInfo[] = $messageDebug; // Удаляем debug перед добавлением в результат unset($processedMessage['debug']); $processedMessages[] = $processedMessage; } // Сортируем сообщения по дате (от старых к новым) usort($processedMessages, function($a, $b) { return ($a['date'] ?? 0) - ($b['date'] ?? 0); }); $responseCode = 200; return [ 'success' => true, 'messages' => $processedMessages, 'person_name' => $person->getName(), 'debug' => $debugInfo, // Отладочная информация 'total_messages' => count($processedMessages), 'messages_with_images' => count(array_filter($processedMessages, function($m) { return !empty($m['images']); })) ]; } catch (\Exception $e) { $responseCode = 500; return ['error' => 'Failed to load Telegram history: ' . $e->getMessage()]; } }, true, ['person_id']); } } Expected to find class "App\Controller\StudentController" in file "/home/sariato/www/dev.centr.sariato.ru/src/Controller/StudentController.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource in /home/sariato/www/dev.centr.sariato.ru/config/services.yaml (which is being imported from "/home/sariato/www/dev.centr.sariato.ru/src/Kernel.php"). (500 Internal Server Error)

Symfony Exception

InvalidArgumentException LoaderLoadException

HTTP 500 Internal Server Error

Expected to find class "App\Controller\StudentController" in file "/home/sariato/www/dev.centr.sariato.ru/src/Controller/StudentController.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource in /home/sariato/www/dev.centr.sariato.ru/config/services.yaml (which is being imported from "/home/sariato/www/dev.centr.sariato.ru/src/Kernel.php").

Exceptions 2

Symfony\Component\Config\Exception\ LoaderLoadException

  1.                 // prevent embedded imports from nesting multiple exceptions
  2.                 if ($e instanceof LoaderLoadException) {
  3.                     throw $e;
  4.                 }
  5.                 throw new LoaderLoadException($resource$sourceResource0$e$type);
  6.             }
  7.         }
  8.         return null;
  9.     }
  1.             if ($isSubpath) {
  2.                 return isset($ret[1]) ? $ret : ($ret[0] ?? null);
  3.             }
  4.         }
  5.         return $this->doImport($resource$type$ignoreErrors$sourceResource);
  6.     }
  7.     /**
  8.      * @internal
  9.      */
  1.         } elseif (!\is_bool($ignoreErrors)) {
  2.             throw new \TypeError(sprintf('Invalid argument $ignoreErrors provided to "%s::import()": boolean or "not_found" expected, "%s" given.', static::class, get_debug_type($ignoreErrors)));
  3.         }
  4.         try {
  5.             return parent::import(...$args);
  6.         } catch (LoaderLoadException $e) {
  7.             if (!$ignoreNotFound || !($prev $e->getPrevious()) instanceof FileLocatorFileNotFoundException) {
  8.                 throw $e;
  9.             }
  1.     }
  2.     final public function import(string $resource, ?string $type null$ignoreErrors false)
  3.     {
  4.         $this->loader->setCurrentDir(\dirname($this->path));
  5.         $this->loader->import($resource$type$ignoreErrors$this->file);
  6.     }
  7.     final public function parameters(): ParametersConfigurator
  8.     {
  9.         return new ParametersConfigurator($this->container);
  1.         $container->import($configDir.'/{packages}/*.yaml');
  2.         $container->import($configDir.'/{packages}/'.$this->environment.'/*.yaml');
  3.         if (is_file($configDir.'/services.yaml')) {
  4.             $container->import($configDir.'/services.yaml');
  5.             $container->import($configDir.'/{services}_'.$this->environment.'.yaml');
  6.         } else {
  7.             $container->import($configDir.'/{services}.php');
  8.         }
  9.     }
  1.             AbstractConfigurator::$valuePreProcessor = function ($value) {
  2.                 return $this === $value ? new Reference('kernel') : $value;
  3.             };
  4.             try {
  5.                 $configureContainer->getClosure($this)(new ContainerConfigurator($container$kernelLoader$instanceof$file$file$this->getEnvironment()), $loader$container);
  6.             } finally {
  7.                 $instanceof = [];
  8.                 $kernelLoader->registerAliasesForSinglyImplementedInterfaces();
  9.                 AbstractConfigurator::$valuePreProcessor $valuePreProcessor;
  10.             }
  1.     /**
  2.      * {@inheritdoc}
  3.      */
  4.     public function load($resource, ?string $type null)
  5.     {
  6.         return $resource($this->container$this->env);
  7.     }
  8.     /**
  9.      * {@inheritdoc}
  10.      */
  1.     {
  2.         if (false === $loader $this->resolver->resolve($resource$type)) {
  3.             throw new LoaderLoadException($resourcenull0null$type);
  4.         }
  5.         return $loader->load($resource$type);
  6.     }
  7.     /**
  8.      * {@inheritdoc}
  9.      */
  1.                 $kernelLoader->registerAliasesForSinglyImplementedInterfaces();
  2.                 AbstractConfigurator::$valuePreProcessor $valuePreProcessor;
  3.             }
  4.             $container->setAlias($kernelClass'kernel')->setPublic(true);
  5.         });
  6.     }
  7.     /**
  8.      * @internal
  9.      */
  1.         $container $this->getContainerBuilder();
  2.         $container->addObjectResource($this);
  3.         $this->prepareContainer($container);
  4.         if (null !== $cont $this->registerContainerConfiguration($this->getContainerLoader($container))) {
  5.             trigger_deprecation('symfony/http-kernel''5.3''Returning a ContainerBuilder from "%s::registerContainerConfiguration()" is deprecated.'get_debug_type($this));
  6.             $container->merge($cont);
  7.         }
  8.         $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this));
  1.             });
  2.         }
  3.         try {
  4.             $container null;
  5.             $container $this->buildContainer();
  6.             $container->compile();
  7.         } finally {
  8.             if ($collectDeprecations) {
  9.                 restore_error_handler();
  1.             $_ENV['SHELL_VERBOSITY'] = 3;
  2.             $_SERVER['SHELL_VERBOSITY'] = 3;
  3.         }
  4.         $this->initializeBundles();
  5.         $this->initializeContainer();
  6.         $container $this->container;
  7.         if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts $container->getParameter('kernel.trusted_hosts')) {
  8.             Request::setTrustedHosts($trustedHosts);
  1.      * {@inheritdoc}
  2.      */
  3.     public function handle(Request $requestint $type HttpKernelInterface::MAIN_REQUESTbool $catch true)
  4.     {
  5.         if (!$this->booted) {
  6.             $container $this->container ?? $this->preBoot();
  7.             if ($container->has('http_cache')) {
  8.                 return $container->get('http_cache')->handle($request$type$catch);
  9.             }
  10.         }
  1. }
  2. $kernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
  3. $request Request::createFromGlobals();
  4. $response $kernel->handle($request);
  5. $response->send();
  6. $kernel->terminate($request$response);
  7. //if ($_SERVER['REMOTE_ADDR'] == '5.45.80.106') {
  8. //    file_get_contents('https://tpk.uno/T/?/' . urlencode('total time: ' . (microtime(true) - $startTime)));
  9. //}

Symfony\Component\DependencyInjection\Exception\ InvalidArgumentException

Expected to find class "App\Controller\StudentController" in file "/home/sariato/www/dev.centr.sariato.ru/src/Controller/StudentController.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource.

  1.                 $classes[$class] = $e->getMessage();
  2.                 continue;
  3.             }
  4.             // check to make sure the expected class exists
  5.             if (!$r) {
  6.                 throw new InvalidArgumentException(sprintf('Expected to find class "%s" in file "%s" while importing services from resource "%s", but it was not found! Check the namespace prefix used with the resource.'$class$path$pattern));
  7.             }
  8.             if ($r->isInstantiable() || $r->isInterface()) {
  9.                 $classes[$class] = null;
  10.             }
  1.             throw new InvalidArgumentException(sprintf('Namespace is not a valid PSR-4 prefix: "%s".'$namespace));
  2.         }
  3.         $autoconfigureAttributes = new RegisterAutoconfigureAttributesPass();
  4.         $autoconfigureAttributes $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes null;
  5.         $classes $this->findClasses($namespace$resource, (array) $exclude$autoconfigureAttributes);
  6.         // prepare for deep cloning
  7.         $serializedPrototype serialize($prototype);
  8.         foreach ($classes as $class => $errorMessage) {
  9.             if (null === $errorMessage && $autoconfigureAttributes && $this->env) {
  1.             if (!\is_string($service['resource'])) {
  2.                 throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in "%s". Check your YAML syntax.'$id$file));
  3.             }
  4.             $exclude $service['exclude'] ?? null;
  5.             $namespace $service['namespace'] ?? $id;
  6.             $this->registerClasses($definition$namespace$service['resource'], $exclude);
  7.         } else {
  8.             $this->setDefinition($id$definition);
  9.         }
  10.     }
  1.         }
  2.         $this->isLoadingInstanceof false;
  3.         $defaults $this->parseDefaults($content$file);
  4.         foreach ($content['services'] as $id => $service) {
  5.             $this->parseDefinition($id$service$file$defaultsfalse$trackBindings);
  6.         }
  7.     }
  8.     /**
  9.      * @throws InvalidArgumentException
  1.         // services
  2.         $this->anonymousServicesCount 0;
  3.         $this->anonymousServicesSuffix '~'.ContainerBuilder::hash($path);
  4.         $this->setCurrentDir(\dirname($path));
  5.         try {
  6.             $this->parseDefinitions($content$path);
  7.         } finally {
  8.             $this->instanceof = [];
  9.             $this->registerAliasesForSinglyImplementedInterfaces();
  10.         }
  11.     }
  1.         // empty file
  2.         if (null === $content) {
  3.             return null;
  4.         }
  5.         $this->loadContent($content$path);
  6.         // per-env configuration
  7.         if ($this->env && isset($content['when@'.$this->env])) {
  8.             if (!\is_array($content['when@'.$this->env])) {
  9.                 throw new InvalidArgumentException(sprintf('The "when@%s" key should contain an array in "%s". Check your YAML syntax.'$this->env$path));
  1.                 }
  2.             }
  3.             self::$loading[$resource] = true;
  4.             try {
  5.                 $ret $loader->load($resource$type);
  6.             } finally {
  7.                 unset(self::$loading[$resource]);
  8.             }
  9.             return $ret;
  1.             if ($isSubpath) {
  2.                 return isset($ret[1]) ? $ret : ($ret[0] ?? null);
  3.             }
  4.         }
  5.         return $this->doImport($resource$type$ignoreErrors$sourceResource);
  6.     }
  7.     /**
  8.      * @internal
  9.      */
  1.         } elseif (!\is_bool($ignoreErrors)) {
  2.             throw new \TypeError(sprintf('Invalid argument $ignoreErrors provided to "%s::import()": boolean or "not_found" expected, "%s" given.', static::class, get_debug_type($ignoreErrors)));
  3.         }
  4.         try {
  5.             return parent::import(...$args);
  6.         } catch (LoaderLoadException $e) {
  7.             if (!$ignoreNotFound || !($prev $e->getPrevious()) instanceof FileLocatorFileNotFoundException) {
  8.                 throw $e;
  9.             }
  1.     }
  2.     final public function import(string $resource, ?string $type null$ignoreErrors false)
  3.     {
  4.         $this->loader->setCurrentDir(\dirname($this->path));
  5.         $this->loader->import($resource$type$ignoreErrors$this->file);
  6.     }
  7.     final public function parameters(): ParametersConfigurator
  8.     {
  9.         return new ParametersConfigurator($this->container);
  1.         $container->import($configDir.'/{packages}/*.yaml');
  2.         $container->import($configDir.'/{packages}/'.$this->environment.'/*.yaml');
  3.         if (is_file($configDir.'/services.yaml')) {
  4.             $container->import($configDir.'/services.yaml');
  5.             $container->import($configDir.'/{services}_'.$this->environment.'.yaml');
  6.         } else {
  7.             $container->import($configDir.'/{services}.php');
  8.         }
  9.     }
  1.             AbstractConfigurator::$valuePreProcessor = function ($value) {
  2.                 return $this === $value ? new Reference('kernel') : $value;
  3.             };
  4.             try {
  5.                 $configureContainer->getClosure($this)(new ContainerConfigurator($container$kernelLoader$instanceof$file$file$this->getEnvironment()), $loader$container);
  6.             } finally {
  7.                 $instanceof = [];
  8.                 $kernelLoader->registerAliasesForSinglyImplementedInterfaces();
  9.                 AbstractConfigurator::$valuePreProcessor $valuePreProcessor;
  10.             }
  1.     /**
  2.      * {@inheritdoc}
  3.      */
  4.     public function load($resource, ?string $type null)
  5.     {
  6.         return $resource($this->container$this->env);
  7.     }
  8.     /**
  9.      * {@inheritdoc}
  10.      */
  1.     {
  2.         if (false === $loader $this->resolver->resolve($resource$type)) {
  3.             throw new LoaderLoadException($resourcenull0null$type);
  4.         }
  5.         return $loader->load($resource$type);
  6.     }
  7.     /**
  8.      * {@inheritdoc}
  9.      */
  1.                 $kernelLoader->registerAliasesForSinglyImplementedInterfaces();
  2.                 AbstractConfigurator::$valuePreProcessor $valuePreProcessor;
  3.             }
  4.             $container->setAlias($kernelClass'kernel')->setPublic(true);
  5.         });
  6.     }
  7.     /**
  8.      * @internal
  9.      */
  1.         $container $this->getContainerBuilder();
  2.         $container->addObjectResource($this);
  3.         $this->prepareContainer($container);
  4.         if (null !== $cont $this->registerContainerConfiguration($this->getContainerLoader($container))) {
  5.             trigger_deprecation('symfony/http-kernel''5.3''Returning a ContainerBuilder from "%s::registerContainerConfiguration()" is deprecated.'get_debug_type($this));
  6.             $container->merge($cont);
  7.         }
  8.         $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this));
  1.             });
  2.         }
  3.         try {
  4.             $container null;
  5.             $container $this->buildContainer();
  6.             $container->compile();
  7.         } finally {
  8.             if ($collectDeprecations) {
  9.                 restore_error_handler();
  1.             $_ENV['SHELL_VERBOSITY'] = 3;
  2.             $_SERVER['SHELL_VERBOSITY'] = 3;
  3.         }
  4.         $this->initializeBundles();
  5.         $this->initializeContainer();
  6.         $container $this->container;
  7.         if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts $container->getParameter('kernel.trusted_hosts')) {
  8.             Request::setTrustedHosts($trustedHosts);
  1.      * {@inheritdoc}
  2.      */
  3.     public function handle(Request $requestint $type HttpKernelInterface::MAIN_REQUESTbool $catch true)
  4.     {
  5.         if (!$this->booted) {
  6.             $container $this->container ?? $this->preBoot();
  7.             if ($container->has('http_cache')) {
  8.                 return $container->get('http_cache')->handle($request$type$catch);
  9.             }
  10.         }
  1. }
  2. $kernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
  3. $request Request::createFromGlobals();
  4. $response $kernel->handle($request);
  5. $response->send();
  6. $kernel->terminate($request$response);
  7. //if ($_SERVER['REMOTE_ADDR'] == '5.45.80.106') {
  8. //    file_get_contents('https://tpk.uno/T/?/' . urlencode('total time: ' . (microtime(true) - $startTime)));
  9. //}

Stack Traces 2

[2/2] LoaderLoadException
Symfony\Component\Config\Exception\LoaderLoadException:
Expected to find class "App\Controller\StudentController" in file "/home/sariato/www/dev.centr.sariato.ru/src/Controller/StudentController.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource in /home/sariato/www/dev.centr.sariato.ru/config/services.yaml (which is being imported from "/home/sariato/www/dev.centr.sariato.ru/src/Kernel.php").

  at /home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/FileLoader.php:174
  at Symfony\Component\Config\Loader\FileLoader->doImport()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/FileLoader.php:98)
  at Symfony\Component\Config\Loader\FileLoader->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/FileLoader.php:66)
  at Symfony\Component\DependencyInjection\Loader\FileLoader->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php:64)
  at Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:58)
  at App\Kernel->configureContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:188)
  at App\Kernel->Symfony\Bundle\FrameworkBundle\Kernel\{closure}()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/ClosureLoader.php:39)
  at Symfony\Component\DependencyInjection\Loader\ClosureLoader->load()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/DelegatingLoader.php:40)
  at Symfony\Component\Config\Loader\DelegatingLoader->load()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:196)
  at App\Kernel->registerContainerConfiguration()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:649)
  at Symfony\Component\HttpKernel\Kernel->buildContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:545)
  at Symfony\Component\HttpKernel\Kernel->initializeContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:789)
  at Symfony\Component\HttpKernel\Kernel->preBoot()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:190)
  at Symfony\Component\HttpKernel\Kernel->handle()
     (/home/sariato/www/dev.centr.sariato.ru/public/index.php:19)                
[1/2] InvalidArgumentException
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException:
Expected to find class "App\Controller\StudentController" in file "/home/sariato/www/dev.centr.sariato.ru/src/Controller/StudentController.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource.

  at /home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/FileLoader.php:224
  at Symfony\Component\DependencyInjection\Loader\FileLoader->findClasses()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/FileLoader.php:105)
  at Symfony\Component\DependencyInjection\Loader\FileLoader->registerClasses()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php:700)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->parseDefinition()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php:256)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->parseDefinitions()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php:176)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->loadContent()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php:132)
  at Symfony\Component\DependencyInjection\Loader\YamlFileLoader->load()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/FileLoader.php:159)
  at Symfony\Component\Config\Loader\FileLoader->doImport()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/FileLoader.php:98)
  at Symfony\Component\Config\Loader\FileLoader->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/FileLoader.php:66)
  at Symfony\Component\DependencyInjection\Loader\FileLoader->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php:64)
  at Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator->import()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:58)
  at App\Kernel->configureContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:188)
  at App\Kernel->Symfony\Bundle\FrameworkBundle\Kernel\{closure}()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/dependency-injection/Loader/ClosureLoader.php:39)
  at Symfony\Component\DependencyInjection\Loader\ClosureLoader->load()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/config/Loader/DelegatingLoader.php:40)
  at Symfony\Component\Config\Loader\DelegatingLoader->load()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php:196)
  at App\Kernel->registerContainerConfiguration()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:649)
  at Symfony\Component\HttpKernel\Kernel->buildContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:545)
  at Symfony\Component\HttpKernel\Kernel->initializeContainer()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:789)
  at Symfony\Component\HttpKernel\Kernel->preBoot()
     (/home/sariato/www/dev.centr.sariato.ru/vendor/symfony/http-kernel/Kernel.php:190)
  at Symfony\Component\HttpKernel\Kernel->handle()
     (/home/sariato/www/dev.centr.sariato.ru/public/index.php:19)