Files
backend/src/Service/XmlFeedGenerator/XmlFeedGeneratorV1Service.php
T

263 lines
9.0 KiB
PHP

<?php
namespace App\Service\XmlFeedGenerator;
use DOMDocument;
use DOMElement;
use App\Dto\SpecialistFilterDto;
use App\Entity\Filial;
use App\Entity\Specialist;
use App\Service\PriceList\PriceListService;
use App\Service\Specialist\SpecialistService;
use App\Service\Helper\HelperService;
use Doctrine\DBAL\Connection;
use Psr\Log\LoggerInterface;
class XmlFeedGeneratorV1Service
{
private DOMDocument $dom;
private Filial $filial;
/** @var array<int, Filial> */
private array $filialsByFid = [];
public function __construct(
private PriceListService $priceListService,
private SpecialistService $specialistService,
private HelperService $helperService,
private Connection $connection,
private ?LoggerInterface $logger = null,
) {
$this->dom = new DOMDocument('1.0', 'UTF-8');
$this->dom->formatOutput = true;
}
/**
* @param Filial|Filial[] $filials один филиал или массив филиалов (например, по региону)
*/
public function generateFeed(Filial|array $filials): string
{
$filialList = is_array($filials) ? $filials : [$filials];
if ($filialList === []) {
$this->dom = new DOMDocument('1.0', 'UTF-8');
$this->dom->formatOutput = true;
return $this->dom->saveXML();
}
$this->dom = new DOMDocument('1.0', 'UTF-8');
$this->dom->formatOutput = true;
$this->filial = $filialList[0];
$this->filialsByFid = [];
foreach ($filialList as $f) {
$this->filialsByFid[$f->getFid()] = $f;
}
$ymlCatalog = $this->dom->createElement('yml_catalog');
$ymlCatalog->setAttribute('date', date('Y-m-d H:i'));
$this->dom->appendChild($ymlCatalog);
$shop = $this->dom->createElement('shop');
$ymlCatalog->appendChild($shop);
$this->addShopInfo($shop);
$this->addCurrencies($shop);
$this->addCategories($shop);
$this->addSets($shop);
$this->addOffers($shop);
return $this->dom->saveXML();
}
private function addShopInfo(DOMElement $shop): void
{
$this->addTextElement($shop, 'name', $this->getShopName());
$this->addTextElement($shop, 'company', $this->filial->getCompany());
$this->addTextElement($shop, 'url', $this->filial->getOrigin());
$this->addTextElement($shop, 'email', $this->filial->getEmail());
}
private function addCurrencies(DOMElement $shop): void
{
$currencies = $this->dom->createElement('currencies');
$currency = $this->dom->createElement('currency');
$currency->setAttribute('id', 'RUR');
$currency->setAttribute('rate', '1');
$currencies->appendChild($currency);
$shop->appendChild($currencies);
}
private function addCategories(DOMElement $shop): void
{
$categories = $this->dom->createElement('categories');
$category = $this->dom->createElement('category', 'Врач');
$category->setAttribute('id', '1');
$categories->appendChild($category);
$shop->appendChild($categories);
}
private function addSets(DOMElement $shop): void
{
$sets = $this->dom->createElement('sets');
$departments = $this->connection->fetchAllAssociative(
'SELECT did, name FROM departments WHERE active = :active ORDER BY id ASC',
['active' => true]
);
foreach ($departments as $department) {
$set = $this->dom->createElement('set');
$set->setAttribute('id', (string) $department['did']);
$name = $this->dom->createElement('name', (string) $department['name']);
$set->appendChild($name);
$sets->appendChild($set);
}
$shop->appendChild($sets);
}
private function getShopName(): string
{
return match ($this->filial->getRegionId()) {
94 => 'Клиника ВМТ Сова',
default => match ($this->filial->getFid()) {
9 => 'Совёнок',
default => 'Сова',
}
};
}
private function getShopPicture(): string
{
$picture = match ($this->filial->getRegionId()) {
94 => 'wmtmed.png',
default => match ($this->filial->getFid()) {
9 => 'sovenok.png',
10 => 'comfort.jpg',
default => 'sovamed.png',
}
};
return "https://api.sovamed.ru/images/logo/{$picture}";
}
private function getSpecialistLink(Specialist $specialist): string
{
$url = $this->filial->getOrigin();
$url .= match ($this->filial->getId()) {
9 => '/doctors/',
14 => '/doctors/',
10 => '/doctors/',
8 => '/specialisty',
default => '/vrachi'
};
if (!in_array($this->filial->getId(), [9, 14, 10])) {
$sType = $specialist->getSType();
if ($sType !== null) {
$url .= match ($sType) {
0 => '/vzroslyj-vrach/',
1 => '/detskij-vrach/',
2 => '/administraciya/',
default => '/vzroslyj-vrach/',
};
} else {
$this->logger?->info('Specialist type is not set', ['specialist' => $specialist->getId()]);
}
}
$url .= $specialist->getAlias();
$url .= '/';
return $url;
}
private function getCity(): string
{
return match ((int) $this->filial->getRegionId()) {
91 => 'Саратов',
92 => 'Волгоград',
93 => 'Воронеж',
94 => 'Краснодар',
default => ''
};
}
private function addOffers(DOMElement $shop): void
{
$offersElement = $this->dom->createElement('offers');
$fids = array_keys($this->filialsByFid);
if ($fids === []) {
$shop->appendChild($offersElement);
return;
}
$filter = new SpecialistFilterDto();
$filter->kiosk = true;
$filter->sFilial = array_map('strval', $fids);
$specialistList = $this->specialistService->getList($filter);
foreach ($specialistList as $specialist) {
$specialistDescription = $specialist->getPost();
$offerElement = $this->dom->createElement('offer');
$offerElement->setAttribute('id', (string) $specialist->getId());
$url = $this->getSpecialistLink($specialist);
$experience = $specialist->getExperience();
$experienceYears = $experience && is_numeric($experience) && $experience > 1900 && $experience <= date('Y')
? date('Y') - (int) $experience
: null;
if ($experienceYears !== null) {
$specialistDescription .= ' с опытом работы ' . $this->helperService->textYear($experienceYears, true);
}
$specialistDescription .= '. Запись к специалисту на сайте';
$this->addTextElement($offerElement, 'name', $specialist->getName() ?? '');
$this->addTextElement($offerElement, 'description', $specialistDescription ?? '');
$this->addTextElement($offerElement, 'url', $url);
$this->addTextElement($offerElement, 'set-ids', $specialist->getDcodes());
$picture = "https://api.sovamed.ru/specialist/picture/{$specialist->getId()}";
$this->addTextElement($offerElement, 'picture', $picture);
$this->addTextElement($offerElement, 'categoryId', '1');
$this->addTextElement($offerElement, 'currencyId', 'RUR');
$offersElement->appendChild($offerElement);
}
$shop->appendChild($offersElement);
}
private function addTextElement(DOMElement $parent, string $name, $value): void
{
if ($value !== null && $value !== '') {
$parent->appendChild($this->dom->createElement($name, $this->prepareXmlContent((string)$value)));
}
}
private function addParamElement(DOMElement $parent, string $name, $value): void
{
if ($value !== null && $value !== '') {
$param = $this->dom->createElement('param', $this->prepareXmlContent((string)$value));
$param->setAttribute('name', $name);
$parent->appendChild($param);
}
}
private function prepareXmlContent($content): string
{
$content = str_replace('&', '&amp;', $content);
$validEntities = [
'&amp;nbsp;' => '&#160;',
'&amp;amp;' => '&amp;',
'&amp;lt;' => '&lt;',
'&amp;gt;' => '&gt;',
'&amp;quot;' => '&quot;',
'&amp;apos;' => '&apos;'
];
$content = str_replace(array_keys($validEntities), array_values($validEntities), $content);
return htmlspecialchars($content, ENT_XML1 | ENT_QUOTES, 'UTF-8');
}
}