<?php
namespace WebBundle\Service;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Exception;
use WebBundle\Helper\App;
use WebBundle\Helper\FilterHelper;
use WebBundle\Helper\StrHelper;
use WebBundle\Repository\ArticleRepository;
use WebBundle\Repository\CollectionRepository;
use WebBundle\Repository\FilterRepository;
use WebBundle\Repository\InteriorRepository;
class CollectionSettingsService extends ExtendService
{
/** @var FilterRepository */
protected $repoFilter;
/** @var ArticleRepository */
protected $repoArticle;
/** @var InteriorRepository */
protected $repoInterior;
/** @var CollectionRepository */
protected $repoColl;
/**
* CollectionSettingsService constructor.
* @throws Exception
*/
public function __construct()
{
$this->repoFilter = App::getRepository('WebBundle:FilterEntity');
$this->repoArticle = App::getRepository('WebBundle:Article');
$this->repoInterior = App::getRepository('WebBundle:Interior');
$this->repoColl = App::getRepository('WebBundle:Collection');
return $this;
}
private function parseAttr($attr)
{
$arr = [];
$keys = ['applies', 'styles', 'style', 'textures', 'pei', 'type', 'material', 'using', 'surface', 'edgeType', 'sliding', 'offShade'];
if (isset($attr['expressSample'])) {
if ($attr['expressSample']) {
$arr['articleQuickSample'] = [
'id' => 1,
'name' => 'Экспресс образцы',
'alias' => 'articleQuickSample',
'key' => 'expressSample',
];
}
}
foreach ($keys as $key) {
if (!empty($attr[$key])) {
$item = $attr[$key];
if (!empty($item['hide'])) {
// скрытые фильтры не показываем в свойствах коллекции
continue;
}
if (!empty($item['alias'])) {
$item['key'] = $key;
$arr[$item['alias']] = $item;
} else {
if (is_array($item)) {
foreach ($item as $row) {
if(empty($row['alias'])){
continue;
}
$row['key'] = $key;
$arr[$row['alias']] = $row;
}
} else {
$i = FilterHelper::normaliseAltName($item);
$arr[$i] = $item;
}
}
}
}
return $arr;
}
private function parseAttrDesigner($authors)
{
$arr = [];
foreach ($authors as $author) {
$key = 'designer_' . FilterHelper::normaliseAltName($author);
$arr[$key] = [
'name' => $author,
'alias' => 'designer',
];
}
return $arr;
}
private function getFilterIds($rows, $cid, $status)
{
$ids = [];
foreach ($rows as $k => $row) {
$f = null;
if (preg_match('/pei_(.*)/ui', $k)) {
$alias = 'left_menu_' . strtolower($k);
$f = $this->repoFilter->getFilterIdForSettingsCollectionByLeft($alias);
} elseif (!empty($row['alias'])) {
if ($row['alias'] == 'designer') {
$f = $this->repoFilter->getFilterIdForSettingsColletionByIdDesigner($row['id']);
} else {
$f = $this->repoFilter->getFilterIdForSettingsCollectionByLeft($row['alias']);
}
}
if ($f) {
$ids[$f['name']] = $f;
} else {
if ($status != 2) {
throw new Exception("Не нашли");
// App::dumpExit('Не нашли', $row, ['id' => $cid, 'status' => $status]);
}
}
}
return $ids;
}
/**
* Обновление ID фильтров свойств коллекции
* @param $cid
* @return bool
* @throws Exception
*/
public function updateSettingsCollection($cid)
{
$this->getParseIdFiltersByAtrr($cid);
return true;
}
/**
* Парсим ID фильтров по признакам коллекции и сохраняем их сразу
* @param $cid
* @return array
* @throws ORMException
* @throws OptimisticLockException
* @throws Exception
*/
public function getParseIdFiltersByAtrr($cid)
{
$coll = $this->repoColl->getByIdForParseAttr($cid);
if (!$coll) {
throw new Exception("Ошибка, коллекции ID $cid нет.");
}
$interiors = $this->repoInterior->getInteriorsByCollection($cid);
$articles = $this->repoArticle->getArticleByCollection($cid);
$arr = [];
// смотрим интерьеры если accessible не TRUE
if (!$coll->getAccessible()) {
foreach ($interiors as $interior) {
$arr_ = $this->parseAttr($interior);
$arr = array_merge($arr, $arr_);
}
}
foreach ($articles as $article) {
if(empty($article['file'])){
continue;
}
$arr_ = $this->parseAttr($article);
$arr = array_merge($arr, $arr_);
if (!empty($arr_['left_menu_glased_porcelain_no']) or !empty($arr_['left_menu_glased_porcelain_yes']) or !empty($arr_['left_menu_porcelain'])) {
if (!empty($article['thinGranite']) and $article['thinGranite']) {
// добавляем признак тонкого керамогранита
$arr['left_menu_thin_porcelain_tile'] = [
'id' => 1,
'alias' => 'left_menu_thin_porcelain_tile'
];
} else {
if ($article['thick'] >= 17) {
// добавляем признак утолщенного керамогранита
$arr['left_menu_thick_porcelain_tile'] = [
'id' => 2,
'alias' => 'left_menu_thick_porcelain_tile'
];
}
}
}
}
$desIds = $coll->getAuthorId();
if ($desIds) {
foreach ($desIds as $dId) {
$arr["designer_{$dId}"] = [
'id' => $dId,
'alias' => 'designer',
];
}
// добавляем сам стиль дизайнерский
$arr['left_menu_designer'] = [
'id' => 17,
'alias' => 'left_menu_designer'
];
}
$ids = $this->getFilterIds($arr, $cid, $coll->getStatus());
$ids = array_column($ids, 'id');
$coll->setFids($ids);
App::em()->persist($coll);
App::em()->flush();
return $ids;
}
/**
* Проставляем rank и size для фильтров
* @param $items
* @return array
* @throws Exception
*/
private function setSize($items)
{
$rankService = App::getContainer()->get('app.service.rank');
$rankArr = [];
$items_ = [];
foreach ($items as $k => $item) {
$rank = isset($item['rank']) ? intval($item['rank']) : 0;
$item['rank'] = $rank;
// ставим дефольный размер для всех
$item['size'] = $rankService->fontSizeByRank(50);
$items_[$item['altName']] = $item;
if (!in_array($item['group.altName'], ['resistance_abrasion', 'antislip_coff', 'shade_variation', 'designer'])) {
$rankArr[$item['altName']] = $rank;
}
}
arsort($rankArr);
$rankArr = array_keys($rankArr);
// количество выделяемых в четверти
$cnt = (int)ceil(count($rankArr) / 4);
foreach ($rankArr as $i => $k) {
if ($i <= $cnt) {
// первая четверть
$items_[$k]['size'] = $rankService->fontSizeByRank(100);
} elseif ($i > $cnt and $i <= ( $cnt * 2 )) {
// вторая четверть
$items_[$k]['size'] = $rankService->fontSizeByRank(80);
}
}
return $items_;
}
/**
* @param $fids
* @return string
* @throws Exception
*/
public function getFiltersTxt($fids)
{
$groups = $this->getFilters($fids);
$str = [];
foreach ($groups as $r) {
// убираем surface, вместо нее коэффициенты выводятся
if ($r['altName'] == 'surface') {
continue;
}
$s = null;
if ($r['altName'] == 'shade_variation' || $r['altName'] == 'resistance_abrasion') {
$s = "#{$r['name']}";
} elseif ($r['altName'] == 'antislip_coff') {
$s = "#{$r['nameFull']}";
}
$l = [];
foreach ($r['list'] as $item) {
$name = $item['nameMany'];
if ($r['altName'] == 'resistance_abrasion') {
$name = trim(str_replace('PEI', '', $name));
}
if ($item['altName'] == 'vinil') {
$name = "<b>{$name}</b>";
}
$l[] = $name;
}
if ($s) {
$s = "{$s} " . implode(', ', $l);
} else {
$s = "#" . implode(' #', $l);
}
$str[] = $s;
}
$str = implode(' ', $str);
return $str;
}
/**
* @param $fids
* @return string
* @throws Exception
*/
public function getFiltersHtml($fids): string
{
$groups = $this->getFilters($fids);
return $this->attrToHtml($groups);
}
public function attrToHtml($groups)
{
$html = $this->render(
'@Web/Collection/attrs.html.twig',
[
'lc' => App::getCurLocale(),
'groups' => $groups,
]
);
$html = trim(trim($html), ',');
return str_replace(' ,', ',', $html);
}
/**
* @param $fids
* @return array
* @throws Exception
*/
public function getFilters($fids, bool $forReact=false)
{
$oRouter = App::getRouter();
$items = $this->repoFilter->getForCollSettings($fids);
$items = $this->setSize($items);
$groups = [];
// упаковываем по группам
foreach ($items as $fAlt => $item) {
$grAlt = $item['group.altName'];
// убираем с вывода свойств все виды изделий
// https://te.remote.team/#/discus/AE79130E-DE85-4F4A-0434-AFE6A828C451/
// UPD: Добавил условие для вывода типа изделия в лэере для реакта
// https://te.remote.team/#/discus/ACF4E5F1-9B69-A9B6-76A5-4EA1F860AC17/
if ($grAlt == 'type' && !$forReact) {
continue;
}
// скрыл дизайнеров без коллекций
// https://te.remote.team/#/discus/BB0C92AC-A6BE-10D6-FC74-D4999FCFE2B2/
if ($grAlt == 'designer' and !$item['count']) {
continue;
}
// формируем ссылку на фильтр
$link = $item['slug'];
if ($link and $item['count']) {
$link = $oRouter->generate('app_catalog', ['key' => $link]);
} else {
$link = null;
}
if (empty($groups[$grAlt])) {
$nameFull = null;
switch ($grAlt) {
case 'antislip_coff':
//$nameFull = App::getTranslator()->trans('catalog.options.non_slip_rating', ['%d%' => '']);
$nameFull = App::getTranslator()->trans('antislip_full_name', ['%d%' => '']);
break;
case 'resistance_abrasion':
$nameFull = App::getTranslator()->trans('catalog.options.pei');
break;
case 'shade_variation':
$nameFull = App::getTranslator()->trans('catalog.options.shade_variation', ['%d%' => '']);
break;
}
$name = $item['group.name'];
// для PEI оставляем верний регистр
if ($grAlt != 'resistance_abrasion') {
$name = StrHelper::toLower($name);
}
$groups[$grAlt] = [
'id' => $item['group.id'],
'altName' => $item['group.altName'],
'name' => $name,
'nameFull' => $nameFull,
'list' => [],
];
}
$groups[$grAlt]['list'][$fAlt] = [
'id' => $item['id'],
'sphinxId' => $item['sphinxId'],
'sphinxName' => $item['sphinxName'],
'altName' => $item['altName'],
'name' => $item['name'],
'nameMany' => $item['nameMany'],
'nameFull' => $item['nameFull'],
'slug' => $item['slug'],
'link' => $link,
'count' => $item['count'],
'rank' => $item['rank'],
'size' => $item['size'],
];
}
// переносим в конец
if (!empty($groups['antislip_coff'])) {
$shade = $groups['antislip_coff'];
unset($groups['antislip_coff']);
$groups['antislip_coff'] = $shade;
}
// удаляем признак дизайнеров, если есть сами дизайнеры у нас
if (!empty($groups['designer'])) {
$designer = $groups['style']['list']['designer'];
$designer['list'] = $groups['designer']['list'];
$designer['nameFull'] = StrHelper::toLower($designer['nameFull']);
$groups['designer'] = $designer;
unset($groups['style']['list']['designer']);
}
// переносим в конец
if (!empty($groups['resistance_abrasion'])) {
$resistance = $groups['resistance_abrasion'];
unset($groups['resistance_abrasion']);
$groups['resistance_abrasion'] = $resistance;
}
// переносим в конец
if (!empty($groups['shade_variation'])) {
$shade = $groups['shade_variation'];
unset($groups['shade_variation']);
$groups['shade_variation'] = $shade;
}
// переносим в конец
if (!empty($groups['designer'])) {
$designer = $groups['designer'];
unset($groups['designer']);
$groups['designer'] = $designer;
}
return $groups;
}
public function arrayInsert(&$array, $position, $insert)
{
if (is_int($position)) {
array_splice($array, $position, 0, $insert);
} else {
$pos = array_search($position, array_keys($array));
$array = array_merge(
array_slice($array, 0, $pos+1),
$insert,
array_slice($array, $pos+1)
);
}
}
}