chore: initial import for test contour
This commit is contained in:
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Entity\Specialist;
|
||||
use App\Service\Bitrix\BitrixService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'bitrix-update-doctors',
|
||||
description: 'Обновления врачей из CMS Bitrix',
|
||||
)]
|
||||
class BitrixUpdateDoctorsCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private BitrixService $bitrixService
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$this->logger->info('start: bitrix-update-doctors');
|
||||
$io->info('Началось выполнение.');
|
||||
|
||||
$specialistList = $this->entityManager->getRepository(Specialist::class)->findAll();
|
||||
$count = 0;
|
||||
|
||||
foreach ($specialistList as $specialist) {
|
||||
$dcodes = $specialist->getDcodes();
|
||||
|
||||
if (empty($dcodes) || $dcodes === '0' || $dcodes === 0) {
|
||||
$specialist->setDcodes(null);
|
||||
} else {
|
||||
$dcodesArray = explode(',', $dcodes);
|
||||
|
||||
$filteredDcodes = array_filter(
|
||||
array_unique($dcodesArray),
|
||||
function($item) {
|
||||
return strlen(trim($item)) >= 7 && trim($item) !== '0';
|
||||
}
|
||||
);
|
||||
|
||||
if (empty($filteredDcodes)) {
|
||||
$specialist->setDcodes(null);
|
||||
} else {
|
||||
$specialist->setDcodes(implode(',', $filteredDcodes));
|
||||
}
|
||||
}
|
||||
|
||||
// $kodoper = $this->bitrixService->getServiceCode($specialist->getId());
|
||||
|
||||
// if (!empty($kodoper)) {
|
||||
// $specialist->setKodoper($kodoper);
|
||||
// $this->entityManager->persist($specialist);
|
||||
// }
|
||||
|
||||
$count ++;
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
$this->logger->info('end: bitrix-update-doctors ' . $count);
|
||||
$io->success('load: ' . $count);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Entity\Specialist;
|
||||
use App\Entity\Review;
|
||||
use App\Service\Bitrix\BitrixService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
|
||||
|
||||
#[AsCommand(
|
||||
name: 'bitrix-update-reviews',
|
||||
description: 'Обновления отзывов врачей из CMS Bitrix',
|
||||
)]
|
||||
final class BitrixUpdateReviewsCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private BitrixService $bitrixService
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private $review = [
|
||||
'source' => null,
|
||||
'rating' => 5
|
||||
];
|
||||
|
||||
private function safeUtf8Clean($text)
|
||||
{
|
||||
$result = '';
|
||||
$length = strlen($text);
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$byte = ord($text[$i]);
|
||||
|
||||
// Валидные ASCII символы
|
||||
if ($byte <= 0x7F) {
|
||||
// Разрешаем только печатаемые ASCII и управляющие символы
|
||||
if ($byte >= 0x20 || $byte == 0x09 || $byte == 0x0A || $byte == 0x0D) {
|
||||
$result .= $text[$i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Многобайтовые UTF-8 последовательности
|
||||
if (($byte & 0xE0) == 0xC0) {
|
||||
// 2-байтовая последовательность
|
||||
if ($i + 1 < $length) {
|
||||
$byte2 = ord($text[$i + 1]);
|
||||
if (($byte2 & 0xC0) == 0x80) {
|
||||
$result .= $text[$i] . $text[$i + 1];
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
} elseif (($byte & 0xF0) == 0xE0) {
|
||||
// 3-байтовая последовательность
|
||||
if ($i + 2 < $length) {
|
||||
$byte2 = ord($text[$i + 1]);
|
||||
$byte3 = ord($text[$i + 2]);
|
||||
if (($byte2 & 0xC0) == 0x80 && ($byte3 & 0xC0) == 0x80) {
|
||||
$result .= $text[$i] . $text[$i + 1] . $text[$i + 2];
|
||||
$i += 2;
|
||||
}
|
||||
}
|
||||
} elseif (($byte & 0xF8) == 0xF0) {
|
||||
// 4-байтовая последовательность
|
||||
if ($i + 3 < $length) {
|
||||
$byte2 = ord($text[$i + 1]);
|
||||
$byte3 = ord($text[$i + 2]);
|
||||
$byte4 = ord($text[$i + 3]);
|
||||
if (($byte2 & 0xC0) == 0x80 && ($byte3 & 0xC0) == 0x80 && ($byte4 & 0xC0) == 0x80) {
|
||||
$result .= $text[$i] . $text[$i + 1] . $text[$i + 2] . $text[$i + 3];
|
||||
$i += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function processName(array $data): void
|
||||
{
|
||||
$name = $this->safeUtf8Clean($data['VALUE']);
|
||||
|
||||
$this->review['name'] = empty($name)? 'Анонимно': $name;
|
||||
$this->review['dateCreate'] = \DateTime::createFromFormat('Y-m-d H:i:s', $data['DATE_CREATE']);
|
||||
$this->review['active'] = ($data['ACTIVE'] == 'Y')? true: false;
|
||||
}
|
||||
|
||||
private function processMessage(string $value): void
|
||||
{
|
||||
$message = $this->safeUtf8Clean($value);
|
||||
|
||||
$message = preg_replace('/a:\d+:\{.*\}|s:\d+:".*"|\w+:\d+:/', '', $message);
|
||||
$message = str_replace('{', '', $message);
|
||||
$message = str_replace('}', '', $message);
|
||||
|
||||
$this->review['message'] = trim(strip_tags($message));
|
||||
}
|
||||
|
||||
private function processSourceLink(string $value): void
|
||||
{
|
||||
preg_match('/https?:\/\/[^\s<>"\']+/i', $value, $matches);
|
||||
|
||||
if (!empty($matches[0])) {
|
||||
$this->review['source'] = $this->safeUtf8Clean(substr($matches[0], 0, 255));
|
||||
}
|
||||
}
|
||||
|
||||
private function processRating($value): void
|
||||
{
|
||||
$this->review['rating'] = max(1, min(5, $value));
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->info('Началось выполнение.');
|
||||
|
||||
$this->logger->info('start: bitrix-update-reviews');
|
||||
|
||||
$specialistAll = $this->entityManager->getRepository(Specialist::class)->findAll();
|
||||
$progressBar = new ProgressBar($output, count($specialistAll));
|
||||
|
||||
unset($specialistAll);
|
||||
|
||||
$page = 1;
|
||||
$batchSize = 5;
|
||||
|
||||
do {
|
||||
$progressBar->advance();
|
||||
$query = $this->entityManager->getRepository(Specialist::class)
|
||||
->createQueryBuilder('s')
|
||||
->setFirstResult(($page - 1) * $batchSize)
|
||||
->setMaxResults($batchSize)
|
||||
->getQuery();
|
||||
|
||||
$paginator = new Paginator($query);
|
||||
$specialistList = iterator_to_array($paginator);
|
||||
$page++;
|
||||
|
||||
$this->loadData($specialistList);
|
||||
$this->entityManager->clear();
|
||||
|
||||
gc_collect_cycles();
|
||||
} while (count($specialistList) > 0);
|
||||
|
||||
$this->entityManager->clear();
|
||||
$progressBar->finish();
|
||||
$output->writeln('');
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function loadData(array $specialistList)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($specialistList as $specialist) {
|
||||
|
||||
$reviews = $this->bitrixService->getReviews($specialist->getId());
|
||||
|
||||
foreach ($reviews as $key => $params) {
|
||||
$this->review['externalId'] = (int) $params['REVIEW_ID'];
|
||||
|
||||
$review = $this->entityManager->getRepository(Review::class)
|
||||
->findOneBy(['externalId' => $this->review['externalId']]);
|
||||
|
||||
foreach ($params['DATA'] as $data) {
|
||||
$code = $data['CODE'];
|
||||
$value = $data['VALUE'];
|
||||
|
||||
match ($code) {
|
||||
"NAME" => $this->processName($data),
|
||||
"MESSAGE" => $this->processMessage($value),
|
||||
"SOURCE_LINK" => $this->processSourceLink($value),
|
||||
"RATING" => $this->processRating((int) $value),
|
||||
default => null // Игнорируем неизвестные коды
|
||||
};
|
||||
}
|
||||
|
||||
if (!$this->review['active'] || empty($this->review['message'])) continue;
|
||||
|
||||
if (!$review) {
|
||||
$review = new Review;
|
||||
$review->setExternalId($this->review['externalId']);
|
||||
}
|
||||
|
||||
$review
|
||||
->setActive($this->review['active'])
|
||||
->setDateCreate($this->review['dateCreate'])
|
||||
->setSource($this->review['source'])
|
||||
->setRating($this->review['rating'])
|
||||
->setAuthor($this->review['name'])
|
||||
->setMessage($this->review['message']);
|
||||
|
||||
$specialist->addReview($review);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->entityManager->flush();
|
||||
} catch (DriverException $e) {
|
||||
$this->logger->error('Problematic parameters: ' . print_r($this->review, true));
|
||||
|
||||
// Проверяем каждый параметр на валидность UTF-8
|
||||
foreach ($this->review as $index => $param) {
|
||||
if (is_string($param) && !mb_check_encoding($param, 'UTF-8')) {
|
||||
$this->logger->error("Invalid UTF-8 in parameter $index: " . bin2hex($param));
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$count ++;
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\ScheduleCache\ScheduleCacheService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:schedule:clear-cache',
|
||||
description: 'Clear old schedule cache'
|
||||
)]
|
||||
class ClearScheduleCacheCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private ScheduleCacheService $cacheService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('hours', null, InputOption::VALUE_REQUIRED, 'Clear cache older than X hours', 24)
|
||||
->addOption('stats', null, InputOption::VALUE_NONE, 'Show cache statistics')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if ($input->getOption('stats')) {
|
||||
$stats = $this->cacheService->getCacheStats();
|
||||
|
||||
$io->title('Schedule Cache Statistics');
|
||||
$io->table(
|
||||
['Metric', 'Value'],
|
||||
[
|
||||
['Total Records', number_format($stats['total_records'])],
|
||||
['Unique Queries', number_format($stats['unique_queries'])],
|
||||
['Oldest Record', $stats['oldest_record']->format('Y-m-d H:i:s')],
|
||||
['Newest Record', $stats['newest_record']->format('Y-m-d H:i:s')]
|
||||
]
|
||||
);
|
||||
|
||||
if (!empty($stats['last_7_days'])) {
|
||||
$io->section('Last 7 Days Activity');
|
||||
$rows = [];
|
||||
foreach ($stats['last_7_days'] as $day) {
|
||||
$rows[] = [
|
||||
$day['day'],
|
||||
number_format($day['records_count']),
|
||||
number_format($day['queries_count'])
|
||||
];
|
||||
}
|
||||
$io->table(['Date', 'Records', 'Queries'], $rows);
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$hours = (int)$input->getOption('hours');
|
||||
$olderThan = new \DateTime(sprintf('-%d hours', $hours));
|
||||
|
||||
$io->note(sprintf('Clearing cache older than %s', $olderThan->format('Y-m-d H:i:s')));
|
||||
|
||||
try {
|
||||
$deletedCount = $this->cacheService->clearOldCache($olderThan);
|
||||
|
||||
$io->success(sprintf('Successfully cleared %d cache records older than %d hours', $deletedCount, $hours));
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$io->error(sprintf('Error clearing cache: %s', $e->getMessage()));
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Department;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use App\Service\Client\Interfaces\InfoclinicaClientServiceInterface;
|
||||
use App\Service\Translite\Interfaces\TransliteServiceInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:deps',
|
||||
description: 'Пакетное обновление отделений для врачей',
|
||||
)]
|
||||
class UploadDepartmentsCommand extends Command
|
||||
{
|
||||
private const BATCH_SIZE = 100;
|
||||
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private InfoclinicaClientServiceInterface $client,
|
||||
private TransliteServiceInterface $transliteService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void { }
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Пакетное обновление отделений');
|
||||
|
||||
try {
|
||||
// Используем InfoclinicaClientServiceInterface для запроса
|
||||
$httpResponse = $this->client->request('GET', '/specialists/departments');
|
||||
$responseData = $httpResponse->toArray();
|
||||
|
||||
if (empty($responseData['data'])) {
|
||||
$io->success('Нет данных для обработки');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$totalRecords = count($responseData['data']);
|
||||
$io->info("Загружено записей из API: {$totalRecords}");
|
||||
|
||||
// Убираем возможные дубликаты из данных API (по did)
|
||||
$uniqueData = $this->removeDuplicates($responseData['data']);
|
||||
$uniqueCount = count($uniqueData);
|
||||
|
||||
if ($uniqueCount < $totalRecords) {
|
||||
$io->note("Удалено дубликатов: " . ($totalRecords - $uniqueCount));
|
||||
$io->info("Уникальных записей для обработки: {$uniqueCount}");
|
||||
}
|
||||
|
||||
// Пакетная обработка с UPSERT
|
||||
$processed = $this->processWithUpsert($uniqueData, $io);
|
||||
|
||||
// Статистика
|
||||
$io->table(
|
||||
['Статистика', 'Значение'],
|
||||
[
|
||||
['Всего записей в API', $totalRecords],
|
||||
['Уникальных записей', $uniqueCount],
|
||||
['Успешно обработано', $processed],
|
||||
['Пропущено', $uniqueCount - $processed]
|
||||
]
|
||||
);
|
||||
|
||||
$io->success('Обработка завершена успешно');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
$io->error('Trace: ' . $e->getTraceAsString());
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет дубликаты по полю id (did)
|
||||
*/
|
||||
private function removeDuplicates(array $data): array
|
||||
{
|
||||
$unique = [];
|
||||
foreach ($data as $item) {
|
||||
if (!isset($item['id'])) {
|
||||
continue;
|
||||
}
|
||||
$unique[$item['id']] = $item; // id из API как ключ для уникальности
|
||||
}
|
||||
return array_values($unique);
|
||||
}
|
||||
|
||||
/**
|
||||
* Основной метод обработки с UPSERT
|
||||
* Возвращает количество успешно обработанных записей
|
||||
*/
|
||||
private function processWithUpsert(array $data, SymfonyStyle $io): int
|
||||
{
|
||||
$connection = $this->entityManager->getConnection();
|
||||
$tableName = $this->entityManager->getClassMetadata(Department::class)->getTableName();
|
||||
|
||||
$total = count($data);
|
||||
$processed = 0;
|
||||
$skipped = 0;
|
||||
|
||||
$io->progressStart($total);
|
||||
|
||||
// Обрабатываем пакетами
|
||||
for ($i = 0; $i < $total; $i += self::BATCH_SIZE) {
|
||||
$batch = array_slice($data, $i, self::BATCH_SIZE);
|
||||
|
||||
try {
|
||||
$batchProcessed = $this->executeUpsertBatch($connection, $tableName, $batch, $io);
|
||||
$processed += $batchProcessed;
|
||||
|
||||
$io->progressAdvance(count($batch));
|
||||
|
||||
// Периодически выводим статистику
|
||||
if ($i % (self::BATCH_SIZE * 10) === 0 || $i + self::BATCH_SIZE >= $total) {
|
||||
$io->writeln(sprintf(
|
||||
' [%s] Обработано: %d/%d (%.1f%%)',
|
||||
date('H:i:s'),
|
||||
$processed,
|
||||
$total,
|
||||
($processed / $total) * 100
|
||||
));
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->warning(sprintf(
|
||||
'Ошибка в пакете %d-%d: %s',
|
||||
$i + 1,
|
||||
min($i + self::BATCH_SIZE, $total),
|
||||
$e->getMessage()
|
||||
));
|
||||
|
||||
// Если ошибка в пакете, пробуем обработать по одной записи
|
||||
$batchProcessed = $this->handleBatchError($connection, $tableName, $batch, $io);
|
||||
$processed += $batchProcessed;
|
||||
$skipped += (count($batch) - $batchProcessed);
|
||||
}
|
||||
}
|
||||
|
||||
$io->progressFinish();
|
||||
|
||||
if ($skipped > 0) {
|
||||
$io->warning("Пропущено записей из-за ошибок: {$skipped}");
|
||||
}
|
||||
|
||||
return $processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет UPSERT для пакета данных
|
||||
* Возвращает количество успешно обработанных записей в пакете
|
||||
*/
|
||||
private function executeUpsertBatch($connection, string $tableName, array $batch, SymfonyStyle $io): int
|
||||
{
|
||||
if (empty($batch)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sqlParts = [];
|
||||
$params = [];
|
||||
$validItems = 0;
|
||||
|
||||
foreach ($batch as $index => $item) {
|
||||
if (!isset($item['id']) || !isset($item['name'])) {
|
||||
continue; // Пропускаем некорректные записи
|
||||
}
|
||||
|
||||
$sqlParts[] = sprintf(
|
||||
'(:did_%d, :name_%d, :alias_%d, :active_%d, :online_mode_%d)',
|
||||
$index, $index, $index, $index, $index
|
||||
);
|
||||
|
||||
$params['did_' . $index] = (int) $item['id'];
|
||||
$params['name_' . $index] = $item['name'];
|
||||
$params['alias_' . $index] = $this->transliteService->translit($item['name']);
|
||||
$params['active_' . $index] = true;
|
||||
$params['online_mode_' . $index] = $item['onlineMode'] ?? false;
|
||||
|
||||
$validItems++;
|
||||
}
|
||||
|
||||
if (empty($sqlParts)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$valuesSql = implode(', ', $sqlParts);
|
||||
$updateSql = sprintf(
|
||||
'UPDATE %1$s AS d
|
||||
SET
|
||||
name = src.name,
|
||||
alias = src.alias,
|
||||
active = CAST(src.active AS BOOLEAN),
|
||||
online_mode = CAST(src.online_mode AS BOOLEAN)
|
||||
FROM (VALUES %2$s) AS src(did, name, alias, active, online_mode)
|
||||
WHERE d.did = CAST(src.did AS BIGINT)',
|
||||
$tableName,
|
||||
$valuesSql
|
||||
);
|
||||
|
||||
$insertSql = sprintf(
|
||||
'INSERT INTO %1$s (did, name, alias, active, online_mode)
|
||||
SELECT
|
||||
CAST(src.did AS BIGINT),
|
||||
src.name,
|
||||
src.alias,
|
||||
CAST(src.active AS BOOLEAN),
|
||||
CAST(src.online_mode AS BOOLEAN)
|
||||
FROM (VALUES %2$s) AS src(did, name, alias, active, online_mode)
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM %1$s d WHERE d.did = CAST(src.did AS BIGINT)
|
||||
)',
|
||||
$tableName,
|
||||
$valuesSql
|
||||
);
|
||||
|
||||
$connection->executeStatement($updateSql, $params);
|
||||
$connection->executeStatement($insertSql, $params);
|
||||
|
||||
return $validItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Обрабатывает ошибку пакета, пробуя вставить записи по одной
|
||||
* Возвращает количество успешно обработанных записей
|
||||
*/
|
||||
private function handleBatchError($connection, string $tableName, array $batch, SymfonyStyle $io): int
|
||||
{
|
||||
$successCount = 0;
|
||||
|
||||
foreach ($batch as $item) {
|
||||
try {
|
||||
if ($this->executeSingleUpsert($connection, $tableName, $item)) {
|
||||
$successCount++;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$io->warning(sprintf(
|
||||
'Не удалось обработать запись did=%s: %s',
|
||||
$item['id'] ?? 'unknown',
|
||||
$e->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $successCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет UPSERT для одной записи
|
||||
* Возвращает true если успешно
|
||||
*/
|
||||
private function executeSingleUpsert($connection, string $tableName, array $item): bool
|
||||
{
|
||||
if (!isset($item['id']) || !isset($item['name'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$alias = $this->transliteService->translit($item['name']);
|
||||
$active = $item['active'] ?? true;
|
||||
$onlineMode = $item['onlineMode'] ?? false;
|
||||
|
||||
$updateSql = sprintf(
|
||||
'UPDATE %s
|
||||
SET
|
||||
name = :name,
|
||||
alias = :alias,
|
||||
active = :active,
|
||||
online_mode = :online_mode
|
||||
WHERE did = :did',
|
||||
$tableName
|
||||
);
|
||||
|
||||
$insertSql = sprintf(
|
||||
'INSERT INTO %s (did, name, alias, active, online_mode)
|
||||
SELECT :did, :name, :alias, :active, :online_mode
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM %s WHERE did = :did
|
||||
)',
|
||||
$tableName,
|
||||
$tableName
|
||||
);
|
||||
|
||||
$params = [
|
||||
'did' => (int) $item['id'],
|
||||
'name' => $item['name'],
|
||||
'alias' => $alias,
|
||||
'active' => $active,
|
||||
'online_mode' => $onlineMode
|
||||
];
|
||||
|
||||
$connection->executeStatement($updateSql, $params);
|
||||
$connection->executeStatement($insertSql, $params);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\DiseaseCrudService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:diseases',
|
||||
description: 'Обновление таблицы disease из view_disease',
|
||||
)]
|
||||
final class UploadDiseasesCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private DiseaseCrudService $diseaseCrudService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('view', null, InputOption::VALUE_OPTIONAL, 'SQL view name', 'public.view_disease');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$viewName = $input->getOption('view');
|
||||
if (empty($viewName)) {
|
||||
$viewName = 'public.view_disease';
|
||||
}
|
||||
$viewName = (string) $viewName;
|
||||
|
||||
$io->title('Disease: sync from view_disease');
|
||||
|
||||
try {
|
||||
$this->logger->info('Disease sync start', ['view' => $viewName]);
|
||||
$affected = $this->diseaseCrudService->syncFromViewDisease($viewName);
|
||||
$io->success('Sync finished. Affected rows: ' . $affected);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('Disease sync failed', [
|
||||
'view' => $viewName,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Idoctor;
|
||||
use App\Entity\Department;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use App\Service\Client\Interfaces\InfoclinicaClientServiceInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:doctors',
|
||||
description: 'Пакетное обновление врачей из инфоклиники',
|
||||
)]
|
||||
class UploadDoctorsCommand extends Command
|
||||
{
|
||||
private const BATCH_SIZE = 150;
|
||||
private const CHUNK_SIZE = 300;
|
||||
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private InfoclinicaClientServiceInterface $client
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addArgument('onlineMode', InputArgument::OPTIONAL, 'Режим онлайн (0 или 1)', 0);
|
||||
$this->addOption('department', 'd', InputOption::VALUE_OPTIONAL, 'ID конкретного отделения');
|
||||
$this->addOption('firstrow', 'f', InputOption::VALUE_OPTIONAL, 'Первая строка', 1);
|
||||
$this->addOption('lastrow', 'l', InputOption::VALUE_OPTIONAL, 'Последняя строка', 900);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Пакетное обновление врачей');
|
||||
|
||||
try {
|
||||
$onlineMode = (bool) $input->getArgument('onlineMode');
|
||||
$departmentId = (int) $input->getOption('department');
|
||||
$firstRow = (int) $input->getOption('firstrow');
|
||||
$lastRow = (int) $input->getOption('lastrow');
|
||||
|
||||
$departments = $this->getDepartmentsToProcess($departmentId);
|
||||
|
||||
if (empty($departments)) {
|
||||
$io->warning('Не найдено отделений для обработки');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$io->info('Найдено отделений: ' . count($departments));
|
||||
$io->info('Режим онлайн: ' . ($onlineMode ? 'Да' : 'Нет'));
|
||||
|
||||
$totalDoctorsProcessed = 0;
|
||||
|
||||
foreach ($departments as $index => $department) {
|
||||
$io->section('Обработка отделения: ' . $department['name'] . ' (ID: ' . $department['did'] . ')');
|
||||
|
||||
$doctorsData = $this->fetchDoctorsData($department['did'], $onlineMode, $firstRow, $lastRow, $io);
|
||||
|
||||
if (empty($doctorsData)) {
|
||||
$io->note('Нет данных врачей для отделения');
|
||||
continue;
|
||||
}
|
||||
|
||||
$processed = $this->processDoctorsBatch($doctorsData, $department['did'], $onlineMode, $io);
|
||||
$totalDoctorsProcessed += $processed;
|
||||
$io->writeln(sprintf(
|
||||
'Обработано врачей в отделении: %d',
|
||||
$processed
|
||||
));
|
||||
|
||||
if ($index < count($departments) - 1) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$this->entityManager->clear();
|
||||
}
|
||||
|
||||
$io->success(sprintf('Обработка завершена. Всего обработано врачей: %d', $totalDoctorsProcessed));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function getDepartmentsToProcess(?int $departmentId): array
|
||||
{
|
||||
$repository = $this->entityManager->getRepository(Department::class);
|
||||
$qb = $repository->createQueryBuilder('d')
|
||||
->select('d.did AS did, d.name AS name')
|
||||
->orderBy('d.id', 'ASC');
|
||||
|
||||
if ($departmentId) {
|
||||
$qb->andWhere('d.did = :departmentId')
|
||||
->setParameter('departmentId', $departmentId);
|
||||
} else {
|
||||
$qb->andWhere('d.active = :active')
|
||||
->setParameter('active', true);
|
||||
}
|
||||
|
||||
$departments = $qb->getQuery()->getArrayResult();
|
||||
|
||||
return array_map(static fn (array $department): array => [
|
||||
'did' => (int) $department['did'],
|
||||
'name' => (string) $department['name'],
|
||||
], $departments);
|
||||
}
|
||||
|
||||
private function fetchDoctorsData(int $departmentId, bool $onlineMode, int $firstRow, int $lastRow, SymfonyStyle $io): array
|
||||
{
|
||||
$allDoctors = [];
|
||||
$chunkSize = self::CHUNK_SIZE;
|
||||
|
||||
for ($start = $firstRow; $start <= $lastRow; $start += $chunkSize) {
|
||||
$end = min($start + $chunkSize - 1, $lastRow);
|
||||
|
||||
$path = sprintf(
|
||||
'/specialists/doctors?departments=%d&onlineMode=%d&firstrow=%d&lastrow=%d',
|
||||
$departmentId,
|
||||
$onlineMode ? 1 : 0,
|
||||
$start,
|
||||
$end
|
||||
);
|
||||
|
||||
try {
|
||||
$httpResponse = $this->client->request('GET', $path);
|
||||
$response = $httpResponse->toArray() ?: [];
|
||||
|
||||
if (!empty($response['data'])) {
|
||||
$allDoctors = array_merge($allDoctors, $response['data']);
|
||||
$io->writeln(sprintf('Загружено врачей: %d (%d-%d)', count($response['data']), $start, $end));
|
||||
}
|
||||
|
||||
if (count($response['data'] ?? []) < $chunkSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(200000);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->warning('Ошибка при загрузке данных для отделения ' . $departmentId . ': ' . $e->getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $allDoctors;
|
||||
}
|
||||
|
||||
private function processDoctorsBatch(array $doctorsData, int $departmentId, bool $onlineMode, SymfonyStyle $io): int
|
||||
{
|
||||
if (empty($doctorsData)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Получаем существующих врачей
|
||||
$existingDoctors = $this->getExistingDoctors($doctorsData, $departmentId, $onlineMode);
|
||||
|
||||
$processed = 0;
|
||||
$batchCount = 0;
|
||||
|
||||
foreach ($doctorsData as $index => $doctorData) {
|
||||
try {
|
||||
$doctorKey = $this->getDoctorKey($doctorData['dcode'], $departmentId, $onlineMode);
|
||||
|
||||
$iDoctor = $existingDoctors[$doctorKey] ?? new Idoctor();
|
||||
|
||||
$this->updateDoctorEntity($iDoctor, $doctorData, $departmentId, $onlineMode);
|
||||
|
||||
$this->entityManager->persist($iDoctor);
|
||||
$processed++;
|
||||
$batchCount++;
|
||||
|
||||
if ($batchCount % self::BATCH_SIZE === 0) {
|
||||
$this->entityManager->flush();
|
||||
$io->writeln(sprintf('Сохранено пакет: %d врачей', self::BATCH_SIZE));
|
||||
$batchCount = 0;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->warning('Ошибка при обработке врача ' . ($doctorData['dcode'] ?? 'unknown') . ': ' . $e->getMessage());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($batchCount > 0) {
|
||||
$this->entityManager->flush();
|
||||
$io->writeln(sprintf('Сохранено остальных: %d врачей', $batchCount));
|
||||
}
|
||||
|
||||
return $processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает существующих врачей
|
||||
*/
|
||||
private function getExistingDoctors(array $doctorsData, int $departmentId, bool $onlineMode): array
|
||||
{
|
||||
$dCodes = array_column($doctorsData, 'dcode');
|
||||
|
||||
if (empty($dCodes)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$existingDoctors = $this->entityManager->getRepository(Idoctor::class)
|
||||
->createQueryBuilder('d')
|
||||
->where('d.dcode IN (:dCodes)')
|
||||
->andWhere('d.department = :department')
|
||||
->andWhere('d.onlineMode = :onlineMode')
|
||||
->setParameter('dCodes', $dCodes)
|
||||
->setParameter('department', $departmentId)
|
||||
->setParameter('onlineMode', $onlineMode)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$result = [];
|
||||
foreach ($existingDoctors as $doctor) {
|
||||
$key = $this->getDoctorKey(
|
||||
$doctor->getDcode(),
|
||||
$doctor->getDepartment(),
|
||||
$doctor->getOnlineMode()
|
||||
);
|
||||
$result[$key] = $doctor;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает уникальный ключ для врача
|
||||
*/
|
||||
private function getDoctorKey(string $dcode, int $departmentId, bool $onlineMode): string
|
||||
{
|
||||
return sprintf('%s_%d_%d', $dcode, $departmentId, $onlineMode ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет сущность врача
|
||||
*/
|
||||
private function updateDoctorEntity(Idoctor $doctor, array $data, int $departmentId, bool $onlineMode): void
|
||||
{
|
||||
$doctor
|
||||
->setDcode($data['dcode'] ?? '')
|
||||
->setName($data['name'] ?? '')
|
||||
->setDepartment($departmentId)
|
||||
->setFilial($data['filialId'] ?? null)
|
||||
->setNearestDate($data['nearestDate'] ?? null)
|
||||
->setOnlineMode($onlineMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Filial;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Service\Translite\Interfaces\TransliteServiceInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:filials',
|
||||
description: 'Обнвление филиалов',
|
||||
)]
|
||||
class UploadFilialsCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private HttpClientInterface $client,
|
||||
private TransliteServiceInterface $transliteService,
|
||||
private string $widgetApiUrl,
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void { }
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->logger->info('Началось обнвление филиалов');
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$response = $this->client->request('GET', '/filials/list', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'base_uri' => $this->widgetApiUrl,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'sovamed_bot'
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $response->toArray();
|
||||
|
||||
$io->info('load:' . count($response['data']));
|
||||
foreach ($response['data'] as $item) {
|
||||
$filial = $this->entityManager->getRepository(Filial::class)
|
||||
->findOneBy(['fid' => $item['id']]);
|
||||
|
||||
if (is_null($filial)) {
|
||||
$filial = new Filial();
|
||||
}
|
||||
|
||||
preg_match('/(ул\.\s*[А-я]+(?:\s+[А-я]+)*)\s*,?\s*д\.\s*(\S+)/u', $item['address'], $matches);
|
||||
|
||||
if (isset($matches[1]) && isset($matches[2])) {
|
||||
$street = $matches[1];
|
||||
$house = $matches[2];
|
||||
|
||||
$filial->setShortName("$street,$house");
|
||||
}
|
||||
|
||||
$filial
|
||||
->setFid($item['id'])
|
||||
->setName($item['name'])
|
||||
->setAddress($item['address'])
|
||||
->setActive(true)
|
||||
->setRegionId($this->findRegionId($item['address']))
|
||||
;
|
||||
|
||||
$this->entityManager->persist($filial);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
$io->success('loaded');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function findRegionId($address) {
|
||||
$cities = [
|
||||
91 => "Саратов",
|
||||
92 => "Волгоград",
|
||||
93 => "Воронеж",
|
||||
94 => "Краснодар",
|
||||
];
|
||||
|
||||
foreach ($cities as $key => $city) {
|
||||
if (stripos($address, $city) !== false) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\MedicalCenterCrudService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:medical-centers',
|
||||
description: 'Обновление таблицы medical_center из view_centers'
|
||||
)]
|
||||
final class UploadMedicalCentersCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private MedicalCenterCrudService $medicalCenterCrudService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('view', null, InputOption::VALUE_OPTIONAL, 'SQL view name', 'public.view_centers');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$viewName = $input->getOption('view');
|
||||
if (empty($viewName)) {
|
||||
$viewName = 'public.view_centers';
|
||||
}
|
||||
$viewName = (string) $viewName;
|
||||
|
||||
$io->title('MedicalCenter: sync from view_centers');
|
||||
|
||||
try {
|
||||
$this->logger->info('MedicalCenter sync start', ['view' => $viewName]);
|
||||
$affected = $this->medicalCenterCrudService->syncFromViewCenters($viewName);
|
||||
$io->success('Sync finished. Affected rows: ' . $affected);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('MedicalCenter sync failed', [
|
||||
'view' => $viewName,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\NewsCrudService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:news',
|
||||
description: 'Обновление таблицы news из view_news'
|
||||
)]
|
||||
final class UploadNewsCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private NewsCrudService $newsCrudService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('view', null, InputOption::VALUE_OPTIONAL, 'SQL view name', 'public.view_news');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$viewName = $input->getOption('view');
|
||||
if (empty($viewName)) {
|
||||
$viewName = 'public.view_news';
|
||||
}
|
||||
$viewName = (string) $viewName;
|
||||
|
||||
$io->title('News: sync from view_news');
|
||||
|
||||
try {
|
||||
$this->logger->info('News sync start', ['view' => $viewName]);
|
||||
$affected = $this->newsCrudService->syncFromViewNews($viewName);
|
||||
$io->success('Sync finished. Affected rows: ' . $affected);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('News sync failed', [
|
||||
'view' => $viewName,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\PriceDepartment;
|
||||
use App\Entity\PriceList;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:price',
|
||||
description: 'Обновление цен',
|
||||
)]
|
||||
class UploadPriceCommand extends Command
|
||||
{
|
||||
private $nosleep;
|
||||
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private HttpClientInterface $client,
|
||||
private string $widgetApiUrl,
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('did', InputArgument::OPTIONAL, 'department id update')
|
||||
->addOption('debug', null, InputOption::VALUE_NONE, 'debug on')
|
||||
->addOption('nosleep', null, InputOption::VALUE_OPTIONAL, 'sleep true|false default false')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$departments = $this->entityManager->getRepository(PriceDepartment::class)->findAll();
|
||||
$departmentId = $input->getArgument('did');
|
||||
$debug = $input->getOption('debug');
|
||||
$this->nosleep = $input->getOption('nosleep');
|
||||
|
||||
if ($departmentId) {
|
||||
$departments = $this->entityManager->getRepository(PriceDepartment::class)
|
||||
->findBy(['groupId' => $departmentId]);
|
||||
}
|
||||
|
||||
if (empty($departments)) {
|
||||
$io->error('No departments found');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$batchSize = 100;
|
||||
$processedCount = 0;
|
||||
|
||||
foreach ($departments as $department) {
|
||||
$io->note("Processing department: " . $department->getGroupId());
|
||||
|
||||
foreach ($this->getPricelist($department->getGroupId()) as $collection) {
|
||||
foreach ($collection as $item) {
|
||||
$priceList = $this->entityManager->getRepository(PriceList::class)
|
||||
->findOneBy([
|
||||
'kodoper' => $item['kodoper'],
|
||||
'speccode' => $item['speccode'],
|
||||
'filial' => $item['filial'],
|
||||
'groupId' => $department->getGroupId()
|
||||
]);
|
||||
|
||||
$text = 'update: ';
|
||||
|
||||
if (is_null($priceList)) {
|
||||
$priceList = new PriceList();
|
||||
$text = 'create: ';
|
||||
}
|
||||
|
||||
$priceList
|
||||
->setKodoper($item['kodoper'])
|
||||
->setSchname($item['schname'])
|
||||
->setSpecname($item['specname'])
|
||||
->setSpeccode($item['speccode'])
|
||||
->setPriceInfo($item['priceInfo'])
|
||||
->setDiscpercent($item['discpercent'])
|
||||
->setDiscprice($item['discprice'])
|
||||
->setStructname($item['structname'])
|
||||
->setFname($item['fname'])
|
||||
->setFilial($item['filial'])
|
||||
->setComment($item['comment'])
|
||||
->setMediaId($item['mediaId'])
|
||||
->setDateUpdate(new \DateTime())
|
||||
->setGroupId($department->getGroupId());
|
||||
|
||||
$this->entityManager->persist($priceList);
|
||||
$processedCount++;
|
||||
|
||||
// Пакетное сохранение для экономии памяти
|
||||
if ($processedCount % $batchSize === 0) {
|
||||
$this->entityManager->flush();
|
||||
$this->entityManager->clear();
|
||||
gc_collect_cycles();
|
||||
|
||||
if ($debug) {
|
||||
$io->info("Flushed batch of {$batchSize} records. Memory usage: " .
|
||||
round(memory_get_usage() / 1024 / 1024, 2) . "MB");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Финальное сохранение для оставшихся записей
|
||||
$this->entityManager->flush();
|
||||
$this->entityManager->clear();
|
||||
|
||||
if ($debug) {
|
||||
$io->info('Sleep: 2 sec');
|
||||
}
|
||||
|
||||
if (empty($this->nosleep)) {
|
||||
sleep(2);
|
||||
}
|
||||
}
|
||||
|
||||
$io->success('Successful. Total processed: ' . $processedCount);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function getPricelist($depnum)
|
||||
{
|
||||
$response = [];
|
||||
$flag = true;
|
||||
$firstrow = 1;
|
||||
$lastrow = 500;
|
||||
|
||||
while ($flag) {
|
||||
try {
|
||||
$result = $this->client->request('GET', 'pricelist/list', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'timeout' => 60,
|
||||
'base_uri' => $this->widgetApiUrl,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'sovamed_bot'
|
||||
],
|
||||
'query' => [
|
||||
'depnum' => $depnum,
|
||||
'firstrow' => $firstrow,
|
||||
'lastrow' => $lastrow
|
||||
],
|
||||
]);
|
||||
|
||||
$firstrow = $lastrow + 1;
|
||||
$lastrow += 500;
|
||||
|
||||
$resultData = $result->toArray(false); // false чтобы избежать преобразования в объекты
|
||||
|
||||
if (empty($resultData['data'])) {
|
||||
$flag = false;
|
||||
} else {
|
||||
yield $resultData['data']; // Используем генератор для экономии памяти
|
||||
}
|
||||
|
||||
if (empty($this->nosleep)) {
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$flag = false;
|
||||
// Логирование ошибки можно добавить при необходимости
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\PriceDepartment;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:priceDep',
|
||||
description: 'Обновление отделений для услуг',
|
||||
)]
|
||||
class UploadPriceDepCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private HttpClientInterface $client,
|
||||
private string $widgetApiUrl,
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void { }
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$response = $this->client->request('GET', '/pricelist/departments', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'base_uri' => $this->widgetApiUrl,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'sovamed_bot'
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $response->toArray();
|
||||
|
||||
foreach ($response['data'] as $item) {
|
||||
$department = $this->entityManager->getRepository(PriceDepartment::class)
|
||||
->findOneBy([
|
||||
'groupId' => $item['id']
|
||||
]);
|
||||
|
||||
if (is_null($department)) {
|
||||
$department = new PriceDepartment();
|
||||
}
|
||||
|
||||
if (empty($item['viewInWeb'])) {
|
||||
$item['viewInWeb'] = 0;
|
||||
}
|
||||
|
||||
$department
|
||||
->setGroupId($item['id'])
|
||||
->setName($item['name'])
|
||||
->setViewInWeb($item['viewInWeb'])
|
||||
->setDoctCount($item['schCount'])
|
||||
;
|
||||
|
||||
$this->entityManager->persist($department);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$io->success('load: '. $department->getId());
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\PromoCrudService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:promo',
|
||||
description: 'Обновление таблицы promo из view_promo'
|
||||
)]
|
||||
final class UploadPromoCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private PromoCrudService $promoCrudService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('view', null, InputOption::VALUE_OPTIONAL, 'SQL view name', 'public.view_promo');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$viewName = $input->getOption('view');
|
||||
if (empty($viewName)) {
|
||||
$viewName = 'public.view_promo';
|
||||
}
|
||||
$viewName = (string) $viewName;
|
||||
|
||||
$io->title('Promo: sync from view_promo');
|
||||
|
||||
try {
|
||||
$this->logger->info('Promo sync start', ['view' => $viewName]);
|
||||
$affected = $this->promoCrudService->syncFromViewPromo($viewName);
|
||||
$io->success('Sync finished. Affected rows: ' . $affected);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('Promo sync failed', [
|
||||
'view' => $viewName,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\SiteServiceCrudService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'upload:site-services',
|
||||
description: 'Обновление таблицы site_services из public.view_services'
|
||||
)]
|
||||
final class UploadSiteServicesCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private SiteServiceCrudService $siteServiceCrudService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('view', null, InputOption::VALUE_OPTIONAL, 'SQL view name', 'public.view_services');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$viewName = $input->getOption('view');
|
||||
if (empty($viewName)) {
|
||||
$viewName = 'public.view_services';
|
||||
}
|
||||
$viewName = (string) $viewName;
|
||||
|
||||
$io->title('Site services: sync from view_services');
|
||||
|
||||
try {
|
||||
$this->logger->info('Site services sync start', ['view' => $viewName]);
|
||||
$affected = $this->siteServiceCrudService->syncFromViewServices($viewName);
|
||||
$io->success('Sync finished. Affected rows: ' . $affected);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('Site services sync failed', [
|
||||
'view' => $viewName,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$io->error('Ошибка: ' . $e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\Article;
|
||||
use App\Repository\ArticleRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/article')]
|
||||
final class ArticleController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['article:read'];
|
||||
private const WRITE_GROUPS = ['article:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Статьи')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'limit', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'alias', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'article_list', methods: ['GET'])]
|
||||
public function list(Request $request, ArticleRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request));
|
||||
|
||||
return $this->json($this->paginator->paginateWithLegacyMeta($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/alias/{alias}', name: 'article_show_by_alias', methods: ['GET'])]
|
||||
public function showByAlias(string $alias, ArticleRepository $repository): JsonResponse
|
||||
{
|
||||
$article = $repository->findOneByAlias($alias);
|
||||
if (!$article) {
|
||||
throw $this->createNotFoundException('Статья не найдена');
|
||||
}
|
||||
|
||||
return $this->crud->read($article, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'article_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Article $article): JsonResponse
|
||||
{
|
||||
return $this->crud->read($article, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Article::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'article_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, Article::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Article::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'article_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, Article $article): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $article, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'article_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Article $article): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($article);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use App\Service\Client\Interfaces\CalltouchClientServiceInterface;
|
||||
use App\Dto\CalltouchCreateRequestDto;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/calltouch')]
|
||||
final class CalltouchController extends AbstractController
|
||||
{
|
||||
public function __construct (
|
||||
private CalltouchClientServiceInterface $calltouchClientService,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) {}
|
||||
|
||||
#[Route('/create-lead', name: 'app_calltouch_create-lead', methods: ['POST'])]
|
||||
public function createLead(CalltouchCreateRequestDto $dto, Request $request): JsonResponse
|
||||
{
|
||||
$requestData = $request->request->all();
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json(['errors' => (string) $errors], 400);
|
||||
}
|
||||
|
||||
// $response = $this->calltouchClientService->requestCreate($dto);
|
||||
|
||||
return $this->json([
|
||||
'request' => $requestData,
|
||||
// 'data' => $response,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class DefaultController extends AbstractController
|
||||
{
|
||||
#[Route('/', name: 'app_default_comingsoon', methods: ['GET'])]
|
||||
public function comingsoon(): Response
|
||||
{
|
||||
return $this->render('service/comingsoon.html.twig', [
|
||||
'title' => 'Account disabled by server administrator',
|
||||
'message' => 'Account disabled by server administrator',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Department;
|
||||
use App\Repository\DepartmentRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[Route('/department')]
|
||||
final class DepartmentController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) { }
|
||||
|
||||
#[OA\Tag(name: 'Список отделений')]
|
||||
#[Route('/list', name: 'department_list', methods: ['GET'])]
|
||||
public function list(DepartmentRepository $repository): JsonResponse
|
||||
{
|
||||
$departmentList = $repository->activeAll();
|
||||
|
||||
return $this->json([
|
||||
'data' => $departmentList
|
||||
], Response::HTTP_OK, [], [
|
||||
'groups' => ['department:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/{did}',
|
||||
name: 'department_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['did' => '\d+']
|
||||
)]
|
||||
public function update(int $did, Request $request, DepartmentRepository $repository): JsonResponse
|
||||
{
|
||||
$department = $repository->findOneBy(['did' => $did]);
|
||||
|
||||
if (!$department) {
|
||||
return new JsonResponse([
|
||||
'message' => 'Department not found'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Department::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['department:write'],
|
||||
'object_to_populate' => $department
|
||||
]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($department);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($department, Response::HTTP_OK, [], [
|
||||
'groups' => ['department:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/create', name: 'department_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
$department = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Department::class,
|
||||
'json',
|
||||
['groups' => ['department:write']]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($department);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($department);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($department, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['department:read']
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\Disease;
|
||||
use App\Repository\DiseaseRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/disease')]
|
||||
final class DiseaseController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['disease:read'];
|
||||
private const WRITE_GROUPS = ['disease:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Заболевания')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'perPage', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'disease_list', methods: ['GET'])]
|
||||
public function list(Request $request, DiseaseRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request));
|
||||
|
||||
return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'disease_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Disease $disease): JsonResponse
|
||||
{
|
||||
return $this->crud->read($disease, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Disease::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'disease_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, Disease::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Disease::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'disease_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, Disease $disease): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $disease, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'disease_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Disease $disease): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($disease);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Filial;
|
||||
use App\Repository\FilialRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use App\Service\FileUploader\Interfaces\FileUploaderServiceInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use App\Service\Image\Interfaces\ImageServiceInterface;
|
||||
use App\Dto\FileUploadDto;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Exception;
|
||||
|
||||
#[Route('/filial')]
|
||||
final class FilialController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer,
|
||||
private ImageServiceInterface $imageService
|
||||
) { }
|
||||
|
||||
#[OA\Tag(name: 'Список филиалов')]
|
||||
#[Route(path: '/list', name: 'filial_list', methods: ['GET'])]
|
||||
public function list(Request $request, FilialRepository $repository): JsonResponse
|
||||
{
|
||||
$regionId = $request->query->getInt('regionId', 0);
|
||||
$criteria = ['active' => true];
|
||||
if ($regionId > 0) {
|
||||
$criteria['regionId'] = $regionId;
|
||||
}
|
||||
$filials = $repository->findBy($criteria);
|
||||
|
||||
return $this->json(['data' => $filials],
|
||||
Response::HTTP_OK, [], [
|
||||
'groups' => ['filial:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
path: '/by-region/{regionId}',
|
||||
name: 'filial_by_region',
|
||||
methods: ['GET'],
|
||||
requirements: ['regionId' => '\d+']
|
||||
)]
|
||||
public function byRegion(int $regionId, FilialRepository $repository): JsonResponse
|
||||
{
|
||||
$filials = $repository->findBy([
|
||||
'regionId' => $regionId,
|
||||
'active' => true
|
||||
]);
|
||||
|
||||
return $this->json(['data' => $filials]
|
||||
, Response::HTTP_OK, [], [
|
||||
'groups' => ['filial:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/{fid}',
|
||||
name: 'filial_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['fid' => '\d+']
|
||||
)]
|
||||
public function update(int $fid, Request $request, FilialRepository $repository): JsonResponse
|
||||
{
|
||||
$filial = $repository->findOneBy(['fid' => $fid]);
|
||||
|
||||
if (!$filial) {
|
||||
return new JsonResponse([
|
||||
'message' => 'Filial not found'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Filial::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['filial:write'],
|
||||
'object_to_populate' => $filial
|
||||
]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($filial);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($filial, Response::HTTP_OK, [], [
|
||||
'groups' => ['filial:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/create', name: 'filial_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
$filial = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Filial::class,
|
||||
'json',
|
||||
['groups' => ['filial:write']]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($filial);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($filial);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($filial, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['filial:read']
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/picture/{id}', name: 'filial_upload_picture', methods: ['POST'], requirements: ['id' => '\d+'])]
|
||||
public function pictureUpload(
|
||||
Filial $filial,
|
||||
Request $request,
|
||||
FileUploadDto $dto,
|
||||
FileUploaderServiceInterface $fileUploader
|
||||
): JsonResponse {
|
||||
try {
|
||||
$uploadedFile = $request->files->get('picture');
|
||||
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
return $this->json(['error' => 'File not uploaded'], 400);
|
||||
}
|
||||
|
||||
$dto->file = $uploadedFile;
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, 400);
|
||||
}
|
||||
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $filial->getPicture());
|
||||
$fileUploader->setTargetDirectory('filial');
|
||||
$fileName = $fileUploader->upload($uploadedFile);
|
||||
|
||||
$filial->setPicture('filial/'. $fileName);
|
||||
$this->em->persist($filial);
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
return $this->json($filial, 200, [], [
|
||||
'groups' => ['filial:read']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'File upload failed',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/picture/{id}', name: 'filial_picture', methods: ['GET'])]
|
||||
public function filialPicture(Filial $filial, Request $request): Response
|
||||
{
|
||||
$height = min($request->query->getInt('height', 300), 800);
|
||||
$width = min($request->query->getInt('width', 300), 600);
|
||||
|
||||
$uploadDir = $this->getParameter('upload_directory');
|
||||
|
||||
return $this->imageService->getPicture($uploadDir . '/'. $filial->getPicture(), $width, $height);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\Helper\HelperService;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
#[Route('/helper')]
|
||||
final class HelperController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private HelperService $helperService
|
||||
) { }
|
||||
|
||||
#[Route('/text-year', name: 'service_textYear', methods: ['GET'])]
|
||||
public function textYear(Request $request): JsonResponse
|
||||
{
|
||||
$year = $request->query->getInt('year', 0);
|
||||
$exp = $request->query->get('exp', '0') === '1';
|
||||
|
||||
$response = $this->helperService->textYear($year, $exp);
|
||||
|
||||
return $this->json(['data' => $response]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Exception\ClientRequestException;
|
||||
use App\Dto\AnonymousReserveRequestDto;
|
||||
use App\Repository\IdoctorRepository;
|
||||
use App\Service\Interfaces\InfoclinicaServiceInterfaces;
|
||||
use App\Service\Specialist\Interfaces\SpecialistServiceInterface;
|
||||
use App\Service\DecoderJWT\Interfaces\JWTDecoderServiceInterface;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use App\Entity\MarkKiosk;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
|
||||
final class InfoclinicaController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private ValidatorInterface $validator,
|
||||
private SpecialistServiceInterface $specialistService,
|
||||
private SerializerInterface $serializer,
|
||||
private JWTDecoderServiceInterface $jwtDecoderService
|
||||
) { }
|
||||
|
||||
#[IsGranted('ROLE_USER')]
|
||||
#[Route('/infoclinica/clvisitsovacheckpass/{filial}', name: 'clvisitsovacheckpass', requirements: ['filial' => '\d+'], methods: ['GET'])]
|
||||
public function clvisitsovacheckpass(
|
||||
int $filial,
|
||||
Request $request,
|
||||
EntityManagerInterface $entityManager
|
||||
): JsonResponse {
|
||||
// Получаем авторизованного пользователя
|
||||
$user = $this->jwtDecoderService->getUser();
|
||||
|
||||
if (!$user) {
|
||||
return $this->json([
|
||||
'error' => 'Пользователь не найден'
|
||||
], 401);
|
||||
}
|
||||
|
||||
$pcode = $user->getUid();
|
||||
|
||||
// Получаем репозиторий
|
||||
$markKioskRepository = $entityManager->getRepository(MarkKiosk::class);
|
||||
|
||||
// Проверяем, существует ли уже запись
|
||||
$markKiosk = $markKioskRepository->findOneBy([
|
||||
'pcode' => $pcode,
|
||||
'filial' => $filial
|
||||
]);
|
||||
|
||||
// Если записи нет, создаем новую
|
||||
if (!$markKiosk) {
|
||||
$markKiosk = new MarkKiosk();
|
||||
$now = new \DateTimeImmutable();
|
||||
|
||||
$markKiosk->setPcode($pcode);
|
||||
$markKiosk->setFilial($filial);
|
||||
$markKiosk->setCreatedAt($now);
|
||||
$markKiosk->setModifyAt($now);
|
||||
|
||||
$entityManager->persist($markKiosk);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
$markKiosk = $markKioskRepository->findOneBy([
|
||||
'pcode' => $pcode,
|
||||
'filial' => $filial
|
||||
]);
|
||||
|
||||
return $this->json($markKiosk->isResult());
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/idoctor/list', name: 'ic_specialist_list', methods: ['GET'])]
|
||||
public function list(Request $request, IdoctorRepository $repository): JsonResponse
|
||||
{
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 500), 500);
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder(
|
||||
$request->query->all()
|
||||
);
|
||||
|
||||
// Создаем адаптер и пагинатор
|
||||
$adapter = new QueryAdapter($qb);
|
||||
$pagerfanta = new Pagerfanta($adapter);
|
||||
|
||||
// Устанавливаем текущую страницу и количество элементов на странице
|
||||
$pagerfanta->setMaxPerPage($perPage);
|
||||
$pagerfanta->setCurrentPage($page);
|
||||
|
||||
// Получаем элементы для текущей страницы
|
||||
$data = $pagerfanta->getCurrentPageResults();
|
||||
|
||||
// Формируем ответ с метаданными пагинации
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $pagerfanta->getNbResults(),
|
||||
'count' => count($data),
|
||||
'per_page' => $pagerfanta->getMaxPerPage(),
|
||||
'current_page' => $pagerfanta->getCurrentPage(),
|
||||
'total_pages' => $pagerfanta->getNbPages(),
|
||||
'has_previous_page' => $pagerfanta->hasPreviousPage(),
|
||||
'has_next_page' => $pagerfanta->hasNextPage(),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['idoctor:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/reservation/anonymous-reserve', name: 'ic_anonymous_reserve', methods: ['POST'])]
|
||||
public function bookingAnonymous(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$bookingDto = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
AnonymousReserveRequestDto::class,
|
||||
'json'
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($bookingDto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json(['errors' => (string) $errors], 400);
|
||||
}
|
||||
|
||||
$reserve = $this->specialistService->createAnonymousReserve($bookingDto);
|
||||
|
||||
return $this->json($reserve, $reserve['status_code'] ?? 200);
|
||||
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return $this->json([
|
||||
'error' => 'Validation failed',
|
||||
'details' => $e->getMessage()
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Location;
|
||||
use App\Entity\Specialist;
|
||||
use App\Repository\LocationRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use App\Service\Sequence\SequenceService;
|
||||
use Exception;
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
final class LocationController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) { }
|
||||
|
||||
#[Route(path: '/locations/empty', name: 'location_empty', methods: ['GET'])]
|
||||
public function empty(LocationRepository $repository): JsonResponse
|
||||
{
|
||||
$locations = $repository->findBy(['specialist' => null]);
|
||||
|
||||
return $this->json([
|
||||
'data' => $locations
|
||||
], Response::HTTP_OK, [], [
|
||||
'groups' => ['location:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
path: '/specialist/{id}/location/create',
|
||||
name: 'locaion_create',
|
||||
methods: ['POST'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function create(
|
||||
Specialist $specialist,
|
||||
Request $request,
|
||||
SequenceService $sequenceService
|
||||
): JsonResponse {
|
||||
$debugInfo = $sequenceService->debugSequence(Location::class);
|
||||
$sequenceService->syncSequence(Location::class);
|
||||
|
||||
$this->em->clear();
|
||||
|
||||
$location = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Location::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['location:write'],
|
||||
DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'
|
||||
]
|
||||
);
|
||||
|
||||
$location->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($location);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($location);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($location, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['location:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
path: '/specialist/{specialistId}/location/{id}',
|
||||
name: 'location_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['id' => '\d+', 'specialistId' => '\d+']
|
||||
)]
|
||||
public function update(Request $request, int $specialistId, Location $location): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Location::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['location:write'],
|
||||
'object_to_populate' => $location,
|
||||
DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'
|
||||
]
|
||||
);
|
||||
|
||||
$specialist = $this->em->getRepository(Specialist::class)->find($specialistId);
|
||||
|
||||
if (!$specialist) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Специалист не найден'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$location->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($location);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($location, Response::HTTP_OK, [], [
|
||||
'groups' => ['location:read', 'to.specialist:read']
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return new JsonResponse(
|
||||
['error' => 'Произошла ошибка при обновлении локации'],
|
||||
Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/location/{id}', name: 'location_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Location $location): JsonResponse {
|
||||
try {
|
||||
$this->em->remove($location);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\MedicalCenter;
|
||||
use App\Repository\MedicalCenterRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/medical-center')]
|
||||
final class MedicalCenterController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['medical_center:read'];
|
||||
private const WRITE_GROUPS = ['medical_center:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Центры')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'perPage', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', description: 'Если не передан — фильтр active=true (как в старом API).', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'medical_center_list', methods: ['GET'])]
|
||||
public function list(Request $request, MedicalCenterRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request, true));
|
||||
|
||||
return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'medical_center_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(MedicalCenter $medicalCenter): JsonResponse
|
||||
{
|
||||
return $this->crud->read($medicalCenter, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: MedicalCenter::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'medical_center_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, MedicalCenter::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: MedicalCenter::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'medical_center_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, MedicalCenter $medicalCenter): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $medicalCenter, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'medical_center_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(MedicalCenter $medicalCenter): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($medicalCenter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\News;
|
||||
use App\Repository\NewsRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/news')]
|
||||
final class NewsController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['news:read'];
|
||||
private const WRITE_GROUPS = ['news:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Новости')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'perPage', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', description: 'Если не передан — фильтр active=true (как в старом API).', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'news_list', methods: ['GET'])]
|
||||
public function list(Request $request, NewsRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request, true));
|
||||
|
||||
return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'news_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(News $news): JsonResponse
|
||||
{
|
||||
return $this->crud->read($news, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: News::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'news_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, News::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: News::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'news_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, News $news): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $news, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'news_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(News $news): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($news);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\PriceDepartmentRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[Route('/pricelist')]
|
||||
final class PriceDepartmentController extends AbstractController
|
||||
{
|
||||
#[OA\Tag(name: 'Список отделений для услуг и цен')]
|
||||
#[Route('/department', name: 'department_price_list', methods: ['GET'])]
|
||||
public function department(PriceDepartmentRepository $repository): JsonResponse
|
||||
{
|
||||
$departmentList = $repository->findAll();
|
||||
|
||||
return $this->json([
|
||||
'data' => $departmentList
|
||||
], Response::HTTP_OK, [], [
|
||||
'groups' => ['departmentPrice:read']
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\PriceListRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[Route('/pricelist')]
|
||||
final class PriceListController extends AbstractController
|
||||
{
|
||||
#[OA\Tag(name: 'Услуги и цены')]
|
||||
#[OA\Parameter(
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
description: 'номер станицы',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'perPage',
|
||||
in: 'query',
|
||||
description: 'количество записей',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'filial',
|
||||
in: 'query',
|
||||
description: 'id филиала',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'search',
|
||||
in: 'query',
|
||||
description: 'поиск по названию или коду услуги',
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[Route('/list', name: 'pricelist_read_all', methods: ['GET'])]
|
||||
public function readAll(Request $request, PriceListRepository $repository): JsonResponse
|
||||
{
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder(
|
||||
$request->query->all()
|
||||
);
|
||||
|
||||
$adapter = new QueryAdapter($qb);
|
||||
$pagerfanta = new Pagerfanta($adapter);
|
||||
$pagerfanta->setMaxPerPage($perPage);
|
||||
$pagerfanta->setCurrentPage($page);
|
||||
$data = $pagerfanta->getCurrentPageResults();
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $pagerfanta->getNbResults(),
|
||||
'count' => count($data),
|
||||
'per_page' => $pagerfanta->getMaxPerPage(),
|
||||
'current_page' => $pagerfanta->getCurrentPage(),
|
||||
'total_pages' => $pagerfanta->getNbPages(),
|
||||
'has_previous_page' => $pagerfanta->hasPreviousPage(),
|
||||
'has_next_page' => $pagerfanta->hasNextPage(),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['pricelist:read']
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\Promo;
|
||||
use App\Repository\PromoRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/promo')]
|
||||
final class PromoController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['promo:read'];
|
||||
private const WRITE_GROUPS = ['promo:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Акции')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'perPage', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', description: 'Если не передан — фильтр active=true (как в старом API).', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'promo_list', methods: ['GET'])]
|
||||
public function list(Request $request, PromoRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request, true));
|
||||
|
||||
return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'promo_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Promo $promo): JsonResponse
|
||||
{
|
||||
return $this->crud->read($promo, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Promo::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'promo_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, Promo::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: Promo::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'promo_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, Promo $promo): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $promo, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'promo_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Promo $promo): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($promo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\ReviewInputDto;
|
||||
use App\Entity\Review;
|
||||
use App\Entity\Specialist;
|
||||
use App\Entity\User;
|
||||
use App\Repository\ReviewRepository;
|
||||
use App\Repository\SpecialistRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
#[Route('/review')]
|
||||
final class ReviewController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Отзывы')]
|
||||
#[Route('/list', name: 'reviews_list', methods: ['GET'])]
|
||||
public function list(Request $request, ReviewRepository $repository): JsonResponse
|
||||
{
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder(
|
||||
$request->query->all()
|
||||
);
|
||||
|
||||
$adapter = new QueryAdapter($qb);
|
||||
$pagerfanta = new Pagerfanta($adapter);
|
||||
$pagerfanta->setMaxPerPage($perPage);
|
||||
$pagerfanta->setCurrentPage($page);
|
||||
$data = $pagerfanta->getCurrentPageResults();
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $pagerfanta->getNbResults(),
|
||||
'count' => count($data),
|
||||
'per_page' => $pagerfanta->getMaxPerPage(),
|
||||
'current_page' => $pagerfanta->getCurrentPage(),
|
||||
'total_pages' => $pagerfanta->getNbPages(),
|
||||
'has_previous_page' => $pagerfanta->hasPreviousPage(),
|
||||
'has_next_page' => $pagerfanta->hasNextPage(),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['review:read', 'to.specialist:read'],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Отзывы')]
|
||||
#[Route('/{id}', name: 'review_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Review $review): JsonResponse
|
||||
{
|
||||
return $this->json($review, Response::HTTP_OK, [], [
|
||||
'groups' => ['review:read', 'to.specialist:read'],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Отзывы')]
|
||||
#[IsGranted('ROLE_USER')]
|
||||
#[Route('/create', name: 'review_create', methods: ['POST'])]
|
||||
public function create(Request $request, SpecialistRepository $specialistRepository): JsonResponse
|
||||
{
|
||||
try {
|
||||
$dto = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
ReviewInputDto::class,
|
||||
'json'
|
||||
);
|
||||
} catch (ExceptionInterface $e) {
|
||||
return $this->json([
|
||||
'error' => 'Ошибка десериализации',
|
||||
'message' => $e->getMessage(),
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$specialist = $specialistRepository->find((int) $dto->specialistId);
|
||||
if ($specialist === null) {
|
||||
return $this->json(['error' => 'Специалист не найден'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
if (!$user instanceof User) {
|
||||
return $this->json(['error' => 'Требуется авторизация'], Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$review = new Review();
|
||||
$this->applyInput(
|
||||
$review,
|
||||
$dto,
|
||||
$specialist,
|
||||
active: false,
|
||||
externalIdFromAuthenticatedUser: $user->getId(),
|
||||
isNewReview: true,
|
||||
);
|
||||
|
||||
$this->em->persist($review);
|
||||
try {
|
||||
$this->em->flush();
|
||||
} catch (\Throwable $e) {
|
||||
return $this->json([
|
||||
'error' => 'Не удалось сохранить отзыв',
|
||||
'message' => $this->getParameter('kernel.debug') ? $e->getMessage() : 'Внутренняя ошибка сервера',
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->json($review, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['review:read', 'to.specialist:read'],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Отзывы')]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'review_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, Review $review, SpecialistRepository $specialistRepository): JsonResponse
|
||||
{
|
||||
try {
|
||||
$dto = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
ReviewInputDto::class,
|
||||
'json'
|
||||
);
|
||||
} catch (ExceptionInterface $e) {
|
||||
return $this->json([
|
||||
'error' => 'Ошибка десериализации',
|
||||
'message' => $e->getMessage(),
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($dto, null, ['Default', 'review_update']);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$specialist = $specialistRepository->find((int) $dto->specialistId);
|
||||
if ($specialist === null) {
|
||||
return $this->json(['error' => 'Специалист не найден'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->applyInput($review, $dto, $specialist, active: (bool) $dto->active, isNewReview: false);
|
||||
|
||||
try {
|
||||
$this->em->flush();
|
||||
} catch (\Throwable $e) {
|
||||
return $this->json([
|
||||
'error' => 'Не удалось сохранить отзыв',
|
||||
'message' => $this->getParameter('kernel.debug') ? $e->getMessage() : 'Внутренняя ошибка сервера',
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->json($review, Response::HTTP_OK, [], [
|
||||
'groups' => ['review:read', 'to.specialist:read'],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Отзывы')]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'review_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Review $review): JsonResponse
|
||||
{
|
||||
$this->em->remove($review);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Doctrine DBAL DateType ожидает {@see \DateTime}, не {@see \DateTimeImmutable}.
|
||||
*/
|
||||
private function toDoctrineDate(\DateTimeInterface $date): \DateTime
|
||||
{
|
||||
return $date instanceof \DateTime ? clone $date : \DateTime::createFromInterface($date);
|
||||
}
|
||||
|
||||
private function applyInput(
|
||||
Review $review,
|
||||
ReviewInputDto $dto,
|
||||
Specialist $specialist,
|
||||
bool $active,
|
||||
?int $externalIdFromAuthenticatedUser = null,
|
||||
bool $isNewReview = false,
|
||||
): void {
|
||||
$review
|
||||
->setSpecialist($specialist)
|
||||
->setActive($active)
|
||||
->setMessage((string) $dto->message)
|
||||
->setAuthor((string) $dto->author)
|
||||
->setRating((float) $dto->rating)
|
||||
->setSource($dto->source);
|
||||
|
||||
if ($isNewReview) {
|
||||
$review->setDateCreate($this->toDoctrineDate(new \DateTimeImmutable('today')));
|
||||
if ($externalIdFromAuthenticatedUser !== null) {
|
||||
$review->setExternalId($externalIdFromAuthenticatedUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\Client\Interfaces\SmartCaptchaClientServiceInterface;
|
||||
use App\Service\Mail\SendMailConfig;
|
||||
use App\Service\Mail\SendMailService;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Validator\Constraints\Email as EmailConstraint;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
final class ServiceController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private SmartCaptchaClientServiceInterface $smartCaptha,
|
||||
private SendMailService $sendMailService,
|
||||
private ValidatorInterface $validator,
|
||||
private SendMailConfig $sendmailConfig
|
||||
) { }
|
||||
|
||||
#[Route('/service/sendmail', name: 'service_sendmail', methods: ['GET'])]
|
||||
public function sendmail(Request $request): JsonResponse
|
||||
{
|
||||
$accessToken = $this->sendmailConfig->getAccessToken();
|
||||
if ($accessToken === '') {
|
||||
return $this->json(['error' => 'Токен доступа не настроен (MAILER_ACCESS_TOKEN)'], 503);
|
||||
}
|
||||
$token = $request->query->get('token', '');
|
||||
if ($token === '' || !hash_equals($accessToken, $token)) {
|
||||
return $this->json(['error' => 'Неверный или отсутствующий токен доступа'], 403);
|
||||
}
|
||||
|
||||
$mailto = $request->query->get('mailto', '');
|
||||
$subject = $request->query->get('subject', '');
|
||||
$message = $request->query->get('message', '');
|
||||
|
||||
if ($mailto === '') {
|
||||
return $this->json(['error' => 'Параметр mailto обязателен'], 400);
|
||||
}
|
||||
$emailViolations = $this->validator->validate($mailto, [new EmailConstraint()]);
|
||||
if (count($emailViolations) > 0) {
|
||||
return $this->json(['error' => 'Некорректный email в параметре mailto'], 400);
|
||||
}
|
||||
if ($subject === '') {
|
||||
return $this->json(['error' => 'Параметр subject обязателен'], 400);
|
||||
}
|
||||
if ($message === '') {
|
||||
return $this->json(['error' => 'Параметр message обязателен'], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->sendMailService->send($mailto, $subject, $message);
|
||||
return $this->json(['success' => true, 'message' => 'Письмо отправлено']);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->json([
|
||||
'error' => 'Ошибка при отправке письма',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/smart-captcha', name: 'service_smart_captcha', methods: ['POST'])]
|
||||
public function smartCaptcha(Request $request): JsonResponse
|
||||
{
|
||||
$response = $this->smartCaptha->validate(
|
||||
$request->request->get('token', ''),
|
||||
$request->getClientIp()
|
||||
);
|
||||
|
||||
return $this->json($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\SiteService;
|
||||
use App\Repository\SiteServiceRepository;
|
||||
use App\Service\Crud\CrudResponder;
|
||||
use App\Service\Pagination\Paginator;
|
||||
use Nelmio\ApiDocBundle\Attribute\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[Route('/site-services')]
|
||||
final class SiteServiceController extends AbstractController
|
||||
{
|
||||
private const READ_GROUPS = ['site_service:read'];
|
||||
private const WRITE_GROUPS = ['site_service:write'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CrudResponder $crud,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Услуги')]
|
||||
#[OA\Parameter(name: 'page', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'perPage', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'regionId', in: 'query', schema: new OA\Schema(type: 'integer'))]
|
||||
#[OA\Parameter(name: 'active', description: 'Если не передан — фильтр active=true (как в старом API).', in: 'query', schema: new OA\Schema(type: 'boolean'))]
|
||||
#[OA\Parameter(name: 'search', in: 'query', schema: new OA\Schema(type: 'string'))]
|
||||
#[Route('/list', name: 'site_service_list', methods: ['GET'])]
|
||||
public function list(Request $request, SiteServiceRepository $repository): JsonResponse
|
||||
{
|
||||
$qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request, true));
|
||||
|
||||
return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [
|
||||
'groups' => self::READ_GROUPS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'site_service_show', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(SiteService $siteService): JsonResponse
|
||||
{
|
||||
return $this->crud->read($siteService, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: SiteService::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/create', name: 'site_service_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
return $this->crud->create($request, SiteService::class, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[OA\RequestBody(content: new OA\JsonContent(ref: new Model(type: SiteService::class, groups: self::WRITE_GROUPS)))]
|
||||
#[Route('/{id}', name: 'site_service_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Request $request, SiteService $siteService): JsonResponse
|
||||
{
|
||||
return $this->crud->update($request, $siteService, self::WRITE_GROUPS, self::READ_GROUPS);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'site_service_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(SiteService $siteService): JsonResponse
|
||||
{
|
||||
return $this->crud->delete($siteService);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\SpecialistUpdateDto;
|
||||
use App\Dto\SpecialistFilterDto;
|
||||
use App\Dto\FileUploadDto;
|
||||
use App\Entity\Specialist;
|
||||
use App\Dto\ScheduleDto;
|
||||
use App\Service\Image\Interfaces\ImageServiceInterface;
|
||||
use App\Service\Specialist\Interfaces\SpecialistServiceInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use App\Service\FileUploader\Interfaces\FileUploaderServiceInterface;
|
||||
use Exception;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use App\Repository\SpecialistRepository;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[Route('/specialist')]
|
||||
final class SpecialistController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ImageServiceInterface $imageService,
|
||||
private ValidatorInterface $validator,
|
||||
private SpecialistServiceInterface $specialistService,
|
||||
private SerializerInterface $serializer
|
||||
) { }
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/create', name: 'specialist_create', methods: ['POST'])]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$specialist = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Specialist::class,
|
||||
'json',
|
||||
['groups' => ['specialist:write']],
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($specialist);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, 400);
|
||||
}
|
||||
|
||||
$this->em->persist($specialist);
|
||||
$this->em->flush();
|
||||
|
||||
$data = $this->serializer->serialize($specialist, 'json', [
|
||||
'groups' => ['specialist:detail', 'from.specialist:read'],
|
||||
'image_size' => 'large'
|
||||
]);
|
||||
|
||||
return new JsonResponse(
|
||||
$data,
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'application/json'],
|
||||
true
|
||||
);
|
||||
} catch (ExceptionInterface $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Ошибка десериализации',
|
||||
'message' => $e->getMessage()
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'specialist_update', methods: ['PUT'], requirements: ['id' => '\d+'])]
|
||||
public function update(Specialist $specialist, Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Specialist::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['specialist:write'],
|
||||
'object_to_populate' => $specialist,
|
||||
]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($specialist);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
$data = $this->serializer->serialize($specialist, 'json', [
|
||||
'groups' => ['specialist:detail', 'from.specialist:read'],
|
||||
'image_size' => 'large'
|
||||
]);
|
||||
|
||||
return new JsonResponse(
|
||||
$data,
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'application/json'],
|
||||
true
|
||||
);
|
||||
|
||||
} catch (ExceptionInterface $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Ошибка десериализации',
|
||||
'message' => $e->getMessage()
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/{id}', name: 'specialist_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])]
|
||||
public function delete(Specialist $specialist, FileUploaderServiceInterface $fileUploader): JsonResponse
|
||||
{
|
||||
try {
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $specialist->getPreviewPicture());
|
||||
|
||||
$this->em->remove($specialist);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Список врачей')]
|
||||
#[OA\Parameter(
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
description: 'номер станицы',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'perPage',
|
||||
in: 'query',
|
||||
description: 'количество записей',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'filial',
|
||||
in: 'query',
|
||||
description: 'id филиала',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'department',
|
||||
in: 'query',
|
||||
description: 'id отделения',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'search',
|
||||
in: 'query',
|
||||
description: 'поиск по имени',
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[Route('/list', name: 'specialist_list', methods: ['GET'])]
|
||||
public function list(
|
||||
Request $request,
|
||||
SpecialistRepository $repository,
|
||||
): JsonResponse {
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$filter = SpecialistFilterDto::fromRequest($request);
|
||||
$total = $this->specialistService->getFilteredCount($filter);
|
||||
$qb = $repository->createFilteredQueryBuilder($filter->toArray());
|
||||
|
||||
$qb->setFirstResult(($page - 1) * $perPage)
|
||||
->setMaxResults($perPage);
|
||||
|
||||
$paginator = new Paginator($qb->getQuery(), true);
|
||||
$data = iterator_to_array($paginator->getIterator(), false);
|
||||
$totalPages = ceil($total / $perPage);
|
||||
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'count' => count($data),
|
||||
'per_page' => $perPage,
|
||||
'current_page' => $page,
|
||||
'total_pages' => $totalPages,
|
||||
'has_previous_page' => $page > 1,
|
||||
'has_next_page' => $page < $totalPages,
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist:read', 'from.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/post', name: 'specialist_post', methods: ['GET'])]
|
||||
public function specialistPost(SpecialistRepository $specialist): JsonResponse
|
||||
{
|
||||
return $this->json($specialist->post());
|
||||
}
|
||||
|
||||
#[Route('/picture/{id}', name: 'specialist_picture', methods: ['GET'])]
|
||||
public function specialistPicture(Specialist $specialist, Request $request): Response
|
||||
{
|
||||
$height = min($request->query->getInt('height', 300), 800);
|
||||
$width = min($request->query->getInt('width', 300), 600);
|
||||
|
||||
$uploadDir = $this->getParameter('upload_directory');
|
||||
|
||||
$file = $this->specialistService->getLoadPicture($specialist->getId());
|
||||
|
||||
return $this->imageService->getPicture($uploadDir . '/' .$file, $width, $height);
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Расписание врачей')]
|
||||
#[OA\Parameter(
|
||||
name: 'st',
|
||||
in: 'query',
|
||||
description: 'Начальная дата (Ymd)',
|
||||
required:true,
|
||||
schema: new OA\Schema(type: 'integer', format:'Ymd')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'en',
|
||||
in: 'query',
|
||||
description: 'Конечна дата (Ymd)',
|
||||
required:true,
|
||||
schema: new OA\Schema(type: 'integer', format:'Y-m-d')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'dcode',
|
||||
in: 'query',
|
||||
description: 'ID врача',
|
||||
required:true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'filial',
|
||||
in: 'query',
|
||||
description: 'ID филиала',
|
||||
required:true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'onlineMode',
|
||||
in: 'query',
|
||||
description: 'Онлайн расписание',
|
||||
required:true,
|
||||
schema: new OA\Schema(type: 'boolean')
|
||||
)]
|
||||
#[Route('/schedule', name: 'specialist_schedule', methods: ['GET'])]
|
||||
public function specialistSchedule(
|
||||
Request $request,
|
||||
ScheduleDto $dto,
|
||||
): JsonResponse {
|
||||
$dto->st = $request->query->get('st');
|
||||
$dto->en = $request->query->get('en');
|
||||
$dto->dcode = $request->query->get('dcode');
|
||||
$dto->onlineMode = $request->query->getBoolean('onlineMode')? 1: 0;
|
||||
$dto->filial = $request->query->get('filial');
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json(['errors' => (string) $errors], 400);
|
||||
}
|
||||
|
||||
$schedule = $this->specialistService->getSchedule($dto);
|
||||
|
||||
return $this->json($schedule, 200, []);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/picture/{id}', name: 'specialist_upload_picture', methods: ['POST'], requirements: ['id' => '\d+'])]
|
||||
public function specialistUpload(
|
||||
Specialist $specialist,
|
||||
Request $request,
|
||||
FileUploadDto $dto,
|
||||
FileUploaderServiceInterface $fileUploader
|
||||
): JsonResponse {
|
||||
try {
|
||||
$uploadedFile = $request->files->get('previewPicture');
|
||||
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
return $this->json(['error' => 'File not uploaded'], 400);
|
||||
}
|
||||
|
||||
$dto->file = $uploadedFile;
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, 400);
|
||||
}
|
||||
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $specialist->getPreviewPicture());
|
||||
$fileUploader->setTargetDirectory('specialist');
|
||||
$fileName = $fileUploader->upload($uploadedFile);
|
||||
|
||||
$specialist->setPreviewPicture('specialist/'. $fileName);
|
||||
$this->em->persist($specialist);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($specialist, 200, [], [
|
||||
'groups' => ['specialist:detail', 'from.specialist:read']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'File upload failed',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Tag(name: 'Детальная информация врача')]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
in: 'path',
|
||||
description: 'id врача',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[Route('/{id}', name: 'specialist_detal', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Specialist $specialist): JsonResponse
|
||||
{
|
||||
return $this->json($specialist, Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist:detail', 'from.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/by/{identifier}', name: 'specialist_detal_by', methods: ['GET'], requirements: ['identifier' => '[a-zA-Z0-9\-_]+'])]
|
||||
public function showBy(string $identifier, Request $request): JsonResponse
|
||||
{
|
||||
$regionId = $request->query->getInt('regionId');
|
||||
$specialist = $this->specialistService->getSpecialist($identifier, $regionId);
|
||||
|
||||
if (!$specialist) {
|
||||
return $this->json(['error' => 'not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->json($specialist, Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist:detail', 'from.specialist:read']
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Specialist;
|
||||
use App\Entity\SpecialistDcodeDescription;
|
||||
use App\Repository\SpecialistDcodeDescriptionRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
final class SpecialistDcodeDescriptionController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route(
|
||||
path: '/specialist-dcode-description/list',
|
||||
name: 'specialist_dcode_description_list',
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function list(Request $request, SpecialistDcodeDescriptionRepository $repository): JsonResponse
|
||||
{
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder($request->query->all());
|
||||
$pager = new Pagerfanta(new QueryAdapter($qb));
|
||||
$pager->setMaxPerPage($perPage);
|
||||
$pager->setCurrentPage($page);
|
||||
$items = iterator_to_array($pager->getCurrentPageResults());
|
||||
$data = array_map(
|
||||
fn (SpecialistDcodeDescription $item) => $this->normalizeWithSpeciality($item),
|
||||
$items
|
||||
);
|
||||
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $pager->getNbResults(),
|
||||
'count' => count($data),
|
||||
'per_page' => $pager->getMaxPerPage(),
|
||||
'current_page' => $pager->getCurrentPage(),
|
||||
'total_pages' => $pager->getNbPages(),
|
||||
'has_previous_page' => $pager->hasPreviousPage(),
|
||||
'has_next_page' => $pager->hasNextPage(),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
'/specialist-dcode-description/{id}',
|
||||
name: 'specialist_dcode_description_detail',
|
||||
methods: ['GET'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function show(SpecialistDcodeDescription $specialistDcodeDescription): JsonResponse
|
||||
{
|
||||
return $this->json($this->normalizeWithSpeciality($specialistDcodeDescription), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist/{specialistId}/specialist-dcode-description/create',
|
||||
name: 'specialist_dcode_description_create',
|
||||
methods: ['POST'],
|
||||
requirements: ['specialistId' => '\d+']
|
||||
)]
|
||||
public function create(int $specialistId, Request $request): JsonResponse
|
||||
{
|
||||
$specialist = $this->em->getRepository(Specialist::class)->find($specialistId);
|
||||
if (!$specialist) {
|
||||
return $this->json(['error' => 'Специалист не найден'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$entity = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
SpecialistDcodeDescription::class,
|
||||
'json',
|
||||
['groups' => ['specialist.dcode.description:write']]
|
||||
);
|
||||
$entity->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($entity);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($entity);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($this->normalizeWithSpeciality($entity), Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist/{specialistId}/specialist-dcode-description/{id}',
|
||||
name: 'specialist_dcode_description_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['specialistId' => '\d+', 'id' => '\d+']
|
||||
)]
|
||||
public function update(Request $request, int $specialistId, SpecialistDcodeDescription $entity): JsonResponse
|
||||
{
|
||||
try {
|
||||
$specialist = $this->em->getRepository(Specialist::class)->find($specialistId);
|
||||
if (!$specialist) {
|
||||
return $this->json(['error' => 'Специалист не найден'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
SpecialistDcodeDescription::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['specialist.dcode.description:write'],
|
||||
'object_to_populate' => $entity,
|
||||
]
|
||||
);
|
||||
$entity->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($entity);
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($this->normalizeWithSpeciality($entity), Response::HTTP_OK);
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'Произошла ошибка при обновлении',
|
||||
'message' => $e->getMessage(),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist-dcode-description/{id}',
|
||||
name: 'specialist_dcode_description_delete',
|
||||
methods: ['DELETE'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function delete(SpecialistDcodeDescription $entity): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->em->remove($entity);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage(),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizeWithSpeciality(SpecialistDcodeDescription $entity): array
|
||||
{
|
||||
$normalized = json_decode($this->serializer->serialize($entity, 'json', [
|
||||
'groups' => ['specialist.dcode.description:read', 'to.specialist:read'],
|
||||
]), true);
|
||||
|
||||
$normalized['speciality'] = $entity->getSpecialist()?->getPost();
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use App\Dto\FileUploadDto;
|
||||
use App\Entity\SpecialistDocs;
|
||||
use App\Entity\Specialist;
|
||||
use App\Repository\SpecialistDocsRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use App\Service\FileUploader\Interfaces\FileUploaderServiceInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use App\Service\Image\Interfaces\ImageServiceInterface;
|
||||
use Exception;
|
||||
|
||||
final class SpecialistDocsController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private ImageServiceInterface $imageService,
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) { }
|
||||
|
||||
#[Route(
|
||||
path: '/specialist-docs/list',
|
||||
name: 'specialist_docs_list',
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function empty(SpecialistDocsRepository $repository): JsonResponse
|
||||
{
|
||||
return $this->json([
|
||||
'data' => $repository->findAll()
|
||||
], Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist.docs:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('specialist-docs/{id}', name: 'specialist_docs_detal', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(SpecialistDocs $specialistDocs): JsonResponse
|
||||
{
|
||||
return $this->json(
|
||||
$specialistDocs,
|
||||
Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist.docs:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/specialist-docs/picture/{id}', name: 'specialist_docs_picture', methods: ['GET'])]
|
||||
public function specialistPicture(SpecialistDocs $specialistDocs, Request $request): Response
|
||||
{
|
||||
$height = min($request->query->getInt('height', 300), 800);
|
||||
$width = min($request->query->getInt('width', 300), 600);
|
||||
|
||||
$uploadDir = $this->getParameter('upload_directory');
|
||||
|
||||
$file = $specialistDocs->getPicture();
|
||||
|
||||
return $this->imageService->getPicture($uploadDir . '/' .$file, $width, $height);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist/{id}/specialist-docs/create',
|
||||
name: 'specialist_docs_create',
|
||||
methods: ['POST'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function create(Specialist $specialist, Request $request): JsonResponse
|
||||
{
|
||||
$specialistDocs = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
SpecialistDocs::class,
|
||||
'json',
|
||||
['groups' => ['specialist.docs:write']]
|
||||
);
|
||||
|
||||
$specialistDocs->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($specialistDocs);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($specialistDocs);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($specialistDocs, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['specialist.docs:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist/{specialistId}/specialist-docs/{id}',
|
||||
name: 'specialist_docs_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['id' => '\d+', 'specialistId' => '\d+']
|
||||
)]
|
||||
public function update(Request $request, int $specialistId, SpecialistDocs $specialistDocs): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
SpecialistDocs::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['specialist.docs:write'],
|
||||
'object_to_populate' => $specialistDocs
|
||||
]
|
||||
);
|
||||
|
||||
$specialist = $this->em->getRepository(Specialist::class)->find($specialistId);
|
||||
|
||||
if (!$specialist) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Специалист не найден'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$specialistDocs->setSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($specialistDocs);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($specialistDocs, Response::HTTP_OK, [], [
|
||||
'groups' => ['specialist.docs:read', 'to.specialist:read']
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist-docs/{id}',
|
||||
name: 'specialist_docs_delete',
|
||||
methods: ['DELETE'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function delete(SpecialistDocs $specialistDocs, FileUploaderServiceInterface $fileUploader): JsonResponse
|
||||
{
|
||||
try {
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $specialistDocs->getPicture());
|
||||
$this->em->remove($specialistDocs);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/specialist-docs/picture/{id}',
|
||||
name: 'specialist_docs_upload_picture',
|
||||
methods: ['POST'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function uploadPicture(
|
||||
SpecialistDocs $specialistDocs,
|
||||
Request $request,
|
||||
FileUploadDto $dto,
|
||||
FileUploaderServiceInterface $fileUploader
|
||||
): JsonResponse {
|
||||
try {
|
||||
$uploadedFile = $request->files->get('picture');
|
||||
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
return $this->json(['error' => 'File not uploaded'], 400);
|
||||
}
|
||||
|
||||
$dto->file = $uploadedFile;
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, 400);
|
||||
}
|
||||
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $specialistDocs->getPicture());
|
||||
$fileUploader->setTargetDirectory($specialistDocs->getType());
|
||||
|
||||
$fileName = $fileUploader->upload($uploadedFile);
|
||||
|
||||
$specialistDocs->setPicture($specialistDocs->getType() . '/' . $fileName);
|
||||
$this->em->persist($specialistDocs);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($specialistDocs, 200, [], [
|
||||
'groups' => ['specialist.docs:read', 'to.specialist:read']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'File upload failed',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\FileUploadDto;
|
||||
use App\Entity\Stock;
|
||||
use App\Entity\Specialist;
|
||||
use App\Repository\StockRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use App\Service\FileUploader\Interfaces\FileUploaderServiceInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use App\Service\Image\Interfaces\ImageServiceInterface;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Exception;
|
||||
|
||||
final class StockController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private ImageServiceInterface $imageService,
|
||||
private EntityManagerInterface $em,
|
||||
private ValidatorInterface $validator,
|
||||
private SerializerInterface $serializer
|
||||
) { }
|
||||
|
||||
#[Route(
|
||||
path: '/stock/list',
|
||||
name: 'stock_list',
|
||||
methods: ['GET']
|
||||
)]
|
||||
public function list(Request $request, StockRepository $repository): JsonResponse
|
||||
{
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder(
|
||||
$request->query->all()
|
||||
);
|
||||
|
||||
$pager = new Pagerfanta(new QueryAdapter($qb));
|
||||
$pager->setMaxPerPage($perPage);
|
||||
$pager->setCurrentPage($page);
|
||||
$data = $pager->getCurrentPageResults();
|
||||
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $pager->getNbResults(),
|
||||
'count' => count($data),
|
||||
'per_page' => $pager->getMaxPerPage(),
|
||||
'current_page' => $pager->getCurrentPage(),
|
||||
'total_pages' => $pager->getNbPages(),
|
||||
'has_previous_page' => $pager->hasPreviousPage(),
|
||||
'has_next_page' => $pager->hasNextPage(),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('stock/{id}', name: 'stock_detal', methods: ['GET'], requirements: ['id' => '\d+'])]
|
||||
public function show(Stock $stock): JsonResponse
|
||||
{
|
||||
return $this->json($stock, Response::HTTP_OK, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/stock/picture/{id}', name: 'stock_picture', methods: ['GET'])]
|
||||
public function picture(Stock $stock, Request $request): Response
|
||||
{
|
||||
$height = min($request->query->getInt('height', 300), 800);
|
||||
$width = min($request->query->getInt('width', 300), 600);
|
||||
|
||||
$uploadDir = $this->getParameter('upload_directory');
|
||||
|
||||
$file = $stock->getPicture();
|
||||
|
||||
return $this->imageService->getPicture($uploadDir . '/' .$file, $width, $height);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: 'stock/{id}/specialist/{specialistId}',
|
||||
name: 'stock_specialist_update',
|
||||
methods: ['DELETE', 'PUT'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function updateSpecialist(Request $request, int $specialistId, Stock $stock): JsonResponse
|
||||
{
|
||||
$specialist = $this->em->getRepository(Specialist::class)->find($specialistId);
|
||||
|
||||
if (!$specialist) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Специалист не найден'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$request->getMethod() === 'PUT'
|
||||
? $stock->addSpecialist($specialist)
|
||||
: $stock->removeSpecialist($specialist);
|
||||
|
||||
$errors = $this->validator->validate($stock);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($stock, Response::HTTP_OK, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/stock/create',
|
||||
name: 'stock_create',
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
$stock = $this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Stock::class,
|
||||
'json',
|
||||
['groups' => ['stock:write']]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($stock);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->persist($stock);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($stock, Response::HTTP_CREATED, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/stock/{id}',
|
||||
name: 'stock_update',
|
||||
methods: ['PUT'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function update(Request $request, Stock $stock): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->serializer->deserialize(
|
||||
$request->getContent(),
|
||||
Stock::class,
|
||||
'json',
|
||||
[
|
||||
'groups' => ['stock:write'],
|
||||
'object_to_populate' => $stock
|
||||
]
|
||||
);
|
||||
|
||||
$errors = $this->validator->validate($stock);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($stock, Response::HTTP_OK, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/stock/{id}',
|
||||
name: 'stock_delete',
|
||||
methods: ['DELETE'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function delete(Stock $stock, FileUploaderServiceInterface $fileUploader): JsonResponse
|
||||
{
|
||||
try {
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $stock->getPicture());
|
||||
$this->em->remove($stock);
|
||||
$this->em->flush();
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse([
|
||||
'error' => 'Произошла ошибка при удалении',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route(
|
||||
path: '/stock/picture/{id}',
|
||||
name: 'stock_upload_picture',
|
||||
methods: ['POST'],
|
||||
requirements: ['id' => '\d+']
|
||||
)]
|
||||
public function uploadPicture(
|
||||
Stock $stock,
|
||||
Request $request,
|
||||
FileUploadDto $dto,
|
||||
FileUploaderServiceInterface $fileUploader
|
||||
): JsonResponse {
|
||||
try {
|
||||
$uploadedFile = $request->files->get('picture');
|
||||
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
return $this->json(['error' => 'File not uploaded'], 400);
|
||||
}
|
||||
|
||||
$dto->file = $uploadedFile;
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json($errors, 400);
|
||||
}
|
||||
|
||||
$fileUploader->remove($fileUploader->getTargetDirectory() .'/'. $stock->getPicture());
|
||||
$fileUploader->setTargetDirectory('stock');
|
||||
|
||||
$fileName = $fileUploader->upload($uploadedFile);
|
||||
|
||||
$stock->setPicture('stock/' . $fileName);
|
||||
$this->em->persist($stock);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->json($stock, 200, [], [
|
||||
'groups' => ['stock:read', 'to.specialist:read']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return $this->json([
|
||||
'error' => 'File upload failed',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Dto\RegionDto;
|
||||
use App\Dto\UserAuthDto;
|
||||
use App\Dto\UserLoginDto;
|
||||
use App\Dto\UserUidAuthDto;
|
||||
use App\Service\DecoderJWT\Interfaces\JWTDecoderServiceInterface;
|
||||
use App\Service\User\Interfaces\AuthenticationServiceInterface;
|
||||
use App\Service\User\Interfaces\UserProfileServiceInterface;
|
||||
use App\Service\User\Interfaces\RegistrationServiceInterface;
|
||||
use App\Repository\UserRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
#[Route('/user')]
|
||||
final class UserController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private AuthenticationServiceInterface $auth,
|
||||
private JWTTokenManagerInterface $jwtManager,
|
||||
private ValidatorInterface $validator,
|
||||
private UserRepository $userRepository,
|
||||
private EntityManagerInterface $em
|
||||
) { }
|
||||
|
||||
#[Route('/logout', name:'user_logout', methods:['GET'])]
|
||||
public function logout(): JsonResponse
|
||||
{
|
||||
return $this->json(['successful' => true]);
|
||||
}
|
||||
|
||||
#[Route('/login', name: 'user_login', methods: ['POST'])]
|
||||
#[OA\Tag(name: 'Авторизация пользователя')]
|
||||
#[OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'username', type: 'string', description: 'Email пользователя'),
|
||||
new OA\Property(property: 'password', type: 'string', description: 'Пароль пользователя')
|
||||
],
|
||||
required: ['username', 'password']
|
||||
)
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 200,
|
||||
description: 'Успешная авторизация',
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'successful', type: 'boolean'),
|
||||
new OA\Property(property: 'token', type: 'string', description: 'JWT токен'),
|
||||
new OA\Property(property: 'user', type: 'object', description: 'Данные пользователя')
|
||||
]
|
||||
)
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 400,
|
||||
description: 'Ошибка валидации или неверные учетные данные'
|
||||
)]
|
||||
public function login(UserLoginDto $dto, Request $request): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true);
|
||||
|
||||
if (!$data || !isset($data['username']) || !isset($data['password'])) {
|
||||
return new JsonResponse(['message' => 'Missing credentials'], 400);
|
||||
}
|
||||
|
||||
$dto->email = $data['username'] ?? null;
|
||||
$dto->password = $data['password'] ?? null;
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'errors' => (string) $errors
|
||||
], 400);
|
||||
}
|
||||
|
||||
$userData = $this->auth->jsonAuth($dto);
|
||||
if ($userData['isPasswordValid'] === false || $userData['user'] === null) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'message' => 'Не правильное имя пользователя или пароль'
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Обновляем дату и время авторизации
|
||||
$userData['user']->updateLoggedIn();
|
||||
$this->em->flush();
|
||||
|
||||
$user = $userData['user']->toArray();
|
||||
|
||||
return new JsonResponse([
|
||||
'successful' => true,
|
||||
'token' => $this->jwtManager->create($userData['user']),
|
||||
'user' => $user
|
||||
], 200);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_USER')]
|
||||
#[Route('/', name: 'user_current', methods: ['GET'])]
|
||||
public function index(JWTDecoderServiceInterface $jwtDecoderService): JsonResponse
|
||||
{
|
||||
$user = $jwtDecoderService->getUser();
|
||||
$user = $user->toArray();
|
||||
|
||||
return $this->json([
|
||||
'user' => $user,
|
||||
'successful' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_USER')]
|
||||
#[Route('/change-region', name: 'user_change_region', methods: ['PUT'])]
|
||||
public function changeRegion(
|
||||
UserProfileServiceInterface $userService,
|
||||
RegionDto $dto,
|
||||
Request $request
|
||||
): JsonResponse {
|
||||
|
||||
$data = json_decode($request->getContent(), true);
|
||||
$dto->regionId = $data['regionId'];
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json(['errors' => (string) $errors], 400);
|
||||
}
|
||||
|
||||
$user = $userService->updateRegion($dto);
|
||||
$user = $user->toArray();
|
||||
|
||||
return $this->json([
|
||||
'user' => $user,
|
||||
'successful' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/auth', name: 'user_auth', methods: ['POST'])]
|
||||
public function auth(
|
||||
RegistrationServiceInterface $registration,
|
||||
UserAuthDto $dto,
|
||||
Request $request
|
||||
): JsonResponse {
|
||||
$data = json_decode($request->getContent(), true);
|
||||
|
||||
$dto->uid = $data['uid'] ?? null;
|
||||
$dto->regionId = $data['regionId'] ?? null;
|
||||
$dto->email = $data['email'] ?? null;
|
||||
$dto->password = $data['password'] ?? null;
|
||||
$dto->birthDate = $data['bdate'] ?? null;
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'errors' => (string) $errors
|
||||
], 400);
|
||||
}
|
||||
|
||||
$userData = $this->auth->jwtAuth($dto);
|
||||
|
||||
if ($userData['isPasswordValid'] === false) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'message' => 'Не правильное имя пользователя или пароль'
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($userData['user'] === null) {
|
||||
$userData['user'] = $registration->create($dto);
|
||||
}
|
||||
|
||||
// Обновляем дату и время авторизации
|
||||
$userData['user']->updateLoggedIn();
|
||||
$this->em->flush();
|
||||
|
||||
$user = $userData['user']->toArray();
|
||||
|
||||
return $this->json([
|
||||
'successful' => true,
|
||||
'token' => $this->jwtManager->create($userData['user']),
|
||||
'user' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/auth-by-pcode', name: 'user_auth_by_pcode', methods: ['POST'])]
|
||||
#[OA\Tag(name: 'Авторизация пользователя')]
|
||||
#[OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'pcode', type: 'integer', description: 'Pcode пользователя (UID)'),
|
||||
new OA\Property(property: 'birthDate', type: 'string', description: 'Дата рождения в формате Ymd (например, 19900101) или Y-m-d (например, 1990-01-01)')
|
||||
],
|
||||
required: ['pcode', 'birthDate']
|
||||
)
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 200,
|
||||
description: 'Успешная авторизация. Если пользователь не найден, он будет создан автоматически',
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'successful', type: 'boolean'),
|
||||
new OA\Property(property: 'token', type: 'string', description: 'JWT токен'),
|
||||
new OA\Property(property: 'user', type: 'object', description: 'Данные пользователя')
|
||||
]
|
||||
)
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 400,
|
||||
description: 'Ошибка валидации'
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 500,
|
||||
description: 'Ошибка при создании пользователя'
|
||||
)]
|
||||
public function authByPcode(
|
||||
RegistrationServiceInterface $registration,
|
||||
UserUidAuthDto $dto,
|
||||
Request $request
|
||||
): JsonResponse {
|
||||
$data = json_decode($request->getContent(), true);
|
||||
|
||||
$dto->uid = $data['pcode'] ?? null;
|
||||
$dto->birthDate = $data['birthDate'] ?? $data['bdate'] ?? null;
|
||||
|
||||
$errors = $this->validator->validate($dto);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'errors' => (string) $errors
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Парсим дату рождения
|
||||
$birthDate = \DateTime::createFromFormat('Ymd', $dto->birthDate);
|
||||
if (!$birthDate) {
|
||||
$birthDate = \DateTime::createFromFormat('Y-m-d', $dto->birthDate);
|
||||
}
|
||||
if (!$birthDate) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'errors' => 'Неверный формат даты рождения. Используйте формат Ymd (например, 19900101) или Y-m-d (например, 1990-01-01)'
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Ищем пользователя по uid и birthDate
|
||||
$user = $this->userRepository->findOneByUidAndBirthDate($dto->uid, $birthDate);
|
||||
|
||||
// Если пользователь не найден, создаем его
|
||||
if ($user === null) {
|
||||
try {
|
||||
$user = $registration->createByUidAndBirthDate($dto);
|
||||
} catch (\Exception $e) {
|
||||
return $this->json([
|
||||
'successful' => false,
|
||||
'errors' => 'Ошибка при создании пользователя: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем дату и время авторизации
|
||||
$user->updateLoggedIn();
|
||||
$this->em->flush();
|
||||
|
||||
$userArray = $user->toArray();
|
||||
|
||||
return $this->json([
|
||||
'successful' => true,
|
||||
'token' => $this->jwtManager->create($user),
|
||||
'user' => $userArray
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
final class UsrlogController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
#[Autowire(service: 'doctrine.dbal.cabinet_connection')]
|
||||
private readonly Connection $cabinetConnection
|
||||
) {
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_LOGS')]
|
||||
#[Route('/usrlog/list', name: 'usrlog_list', methods: ['GET'])]
|
||||
public function list(Request $request): JsonResponse
|
||||
{
|
||||
$limit = min(max(1, $request->query->getInt('limit', 50)), 500);
|
||||
$offset = max(0, $request->query->getInt('offset', 0));
|
||||
$usrlogTable = 'public.usrlog';
|
||||
|
||||
$date = $request->query->get('date');
|
||||
$dateFrom = null;
|
||||
$dateTo = null;
|
||||
|
||||
if ($date !== null && $date !== '') {
|
||||
$dateFrom = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $date . ' 00:00:00');
|
||||
$dateTo = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $date . ' 23:59:59');
|
||||
|
||||
if (!$dateFrom || !$dateTo) {
|
||||
return $this->json([
|
||||
'error' => 'Invalid date format. Expected Y-m-d.',
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
$countQb = $this->cabinetConnection->createQueryBuilder()
|
||||
->select('COUNT(*)')
|
||||
->from($usrlogTable, 'u');
|
||||
|
||||
$listQb = $this->cabinetConnection->createQueryBuilder()
|
||||
->select('u.id', 'u.pcode', 'u.agent', 'u.client_ip', 'u.method', 'u.created_at')
|
||||
->from($usrlogTable, 'u')
|
||||
->orderBy('u.created_at', 'DESC')
|
||||
->setFirstResult($offset)
|
||||
->setMaxResults($limit);
|
||||
|
||||
if ($dateFrom && $dateTo) {
|
||||
$countQb
|
||||
->andWhere('u.created_at BETWEEN :date_from AND :date_to')
|
||||
->setParameter('date_from', $dateFrom->format('Y-m-d H:i:s'), ParameterType::STRING)
|
||||
->setParameter('date_to', $dateTo->format('Y-m-d H:i:s'), ParameterType::STRING);
|
||||
|
||||
$listQb
|
||||
->andWhere('u.created_at BETWEEN :date_from AND :date_to')
|
||||
->setParameter('date_from', $dateFrom->format('Y-m-d H:i:s'), ParameterType::STRING)
|
||||
->setParameter('date_to', $dateTo->format('Y-m-d H:i:s'), ParameterType::STRING);
|
||||
}
|
||||
|
||||
$total = (int) $countQb->executeQuery()->fetchOne();
|
||||
$rows = $listQb->executeQuery()->fetchAllAssociative();
|
||||
|
||||
$currentPage = $limit > 0 ? (int) floor($offset / $limit) + 1 : 1;
|
||||
$totalPages = $total > 0 ? (int) ceil($total / $limit) : 0;
|
||||
|
||||
return $this->json([
|
||||
'data' => $rows,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'count' => count($rows),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'current_page' => $currentPage,
|
||||
'total_pages' => $totalPages,
|
||||
'has_previous_page' => $offset > 0,
|
||||
'has_next_page' => ($offset + $limit) < $total,
|
||||
],
|
||||
], Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\WebGetDocinfoRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[Route('/docinfo')]
|
||||
final class WebGetDocinfoController extends AbstractController
|
||||
{
|
||||
|
||||
#[Route('/list', name: 'web_get_docinfo_list', methods: ['GET'])]
|
||||
#[OA\Tag(name: 'WebGetDocinfo')]
|
||||
#[OA\Parameter(
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
description: 'Номер страницы',
|
||||
schema: new OA\Schema(type: 'integer', default: 1)
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'perPage',
|
||||
in: 'query',
|
||||
description: 'Количество записей на странице',
|
||||
schema: new OA\Schema(type: 'integer', default: 100, maximum: 500)
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
in: 'query',
|
||||
description: 'Фильтр по id',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'sourceTable',
|
||||
in: 'query',
|
||||
description: 'Фильтр по source_table',
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'filial',
|
||||
in: 'query',
|
||||
description: 'Фильтр по filial',
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'search',
|
||||
in: 'query',
|
||||
description: 'Поиск по docName и docPost',
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
public function list(
|
||||
Request $request,
|
||||
WebGetDocinfoRepository $repository
|
||||
): JsonResponse {
|
||||
$page = $request->query->getInt('page', 1);
|
||||
$perPage = min($request->query->getInt('perPage', 100), 500);
|
||||
|
||||
$filters = [];
|
||||
if ($request->query->has('id')) {
|
||||
$filters['id'] = $request->query->getInt('id');
|
||||
}
|
||||
if ($request->query->has('sourceTable')) {
|
||||
$filters['sourceTable'] = $request->query->get('sourceTable');
|
||||
}
|
||||
if ($request->query->has('filial')) {
|
||||
$filters['filial'] = $request->query->getInt('filial');
|
||||
}
|
||||
if ($request->query->has('search')) {
|
||||
$filters['search'] = $request->query->get('search');
|
||||
}
|
||||
|
||||
$qb = $repository->createFilteredQueryBuilder($filters);
|
||||
|
||||
// Подсчет общего количества
|
||||
$countQb = clone $qb;
|
||||
$countQb->select('COUNT(w.id)');
|
||||
$total = (int) $countQb->getQuery()->getSingleScalarResult();
|
||||
|
||||
// Пагинация
|
||||
$qb->setFirstResult(($page - 1) * $perPage)
|
||||
->setMaxResults($perPage);
|
||||
|
||||
$data = $qb->getQuery()->getResult();
|
||||
$totalPages = ceil($total / $perPage);
|
||||
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'count' => count($data),
|
||||
'per_page' => $perPage,
|
||||
'current_page' => $page,
|
||||
'total_pages' => $totalPages,
|
||||
'has_previous_page' => $page > 1,
|
||||
'has_next_page' => $page < $totalPages,
|
||||
],
|
||||
];
|
||||
|
||||
return $this->json($response, Response::HTTP_OK, [], [
|
||||
'groups' => ['web_get_docinfo:read']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/dms/{filial}/{dcode}', name: 'web_get_docinfo_dms', methods: ['GET'])]
|
||||
#[OA\Tag(name: 'WebGetDocinfo')]
|
||||
#[OA\Parameter(
|
||||
name: 'filial',
|
||||
in: 'path',
|
||||
description: 'ID филиала',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'dcode',
|
||||
in: 'path',
|
||||
description: 'ID записи (dcode)',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 200,
|
||||
description: 'Информация о DMS',
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'dms', type: 'integer', nullable: true, description: 'Информация о DMS из поля accepts_dms')
|
||||
]
|
||||
)
|
||||
)]
|
||||
#[OA\Response(
|
||||
response: 404,
|
||||
description: 'Запись не найдена'
|
||||
)]
|
||||
public function getDms(
|
||||
int $filial,
|
||||
int $dcode,
|
||||
WebGetDocinfoRepository $repository
|
||||
): JsonResponse {
|
||||
$docinfo = $repository->findByFilialAndId($filial, $dcode);
|
||||
|
||||
if (!$docinfo) {
|
||||
return $this->json(['error' => 'not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->json([
|
||||
'dms' => $docinfo->getAcceptsDms()
|
||||
], Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\XmlFeedGenerator\XmlFeedGeneratorService;
|
||||
use App\Service\XmlFeedGenerator\XmlFeedGeneratorV1Service;
|
||||
use App\Service\Specialist\SpecialistService;
|
||||
use App\Service\Location\LocationService;
|
||||
use App\Service\PriceList\PriceListService;
|
||||
use App\Repository\FilialRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
final class XmlFeedController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private XmlFeedGeneratorService $xmlFeed,
|
||||
private XmlFeedGeneratorV1Service $xmlFeedv1,
|
||||
private SpecialistService $specialistService,
|
||||
private FilialRepository $filialRepository,
|
||||
private LocationService $locationService,
|
||||
private PriceListService $priceListService,
|
||||
|
||||
) {}
|
||||
|
||||
#[Route('/xml/feed', name: 'yandex_feed', methods:['GET'])]
|
||||
public function generateFeed(Request $request): Response
|
||||
{
|
||||
$currentFilial = $this->filialRepository->findOneBy([
|
||||
'fid' => $request->query->getInt('filial', 0)
|
||||
]);
|
||||
|
||||
if (!$currentFilial) {
|
||||
return new Response();
|
||||
}
|
||||
|
||||
// Собираем UTM-параметры из запроса
|
||||
$utmParams = [
|
||||
'utm_source' => $request->query->get('utm_source'),
|
||||
'utm_medium' => $request->query->get('utm_medium'),
|
||||
'utm_campaign' => $request->query->get('utm_campaign'),
|
||||
'utm_term' => $request->query->get('utm_term'),
|
||||
'utm_content' => $request->query->get('utm_content'),
|
||||
];
|
||||
|
||||
$xmlContent = $this->xmlFeed->generateFeed($currentFilial, $utmParams);
|
||||
|
||||
$response = new Response($xmlContent);
|
||||
$response->headers->set('Content-Type', 'application/xml; charset=utf-8');
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Route('/xml/feed/v1', name: 'yandex_feed_v1', methods:['GET'])]
|
||||
public function generateFeedV1(Request $request): Response
|
||||
{
|
||||
$filialsParam = $request->query->get('filials');
|
||||
$regionId = $request->query->getInt('regionId', 0);
|
||||
|
||||
if ($filialsParam !== null && $filialsParam !== '') {
|
||||
$allowedFids = array_map('intval', array_filter(explode(',', $filialsParam)));
|
||||
if ($allowedFids !== []) {
|
||||
// При явном списке filials — загружаем по fid и active, без привязки к regionId
|
||||
$filials = $this->filialRepository->findBy(
|
||||
['fid' => $allowedFids, 'active' => true],
|
||||
['fid' => 'ASC']
|
||||
);
|
||||
$byFid = [];
|
||||
foreach ($filials as $f) {
|
||||
$byFid[$f->getFid()] = $f;
|
||||
}
|
||||
$filials = [];
|
||||
foreach ($allowedFids as $fid) {
|
||||
if (isset($byFid[$fid])) {
|
||||
$filials[] = $byFid[$fid];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$filials = [];
|
||||
}
|
||||
} else {
|
||||
$filials = $this->filialRepository->findBy(
|
||||
[
|
||||
'regionId' => $regionId,
|
||||
'active' => true,
|
||||
],
|
||||
['fid' => 'ASC']
|
||||
);
|
||||
}
|
||||
|
||||
if ($filials === []) {
|
||||
return new Response();
|
||||
}
|
||||
|
||||
$xmlContent = $this->xmlFeedv1->generateFeed($filials);
|
||||
|
||||
$response = new Response($xmlContent);
|
||||
$response->headers->set('Content-Type', 'application/xml; charset=utf-8');
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class AnonymousReserveRequestDto
|
||||
{
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('boolean')]
|
||||
public bool $accept = true;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
#[Assert\Length(min: 2, max: 100)]
|
||||
public string $fio;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
public string $captcha;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Email]
|
||||
public string $email;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
#[Assert\Regex(
|
||||
pattern: '/^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$/',
|
||||
message: 'Телефон должен быть в формате: +7(999)999-99-99'
|
||||
)]
|
||||
public string $phone;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
#[Assert\Regex('/^\d{2}:\d{2}-\d{2}:\d{2}$/')]
|
||||
public string $time;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
#[Assert\Regex('/^\d{8}$/')]
|
||||
public string $workDate;
|
||||
|
||||
#[Assert\Type('array')]
|
||||
public array $services = [];
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('integer')]
|
||||
public int $filial;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('integer')]
|
||||
public int $timezone = 3;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('integer')]
|
||||
public int $schedident;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('string')]
|
||||
public string $rnum;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Type('integer')]
|
||||
public int $specialist;
|
||||
|
||||
public function resetveToArray(): array
|
||||
{
|
||||
|
||||
$timeParts = explode('-', $this->time);
|
||||
|
||||
return [
|
||||
'date' => $this->workDate,
|
||||
'st' => $timeParts[0],
|
||||
'en' => $timeParts[1],
|
||||
'services' => $this->services,
|
||||
'filial' => $this->filial,
|
||||
'timezone' => $this->timezone,
|
||||
'schedident' => $this->schedident,
|
||||
'rnum' => $this->rnum,
|
||||
'dcode' => $this->specialist,
|
||||
];
|
||||
}
|
||||
|
||||
public function toJson(): string
|
||||
{
|
||||
return json_encode($this->resetveToArray(), JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'accept' => $this->accept,
|
||||
'fio' => $this->fio,
|
||||
'captcha' => $this->captcha,
|
||||
'email' => $this->email,
|
||||
'phone' => $this->phone,
|
||||
'reserve' => $this->toJson()
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
|
||||
// use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CalltouchCreateRequestDto
|
||||
{
|
||||
public int $regionId;
|
||||
public string $requestNumber;
|
||||
public string $subject;
|
||||
public string $requestUrl;
|
||||
public string $requestDate;
|
||||
public ?string $sessionId;
|
||||
public ?string $phoneNumber;
|
||||
public ?string $email;
|
||||
public ?string $fio;
|
||||
public array $addTags;
|
||||
public array $customSources;
|
||||
public array $customFields;
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'requestNumber' => $this->requestNumber,
|
||||
'subject' => $this->subject,
|
||||
'requestUrl' => $this->requestUrl,
|
||||
'requestDate' => $this->requestDate,
|
||||
'sessionId' => $this->sessionId,
|
||||
'phoneNumber' => $this->phoneNumber,
|
||||
'email' => $this->email,
|
||||
'fio' => $this->fio,
|
||||
'addTags' => $this->addTags,
|
||||
'customSources' => $this->customSources,
|
||||
'customFields' => $this->customFields
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Content;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
final readonly class ContentFilterDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?int $regionId = null,
|
||||
public ?bool $active = null,
|
||||
public ?string $alias = null,
|
||||
public ?string $search = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?bool $defaultActive если задан (например, true), подставляется,
|
||||
* когда query-параметр `active` отсутствует или пустой.
|
||||
* Легаси: в старых list-эндпоинтах News/Promo/MedicalCenter/SiteService
|
||||
* при отсутствии `active` подразумевалось active = true.
|
||||
*/
|
||||
public static function fromRequest(Request $request, ?bool $defaultActive = null): self
|
||||
{
|
||||
$active = self::nullableBool($request->query->get('active'));
|
||||
|
||||
return new self(
|
||||
regionId: self::positiveInt($request->query->get('regionId', $request->query->get('region_id'))),
|
||||
active: $active ?? $defaultActive,
|
||||
alias: self::nonEmptyString($request->query->get('alias')),
|
||||
search: self::nonEmptyString($request->query->get('search', $request->query->get('q'))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Symfony QueryBag может отдать массив при ?regionId[]=… — не передаём его в is_numeric (TypeError в PHP 8).
|
||||
*/
|
||||
private static function positiveInt(mixed $value): ?int
|
||||
{
|
||||
if ($value === null || $value === '' || !is_scalar($value) || !is_numeric($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = (int) $value;
|
||||
|
||||
return $value > 0 ? $value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* При ?active[]=… query->get вернёт массив — отбрасываем без вызова filter_var по нему.
|
||||
*/
|
||||
private static function nullableBool(mixed $value): ?bool
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_scalar($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
}
|
||||
|
||||
private static function nonEmptyString(mixed $value): ?string
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
|
||||
return $value !== '' ? $value : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class FileUploadDto
|
||||
{
|
||||
#[Assert\NotBlank(message: 'Файл не должен быть пустым')]
|
||||
#[Assert\File(
|
||||
maxSize: '5M',
|
||||
mimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
||||
mimeTypesMessage: 'Пожалуйста, загрузите файл в формате JPG, PNG или webp'
|
||||
)]
|
||||
public ?UploadedFile $file = null;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class RegionDto
|
||||
{
|
||||
#[Assert\NotNull(message: "regionId не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "regionId должен быть целым числом")]
|
||||
#[Assert\Positive(message: "regionId должен быть положительным числом")]
|
||||
public ?int $regionId;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
// use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class RegistrationDto
|
||||
{
|
||||
public bool $accept = false;
|
||||
public string $firstName;
|
||||
public string $lastName;
|
||||
public string $middleName;
|
||||
public bool $refuseCall = true;
|
||||
public bool $refuseSms = true;
|
||||
public string $birthDate;
|
||||
public string $email;
|
||||
public string $phone;
|
||||
public bool $confirmed;
|
||||
public int $gender = 1; // male 1 | female 0
|
||||
public string $checkData;
|
||||
public string $captcha;
|
||||
public string $snils;
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'accept' => $this->accept,
|
||||
'firstName' => $this->firstName,
|
||||
'lastName' => $this->lastName,
|
||||
'middleName' => $this->middleName,
|
||||
'refuseCall' => $this->refuseCall,
|
||||
'refuseSms' => $this->refuseSms,
|
||||
'email' => $this->email,
|
||||
'phone' => $this->phone,
|
||||
'confirmed' => $this->confirmed,
|
||||
'gender' => $this->gender,
|
||||
'checkData' => $this->checkData,
|
||||
'captcha' => $this->captcha,
|
||||
'snils' => $this->snils
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
final class ReviewInputDto
|
||||
{
|
||||
#[Assert\NotNull(message: 'Укажите идентификатор специалиста')]
|
||||
#[Assert\Type(type: 'numeric', message: 'specialistId должен быть числом')]
|
||||
public mixed $specialistId = null;
|
||||
|
||||
#[Assert\NotNull(groups: ['review_update'], message: 'Укажите active')]
|
||||
public ?bool $active = null;
|
||||
|
||||
#[Assert\NotBlank(message: 'Укажите текст отзыва')]
|
||||
public ?string $message = null;
|
||||
|
||||
#[Assert\NotBlank(message: 'Укажите автора')]
|
||||
#[Assert\Length(max: 255)]
|
||||
public ?string $author = null;
|
||||
|
||||
#[Assert\NotNull(message: 'Укажите оценку')]
|
||||
#[Assert\Range(min: 1, max: 5, notInRangeMessage: 'Оценка должна быть от {{ min }} до {{ max }}')]
|
||||
public ?float $rating = null;
|
||||
|
||||
#[Assert\Length(max: 255)]
|
||||
public ?string $source = null;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
class ScheduleDayDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $schedident,
|
||||
public string $rnum,
|
||||
public string $dcode,
|
||||
public int $filial,
|
||||
public array $intervals,
|
||||
public string $depnum,
|
||||
public bool $isFree
|
||||
) {}
|
||||
}
|
||||
|
||||
class ScheduleIntervalDto
|
||||
{
|
||||
public function __construct(
|
||||
public string $time,
|
||||
public bool $isFree
|
||||
) {}
|
||||
}
|
||||
|
||||
class ScheduleResponseDto
|
||||
{
|
||||
public function __construct(
|
||||
public array $schedule = [],
|
||||
public array $nearestDate = []
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class ScheduleDto
|
||||
{
|
||||
#[Assert\NotNull(message: "st не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "st должен быть целым числом")]
|
||||
#[Assert\Positive(message: "st должен быть положительным числом")]
|
||||
public ?int $st;
|
||||
|
||||
#[Assert\NotNull(message: "en не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "en должен быть целым числом")]
|
||||
#[Assert\Positive(message: "en должен быть положительным числом")]
|
||||
public ?int $en;
|
||||
|
||||
#[Assert\NotNull(message: "dcode не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "dcode должен быть целым числом")]
|
||||
#[Assert\Positive(message: "dcode должен быть положительным числом")]
|
||||
public ?int $dcode;
|
||||
|
||||
#[Assert\NotNull(message: "filial не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "filial должен быть целым числом")]
|
||||
#[Assert\Positive(message: "filial должен быть положительным числом")]
|
||||
public ?int $filial;
|
||||
|
||||
#[Assert\NotNull(message: "onlineMode не может быть пустым")]
|
||||
#[Assert\Type(type: 'boolean', message: "onlineMode должен быть булевом")]
|
||||
public ?bool $onlineMode;
|
||||
|
||||
public function toQueryString(): string
|
||||
{
|
||||
return http_build_query([
|
||||
'st' => $this->st,
|
||||
'en' => $this->en,
|
||||
'dcode' => $this->dcode,
|
||||
'onlineMode' => $this->onlineMode,
|
||||
'filialId' => $this->filial,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class SpecialistFilterDto
|
||||
{
|
||||
public ?bool $active = null;
|
||||
public ?array $sType = null;
|
||||
public ?int $regionId = null;
|
||||
public ?array $dcode = null;
|
||||
public ?string $department = null;
|
||||
public ?string $alias = null;
|
||||
public ?array $tags = null;
|
||||
public ?bool $onlineMode = null;
|
||||
public ?string $dateFrom = null;
|
||||
public ?string $dateTo = null;
|
||||
public ?array $kodoper = null;
|
||||
public ?string $search = null;
|
||||
public ?string $category = null;
|
||||
public ?string $patientAge = null;
|
||||
public ?bool $displaySchedule = null;
|
||||
public ?string $orderBy = null;
|
||||
public ?int $filial = null;
|
||||
public ?array $sFilial = null;
|
||||
public ?bool $kiosk = null;
|
||||
|
||||
public static function fromRequest(Request $request): self
|
||||
{
|
||||
$dto = new self();
|
||||
|
||||
$dto->active = $request->query->has('active')
|
||||
? filter_var($request->query->get('active'), FILTER_VALIDATE_BOOLEAN)
|
||||
: null;
|
||||
$dto->sType = $request->query->all('sType');
|
||||
$dto->regionId = $request->query->getInt('regionId', 0) ?: null;
|
||||
$dto->dcode = $request->query->all('dcode');
|
||||
$dto->department = $request->query->get('department');
|
||||
$dto->alias = $request->query->get('alias');
|
||||
$dto->tags = $request->query->all('tags');
|
||||
$dto->onlineMode = $request->query->has('onlineMode')
|
||||
? filter_var($request->query->get('onlineMode'), FILTER_VALIDATE_BOOLEAN)
|
||||
: null;
|
||||
$dto->dateFrom = $request->query->get('dateFrom');
|
||||
$dto->dateTo = $request->query->get('dateTo');
|
||||
$dto->kodoper = $request->query->all('kodoper');
|
||||
$dto->search = $request->query->get('search');
|
||||
$dto->category = $request->query->get('category');
|
||||
$dto->patientAge = $request->query->get('patientAge');
|
||||
$dto->displaySchedule = $request->query->has('displaySchedule')
|
||||
? filter_var($request->query->get('displaySchedule'), FILTER_VALIDATE_BOOLEAN)
|
||||
: null;
|
||||
$dto->orderBy = $request->query->get('orderBy');
|
||||
$dto->filial = $request->query->getInt('filial', 0) ?: null;
|
||||
$dto->sFilial = $request->query->all('sFilial');
|
||||
$dto->kiosk = $request->query->has('isKiosk')
|
||||
? filter_var($request->query->get('isKiosk'), FILTER_VALIDATE_BOOLEAN)
|
||||
: null;
|
||||
|
||||
return $dto;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'active' => $this->active,
|
||||
'sType' => $this->sType,
|
||||
'regionId' => $this->regionId,
|
||||
'dcode' => $this->dcode,
|
||||
'department' => $this->department,
|
||||
'alias' => $this->alias,
|
||||
'tags' => $this->tags,
|
||||
'onlineMode' => $this->onlineMode,
|
||||
'dateFrom' => $this->dateFrom,
|
||||
'dateTo' => $this->dateTo,
|
||||
'kodoper' => $this->kodoper,
|
||||
'search' => $this->search,
|
||||
'category' => $this->category,
|
||||
'patientAge' => $this->patientAge,
|
||||
'displaySchedule' => $this->displaySchedule,
|
||||
'orderBy' => $this->orderBy,
|
||||
'filial' => $this->filial,
|
||||
'sFilial' => $this->sFilial,
|
||||
'kiosk' => $this->kiosk
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class UserAuthDto
|
||||
{
|
||||
#[Assert\Email]
|
||||
#[Assert\NotBlank(message: "Полное email не может быть пустым")]
|
||||
public ?string $email;
|
||||
|
||||
#[Assert\NotNull(message: "password не может быть пустым")]
|
||||
#[Assert\Length(
|
||||
min: 8,
|
||||
max: 100,
|
||||
minMessage: 'Пароль должен содержать минимум 8 символов.',
|
||||
maxMessage: 'Пароль не должен превышать 100 символов.'
|
||||
)]
|
||||
public ?string $password;
|
||||
|
||||
#[Assert\NotNull(message: "regionId не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "regionId должен быть целым числом")]
|
||||
#[Assert\Positive(message: "regionId должен быть положительным числом")]
|
||||
public ?int $regionId;
|
||||
|
||||
#[Assert\NotNull(message: "UID не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "UID должен быть целым числом")]
|
||||
#[Assert\Positive(message: "UID должен быть положительным числом")]
|
||||
public ?int $uid;
|
||||
|
||||
#[Assert\NotBlank(message: "Дата рождения не может быть пустой")]
|
||||
#[Assert\LessThan(
|
||||
value: "now",
|
||||
message: "Дата рождения не может быть в будущем"
|
||||
)]
|
||||
public ?string $birthDate;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class UserLoginDto
|
||||
{
|
||||
#[Assert\Email]
|
||||
#[Assert\NotBlank(message: "Полное email не может быть пустым")]
|
||||
public ?string $email;
|
||||
|
||||
#[Assert\NotNull(message: "password не может быть пустым")]
|
||||
#[Assert\Length(
|
||||
min: 8,
|
||||
max: 100,
|
||||
minMessage: 'Пароль должен содержать минимум 8 символов.',
|
||||
maxMessage: 'Пароль не должен превышать 100 символов.'
|
||||
)]
|
||||
public ?string $password;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class UserUidAuthDto
|
||||
{
|
||||
#[Assert\NotNull(message: "UID не может быть пустым")]
|
||||
#[Assert\Type(type: 'integer', message: "UID должен быть целым числом")]
|
||||
#[Assert\Positive(message: "UID должен быть положительным числом")]
|
||||
public ?int $uid;
|
||||
|
||||
#[Assert\NotBlank(message: "Дата рождения не может быть пустой")]
|
||||
#[Assert\LessThan(
|
||||
value: "now",
|
||||
message: "Дата рождения не может быть в будущем"
|
||||
)]
|
||||
public ?string $birthDate;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\AlertSmsRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use DateTimeInterface;
|
||||
|
||||
#[ORM\Entity(repositoryClass: AlertSmsRepository::class)]
|
||||
class AlertSms
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\OneToOne(targetEntity: Record::class, inversedBy: 'alertSms', cascade: ['persist', 'remove'])]
|
||||
private ?Record $record = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
private ?DateTimeInterface $dateCreate = null;
|
||||
|
||||
#[ORM\Column(type: 'text')]
|
||||
private ?string $response = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getRecord(): ?Record
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
public function setRecord(?Record $record): self
|
||||
{
|
||||
$this->record = $record;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateCreate(): ?DateTimeInterface
|
||||
{
|
||||
return $this->dateCreate;
|
||||
}
|
||||
|
||||
public function setDateCreate(DateTimeInterface $dateCreate): self
|
||||
{
|
||||
$this->dateCreate = $dateCreate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResponse(): ?string
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function setResponse(string $response): self
|
||||
{
|
||||
$this->response = $response;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\ArticleRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ArticleRepository::class)]
|
||||
#[ORM\Table(name: 'article')]
|
||||
#[ORM\Index(name: 'idx_article_region_id', columns: ['region_id'])]
|
||||
#[ORM\Index(name: 'idx_article_active', columns: ['active'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Article
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[Groups(['article:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(name: 'preview_picture', type: Types::TEXT, nullable: true)]
|
||||
private ?string $previewPicture = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $doctors = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $services = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[Groups(['article:read', 'article:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $content = null;
|
||||
|
||||
#[Groups(['article:read'])]
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreviewPicture(): ?string
|
||||
{
|
||||
return $this->previewPicture;
|
||||
}
|
||||
|
||||
public function setPreviewPicture(?string $previewPicture): static
|
||||
{
|
||||
$this->previewPicture = $previewPicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): static
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDoctors(): ?array
|
||||
{
|
||||
return $this->doctors;
|
||||
}
|
||||
|
||||
public function setDoctors(?array $doctors): static
|
||||
{
|
||||
$this->doctors = $doctors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServices(): ?array
|
||||
{
|
||||
return $this->services;
|
||||
}
|
||||
|
||||
public function setServices(?array $services): static
|
||||
{
|
||||
$this->services = $services;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): static
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): static
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): static
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): static
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): static
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\BannerRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=BannerRepository::class)
|
||||
*/
|
||||
class Banner
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $href;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $src;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private $active;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity=City::class, inversedBy="banner")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private $city;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getHref(): ?string
|
||||
{
|
||||
return $this->href;
|
||||
}
|
||||
|
||||
public function setHref(string $href): self
|
||||
{
|
||||
$this->href = $href;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSrc(): ?string
|
||||
{
|
||||
return $this->src;
|
||||
}
|
||||
|
||||
public function setSrc(string $src): self
|
||||
{
|
||||
$this->src = $src;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCity(): ?City
|
||||
{
|
||||
return $this->city;
|
||||
}
|
||||
|
||||
public function setCity(City $city): self
|
||||
{
|
||||
$this->city = $city;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Behavior;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Требует у класса-сущности свойство `$updateAt` (mapped column).
|
||||
*
|
||||
* @property \DateTimeInterface|null $updateAt
|
||||
*/
|
||||
trait UpdateTimestampTrait
|
||||
{
|
||||
#[ORM\PrePersist]
|
||||
public function setInitialUpdateAt(): void
|
||||
{
|
||||
if ($this->updateAt === null) {
|
||||
$this->updateAt = new \DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\PreUpdate]
|
||||
public function refreshUpdateAt(): void
|
||||
{
|
||||
$this->updateAt = new \DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\DepartmentRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: DepartmentRepository::class)]
|
||||
#[ORM\Table(name: 'departments', uniqueConstraints: [
|
||||
new ORM\UniqueConstraint(name: 'uniq_department_did', columns: ['did'])
|
||||
])]
|
||||
class Department
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private ?string $did = null;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private ?bool $onlineMode = null;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(type: 'boolean', options: ['default' => true])]
|
||||
private bool $active = true;
|
||||
|
||||
#[Groups(['department:read', 'department:write'])]
|
||||
#[ORM\Column(name: 'group_name', type: 'string', length: 255, nullable: true)]
|
||||
private ?string $groupName = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDid(): ?string
|
||||
{
|
||||
return $this->did;
|
||||
}
|
||||
|
||||
public function setDid(?string $did): self
|
||||
{
|
||||
$this->did = $did;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOnlineMode(): ?bool
|
||||
{
|
||||
return $this->onlineMode;
|
||||
}
|
||||
|
||||
public function setOnlineMode(?bool $onlineMode): self
|
||||
{
|
||||
$this->onlineMode = $onlineMode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGroupName(): ?string
|
||||
{
|
||||
return $this->groupName;
|
||||
}
|
||||
|
||||
public function setGroupName(?string $groupName): self
|
||||
{
|
||||
$this->groupName = $groupName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'did' => $this->getDid(),
|
||||
'name' => $this->getName(),
|
||||
'onlineMode' => $this->getOnlineMode(),
|
||||
'alias' => $this->getAlias(),
|
||||
'active' => $this->getActive(),
|
||||
'groupName' => $this->getGroupName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\DiseaseRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: DiseaseRepository::class)]
|
||||
#[ORM\Table(name: 'disease')]
|
||||
#[ORM\Index(name: 'idx_disease_region_id', columns: ['region_id'])]
|
||||
#[ORM\Index(name: 'idx_disease_active', columns: ['active'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Disease
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[Groups(['disease:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'preview_picture', type: Types::TEXT, nullable: true)]
|
||||
private ?string $previewPicture = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[Groups(['disease:read'])]
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'hide_picture', type: Types::BOOLEAN, nullable: true)]
|
||||
private ?bool $hidePicture = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'read_time', type: Types::TEXT, nullable: true)]
|
||||
private ?string $readTime = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'diseases_name', type: Types::TEXT, nullable: true)]
|
||||
private ?string $diseasesName = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'tags_important', type: 'jsonb', nullable: true)]
|
||||
private ?array $tagsImportant = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $tags = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'diseases_other_name', type: Types::TEXT, nullable: true)]
|
||||
private ?string $diseasesOtherName = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $symptom = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $staff = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'link_services', type: 'jsonb', nullable: true)]
|
||||
private ?array $linkServices = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'staff_list', type: 'jsonb', nullable: true)]
|
||||
private ?array $staffList = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'staff_post', type: 'jsonb', nullable: true)]
|
||||
private ?array $staffPost = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'staff_post_exclude', type: 'jsonb', nullable: true)]
|
||||
private ?array $staffPostExclude = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'link_faq', type: 'jsonb', nullable: true)]
|
||||
private ?array $linkFaq = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $bibliography = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(name: 'staff_check', type: 'jsonb', nullable: true)]
|
||||
private ?array $staffCheck = null;
|
||||
|
||||
#[Groups(['disease:read', 'disease:write'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $content = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): static
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreviewPicture(): ?string
|
||||
{
|
||||
return $this->previewPicture;
|
||||
}
|
||||
|
||||
public function setPreviewPicture(?string $previewPicture): static
|
||||
{
|
||||
$this->previewPicture = $previewPicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): static
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): static
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): static
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): static
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): static
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHidePicture(): ?bool
|
||||
{
|
||||
return $this->hidePicture;
|
||||
}
|
||||
|
||||
public function setHidePicture(?bool $hidePicture): static
|
||||
{
|
||||
$this->hidePicture = $hidePicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReadTime(): ?string
|
||||
{
|
||||
return $this->readTime;
|
||||
}
|
||||
|
||||
public function setReadTime(?string $readTime): static
|
||||
{
|
||||
$this->readTime = $readTime;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiseasesName(): ?string
|
||||
{
|
||||
return $this->diseasesName;
|
||||
}
|
||||
|
||||
public function setDiseasesName(?string $diseasesName): static
|
||||
{
|
||||
$this->diseasesName = $diseasesName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTagsImportant(): ?array
|
||||
{
|
||||
return $this->tagsImportant;
|
||||
}
|
||||
|
||||
public function setTagsImportant(?array $tagsImportant): static
|
||||
{
|
||||
$this->tagsImportant = $tagsImportant;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTags(): ?array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function setTags(?array $tags): static
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiseasesOtherName(): ?string
|
||||
{
|
||||
return $this->diseasesOtherName;
|
||||
}
|
||||
|
||||
public function setDiseasesOtherName(?string $diseasesOtherName): static
|
||||
{
|
||||
$this->diseasesOtherName = $diseasesOtherName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymptom(): ?string
|
||||
{
|
||||
return $this->symptom;
|
||||
}
|
||||
|
||||
public function setSymptom(?string $symptom): static
|
||||
{
|
||||
$this->symptom = $symptom;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaff(): ?string
|
||||
{
|
||||
return $this->staff;
|
||||
}
|
||||
|
||||
public function setStaff(?string $staff): static
|
||||
{
|
||||
$this->staff = $staff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkServices(): ?array
|
||||
{
|
||||
return $this->linkServices;
|
||||
}
|
||||
|
||||
public function setLinkServices(?array $linkServices): static
|
||||
{
|
||||
$this->linkServices = $linkServices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaffList(): ?array
|
||||
{
|
||||
return $this->staffList;
|
||||
}
|
||||
|
||||
public function setStaffList(?array $staffList): static
|
||||
{
|
||||
$this->staffList = $staffList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaffPost(): ?array
|
||||
{
|
||||
return $this->staffPost;
|
||||
}
|
||||
|
||||
public function setStaffPost(?array $staffPost): static
|
||||
{
|
||||
$this->staffPost = $staffPost;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaffPostExclude(): ?array
|
||||
{
|
||||
return $this->staffPostExclude;
|
||||
}
|
||||
|
||||
public function setStaffPostExclude(?array $staffPostExclude): static
|
||||
{
|
||||
$this->staffPostExclude = $staffPostExclude;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkFaq(): ?array
|
||||
{
|
||||
return $this->linkFaq;
|
||||
}
|
||||
|
||||
public function setLinkFaq(?array $linkFaq): static
|
||||
{
|
||||
$this->linkFaq = $linkFaq;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBibliography(): ?string
|
||||
{
|
||||
return $this->bibliography;
|
||||
}
|
||||
|
||||
public function setBibliography(?string $bibliography): static
|
||||
{
|
||||
$this->bibliography = $bibliography;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaffCheck(): ?array
|
||||
{
|
||||
return $this->staffCheck;
|
||||
}
|
||||
|
||||
public function setStaffCheck(?array $staffCheck): static
|
||||
{
|
||||
$this->staffCheck = $staffCheck;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): static
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\FilialRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: FilialRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Filial
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[Groups(['filial:read'])]
|
||||
private int $id;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $fid;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $name;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $address;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
private ?int $siteId = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'boolean', options: ['default' => true])]
|
||||
private bool $active = true;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private ?string $company = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $shortName = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $phone = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $policy = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $picture = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $email = null;
|
||||
|
||||
#[Groups(['filial:read', 'filial:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $origin = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getFid(): ?int
|
||||
{
|
||||
return $this->fid;
|
||||
}
|
||||
|
||||
public function setFid(int $fid): self
|
||||
{
|
||||
$this->fid = $fid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSiteId(): ?int
|
||||
{
|
||||
return $this->siteId;
|
||||
}
|
||||
|
||||
public function setSiteId(?int $siteId): self
|
||||
{
|
||||
$this->siteId = $siteId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAddress(): ?string
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
public function setAddress(?string $address): self
|
||||
{
|
||||
$this->address = $address;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCompany(): ?string
|
||||
{
|
||||
return $this->company;
|
||||
}
|
||||
|
||||
public function setCompany(?string $company): self
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShortName(): ?string
|
||||
{
|
||||
return $this->shortName;
|
||||
}
|
||||
|
||||
public function setShortName(?string $shortName): static
|
||||
{
|
||||
$this->shortName = $shortName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhone(): ?string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
public function setPhone(?string $phone): static
|
||||
{
|
||||
$this->phone = $phone;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPolicy(): ?string
|
||||
{
|
||||
return $this->policy;
|
||||
}
|
||||
|
||||
public function setPolicy(?string $policy): static
|
||||
{
|
||||
$this->policy = $policy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPicture(): ?string
|
||||
{
|
||||
return $this->picture;
|
||||
}
|
||||
|
||||
public function setPicture(?string $picture): static
|
||||
{
|
||||
$this->picture = $picture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(?string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOrigin(): ?string
|
||||
{
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
public function setOrigin(?string $origin): static
|
||||
{
|
||||
$this->origin = $origin;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\IdoctorRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: IdoctorRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Idoctor
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private int $id;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private int $dcode;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $name;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private int $department;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $filial;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $nearestDate;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $onlineMode;
|
||||
|
||||
#[Groups(['idoctor:read'])]
|
||||
#[ORM\Column(type: 'datetime', nullable: true)]
|
||||
private ?\DateTimeInterface $updated = null;
|
||||
|
||||
#[ORM\PreFlush]
|
||||
public function onPreFlush()
|
||||
{
|
||||
$this->updated = new \DateTime("now");
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDcode(): ?string
|
||||
{
|
||||
return $this->dcode;
|
||||
}
|
||||
|
||||
public function setDcode(string $dcode): self
|
||||
{
|
||||
$this->dcode = $dcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepartment(): ?string
|
||||
{
|
||||
return $this->department;
|
||||
}
|
||||
|
||||
public function setDepartment(string $department): self
|
||||
{
|
||||
$this->department = $department;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): ?int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(int $filial): self
|
||||
{
|
||||
$this->filial = $filial;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNearestDate(): ?string
|
||||
{
|
||||
return $this->nearestDate;
|
||||
}
|
||||
|
||||
public function setNearestDate(string $nearestDate): self
|
||||
{
|
||||
$this->nearestDate = $nearestDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOnlineMode(): bool
|
||||
{
|
||||
return $this->onlineMode;
|
||||
}
|
||||
|
||||
public function setOnlineMode(bool $onlineMode): self
|
||||
{
|
||||
$this->onlineMode = $onlineMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\LocationRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: LocationRepository::class)]
|
||||
#[ORM\Index(columns: ['specialist_id'], name: 'idx_location_specialist_id')]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Location
|
||||
{
|
||||
#[Groups(['from.specialist:read', 'location:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private int $id;
|
||||
|
||||
#[Groups(['from.specialist:read', 'location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'bigint', nullable: true)]
|
||||
private ?int $dcode;
|
||||
|
||||
#[Groups(['from.specialist:read','location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private int $department;
|
||||
|
||||
#[Groups(['from.specialist:read', 'location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $filial;
|
||||
|
||||
#[Groups(['from.specialist:read', 'location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $onlineMode;
|
||||
|
||||
#[Groups(['from.specialist:read', 'location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $active;
|
||||
|
||||
#[Groups(['from.specialist:read', 'location:read', 'location:write'])]
|
||||
#[ORM\Column(type: 'date', nullable: true)]
|
||||
private ?\DateTimeInterface $nearestDate = null;
|
||||
|
||||
#[Groups(['location:read'])]
|
||||
#[ORM\ManyToOne(
|
||||
targetEntity: Specialist::class,
|
||||
inversedBy: 'locations',
|
||||
cascade: ['persist']
|
||||
)]
|
||||
#[ORM\JoinColumn(name: "specialist_id", referencedColumnName: "id")]
|
||||
private ?Specialist $specialist;
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDcode(): ?int
|
||||
{
|
||||
return $this->dcode;
|
||||
}
|
||||
|
||||
public function setDcode(?int $dcode): self
|
||||
{
|
||||
$this->dcode = (int) $dcode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepartment(): int
|
||||
{
|
||||
return $this->department;
|
||||
}
|
||||
|
||||
public function setDepartment(int $department): self
|
||||
{
|
||||
$this->department = $department;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(int $filial): self
|
||||
{
|
||||
$this->filial = $filial;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOnlineMode(): bool
|
||||
{
|
||||
return $this->onlineMode;
|
||||
}
|
||||
|
||||
public function setOnlineMode(bool $onlineMode): self
|
||||
{
|
||||
$this->onlineMode = $onlineMode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNearestDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->nearestDate;
|
||||
}
|
||||
|
||||
public function setNearestDate(?\DateTimeInterface $nearestDate): self
|
||||
{
|
||||
$this->nearestDate = $nearestDate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpecialist(): ?Specialist
|
||||
{
|
||||
return $this->specialist;
|
||||
}
|
||||
|
||||
public function setSpecialist(?Specialist $specialist): self
|
||||
{
|
||||
$this->specialist = $specialist;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\MarkKioskRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MarkKioskRepository::class)]
|
||||
class MarkKiosk
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::BIGINT)]
|
||||
private ?string $pcode = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $filial = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?\DateTimeImmutable $created_at = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?\DateTimeImmutable $modify_at = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $result = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getPcode(): ?string
|
||||
{
|
||||
return $this->pcode;
|
||||
}
|
||||
|
||||
public function setPcode(string $pcode): static
|
||||
{
|
||||
$this->pcode = $pcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): ?int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(int $filial): static
|
||||
{
|
||||
$this->filial = $filial;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->created_at;
|
||||
}
|
||||
|
||||
public function setCreatedAt(\DateTimeImmutable $created_at): static
|
||||
{
|
||||
$this->created_at = $created_at;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModifyAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->modify_at;
|
||||
}
|
||||
|
||||
public function setModifyAt(\DateTimeImmutable $modify_at): static
|
||||
{
|
||||
$this->modify_at = $modify_at;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isResult(): ?bool
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function setResult(?bool $result): static
|
||||
{
|
||||
$this->result = $result;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\MedicalCenterRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MedicalCenterRepository::class)]
|
||||
#[ORM\Table(name: 'medical_center')]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class MedicalCenter
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
#[Groups(['medical_center:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $content = null;
|
||||
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
#[Groups(['medical_center:read'])]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
#[ORM\Column(name: 'kod_uslug', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $kodUslug = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $doctors = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $services = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $articles = null;
|
||||
|
||||
#[ORM\Column(name: 'txt_up', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $txtUp = null;
|
||||
|
||||
#[ORM\Column(name: 'main_link_staff', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $mainLinkStaff = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $contraindications = null;
|
||||
|
||||
#[ORM\Column(name: 'hide_picture', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?int $hidePicture = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $indications = null;
|
||||
|
||||
#[ORM\Column(name: 'link_sale', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $linkSale = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_list', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $plusList = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $plusText = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $plusTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'process_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $processText = null;
|
||||
|
||||
#[ORM\Column(name: 'process_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $processTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'services_list', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $servicesList = null;
|
||||
|
||||
#[ORM\Column(name: 'services_photos', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $servicesPhotos = null;
|
||||
|
||||
#[ORM\Column(name: 'services_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $servicesTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'sort_staff', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?array $sortStaff = null;
|
||||
|
||||
#[ORM\Column(name: 'training_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $trainingText = null;
|
||||
|
||||
#[ORM\Column(name: 'training_text_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $trainingTextTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'why_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $whyText = null;
|
||||
|
||||
#[ORM\Column(name: 'why_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['medical_center:read', 'medical_center:write'])]
|
||||
private ?string $whyTitle = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): self
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): self
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getKodUslug(): ?array
|
||||
{
|
||||
return $this->kodUslug;
|
||||
}
|
||||
|
||||
public function setKodUslug(?array $kodUslug): self
|
||||
{
|
||||
$this->kodUslug = $kodUslug;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDoctors(): ?array
|
||||
{
|
||||
return $this->doctors;
|
||||
}
|
||||
|
||||
public function setDoctors(?array $doctors): self
|
||||
{
|
||||
$this->doctors = $doctors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServices(): ?array
|
||||
{
|
||||
return $this->services;
|
||||
}
|
||||
|
||||
public function setServices(?array $services): self
|
||||
{
|
||||
$this->services = $services;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getArticles(): ?array
|
||||
{
|
||||
return $this->articles;
|
||||
}
|
||||
|
||||
public function setArticles(?array $articles): self
|
||||
{
|
||||
$this->articles = $articles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTxtUp(): ?array
|
||||
{
|
||||
return $this->txtUp;
|
||||
}
|
||||
|
||||
public function setTxtUp(?array $txtUp): self
|
||||
{
|
||||
$this->txtUp = $txtUp;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMainLinkStaff(): ?string
|
||||
{
|
||||
return $this->mainLinkStaff;
|
||||
}
|
||||
|
||||
public function setMainLinkStaff(?string $mainLinkStaff): self
|
||||
{
|
||||
$this->mainLinkStaff = $mainLinkStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContraindications(): ?array
|
||||
{
|
||||
return $this->contraindications;
|
||||
}
|
||||
|
||||
public function setContraindications(?array $contraindications): self
|
||||
{
|
||||
$this->contraindications = $contraindications;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHidePicture(): ?int
|
||||
{
|
||||
return $this->hidePicture;
|
||||
}
|
||||
|
||||
public function setHidePicture(?int $hidePicture): self
|
||||
{
|
||||
$this->hidePicture = $hidePicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIndications(): ?array
|
||||
{
|
||||
return $this->indications;
|
||||
}
|
||||
|
||||
public function setIndications(?array $indications): self
|
||||
{
|
||||
$this->indications = $indications;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkSale(): ?array
|
||||
{
|
||||
return $this->linkSale;
|
||||
}
|
||||
|
||||
public function setLinkSale(?array $linkSale): self
|
||||
{
|
||||
$this->linkSale = $linkSale;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusList(): ?array
|
||||
{
|
||||
return $this->plusList;
|
||||
}
|
||||
|
||||
public function setPlusList(?array $plusList): self
|
||||
{
|
||||
$this->plusList = $plusList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusText(): ?string
|
||||
{
|
||||
return $this->plusText;
|
||||
}
|
||||
|
||||
public function setPlusText(?string $plusText): self
|
||||
{
|
||||
$this->plusText = $plusText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusTitle(): ?string
|
||||
{
|
||||
return $this->plusTitle;
|
||||
}
|
||||
|
||||
public function setPlusTitle(?string $plusTitle): self
|
||||
{
|
||||
$this->plusTitle = $plusTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProcessText(): ?string
|
||||
{
|
||||
return $this->processText;
|
||||
}
|
||||
|
||||
public function setProcessText(?string $processText): self
|
||||
{
|
||||
$this->processText = $processText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProcessTitle(): ?string
|
||||
{
|
||||
return $this->processTitle;
|
||||
}
|
||||
|
||||
public function setProcessTitle(?string $processTitle): self
|
||||
{
|
||||
$this->processTitle = $processTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesList(): ?array
|
||||
{
|
||||
return $this->servicesList;
|
||||
}
|
||||
|
||||
public function setServicesList(?array $servicesList): self
|
||||
{
|
||||
$this->servicesList = $servicesList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesPhotos(): ?array
|
||||
{
|
||||
return $this->servicesPhotos;
|
||||
}
|
||||
|
||||
public function setServicesPhotos(?array $servicesPhotos): self
|
||||
{
|
||||
$this->servicesPhotos = $servicesPhotos;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesTitle(): ?string
|
||||
{
|
||||
return $this->servicesTitle;
|
||||
}
|
||||
|
||||
public function setServicesTitle(?string $servicesTitle): self
|
||||
{
|
||||
$this->servicesTitle = $servicesTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSortStaff(): ?array
|
||||
{
|
||||
return $this->sortStaff;
|
||||
}
|
||||
|
||||
public function setSortStaff(?array $sortStaff): self
|
||||
{
|
||||
$this->sortStaff = $sortStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTrainingText(): ?string
|
||||
{
|
||||
return $this->trainingText;
|
||||
}
|
||||
|
||||
public function setTrainingText(?string $trainingText): self
|
||||
{
|
||||
$this->trainingText = $trainingText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTrainingTextTitle(): ?string
|
||||
{
|
||||
return $this->trainingTextTitle;
|
||||
}
|
||||
|
||||
public function setTrainingTextTitle(?string $trainingTextTitle): self
|
||||
{
|
||||
$this->trainingTextTitle = $trainingTextTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyText(): ?string
|
||||
{
|
||||
return $this->whyText;
|
||||
}
|
||||
|
||||
public function setWhyText(?string $whyText): self
|
||||
{
|
||||
$this->whyText = $whyText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyTitle(): ?string
|
||||
{
|
||||
return $this->whyTitle;
|
||||
}
|
||||
|
||||
public function setWhyTitle(?string $whyTitle): self
|
||||
{
|
||||
$this->whyTitle = $whyTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\NewsRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: NewsRepository::class)]
|
||||
#[ORM\Table(name: 'news')]
|
||||
#[ORM\Index(name: 'idx_news_region_id', columns: ['region_id'])]
|
||||
#[ORM\Index(name: 'idx_news_active', columns: ['active'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class News
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
#[Groups(['news:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $content = null;
|
||||
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
#[Groups(['news:read'])]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
#[ORM\Column(name: 'link_el_price', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $linkElPrice = null;
|
||||
|
||||
#[ORM\Column(name: 'short_name', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $shortName = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $timer = null;
|
||||
|
||||
#[ORM\Column(name: 'timer_bg', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?string $timerBg = null;
|
||||
|
||||
#[ORM\Column(name: 'form_order', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?array $formOrder = null;
|
||||
|
||||
#[ORM\Column(name: 'link_services', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?array $linkServices = null;
|
||||
|
||||
#[ORM\Column(name: 'link_staff', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?array $linkStaff = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['news:read', 'news:write'])]
|
||||
private ?array $photos = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): self
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): self
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkElPrice(): ?string
|
||||
{
|
||||
return $this->linkElPrice;
|
||||
}
|
||||
|
||||
public function setLinkElPrice(?string $linkElPrice): self
|
||||
{
|
||||
$this->linkElPrice = $linkElPrice;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShortName(): ?string
|
||||
{
|
||||
return $this->shortName;
|
||||
}
|
||||
|
||||
public function setShortName(?string $shortName): self
|
||||
{
|
||||
$this->shortName = $shortName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimer(): ?string
|
||||
{
|
||||
return $this->timer;
|
||||
}
|
||||
|
||||
public function setTimer(?string $timer): self
|
||||
{
|
||||
$this->timer = $timer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimerBg(): ?string
|
||||
{
|
||||
return $this->timerBg;
|
||||
}
|
||||
|
||||
public function setTimerBg(?string $timerBg): self
|
||||
{
|
||||
$this->timerBg = $timerBg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFormOrder(): ?array
|
||||
{
|
||||
return $this->formOrder;
|
||||
}
|
||||
|
||||
public function setFormOrder(?array $formOrder): self
|
||||
{
|
||||
$this->formOrder = $formOrder;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkServices(): ?array
|
||||
{
|
||||
return $this->linkServices;
|
||||
}
|
||||
|
||||
public function setLinkServices(?array $linkServices): self
|
||||
{
|
||||
$this->linkServices = $linkServices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkStaff(): ?array
|
||||
{
|
||||
return $this->linkStaff;
|
||||
}
|
||||
|
||||
public function setLinkStaff(?array $linkStaff): self
|
||||
{
|
||||
$this->linkStaff = $linkStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhotos(): ?array
|
||||
{
|
||||
return $this->photos;
|
||||
}
|
||||
|
||||
public function setPhotos(?array $photos): self
|
||||
{
|
||||
$this->photos = $photos;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\PriceDepartmentRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PriceDepartmentRepository::class)]
|
||||
class PriceDepartment
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column]
|
||||
#[Groups(['departmentPrice:write'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['departmentPrice:read', 'departmentPrice:write'])]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['departmentPrice:read', 'departmentPrice:write'])]
|
||||
private ?int $groupId = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['departmentPrice:read', 'departmentPrice:write'])]
|
||||
private ?int $doctCount = null;
|
||||
|
||||
#[ORM\Column]
|
||||
#[Groups(['departmentPrice:read', 'departmentPrice:write'])]
|
||||
private ?bool $viewInWeb = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGroupId(): ?int
|
||||
{
|
||||
return $this->groupId;
|
||||
}
|
||||
|
||||
public function setGroupId(?int $groupId): static
|
||||
{
|
||||
$this->groupId = $groupId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDoctCount(): ?int
|
||||
{
|
||||
return $this->doctCount;
|
||||
}
|
||||
|
||||
public function setDoctCount(?int $doctCount): static
|
||||
{
|
||||
$this->doctCount = $doctCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isViewInWeb(): ?bool
|
||||
{
|
||||
return $this->viewInWeb;
|
||||
}
|
||||
|
||||
public function setViewInWeb(bool $viewInWeb): static
|
||||
{
|
||||
$this->viewInWeb = $viewInWeb;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\PriceListRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PriceListRepository::class)]
|
||||
#[ORM\Index(name: 'idx_price_list_schname', columns: ['schname'])]
|
||||
#[ORM\Index(name: 'idx_price_list_kodoper', columns: ['kodoper'])]
|
||||
#[ORM\Index(name: 'idx_price_list_filial', columns: ['filial'])]
|
||||
class PriceList
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $kodoper = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $schname = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $specname = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(type: Types::BIGINT, nullable: true)]
|
||||
private ?string $speccode = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?array $priceInfo = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $discprice = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $structname = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $fname = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $filial = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $comment = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $mediaId = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column]
|
||||
private ?\DateTime $dateUpdate = null;
|
||||
|
||||
#[Groups(['pricelist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $groupId = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $discpercent = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getKodoper(): ?string
|
||||
{
|
||||
return $this->kodoper;
|
||||
}
|
||||
|
||||
public function setKodoper(?string $kodoper): static
|
||||
{
|
||||
$this->kodoper = $kodoper;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSchname(): ?string
|
||||
{
|
||||
return $this->schname;
|
||||
}
|
||||
|
||||
public function setSchname(?string $schname): static
|
||||
{
|
||||
$this->schname = $schname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpecname(): ?string
|
||||
{
|
||||
return $this->specname;
|
||||
}
|
||||
|
||||
public function setSpecname(?string $specname): static
|
||||
{
|
||||
$this->specname = $specname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpeccode(): ?string
|
||||
{
|
||||
return $this->speccode;
|
||||
}
|
||||
|
||||
public function setSpeccode(?string $speccode): static
|
||||
{
|
||||
$this->speccode = $speccode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPriceInfo(): ?array
|
||||
{
|
||||
return $this->priceInfo;
|
||||
}
|
||||
|
||||
public function setPriceInfo(?array $priceInfo): static
|
||||
{
|
||||
$this->priceInfo = $priceInfo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiscprice(): ?string
|
||||
{
|
||||
return $this->discprice;
|
||||
}
|
||||
|
||||
public function setDiscprice(?string $discprice): static
|
||||
{
|
||||
$this->discprice = $discprice;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStructname(): ?string
|
||||
{
|
||||
return $this->structname;
|
||||
}
|
||||
|
||||
public function setStructname(?string $structname): static
|
||||
{
|
||||
$this->structname = $structname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFname(): ?string
|
||||
{
|
||||
return $this->fname;
|
||||
}
|
||||
|
||||
public function setFname(?string $fname): static
|
||||
{
|
||||
$this->fname = $fname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): ?int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(?int $filial): static
|
||||
{
|
||||
$this->filial = $filial;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getComment(): ?string
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
public function setComment(?string $comment): static
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMediaId(): ?int
|
||||
{
|
||||
return $this->mediaId;
|
||||
}
|
||||
|
||||
public function setMediaId(?int $mediaId): static
|
||||
{
|
||||
$this->mediaId = $mediaId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateUpdate(): ?\DateTime
|
||||
{
|
||||
return $this->dateUpdate;
|
||||
}
|
||||
|
||||
public function setDateUpdate(\DateTime $dateUpdate): static
|
||||
{
|
||||
$this->dateUpdate = $dateUpdate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGroupId(): ?int
|
||||
{
|
||||
return $this->groupId;
|
||||
}
|
||||
|
||||
public function setGroupId(?int $groupId): static
|
||||
{
|
||||
$this->groupId = $groupId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiscpercent(): ?string
|
||||
{
|
||||
return $this->discpercent;
|
||||
}
|
||||
|
||||
public function setDiscpercent(?string $discpercent): static
|
||||
{
|
||||
$this->discpercent = $discpercent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\PromoRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PromoRepository::class)]
|
||||
#[ORM\Table(name: 'promo')]
|
||||
#[ORM\Index(name: 'idx_promo_region_id', columns: ['region_id'])]
|
||||
#[ORM\Index(name: 'idx_promo_active', columns: ['active'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Promo
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
#[Groups(['promo:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $content = null;
|
||||
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
#[Groups(['promo:read'])]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?array $clinics = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $timer = null;
|
||||
|
||||
#[ORM\Column(name: 'timer_bg', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $timerBg = null;
|
||||
|
||||
#[ORM\Column(name: 'short_name', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $shortName = null;
|
||||
|
||||
#[ORM\Column(name: 'link_services', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?array $linkServices = null;
|
||||
|
||||
#[ORM\Column(name: 'link_staff', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?array $linkStaff = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?string $period = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['promo:read', 'promo:write'])]
|
||||
private ?array $photos = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): self
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): self
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClinics(): ?array
|
||||
{
|
||||
return $this->clinics;
|
||||
}
|
||||
|
||||
public function setClinics(?array $clinics): self
|
||||
{
|
||||
$this->clinics = $clinics;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimer(): ?string
|
||||
{
|
||||
return $this->timer;
|
||||
}
|
||||
|
||||
public function setTimer(?string $timer): self
|
||||
{
|
||||
$this->timer = $timer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimerBg(): ?string
|
||||
{
|
||||
return $this->timerBg;
|
||||
}
|
||||
|
||||
public function setTimerBg(?string $timerBg): self
|
||||
{
|
||||
$this->timerBg = $timerBg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShortName(): ?string
|
||||
{
|
||||
return $this->shortName;
|
||||
}
|
||||
|
||||
public function setShortName(?string $shortName): self
|
||||
{
|
||||
$this->shortName = $shortName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkServices(): ?array
|
||||
{
|
||||
return $this->linkServices;
|
||||
}
|
||||
|
||||
public function setLinkServices(?array $linkServices): self
|
||||
{
|
||||
$this->linkServices = $linkServices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkStaff(): ?array
|
||||
{
|
||||
return $this->linkStaff;
|
||||
}
|
||||
|
||||
public function setLinkStaff(?array $linkStaff): self
|
||||
{
|
||||
$this->linkStaff = $linkStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPeriod(): ?string
|
||||
{
|
||||
return $this->period;
|
||||
}
|
||||
|
||||
public function setPeriod(?string $period): self
|
||||
{
|
||||
$this->period = $period;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhotos(): ?array
|
||||
{
|
||||
return $this->photos;
|
||||
}
|
||||
|
||||
public function setPhotos(?array $photos): self
|
||||
{
|
||||
$this->photos = $photos;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\RecordRepository;
|
||||
use App\Bundle\Crypt\AES;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use DateTimeInterface;
|
||||
|
||||
#[ORM\Entity(repositoryClass: RecordRepository::class)]
|
||||
class Record
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $specialistId = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $phone = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
private ?DateTimeInterface $createAt = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $hash = null;
|
||||
|
||||
#[ORM\Column(type: 'json')]
|
||||
private array $reserve = [];
|
||||
|
||||
#[ORM\OneToOne(targetEntity: AlertSms::class, mappedBy: 'record', cascade: ['persist', 'remove'])]
|
||||
private ?AlertSms $alertSms = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getSpecialistId(): ?int
|
||||
{
|
||||
return $this->specialistId;
|
||||
}
|
||||
|
||||
public function setSpecialistId(int $specialistId): self
|
||||
{
|
||||
$this->specialistId = $specialistId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhone(): ?string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
public function setPhone(string $phone): self
|
||||
{
|
||||
$this->phone = $phone;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreateAt(): ?DateTimeInterface
|
||||
{
|
||||
return $this->createAt;
|
||||
}
|
||||
|
||||
public function setCreateAt(DateTimeInterface $createAt): self
|
||||
{
|
||||
$this->createAt = $createAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHash(): ?string
|
||||
{
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
public function setHash(string $hash): self
|
||||
{
|
||||
$this->hash = md5($hash);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReserve(): array
|
||||
{
|
||||
return $this->reserve;
|
||||
}
|
||||
|
||||
public function setReserve(array $reserve): self
|
||||
{
|
||||
$this->reserve = $reserve;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlertSms(): ?AlertSms
|
||||
{
|
||||
return $this->alertSms;
|
||||
}
|
||||
|
||||
public function setAlertSms(?AlertSms $alertSms): self
|
||||
{
|
||||
// unset the owning side of the relation if necessary
|
||||
if ($alertSms === null && $this->alertSms !== null) {
|
||||
$this->alertSms->setRecord(null);
|
||||
}
|
||||
|
||||
// set the owning side of the relation if necessary
|
||||
if ($alertSms !== null && $alertSms->getRecord() !== $this) {
|
||||
$alertSms->setRecord($this);
|
||||
}
|
||||
|
||||
$this->alertSms = $alertSms;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Specialist;
|
||||
use App\Repository\ReviewRepository;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ReviewRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Review
|
||||
{
|
||||
#[Groups(['from.specialist:read', 'review:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private $id;
|
||||
|
||||
#[Groups(['review:read'])]
|
||||
#[ORM\ManyToOne(
|
||||
targetEntity: Specialist::class,
|
||||
inversedBy: 'reviews'
|
||||
)]
|
||||
#[ORM\JoinColumn(name: "specialist_id", referencedColumnName: "id")]
|
||||
private Specialist $specialist;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read', 'review:write'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private $active;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read'])]
|
||||
#[ORM\Column(type: 'date')]
|
||||
private $dateCreate;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read', 'review:write'])]
|
||||
#[ORM\Column(type: 'text')]
|
||||
private $message;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read', 'review:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private $author;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read', 'review:write'])]
|
||||
#[ORM\Column(type: 'float')]
|
||||
private $rating;
|
||||
|
||||
#[Groups(['from.specialist:read', 'review:read', 'review:write'])]
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private $source;
|
||||
|
||||
#[Groups(['review:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $externalId = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateCreate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->dateCreate;
|
||||
}
|
||||
|
||||
public function setDateCreate(\DateTimeInterface $dateCreate): self
|
||||
{
|
||||
$this->dateCreate = $dateCreate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMessage(): ?string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function setMessage(string $message): self
|
||||
{
|
||||
$this->message = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAuthor(): ?string
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
public function setAuthor(string $author): self
|
||||
{
|
||||
$this->author = $author;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRating(): ?float
|
||||
{
|
||||
return $this->rating;
|
||||
}
|
||||
|
||||
public function setRating(float $rating): self
|
||||
{
|
||||
$this->rating = $rating;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSource(): ?string
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
public function setSource(?string $source): self
|
||||
{
|
||||
$this->source = $source;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function getSpecialist(): ?Specialist
|
||||
{
|
||||
return $this->specialist;
|
||||
}
|
||||
|
||||
public function setSpecialist(?Specialist $specialist): static
|
||||
{
|
||||
$this->specialist = $specialist;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getExternalId(): ?int
|
||||
{
|
||||
return $this->externalId;
|
||||
}
|
||||
|
||||
public function setExternalId(?int $externalId): static
|
||||
{
|
||||
$this->externalId = $externalId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ScheduleRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ScheduleRepository::class)]
|
||||
#[ORM\Index(columns: ['query_string', 'created_at'], name: 'query_created_idx')]
|
||||
#[ORM\Index(columns: ['department', 'workdate'], name: 'department_date_idx')]
|
||||
#[ORM\Index(columns: ['online_mode'], name: 'online_mode_idx')]
|
||||
class Schedule
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::BIGINT)]
|
||||
private ?string $dcode = null;
|
||||
|
||||
#[ORM\Column(type: Types::BIGINT)]
|
||||
private ?string $department = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $filial = null;
|
||||
|
||||
#[ORM\Column(type: Types::BIGINT)]
|
||||
private ?string $schedident = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $workdate = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $rnum = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $rfloor = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $rbuilding = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $time = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $isFree = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $onlineMode = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT)]
|
||||
private ?string $queryString = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||
private ?\DateTimeInterface $createdAt = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $intervalIsFree = null;
|
||||
|
||||
#[ORM\Column(type: Types::JSON, nullable: true)]
|
||||
private ?array $priceInfo = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDcode(): ?string
|
||||
{
|
||||
return $this->dcode;
|
||||
}
|
||||
|
||||
public function setDcode(string $dcode): static
|
||||
{
|
||||
$this->dcode = $dcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepartment(): ?string
|
||||
{
|
||||
return $this->department;
|
||||
}
|
||||
|
||||
public function setDepartment(string $department): static
|
||||
{
|
||||
$this->department = $department;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): ?int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(int $filial): static
|
||||
{
|
||||
$this->filial = $filial;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSchedident(): ?string
|
||||
{
|
||||
return $this->schedident;
|
||||
}
|
||||
|
||||
public function setSchedident(string $schedident): static
|
||||
{
|
||||
$this->schedident = $schedident;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWorkdate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->workdate;
|
||||
}
|
||||
|
||||
public function setWorkdate(\DateTimeInterface $workdate): static
|
||||
{
|
||||
$this->workdate = $workdate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRnum(): ?string
|
||||
{
|
||||
return $this->rnum;
|
||||
}
|
||||
|
||||
public function setRnum(string $rnum): static
|
||||
{
|
||||
$this->rnum = $rnum;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRfloor(): ?string
|
||||
{
|
||||
return $this->rfloor;
|
||||
}
|
||||
|
||||
public function setRfloor(?string $rfloor): static
|
||||
{
|
||||
$this->rfloor = $rfloor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRbuilding(): ?string
|
||||
{
|
||||
return $this->rbuilding;
|
||||
}
|
||||
|
||||
public function setRbuilding(?string $rbuilding): static
|
||||
{
|
||||
$this->rbuilding = $rbuilding;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTime(): ?string
|
||||
{
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
public function setTime(string $time): static
|
||||
{
|
||||
$this->time = $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFree(): ?bool
|
||||
{
|
||||
return $this->isFree;
|
||||
}
|
||||
|
||||
public function setIsFree(bool $isFree): static
|
||||
{
|
||||
$this->isFree = $isFree;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isOnlineMode(): ?bool
|
||||
{
|
||||
return $this->onlineMode;
|
||||
}
|
||||
|
||||
public function setOnlineMode(bool $onlineMode): static
|
||||
{
|
||||
$this->onlineMode = $onlineMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQueryString(): ?string
|
||||
{
|
||||
return $this->queryString;
|
||||
}
|
||||
|
||||
public function setQueryString(?string $queryString): static
|
||||
{
|
||||
$this->queryString = $queryString;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(?\DateTimeInterface $createdAt): static
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isIntervalIsFree(): ?bool
|
||||
{
|
||||
return $this->intervalIsFree;
|
||||
}
|
||||
|
||||
public function setIntervalIsFree(bool $intervalIsFree): static
|
||||
{
|
||||
$this->intervalIsFree = $intervalIsFree;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPriceInfo(): ?array
|
||||
{
|
||||
return $this->priceInfo;
|
||||
}
|
||||
|
||||
public function setPriceInfo(?array $priceInfo): static
|
||||
{
|
||||
$this->priceInfo = $priceInfo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,933 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Behavior\UpdateTimestampTrait;
|
||||
use App\Repository\SiteServiceRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SiteServiceRepository::class)]
|
||||
#[ORM\Table(name: 'site_services')]
|
||||
#[ORM\Index(name: 'idx_site_services_region_id', columns: ['region_id'])]
|
||||
#[ORM\Index(name: 'idx_site_services_active', columns: ['active'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class SiteService
|
||||
{
|
||||
use UpdateTimestampTrait;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
#[Groups(['site_service:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[ORM\Column(name: 'region_id', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $alias = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $content = null;
|
||||
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
#[Groups(['site_service:read'])]
|
||||
private ?\DateTimeInterface $updateAt = null;
|
||||
|
||||
#[ORM\Column(name: 'link_videoreviews', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $linkVideoreviews = null;
|
||||
|
||||
#[ORM\Column(name: 'preview_img', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $previewImg = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $faq = null;
|
||||
|
||||
#[ORM\Column(name: 'part_price', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $partPrice = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $pokazaniya = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $preparation = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $protivopokazaniya = null;
|
||||
|
||||
#[ORM\Column(name: 'hide_sign_btn', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $hideSignBtn = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $quiz = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $tags = null;
|
||||
|
||||
#[ORM\Column(name: 'tags_important', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $tagsImportant = null;
|
||||
|
||||
#[ORM\Column(name: 'banner_img', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $bannerImg = null;
|
||||
|
||||
#[ORM\Column(name: 'banner_img_m', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $bannerImgM = null;
|
||||
|
||||
#[ORM\Column(name: 'banner_img_url', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $bannerImgUrl = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $clinics = null;
|
||||
|
||||
#[ORM\Column(name: 'download_file', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $downloadFile = null;
|
||||
|
||||
#[ORM\Column(name: 'full_width_banner', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $fullWidthBanner = null;
|
||||
|
||||
#[ORM\Column(name: 'staff_up', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $staffUp = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $advantages = null;
|
||||
|
||||
#[ORM\Column(name: 'hide_picture', type: Types::INTEGER, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?int $hidePicture = null;
|
||||
|
||||
#[ORM\Column(name: 'kod_uslug', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $kodUslug = null;
|
||||
|
||||
#[ORM\Column(name: 'link_price', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $linkPrice = null;
|
||||
|
||||
#[ORM\Column(name: 'photos_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $photosTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'sale_id', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $saleId = null;
|
||||
|
||||
#[ORM\Column(name: 'sort_staff', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $sortStaff = null;
|
||||
|
||||
#[ORM\Column(name: 'contraindications_list', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $contraindicationsList = null;
|
||||
|
||||
#[ORM\Column(name: 'custom_block_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $customBlockText = null;
|
||||
|
||||
#[ORM\Column(name: 'custom_block_text2', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $customBlockText2 = null;
|
||||
|
||||
#[ORM\Column(name: 'custom_block_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $customBlockTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'custom_block_title2', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $customBlockTitle2 = null;
|
||||
|
||||
#[ORM\Column(name: 'indications_list', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $indicationsList = null;
|
||||
|
||||
#[ORM\Column(name: 'link_articles_services', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $linkArticlesServices = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_list', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $plusList = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $plusText = null;
|
||||
|
||||
#[ORM\Column(name: 'plus_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $plusTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'prepare_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $prepareTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'process_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $processText = null;
|
||||
|
||||
#[ORM\Column(name: 'process_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $processTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'services_list', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $servicesList = null;
|
||||
|
||||
#[ORM\Column(name: 'services_photos', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $servicesPhotos = null;
|
||||
|
||||
#[ORM\Column(name: 'services_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $servicesTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'text_up', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $textUp = null;
|
||||
|
||||
#[ORM\Column(name: 'training_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $trainingText = null;
|
||||
|
||||
#[ORM\Column(name: 'why_text', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $whyText = null;
|
||||
|
||||
#[ORM\Column(name: 'why_title', type: Types::TEXT, nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?string $whyTitle = null;
|
||||
|
||||
#[ORM\Column(name: 'link_faq', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $linkFaq = null;
|
||||
|
||||
#[ORM\Column(name: 'link_services', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $linkServices = null;
|
||||
|
||||
#[ORM\Column(name: 'link_staff', type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $linkStaff = null;
|
||||
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
#[Groups(['site_service:read', 'site_service:write'])]
|
||||
private ?array $photos = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(?bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(?string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): self
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
|
||||
public function setUpdateAt(?\DateTimeInterface $updateAt): self
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkVideoreviews(): ?array
|
||||
{
|
||||
return $this->linkVideoreviews;
|
||||
}
|
||||
|
||||
public function setLinkVideoreviews(?array $linkVideoreviews): self
|
||||
{
|
||||
$this->linkVideoreviews = $linkVideoreviews;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreviewImg(): ?string
|
||||
{
|
||||
return $this->previewImg;
|
||||
}
|
||||
|
||||
public function setPreviewImg(?string $previewImg): self
|
||||
{
|
||||
$this->previewImg = $previewImg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFaq(): ?array
|
||||
{
|
||||
return $this->faq;
|
||||
}
|
||||
|
||||
public function setFaq(?array $faq): self
|
||||
{
|
||||
$this->faq = $faq;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPartPrice(): ?string
|
||||
{
|
||||
return $this->partPrice;
|
||||
}
|
||||
|
||||
public function setPartPrice(?string $partPrice): self
|
||||
{
|
||||
$this->partPrice = $partPrice;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPokazaniya(): ?string
|
||||
{
|
||||
return $this->pokazaniya;
|
||||
}
|
||||
|
||||
public function setPokazaniya(?string $pokazaniya): self
|
||||
{
|
||||
$this->pokazaniya = $pokazaniya;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreparation(): ?string
|
||||
{
|
||||
return $this->preparation;
|
||||
}
|
||||
|
||||
public function setPreparation(?string $preparation): self
|
||||
{
|
||||
$this->preparation = $preparation;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProtivopokazaniya(): ?string
|
||||
{
|
||||
return $this->protivopokazaniya;
|
||||
}
|
||||
|
||||
public function setProtivopokazaniya(?string $protivopokazaniya): self
|
||||
{
|
||||
$this->protivopokazaniya = $protivopokazaniya;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHideSignBtn(): ?array
|
||||
{
|
||||
return $this->hideSignBtn;
|
||||
}
|
||||
|
||||
public function setHideSignBtn(?array $hideSignBtn): self
|
||||
{
|
||||
$this->hideSignBtn = $hideSignBtn;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuiz(): ?array
|
||||
{
|
||||
return $this->quiz;
|
||||
}
|
||||
|
||||
public function setQuiz(?array $quiz): self
|
||||
{
|
||||
$this->quiz = $quiz;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTags(): ?array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function setTags(?array $tags): self
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTagsImportant(): ?array
|
||||
{
|
||||
return $this->tagsImportant;
|
||||
}
|
||||
|
||||
public function setTagsImportant(?array $tagsImportant): self
|
||||
{
|
||||
$this->tagsImportant = $tagsImportant;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBannerImg(): ?string
|
||||
{
|
||||
return $this->bannerImg;
|
||||
}
|
||||
|
||||
public function setBannerImg(?string $bannerImg): self
|
||||
{
|
||||
$this->bannerImg = $bannerImg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBannerImgM(): ?string
|
||||
{
|
||||
return $this->bannerImgM;
|
||||
}
|
||||
|
||||
public function setBannerImgM(?string $bannerImgM): self
|
||||
{
|
||||
$this->bannerImgM = $bannerImgM;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBannerImgUrl(): ?string
|
||||
{
|
||||
return $this->bannerImgUrl;
|
||||
}
|
||||
|
||||
public function setBannerImgUrl(?string $bannerImgUrl): self
|
||||
{
|
||||
$this->bannerImgUrl = $bannerImgUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClinics(): ?array
|
||||
{
|
||||
return $this->clinics;
|
||||
}
|
||||
|
||||
public function setClinics(?array $clinics): self
|
||||
{
|
||||
$this->clinics = $clinics;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDownloadFile(): ?string
|
||||
{
|
||||
return $this->downloadFile;
|
||||
}
|
||||
|
||||
public function setDownloadFile(?string $downloadFile): self
|
||||
{
|
||||
$this->downloadFile = $downloadFile;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFullWidthBanner(): ?string
|
||||
{
|
||||
return $this->fullWidthBanner;
|
||||
}
|
||||
|
||||
public function setFullWidthBanner(?string $fullWidthBanner): self
|
||||
{
|
||||
$this->fullWidthBanner = $fullWidthBanner;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStaffUp(): ?array
|
||||
{
|
||||
return $this->staffUp;
|
||||
}
|
||||
|
||||
public function setStaffUp(?array $staffUp): self
|
||||
{
|
||||
$this->staffUp = $staffUp;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAdvantages(): ?array
|
||||
{
|
||||
return $this->advantages;
|
||||
}
|
||||
|
||||
public function setAdvantages(?array $advantages): self
|
||||
{
|
||||
$this->advantages = $advantages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHidePicture(): ?int
|
||||
{
|
||||
return $this->hidePicture;
|
||||
}
|
||||
|
||||
public function setHidePicture(?int $hidePicture): self
|
||||
{
|
||||
$this->hidePicture = $hidePicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getKodUslug(): ?string
|
||||
{
|
||||
return $this->kodUslug;
|
||||
}
|
||||
|
||||
public function setKodUslug(?string $kodUslug): self
|
||||
{
|
||||
$this->kodUslug = $kodUslug;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkPrice(): ?string
|
||||
{
|
||||
return $this->linkPrice;
|
||||
}
|
||||
|
||||
public function setLinkPrice(?string $linkPrice): self
|
||||
{
|
||||
$this->linkPrice = $linkPrice;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhotosTitle(): ?string
|
||||
{
|
||||
return $this->photosTitle;
|
||||
}
|
||||
|
||||
public function setPhotosTitle(?string $photosTitle): self
|
||||
{
|
||||
$this->photosTitle = $photosTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSaleId(): ?array
|
||||
{
|
||||
return $this->saleId;
|
||||
}
|
||||
|
||||
public function setSaleId(?array $saleId): self
|
||||
{
|
||||
$this->saleId = $saleId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSortStaff(): ?array
|
||||
{
|
||||
return $this->sortStaff;
|
||||
}
|
||||
|
||||
public function setSortStaff(?array $sortStaff): self
|
||||
{
|
||||
$this->sortStaff = $sortStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContraindicationsList(): ?string
|
||||
{
|
||||
return $this->contraindicationsList;
|
||||
}
|
||||
|
||||
public function setContraindicationsList(?string $contraindicationsList): self
|
||||
{
|
||||
$this->contraindicationsList = $contraindicationsList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomBlockText(): ?string
|
||||
{
|
||||
return $this->customBlockText;
|
||||
}
|
||||
|
||||
public function setCustomBlockText(?string $customBlockText): self
|
||||
{
|
||||
$this->customBlockText = $customBlockText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomBlockText2(): ?string
|
||||
{
|
||||
return $this->customBlockText2;
|
||||
}
|
||||
|
||||
public function setCustomBlockText2(?string $customBlockText2): self
|
||||
{
|
||||
$this->customBlockText2 = $customBlockText2;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomBlockTitle(): ?string
|
||||
{
|
||||
return $this->customBlockTitle;
|
||||
}
|
||||
|
||||
public function setCustomBlockTitle(?string $customBlockTitle): self
|
||||
{
|
||||
$this->customBlockTitle = $customBlockTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomBlockTitle2(): ?string
|
||||
{
|
||||
return $this->customBlockTitle2;
|
||||
}
|
||||
|
||||
public function setCustomBlockTitle2(?string $customBlockTitle2): self
|
||||
{
|
||||
$this->customBlockTitle2 = $customBlockTitle2;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIndicationsList(): ?string
|
||||
{
|
||||
return $this->indicationsList;
|
||||
}
|
||||
|
||||
public function setIndicationsList(?string $indicationsList): self
|
||||
{
|
||||
$this->indicationsList = $indicationsList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkArticlesServices(): ?array
|
||||
{
|
||||
return $this->linkArticlesServices;
|
||||
}
|
||||
|
||||
public function setLinkArticlesServices(?array $linkArticlesServices): self
|
||||
{
|
||||
$this->linkArticlesServices = $linkArticlesServices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusList(): ?string
|
||||
{
|
||||
return $this->plusList;
|
||||
}
|
||||
|
||||
public function setPlusList(?string $plusList): self
|
||||
{
|
||||
$this->plusList = $plusList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusText(): ?string
|
||||
{
|
||||
return $this->plusText;
|
||||
}
|
||||
|
||||
public function setPlusText(?string $plusText): self
|
||||
{
|
||||
$this->plusText = $plusText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlusTitle(): ?string
|
||||
{
|
||||
return $this->plusTitle;
|
||||
}
|
||||
|
||||
public function setPlusTitle(?string $plusTitle): self
|
||||
{
|
||||
$this->plusTitle = $plusTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPrepareTitle(): ?string
|
||||
{
|
||||
return $this->prepareTitle;
|
||||
}
|
||||
|
||||
public function setPrepareTitle(?string $prepareTitle): self
|
||||
{
|
||||
$this->prepareTitle = $prepareTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProcessText(): ?string
|
||||
{
|
||||
return $this->processText;
|
||||
}
|
||||
|
||||
public function setProcessText(?string $processText): self
|
||||
{
|
||||
$this->processText = $processText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProcessTitle(): ?string
|
||||
{
|
||||
return $this->processTitle;
|
||||
}
|
||||
|
||||
public function setProcessTitle(?string $processTitle): self
|
||||
{
|
||||
$this->processTitle = $processTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesList(): ?string
|
||||
{
|
||||
return $this->servicesList;
|
||||
}
|
||||
|
||||
public function setServicesList(?string $servicesList): self
|
||||
{
|
||||
$this->servicesList = $servicesList;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesPhotos(): ?array
|
||||
{
|
||||
return $this->servicesPhotos;
|
||||
}
|
||||
|
||||
public function setServicesPhotos(?array $servicesPhotos): self
|
||||
{
|
||||
$this->servicesPhotos = $servicesPhotos;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServicesTitle(): ?string
|
||||
{
|
||||
return $this->servicesTitle;
|
||||
}
|
||||
|
||||
public function setServicesTitle(?string $servicesTitle): self
|
||||
{
|
||||
$this->servicesTitle = $servicesTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTextUp(): ?string
|
||||
{
|
||||
return $this->textUp;
|
||||
}
|
||||
|
||||
public function setTextUp(?string $textUp): self
|
||||
{
|
||||
$this->textUp = $textUp;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTrainingText(): ?string
|
||||
{
|
||||
return $this->trainingText;
|
||||
}
|
||||
|
||||
public function setTrainingText(?string $trainingText): self
|
||||
{
|
||||
$this->trainingText = $trainingText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyText(): ?string
|
||||
{
|
||||
return $this->whyText;
|
||||
}
|
||||
|
||||
public function setWhyText(?string $whyText): self
|
||||
{
|
||||
$this->whyText = $whyText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyTitle(): ?string
|
||||
{
|
||||
return $this->whyTitle;
|
||||
}
|
||||
|
||||
public function setWhyTitle(?string $whyTitle): self
|
||||
{
|
||||
$this->whyTitle = $whyTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkFaq(): ?array
|
||||
{
|
||||
return $this->linkFaq;
|
||||
}
|
||||
|
||||
public function setLinkFaq(?array $linkFaq): self
|
||||
{
|
||||
$this->linkFaq = $linkFaq;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkServices(): ?array
|
||||
{
|
||||
return $this->linkServices;
|
||||
}
|
||||
|
||||
public function setLinkServices(?array $linkServices): self
|
||||
{
|
||||
$this->linkServices = $linkServices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkStaff(): ?array
|
||||
{
|
||||
return $this->linkStaff;
|
||||
}
|
||||
|
||||
public function setLinkStaff(?array $linkStaff): self
|
||||
{
|
||||
$this->linkStaff = $linkStaff;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhotos(): ?array
|
||||
{
|
||||
return $this->photos;
|
||||
}
|
||||
|
||||
public function setPhotos(?array $photos): self
|
||||
{
|
||||
$this->photos = $photos;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,720 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use App\Entity\Location;
|
||||
use App\Entity\Review;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use App\Repository\SpecialistRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SpecialistRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[ORM\Index(name: 'idx_specialist_s_type', columns: ['s_type'])]
|
||||
#[ORM\Index(name: 'idx_specialist_alias', columns: ['alias'])]
|
||||
#[ORM\Index(name: 'idx_specialist_region_id', columns: ['region_id'])]
|
||||
class Specialist
|
||||
{
|
||||
#[Groups(['specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $id;
|
||||
|
||||
#[SerializedName('nameString')]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $name;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private ?string $previewPicture = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $active;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $displaySchedule;
|
||||
|
||||
#[ORM\Column(type: 'string', nullable: true)]
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
private ?string $dcodes = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
private ?int $regionId = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $alias;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private ?string $post = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private ?string $experience = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
private ?int $sType = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
private \DateTimeInterface $updateAt;
|
||||
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: Location::class,
|
||||
mappedBy: 'specialist',
|
||||
cascade: ['persist', 'remove'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
#[Groups(['specialist:detail', 'specialist:read'])]
|
||||
private Collection $locations;
|
||||
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: Review::class,
|
||||
mappedBy: 'specialist',
|
||||
cascade: ['persist', 'remove'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
#[Groups(['specialist:detail'])]
|
||||
private Collection $reviews;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $content = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $tags = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $highlightedTags = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $video = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $videoVertical = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $scheduleText = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $category = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $patientAge = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(type: 'jsonb', nullable: true)]
|
||||
private ?array $kodoper = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $onlyOnlineMode = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $prodoctor = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $prodoctorText = null;
|
||||
|
||||
#[Groups(['specialist:write', 'specialist:detail', 'to.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $prodoctorLink = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, SpecialistDocs>
|
||||
*/
|
||||
#[Groups(['specialist:detail'])]
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: SpecialistDocs::class,
|
||||
mappedBy: 'specialist',
|
||||
cascade: ['remove'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
private Collection $specialistDocs;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Stock>
|
||||
*/
|
||||
#[Groups(['specialist:detail'])]
|
||||
#[ORM\ManyToMany(targetEntity: Stock::class, mappedBy: 'specialist')]
|
||||
private Collection $stocks;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
private ?string $degree = null;
|
||||
|
||||
#[ORM\Column]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
private ?bool $kiosk = null;
|
||||
|
||||
#[ORM\Column(type: Types::JSONB, nullable: true)]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
private mixed $filials = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
private ?bool $acceptsDms = null;
|
||||
|
||||
#[ORM\Column(type: Types::JSONB, nullable: true)]
|
||||
#[Groups(['specialist:write', 'specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
private mixed $specialities = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->locations = new ArrayCollection();
|
||||
$this->specialistDocs = new ArrayCollection();
|
||||
$this->stocks = new ArrayCollection();
|
||||
$this->reviews = new ArrayCollection();
|
||||
}
|
||||
|
||||
#[ORM\PreFlush]
|
||||
public function preFlush()
|
||||
{
|
||||
$this->updateAt = new \DateTime();
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[SerializedName('fullName')]
|
||||
#[Groups(['specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
public function getFullName(): array
|
||||
{
|
||||
$fio = array_map('trim', explode(' ', trim($this->name)));
|
||||
$result = [
|
||||
'lastName' => '',
|
||||
'firstName' => '',
|
||||
'middleName' => ''
|
||||
];
|
||||
|
||||
foreach ($fio as $index => $part) {
|
||||
if ($index === 0) {
|
||||
$result['lastName'] = $part;
|
||||
} elseif ($index === 1) {
|
||||
$result['firstName'] = $part;
|
||||
} elseif ($index === 2) {
|
||||
$result['middleName'] = $part;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getPreviewPicture(): ?string
|
||||
{
|
||||
return $this->previewPicture;
|
||||
}
|
||||
|
||||
public function setPreviewPicture(?string $previewPicture): self
|
||||
{
|
||||
$this->previewPicture = $previewPicture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplaySchedule(): bool
|
||||
{
|
||||
return $this->displaySchedule;
|
||||
}
|
||||
|
||||
public function setDisplaySchedule(bool $displaySchedule): self
|
||||
{
|
||||
$this->displaySchedule = $displaySchedule;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDcodes(): ?string
|
||||
{
|
||||
return $this->dcodes;
|
||||
}
|
||||
|
||||
public function setDcodes(?string $dcodes): self
|
||||
{
|
||||
$this->dcodes = $dcodes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlias(): string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias(string $alias): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPost(): ?string
|
||||
{
|
||||
return $this->post;
|
||||
}
|
||||
|
||||
public function setPost(?string $post): self
|
||||
{
|
||||
$this->post = $post;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getExperience(): ?string
|
||||
{
|
||||
return $this->experience;
|
||||
}
|
||||
|
||||
public function setExperience(?string $experience): self
|
||||
{
|
||||
$this->experience = $experience;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSType(): ?int
|
||||
{
|
||||
return $this->sType;
|
||||
}
|
||||
|
||||
public function setSType(?int $sType): self
|
||||
{
|
||||
$this->sType = $sType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): \DateTimeInterface
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
public function getLocations(): Collection
|
||||
{
|
||||
return $this->locations;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): static
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): static
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTags(): ?array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function setTags(?array $tags): static
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHighlightedTags(): ?array
|
||||
{
|
||||
return $this->highlightedTags;
|
||||
}
|
||||
|
||||
public function setHighlightedTags(?array $highlightedTags): static
|
||||
{
|
||||
$this->highlightedTags = $highlightedTags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVideo(): ?string
|
||||
{
|
||||
return $this->video;
|
||||
}
|
||||
|
||||
public function setVideo(?string $video): static
|
||||
{
|
||||
$this->video = $video;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVideoVertical(): ?string
|
||||
{
|
||||
return $this->videoVertical;
|
||||
}
|
||||
|
||||
public function setVideoVertical(?string $videoVertical): static
|
||||
{
|
||||
$this->videoVertical = $videoVertical;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getScheduleText(): ?string
|
||||
{
|
||||
return $this->scheduleText;
|
||||
}
|
||||
|
||||
public function setScheduleText(?string $scheduleText): static
|
||||
{
|
||||
$this->scheduleText = $scheduleText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCategory(): ?string
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
public function setCategory(?string $category): static
|
||||
{
|
||||
$this->category = $category;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPatientAge(): ?int
|
||||
{
|
||||
return $this->patientAge;
|
||||
}
|
||||
|
||||
public function setPatientAge(?int $patientAge): static
|
||||
{
|
||||
$this->patientAge = $patientAge;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getKodoper(): ?array
|
||||
{
|
||||
return $this->kodoper;
|
||||
}
|
||||
|
||||
public function setKodoper(?array $kodoper): static
|
||||
{
|
||||
$this->kodoper = $kodoper;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isOnlyOnlineMode(): ?bool
|
||||
{
|
||||
return $this->onlyOnlineMode;
|
||||
}
|
||||
|
||||
public function setOnlyOnlineMode(?bool $onlyOnlineMode): static
|
||||
{
|
||||
$this->onlyOnlineMode = $onlyOnlineMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isProdoctor(): ?bool
|
||||
{
|
||||
return $this->prodoctor;
|
||||
}
|
||||
|
||||
public function setProdoctor(?bool $prodoctor): static
|
||||
{
|
||||
$this->prodoctor = $prodoctor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProdoctorText(): ?string
|
||||
{
|
||||
return $this->prodoctorText;
|
||||
}
|
||||
|
||||
public function setProdoctorText(?string $prodoctorText): static
|
||||
{
|
||||
$this->prodoctorText = $prodoctorText;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProdoctorLink(): ?string
|
||||
{
|
||||
return $this->prodoctorLink;
|
||||
}
|
||||
|
||||
public function setProdoctorLink(?string $prodoctorLink): static
|
||||
{
|
||||
$this->prodoctorLink = $prodoctorLink;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, SpecialistDocs>
|
||||
*/
|
||||
public function getSpecialistDocs(): Collection
|
||||
{
|
||||
return $this->specialistDocs;
|
||||
}
|
||||
|
||||
public function addSpecialistDoc(SpecialistDocs $specialistDoc): static
|
||||
{
|
||||
if (!$this->specialistDocs->contains($specialistDoc)) {
|
||||
$this->specialistDocs->add($specialistDoc);
|
||||
$specialistDoc->setSpecialist($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSpecialistDoc(SpecialistDocs $specialistDoc): static
|
||||
{
|
||||
if ($this->specialistDocs->removeElement($specialistDoc)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($specialistDoc->getSpecialist() === $this) {
|
||||
$specialistDoc->setSpecialist(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Stock>
|
||||
*/
|
||||
public function getStocks(): Collection
|
||||
{
|
||||
return $this->stocks;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): static
|
||||
{
|
||||
if (!$this->stocks->contains($stock)) {
|
||||
$this->stocks->add($stock);
|
||||
$stock->addSpecialist($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeStock(Stock $stock): static
|
||||
{
|
||||
if ($this->stocks->removeElement($stock)) {
|
||||
$stock->removeSpecialist($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function isDisplaySchedule(): ?bool
|
||||
{
|
||||
return $this->displaySchedule;
|
||||
}
|
||||
|
||||
public function setUpdateAt(\DateTime $updateAt): static
|
||||
{
|
||||
$this->updateAt = $updateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addLocation(Location $location): static
|
||||
{
|
||||
if (!$this->locations->contains($location)) {
|
||||
$this->locations->add($location);
|
||||
$location->setSpecialist($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeLocation(Location $location): static
|
||||
{
|
||||
if ($this->locations->removeElement($location)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($location->getSpecialist() === $this) {
|
||||
$location->setSpecialist(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Review>
|
||||
*/
|
||||
|
||||
public function getReviews(): Collection
|
||||
{
|
||||
return $this->reviews;
|
||||
}
|
||||
|
||||
public function addReview(Review $review): static
|
||||
{
|
||||
if (!$this->reviews->contains($review)) {
|
||||
$this->reviews->add($review);
|
||||
$review->setSpecialist($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeReview(Review $review): static
|
||||
{
|
||||
if ($this->reviews->removeElement($review)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($review->getSpecialist() === $this) {
|
||||
$review->setSpecialist(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[SerializedName('reviewsCount')]
|
||||
#[Groups(['specialist:read', 'specialist:detail', 'to.specialist:read'])]
|
||||
public function getReviewsCount(): int
|
||||
{
|
||||
return count($this->reviews);
|
||||
}
|
||||
|
||||
public function getDegree(): ?string
|
||||
{
|
||||
return $this->degree;
|
||||
}
|
||||
|
||||
public function setDegree(?string $degree): static
|
||||
{
|
||||
$this->degree = $degree;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isKiosk(): ?bool
|
||||
{
|
||||
return $this->kiosk;
|
||||
}
|
||||
|
||||
public function setKiosk(bool $kiosk): static
|
||||
{
|
||||
$this->kiosk = $kiosk;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilials(): mixed
|
||||
{
|
||||
return $this->filials;
|
||||
}
|
||||
|
||||
public function setFilials(mixed $filials): static
|
||||
{
|
||||
$this->filials = $filials;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isAcceptsDms(): ?bool
|
||||
{
|
||||
return $this->acceptsDms;
|
||||
}
|
||||
|
||||
public function setAcceptsDms(?bool $acceptsDms): static
|
||||
{
|
||||
$this->acceptsDms = $acceptsDms;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpecialities(): mixed
|
||||
{
|
||||
return $this->specialities;
|
||||
}
|
||||
|
||||
public function setSpecialities(mixed $specialities): static
|
||||
{
|
||||
$this->specialities = $specialities;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\SpecialistDcodeDescriptionRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SpecialistDcodeDescriptionRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class SpecialistDcodeDescription
|
||||
{
|
||||
#[Groups(['specialist.dcode.description:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read', 'specialist.dcode.description:write'])]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private ?int $dcode = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read', 'specialist.dcode.description:write'])]
|
||||
#[ORM\Column(type: Types::BIGINT, nullable: true)]
|
||||
private ?int $department = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read'])]
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(name: 'specialist_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
||||
private ?Specialist $specialist = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read', 'specialist.dcode.description:write'])]
|
||||
#[ORM\Column(type: Types::TEXT)]
|
||||
private ?string $content = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read'])]
|
||||
#[ORM\Column(name: 'create_at', type: Types::DATETIME_IMMUTABLE)]
|
||||
private ?\DateTimeImmutable $createAt = null;
|
||||
|
||||
#[Groups(['specialist.dcode.description:read'])]
|
||||
#[ORM\Column(name: 'update_at', type: Types::DATETIME_IMMUTABLE)]
|
||||
private ?\DateTimeImmutable $updateAt = null;
|
||||
|
||||
#[ORM\PrePersist]
|
||||
public function onPrePersist(): void
|
||||
{
|
||||
$now = new \DateTimeImmutable();
|
||||
$this->createAt = $now;
|
||||
$this->updateAt = $now;
|
||||
}
|
||||
|
||||
#[ORM\PreUpdate]
|
||||
public function onPreUpdate(): void
|
||||
{
|
||||
$this->updateAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDcode(): ?int
|
||||
{
|
||||
return $this->dcode;
|
||||
}
|
||||
|
||||
public function setDcode(?int $dcode): static
|
||||
{
|
||||
$this->dcode = $dcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepartment(): ?int
|
||||
{
|
||||
return $this->department;
|
||||
}
|
||||
|
||||
public function setDepartment(?int $department): static
|
||||
{
|
||||
$this->department = $department;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpecialist(): ?Specialist
|
||||
{
|
||||
return $this->specialist;
|
||||
}
|
||||
|
||||
public function setSpecialist(?Specialist $specialist): static
|
||||
{
|
||||
$this->specialist = $specialist;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): static
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreateAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->createAt;
|
||||
}
|
||||
|
||||
public function getUpdateAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->updateAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\SpecialistDocsRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SpecialistDocsRepository::class)]
|
||||
class SpecialistDocs
|
||||
{
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read', 'specialist.docs:write'])]
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read', 'specialist.docs:write'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $description = null;
|
||||
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $picture = null;
|
||||
|
||||
#[Assert\Type(type: 'boolean')]
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read', 'specialist.docs:write'])]
|
||||
#[ORM\Column]
|
||||
private ?bool $active = null;
|
||||
|
||||
#[Groups(['from.specialist:read', 'specialist.docs:read', 'specialist.docs:write'])]
|
||||
#[Assert\NotBlank()]
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $type = null;
|
||||
|
||||
#[Groups(['specialist.docs:read'])]
|
||||
#[ORM\ManyToOne(inversedBy: 'specialistDocs')]
|
||||
private ?Specialist $specialist = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): static
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPicture(): ?string
|
||||
{
|
||||
return $this->picture;
|
||||
}
|
||||
|
||||
public function setPicture(?string $picture): static
|
||||
{
|
||||
$this->picture = $picture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isActive(): ?bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): static
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(string $type): static
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSpecialist(): ?Specialist
|
||||
{
|
||||
return $this->specialist;
|
||||
}
|
||||
|
||||
public function setSpecialist(?Specialist $specialist): static
|
||||
{
|
||||
$this->specialist = $specialist;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\StockRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: StockRepository::class)]
|
||||
class Stock
|
||||
{
|
||||
#[Groups(['stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['stock:write', 'stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[Groups(['stock:write', 'stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT)]
|
||||
private ?string $content = null;
|
||||
|
||||
#[Groups(['stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $picture = null;
|
||||
|
||||
#[Groups(['stock:write', 'stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[Groups(['stock:write', 'stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column]
|
||||
private ?\DateTime $startDate = null;
|
||||
|
||||
#[Groups(['stock:write', 'stock:read', 'from.specialist:read'])]
|
||||
#[ORM\Column]
|
||||
private ?\DateTime $endDate = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Specialist>
|
||||
*/
|
||||
#[Groups(['stock:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: Specialist::class, inversedBy: 'stocks')]
|
||||
private Collection $specialist;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->specialist = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(string $content): static
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPicture(): ?string
|
||||
{
|
||||
return $this->picture;
|
||||
}
|
||||
|
||||
public function setPicture(?string $picture): static
|
||||
{
|
||||
$this->picture = $picture;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): static
|
||||
{
|
||||
$this->anons = $anons;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?\DateTime
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function setStartDate(\DateTime $startDate): static
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEndDate(): ?\DateTime
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
public function setEndDate(\DateTime $endDate): static
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Specialist>
|
||||
*/
|
||||
public function getSpecialist(): Collection
|
||||
{
|
||||
return $this->specialist;
|
||||
}
|
||||
|
||||
public function addSpecialist(Specialist $specialist): static
|
||||
{
|
||||
if (!$this->specialist->contains($specialist)) {
|
||||
$this->specialist->add($specialist);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSpecialist(Specialist $specialist): static
|
||||
{
|
||||
$this->specialist->removeElement($specialist);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\Table(name: 'users')]
|
||||
#[UniqueEntity(fields: ['uid'], message: 'An account with the same uid, already exists.')]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'integer', unique: true)]
|
||||
private int $uid;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 180, nullable: true)]
|
||||
private ?string $email = null;
|
||||
|
||||
#[ORM\Column(type: 'json')]
|
||||
private array $roles = [];
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $regionId;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private string $password;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $birthDate = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime', nullable: true)]
|
||||
private ?\DateTimeInterface $loggedIn = null;
|
||||
|
||||
public function toArray() : array
|
||||
{
|
||||
return [
|
||||
'uid' => $this->getUid(),
|
||||
'bdate' => $this->getBirthDate(),
|
||||
'roles' => $this->getRoles(),
|
||||
'regionId' => $this->getRegionId(),
|
||||
'loggedIn' => $this->getLoggedIn()
|
||||
];
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(?string $email): self
|
||||
{
|
||||
$this->email = $email;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A visual identifier that represents this user.
|
||||
*
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return (string) $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getRoles(): array
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
$roles[] = 'ROLE_USER';
|
||||
|
||||
return array_unique($roles);
|
||||
}
|
||||
|
||||
public function setRoles(array $roles): self
|
||||
{
|
||||
$this->roles = $roles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PasswordAuthenticatedUserInterface
|
||||
*/
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): self
|
||||
{
|
||||
$this->password = $password;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
|
||||
public function getSalt(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return (string) $this->email;
|
||||
}
|
||||
|
||||
public function getUid(): int
|
||||
{
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
public function setUid(int $uid): self
|
||||
{
|
||||
$this->uid = $uid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegionId(): ?int
|
||||
{
|
||||
return $this->regionId;
|
||||
}
|
||||
|
||||
public function setRegionId(?int $regionId): self
|
||||
{
|
||||
$this->regionId = $regionId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBirthDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->birthDate;
|
||||
}
|
||||
|
||||
public function setBirthDate(\DateTimeInterface $birthDate): static
|
||||
{
|
||||
$this->birthDate = $birthDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLoggedIn(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->loggedIn;
|
||||
}
|
||||
|
||||
public function setLoggedIn(?\DateTimeInterface $loggedIn): static
|
||||
{
|
||||
$this->loggedIn = $loggedIn;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updateLoggedIn(): static
|
||||
{
|
||||
$this->loggedIn = new \DateTime();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is kept for backward compatibility. The fullName field has been removed.
|
||||
* @return null
|
||||
*/
|
||||
public function getFullName(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\WebGetDocinfoRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: WebGetDocinfoRepository::class)]
|
||||
#[ORM\Table(name: 'web_get_docinfo')]
|
||||
class WebGetDocinfo
|
||||
{
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'bigint')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(name: 'source_table', type: 'string', length: 10)]
|
||||
private ?string $sourceTable = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'doc_name', type: 'string', length: 80, nullable: true)]
|
||||
private ?string $docName = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'doc_post', type: 'string', length: 256, nullable: true)]
|
||||
private ?string $docPost = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'integer', nullable: true)]
|
||||
private ?int $filial = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'smallint', nullable: true)]
|
||||
private ?int $viewinweb = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'bigint', nullable: true)]
|
||||
private ?int $depnum = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'first_schid', type: 'bigint', nullable: true)]
|
||||
private ?int $firstSchid = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'second_schid', type: 'bigint', nullable: true)]
|
||||
private ?int $secondSchid = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'accepts_dms', type: 'integer', nullable: true)]
|
||||
private ?int $acceptsDms = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'string', length: 1024, nullable: true)]
|
||||
private ?string $anons = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'string', length: 4096, nullable: true)]
|
||||
private ?string $content = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'datetime', nullable: true)]
|
||||
private ?\DateTimeInterface $experience = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'smallint', nullable: true)]
|
||||
private ?int $category = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(type: 'string', length: 120, nullable: true)]
|
||||
private ?string $degree = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'patient_bage', type: 'integer', nullable: true)]
|
||||
private ?int $patientBage = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'patient_fage', type: 'integer', nullable: true)]
|
||||
private ?int $patientFage = null;
|
||||
|
||||
#[Groups(['web_get_docinfo:read'])]
|
||||
#[ORM\Column(name: 'updated_at', type: 'datetime', nullable: true)]
|
||||
private ?\DateTimeInterface $updatedAt = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(?int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSourceTable(): ?string
|
||||
{
|
||||
return $this->sourceTable;
|
||||
}
|
||||
|
||||
public function setSourceTable(?string $sourceTable): self
|
||||
{
|
||||
$this->sourceTable = $sourceTable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDocName(): ?string
|
||||
{
|
||||
return $this->docName;
|
||||
}
|
||||
|
||||
public function setDocName(?string $docName): self
|
||||
{
|
||||
$this->docName = $docName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDocPost(): ?string
|
||||
{
|
||||
return $this->docPost;
|
||||
}
|
||||
|
||||
public function setDocPost(?string $docPost): self
|
||||
{
|
||||
$this->docPost = $docPost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilial(): ?int
|
||||
{
|
||||
return $this->filial;
|
||||
}
|
||||
|
||||
public function setFilial(?int $filial): self
|
||||
{
|
||||
$this->filial = $filial;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewinweb(): ?int
|
||||
{
|
||||
return $this->viewinweb;
|
||||
}
|
||||
|
||||
public function setViewinweb(?int $viewinweb): self
|
||||
{
|
||||
$this->viewinweb = $viewinweb;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDepnum(): ?int
|
||||
{
|
||||
return $this->depnum;
|
||||
}
|
||||
|
||||
public function setDepnum(?int $depnum): self
|
||||
{
|
||||
$this->depnum = $depnum;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFirstSchid(): ?int
|
||||
{
|
||||
return $this->firstSchid;
|
||||
}
|
||||
|
||||
public function setFirstSchid(?int $firstSchid): self
|
||||
{
|
||||
$this->firstSchid = $firstSchid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSecondSchid(): ?int
|
||||
{
|
||||
return $this->secondSchid;
|
||||
}
|
||||
|
||||
public function setSecondSchid(?int $secondSchid): self
|
||||
{
|
||||
$this->secondSchid = $secondSchid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAcceptsDms(): ?int
|
||||
{
|
||||
return $this->acceptsDms;
|
||||
}
|
||||
|
||||
public function setAcceptsDms(?int $acceptsDms): self
|
||||
{
|
||||
$this->acceptsDms = $acceptsDms;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnons(): ?string
|
||||
{
|
||||
return $this->anons;
|
||||
}
|
||||
|
||||
public function setAnons(?string $anons): self
|
||||
{
|
||||
$this->anons = $anons;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): ?string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(?string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getExperience(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->experience;
|
||||
}
|
||||
|
||||
public function setExperience(?\DateTimeInterface $experience): self
|
||||
{
|
||||
$this->experience = $experience;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCategory(): ?int
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
public function setCategory(?int $category): self
|
||||
{
|
||||
$this->category = $category;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDegree(): ?string
|
||||
{
|
||||
return $this->degree;
|
||||
}
|
||||
|
||||
public function setDegree(?string $degree): self
|
||||
{
|
||||
$this->degree = $degree;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPatientBage(): ?int
|
||||
{
|
||||
return $this->patientBage;
|
||||
}
|
||||
|
||||
public function setPatientBage(?int $patientBage): self
|
||||
{
|
||||
$this->patientBage = $patientBage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPatientFage(): ?int
|
||||
{
|
||||
return $this->patientFage;
|
||||
}
|
||||
|
||||
public function setPatientFage(?int $patientFage): self
|
||||
{
|
||||
$this->patientFage = $patientFage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
|
||||
{
|
||||
$this->updatedAt = $updatedAt;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\WidgetFormRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: WidgetFormRepository::class)]
|
||||
class WidgetForm
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: WidgetFormInput::class,
|
||||
mappedBy: 'widgetForm',
|
||||
cascade: ['persist', 'remove'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
private Collection $widgetFormInputs;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->widgetFormInputs = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<WidgetFormInput>
|
||||
*/
|
||||
public function getWidgetFormInputs(): Collection
|
||||
{
|
||||
$criteria = Criteria::create()
|
||||
->orderBy(['sort' => Criteria::ASC]);
|
||||
|
||||
return $this->widgetFormInputs->matching($criteria);
|
||||
}
|
||||
|
||||
public function addWidgetFormInput(WidgetFormInput $widgetFormInput): self
|
||||
{
|
||||
if (!$this->widgetFormInputs->contains($widgetFormInput)) {
|
||||
$this->widgetFormInputs->add($widgetFormInput);
|
||||
$widgetFormInput->setWidgetForm($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeWidgetFormInput(WidgetFormInput $widgetFormInput): self
|
||||
{
|
||||
if ($this->widgetFormInputs->removeElement($widgetFormInput)) {
|
||||
if ($widgetFormInput->getWidgetForm() === $this) {
|
||||
$widgetFormInput->setWidgetForm(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\WidgetFormInputRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: WidgetFormInputRepository::class)]
|
||||
class WidgetFormInput
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: "IDENTITY")]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $text = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $type = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private ?string $bitrix24Id = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: WidgetForm::class, inversedBy: 'widgetFormInputs')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?WidgetForm $widgetForm = null;
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $sort = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getText(): ?string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
public function setText(string $text): self
|
||||
{
|
||||
$this->text = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(string $type): self
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBitrix24Id(): ?string
|
||||
{
|
||||
return $this->bitrix24Id;
|
||||
}
|
||||
|
||||
public function setBitrix24Id(string $bitrix24Id): self
|
||||
{
|
||||
$this->bitrix24Id = $bitrix24Id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWidgetForm(): ?WidgetForm
|
||||
{
|
||||
return $this->widgetForm;
|
||||
}
|
||||
|
||||
public function setWidgetForm(?WidgetForm $widgetForm): self
|
||||
{
|
||||
$this->widgetForm = $widgetForm;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSort(): ?int
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
public function setSort(int $sort): self
|
||||
{
|
||||
$this->sort = $sort;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\EventListener;
|
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
class JsonExceptionHandler
|
||||
{
|
||||
public function onKernelException(ExceptionEvent $event): void
|
||||
{
|
||||
$exception = $event->getThrowable();
|
||||
|
||||
// Обрабатываем только определенные типы исключений
|
||||
if (!$exception instanceof NotFoundHttpException &&
|
||||
!$exception instanceof BadRequestHttpException) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Определяем тип ошибки и создаем соответствующий ответ
|
||||
if ($exception instanceof NotFoundHttpException) {
|
||||
$response = new JsonResponse([
|
||||
'error' => 'Not Found',
|
||||
'message' => 'The requested resource was not found',
|
||||
'code' => 404,
|
||||
'status' => 'error'
|
||||
], 404);
|
||||
} elseif ($exception instanceof BadRequestHttpException) {
|
||||
$response = new JsonResponse([
|
||||
'error' => 'Bad Request',
|
||||
'message' => $exception->getMessage() ?: 'Invalid request parameters',
|
||||
'code' => 400,
|
||||
'status' => 'error'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\WidgetFormInput;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
|
||||
class WidgetFormInputType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('text')
|
||||
->add('type', ChoiceType::class, [
|
||||
'choices' => [
|
||||
'Строка' => 'text',
|
||||
'Телефон' => 'phone',
|
||||
'Календаль' => 'date',
|
||||
'Коментарий' => 'textarea',
|
||||
],
|
||||
'empty_data' => null,
|
||||
'required' => false
|
||||
])
|
||||
->add('bitrix24Id')
|
||||
->add('sort')
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => WidgetFormInput::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\WidgetForm;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class WidgetFormType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('name')
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => WidgetForm::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Message;
|
||||
|
||||
use App\Dto\AnonymousReserveRequestDto;
|
||||
use Symfony\Component\Messenger\Attribute\AsMessage;
|
||||
|
||||
#[AsMessage('scheduler_default')]
|
||||
final class GetAnonymousReserveRequestMessage
|
||||
{
|
||||
public function __construct(
|
||||
private AnonymousReserveRequestDto $dto
|
||||
) { }
|
||||
|
||||
public function getDto(): AnonymousReserveRequestDto
|
||||
{
|
||||
return $this->dto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Message;
|
||||
|
||||
#[AsMessage('scheduler_default')]
|
||||
class GetScheduleMessage
|
||||
{
|
||||
private string $queryString;
|
||||
private bool $isOnlineMode;
|
||||
|
||||
public function __construct(string $queryString, bool $isOnlineMode)
|
||||
{
|
||||
$this->queryString = $queryString;
|
||||
$this->isOnlineMode = $isOnlineMode;
|
||||
}
|
||||
|
||||
public function getQueryString(): string
|
||||
{
|
||||
return $this->queryString;
|
||||
}
|
||||
|
||||
public function isOnlineMode(): bool
|
||||
{
|
||||
return $this->isOnlineMode;
|
||||
}
|
||||
|
||||
public function getMessageKey(): string
|
||||
{
|
||||
return sprintf('%s_%s', $this->queryString, $this->isOnlineMode ? 'online' : 'offline');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Message;
|
||||
|
||||
use Symfony\Component\Messenger\Attribute\AsMessage;
|
||||
|
||||
#[AsMessage('scheduler_default')]
|
||||
final class GetSpecialistPictureMessage
|
||||
{
|
||||
public function __construct(
|
||||
private int $spesialistId
|
||||
) { }
|
||||
|
||||
public function getSpesialistId(): int
|
||||
{
|
||||
return $this->spesialistId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\MessageHandler;
|
||||
|
||||
use App\Message\GetAnonymousReserveRequestMessage;
|
||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||
use App\Service\Client\InfoclinicaClientService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
|
||||
#[AsMessageHandler]
|
||||
final class GetAnonymousReserveRequestMessageHandler
|
||||
{
|
||||
private ?int $startTime = null;
|
||||
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private InfoclinicaClientService $clientService
|
||||
) { }
|
||||
|
||||
private function getDuration(): int
|
||||
{
|
||||
if (!$this->startTime) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)round((microtime(true) - $this->startTime) * 1000);
|
||||
}
|
||||
|
||||
public function __invoke(GetAnonymousReserveRequestMessage $message): array
|
||||
{
|
||||
$this->logger->info('[GetAnonymousReserve] Starting processing request', [
|
||||
'query' => $message->getDto(),
|
||||
'message_class' => GetAnonymousReserveRequestMessage::class
|
||||
]);
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
$result = $this->clientService->anonymousReserve($message->getDto());
|
||||
|
||||
|
||||
$this->logger->info('[GetAnonymousReserve] Successfully processed request', [
|
||||
'query' => $message->getDto(),
|
||||
'duration_ms' => $this->getDuration(),
|
||||
'result_count' => count($result)
|
||||
]);
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (HttpExceptionInterface $e) {
|
||||
$exception = [
|
||||
'query' => $message->getDto(),
|
||||
'duration_ms' => $this->getDuration(),
|
||||
'status_code' => $e->getResponse()->getStatusCode(),
|
||||
'error' => $e->getMessage(),
|
||||
'response' => $e->getResponse()->getContent(false)
|
||||
];
|
||||
|
||||
$this->logger->error('[GetAnonymousReserve] API request failed', $exception);
|
||||
|
||||
return $exception;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$exception = [
|
||||
'query' => $message->getDto(),
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
];
|
||||
|
||||
$this->logger->critical('[GetAnonymousReserve] Unexpected error', $exception);
|
||||
return $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\MessageHandler;
|
||||
|
||||
use App\Message\GetScheduleMessage;
|
||||
use App\Service\Client\InfoclinicaClientService;
|
||||
use App\Service\ScheduleCache\ScheduleCacheService;
|
||||
use App\Service\ErrorHandler\ScheduleErrorHandlerService;
|
||||
use App\Service\Performance\PerformanceTrackerService;
|
||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
|
||||
#[AsMessageHandler]
|
||||
final class GetScheduleMessageHandler
|
||||
{
|
||||
public function __construct(
|
||||
private InfoclinicaClientService $clientService,
|
||||
private ScheduleCacheService $cacheService,
|
||||
private ScheduleErrorHandlerService $errorHandler,
|
||||
private PerformanceTrackerService $performanceTracker
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(GetScheduleMessage $message): array
|
||||
{
|
||||
$this->performanceTracker->start();
|
||||
$queryString = $message->getQueryString();
|
||||
$isOnlineMode = $message->isOnlineMode();
|
||||
|
||||
try {
|
||||
// Проверяем кэш
|
||||
$cachedResult = $this->cacheService->getCachedSchedule($queryString, $isOnlineMode);
|
||||
if ($cachedResult !== null) {
|
||||
$this->performanceTracker->stop();
|
||||
return $this->createSuccessResponse($cachedResult, 'cached', $isOnlineMode);
|
||||
}
|
||||
|
||||
// Получаем данные из API
|
||||
// Передаем флаг onlineMode в клиент для формирования правильного запроса
|
||||
$apiResult = $this->clientService->getSchedule($queryString, $isOnlineMode);
|
||||
|
||||
// Сохраняем в кэш
|
||||
$this->cacheService->saveSchedule($apiResult, $queryString, $isOnlineMode);
|
||||
|
||||
$this->performanceTracker->stop();
|
||||
return $this->createSuccessResponse($apiResult, 'api', $isOnlineMode);
|
||||
|
||||
} catch (HttpExceptionInterface $e) {
|
||||
$this->performanceTracker->stop();
|
||||
return $this->errorHandler->handleHttpException(
|
||||
$e,
|
||||
$queryString,
|
||||
$this->performanceTracker->getDurationMs(),
|
||||
$isOnlineMode
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->performanceTracker->stop();
|
||||
return $this->errorHandler->handleGeneralException(
|
||||
$e,
|
||||
$queryString,
|
||||
$this->performanceTracker->getDurationMs(),
|
||||
$isOnlineMode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function createSuccessResponse(array $data, string $source, bool $isOnlineMode): array
|
||||
{
|
||||
// Подсчет статистики
|
||||
$totalIntervals = 0;
|
||||
$totalDays = 0;
|
||||
$totalDepartments = 0;
|
||||
|
||||
foreach ($data['schedule'] ?? [] as $department => $dates) {
|
||||
$totalDepartments++;
|
||||
foreach ($dates as $daySchedule) {
|
||||
$totalDays++;
|
||||
$totalIntervals += count($daySchedule['intervals'] ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($data, [
|
||||
'_meta' => [
|
||||
'source' => $source,
|
||||
'online_mode' => $isOnlineMode,
|
||||
'duration_ms' => $this->performanceTracker->getDurationMs(),
|
||||
'departments_count' => $totalDepartments,
|
||||
'days_count' => $totalDays,
|
||||
'intervals_count' => $totalIntervals,
|
||||
'timestamp' => (new \DateTime())->format('c')
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\MessageHandler;
|
||||
|
||||
use App\Message\GetSpecialistPictureMessage;
|
||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||
use App\Service\Client\BitrixClientService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Service\FileUploader\Interfaces\FileUploaderServiceInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use App\Entity\Specialist;
|
||||
|
||||
#[AsMessageHandler]
|
||||
final class GetSpecialistPictureMessageHandler
|
||||
{
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private BitrixClientService $bitixClient,
|
||||
private FileUploaderServiceInterface $fileUploaderService,
|
||||
private EntityManagerInterface $em
|
||||
) {
|
||||
$this->logger = $logger->withName('bitrix');
|
||||
}
|
||||
|
||||
public function __invoke(GetSpecialistPictureMessage $message): string
|
||||
{
|
||||
$specialist = $this->em->getRepository(Specialist::class)
|
||||
->find($message->getSpesialistId());
|
||||
|
||||
$urlPicture = $specialist->getPreviewPicture();
|
||||
|
||||
if (!str_starts_with($urlPicture, '/upload/iblock/'))
|
||||
return $urlPicture;
|
||||
|
||||
$this->logger->info('[GetSpecialistPictureMessage] Starting processing request', [
|
||||
'specialist_id' => $specialist->getId(),
|
||||
'preview_picture' => $specialist->getPreviewPicture(),
|
||||
'message_class' => GetSpecialistPictureMessage::class
|
||||
]);
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
// Получаем содержимое изображения
|
||||
$fileContent = $this->bitixClient->getSpecialistImage($urlPicture);
|
||||
|
||||
// Создаем временный файл
|
||||
$tempFilePath = sys_get_temp_dir() . '/' . uniqid('img_', true);
|
||||
file_put_contents($tempFilePath, $fileContent);
|
||||
|
||||
$uploadedFile = new UploadedFile(
|
||||
$tempFilePath,
|
||||
basename($urlPicture),
|
||||
mime_content_type($tempFilePath),
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
$this->fileUploaderService->setTargetDirectory('specialist');
|
||||
$fileName = $this->fileUploaderService->upload($uploadedFile);
|
||||
|
||||
$duration = round((microtime(true) - $startTime) * 1000, 2);
|
||||
|
||||
$this->logger->info('[GetSpecialistPictureMessage] Successfully processed request', [
|
||||
'specialist_id' => $specialist->getId(),
|
||||
'duration_ms' => $duration,
|
||||
'file_name' => $fileName
|
||||
]);
|
||||
|
||||
$specialist->setPreviewPicture('specialist/'. $fileName);
|
||||
|
||||
$this->em->persist($specialist);
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
@unlink($tempFilePath);
|
||||
|
||||
return 'specialist/' . $fileName;
|
||||
|
||||
} catch (HttpExceptionInterface $e) {
|
||||
$this->logger->error('[GetSpecialistPictureMessage] API request failed', [
|
||||
'specialist_id' => $specialist->getId(),
|
||||
'preview_picture' => $specialist->getPreviewPicture(),
|
||||
'status_code' => $e->getResponse()->getStatusCode(),
|
||||
'error' => $e->getMessage(),
|
||||
'response' => $e->getResponse()->getContent(false)
|
||||
]);
|
||||
throw $e;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->critical('[GetSpecialistPictureMessage] Unexpected error', [
|
||||
'specialist_id' => $specialist->getId(),
|
||||
'preview_picture' => $specialist->getPreviewPicture(),
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\AlertSms;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method AlertSms|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AlertSms|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AlertSms[] findAll()
|
||||
* @method AlertSms[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class AlertSmsRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, AlertSms::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\Article;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Article>
|
||||
*/
|
||||
class ArticleRepository extends ServiceEntityRepository
|
||||
{
|
||||
use ContentFilterTrait;
|
||||
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Article::class);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('a')->orderBy('a.id', 'DESC');
|
||||
|
||||
$this->applyCommonFilters($qb, 'a', $filters);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск статьи по alias с учётом возможных вариантов написания (исторический функционал).
|
||||
*/
|
||||
public function findOneByAlias(string $alias): ?Article
|
||||
{
|
||||
$alias = trim($alias);
|
||||
if ($alias === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$variants = [
|
||||
$alias,
|
||||
$alias . '-',
|
||||
'/' . ltrim($alias, '/'),
|
||||
];
|
||||
foreach ($variants as $v) {
|
||||
$article = $this->findOneBy(['alias' => $v]);
|
||||
if ($article !== null) {
|
||||
return $article;
|
||||
}
|
||||
}
|
||||
|
||||
// Фолбэк по TRIM(alias) в БД для совместимости со старыми данными.
|
||||
$conn = $this->getEntityManager()->getConnection();
|
||||
$id = $conn->fetchOne(
|
||||
'SELECT id FROM article WHERE TRIM(alias) = :alias LIMIT 1',
|
||||
['alias' => $alias],
|
||||
['alias' => \PDO::PARAM_STR],
|
||||
);
|
||||
if ($id !== false) {
|
||||
return $this->find($id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Banner;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Banner|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Banner|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Banner[] findAll()
|
||||
* @method Banner[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class BannerRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Banner::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
* Общие фильтры для контентных репозиториев (News/Promo/Disease/MedicalCenter/Article/SiteService).
|
||||
*
|
||||
* Trait подключается в Doctrine-репозитории, чтобы не держать бизнес-фильтры
|
||||
* в статическом helper-классе и при этом не копировать одинаковые if-блоки.
|
||||
*
|
||||
* Поддерживается:
|
||||
* - regionId / region_id: целое > 0;
|
||||
* - active: bool;
|
||||
* - alias: точное совпадение;
|
||||
* - search / q: LIKE по lower-case значению заданного поля (по умолчанию `name`).
|
||||
*
|
||||
* Поле поиска параметризовано через $searchField на случай сущностей,
|
||||
* где основное текстовое поле называется иначе (например, `title`).
|
||||
* Если у сущности нет такого свойства, Doctrine упадёт с QueryException — это
|
||||
* лучше ловится тестами на этапе разработки, чем 500 в проде.
|
||||
*
|
||||
* Важно: LOWER($alias.$searchField) при больших таблицах требует функционального
|
||||
* индекса в PostgreSQL, например CREATE INDEX ... ON table (LOWER(name)).
|
||||
*/
|
||||
trait ContentFilterTrait
|
||||
{
|
||||
private function applyCommonFilters(
|
||||
QueryBuilder $qb,
|
||||
string $alias,
|
||||
ContentFilterDto $filters,
|
||||
string $searchField = 'name',
|
||||
): void {
|
||||
if ($filters->regionId !== null) {
|
||||
$qb->andWhere("$alias.regionId = :regionId")
|
||||
->setParameter('regionId', $filters->regionId);
|
||||
}
|
||||
|
||||
if ($filters->active !== null) {
|
||||
$qb->andWhere("$alias.active = :active")
|
||||
->setParameter('active', $filters->active);
|
||||
}
|
||||
|
||||
if ($filters->alias !== null) {
|
||||
$qb->andWhere("$alias.alias = :aliasValue")
|
||||
->setParameter('aliasValue', $filters->alias);
|
||||
}
|
||||
|
||||
if ($filters->search !== null) {
|
||||
$qb->andWhere("LOWER($alias.$searchField) LIKE :search")
|
||||
->setParameter('search', '%' . mb_strtolower($filters->search) . '%');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Department;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @method Department|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Department|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Department[] findAll()
|
||||
* @method Department[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class DepartmentRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Department::class);
|
||||
}
|
||||
|
||||
public function activeAll(): array
|
||||
{
|
||||
return $this->createQueryBuilder('d')
|
||||
->where('d.active = :active')
|
||||
->setParameter('active', true)
|
||||
->orderBy('d.did', 'ASC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('d')
|
||||
->orderBy('d.id', 'ASC');
|
||||
|
||||
foreach ($filters as $filterType => $filterValue) {
|
||||
if ($filterValue === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ($filterType) {
|
||||
'id' => $this->applyDidFilter($qb, $filterValue),
|
||||
'name' => $this->applyNameFilter($qb, $filterValue),
|
||||
'alias' => $this->applyAliasFilter($qb, $filterValue),
|
||||
'active' => $this->applyActiveFilter($qb, $filterValue),
|
||||
'groupName' => $this->applyGroupNameFilter($qb, $filterValue),
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function applyDidFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.did in (:did)')
|
||||
->setParameter('did', $value);
|
||||
}
|
||||
|
||||
private function applyNameFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->like('LOWER(d.name)', 'LOWER(:name)')
|
||||
))
|
||||
->setParameter('name', '%'.$value.'%');
|
||||
}
|
||||
|
||||
private function applyAliasFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.alias = :alias')
|
||||
->setParameter('alias', $value);
|
||||
}
|
||||
|
||||
private function applyActiveFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.active = :active')
|
||||
->setParameter('active', $value);
|
||||
}
|
||||
|
||||
private function applyGroupNameFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.groupName = :groupName')
|
||||
->setParameter('groupName', $value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Dto\Content\ContentFilterDto;
|
||||
use App\Entity\Disease;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Disease|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Disease|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Disease[] findAll()
|
||||
* @method Disease[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class DiseaseRepository extends ServiceEntityRepository
|
||||
{
|
||||
use ContentFilterTrait;
|
||||
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Disease::class);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('d')->orderBy('d.id', 'ASC');
|
||||
|
||||
$this->applyCommonFilters($qb, 'd', $filters);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Filial;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @method Filial|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Filial|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Filial[] findAll()
|
||||
* @method Filial[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class FilialRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Filial::class);
|
||||
}
|
||||
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('f')
|
||||
->orderBy('f.id', 'ASC');
|
||||
|
||||
foreach ($filters as $filterType => $filterValue) {
|
||||
if ($filterValue === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ($filterType) {
|
||||
'name' => $this->applyNameFilter($qb, $filterValue),
|
||||
'address' => $this->applyAddressFilter($qb, $filterValue),
|
||||
'active' => $this->applyActiveFilter($qb, $filterValue),
|
||||
'regionId' => $this->applyRegionIdFilter($qb, $filterValue),
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function applyNameFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->like('LOWER(f.name)', 'LOWER(:name)')
|
||||
))
|
||||
->setParameter('name', '%'.$value.'%');
|
||||
}
|
||||
|
||||
private function applyAddressFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('f.address = :address')
|
||||
->setParameter('address', $value);
|
||||
}
|
||||
|
||||
private function applyActiveFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('f.active = :active')
|
||||
->setParameter('active', $value);
|
||||
}
|
||||
|
||||
private function applyRegionIdFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('f.regionId = :regionId')
|
||||
->setParameter('regionId', $value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Idoctor;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Idoctor>
|
||||
*/
|
||||
class IdoctorRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Idoctor::class);
|
||||
}
|
||||
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('d')
|
||||
->orderBy('d.id', 'ASC');
|
||||
|
||||
foreach ($filters as $filterType => $filterValue) {
|
||||
if ($filterValue === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ($filterType) {
|
||||
'filial' => $this->applyFilialFilter($qb, $filterValue),
|
||||
'department' => $this->applyDepartmentFilter($qb, $filterValue),
|
||||
'dcode' => $this->applyDcodeFilter($qb, $filterValue),
|
||||
'search' => $this->applySearchFilter($qb, $filterValue),
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function applyFilialFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.filial = :filial')
|
||||
->setParameter('filial', $value);
|
||||
}
|
||||
|
||||
private function applyDepartmentFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.department = :department')
|
||||
->setParameter('department', $value);
|
||||
}
|
||||
|
||||
private function applyDcodeFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere('d.dcode = :dcode')
|
||||
->setParameter('dcode', $value);
|
||||
}
|
||||
|
||||
private function applySearchFilter(QueryBuilder $qb, mixed $value): void
|
||||
{
|
||||
$qb->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->like('LOWER(d.name)', 'LOWER(:search)')
|
||||
))
|
||||
->setParameter('search', '%'.$value.'%');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user