<?php
namespace WebBundle\Repository;
use DateTime;
use Doctrine\ORM\QueryBuilder;
use Exception;
use FlexApp\Classes\CommentableEntityTypes;
use FlexApp\Constant\TimeConstant;
use WebBundle\Helper\App;
use WebBundle\Helper\ArrHelper;
use WebBundle\Helper\LocaleHelper;
use WebBundle\Helper\TranslitHelper;
/**
* PublicationRepository
*/
class PublicationRepository extends ExtendEntityRepository
{
/**
* Получаем публикации с учетом локали, где есть хотя бы один коммент
* @param $locale
* @return array
*/
public function getActivePagesArrays($locale): array
{
$query = $this->getEntityManager()->createQuery("
SELECT
DISTINCT p.unid as portalThemeUnid
FROM WebBundle\Entity\Publication p
JOIN FlexApp\Entity\CommentEntity c
WITH COLLATE(p.unid,utf8mb4_unicode_ci) = COLLATE(c.commentableUnid,utf8mb4_unicode_ci)
AND c.locale = :locale
");
$query->setParameter('locale', $locale);
$result = $query->getResult();
foreach ($result as &$row) {
$row['locale'] = $locale;
$row['type'] = CommentableEntityTypes::PUBLICATION;
}
return $result;
}
/**
* Это надо для админки в основном
* @param string $alias
* @return QueryBuilder
*/
public function joinQuery($alias = 'b')
{
$q = $this->createQueryBuilder($alias);
$q->select("{$alias}, url, body, title, description, keywords, statusShow, statusTranslate, hideSingle, preview, likes, author")
->leftJoin("{$alias}.url", 'url')
->leftJoin("{$alias}.body", 'body')
->leftJoin("{$alias}.title", 'title')
->leftJoin("{$alias}.description", 'description')
->leftJoin("{$alias}.keywords", 'keywords')
->leftJoin("{$alias}.statusShow", 'statusShow')
->leftJoin("{$alias}.statusTranslate", 'statusTranslate')
->leftJoin("{$alias}.preview", 'preview')
->leftJoin("{$alias}.likes", 'likes')
->leftJoin("{$alias}.author", 'author')
->leftJoin("{$alias}.hideSingle", 'hideSingle');
return $q;
}
/**
* @param array $param
* @return array
* @throws Exception
* Фильтрация должна быть одинаковая с
* @see PublicationRepository::getPublicationsCount
*/
public function getIdsForShortShow(array $param = []): array
{
$locale = !empty($param['locale']) ? $param['locale'] : App::getCurLocale();
$cc = !empty($param['country']) ? $param['country'] : App::getCurCountry();
$hideSingle = !isset($param['hideSingle']) || boolval($param['hideSingle']);
$s = $this
->createQueryBuilder('b')
->select('b.id, b.publishDate, b.hideCountries')
->leftJoin('b.body', 'body')
->leftJoin('b.statusShow', 'statusShow')
->leftJoin('b.hideSingle', 'hideSingle')
->andWhere('b.enable = true')
->andWhere("statusShow.{$locale} = true")
->andWhere("body.{$locale} != ''")
->andWhere("hideSingle.{$locale} = :hideSingle")
->setParameter('hideSingle', $hideSingle)
->orderBy('b.publishDate', 'ASC');
//блог по снижению ват показываем только для Германии
if (App::getCurCountry() != 'de') {
$s->andWhere('b.id <> :idDe')
->setParameter('idDe', 2235);
}
$q = $s->getQuery()->setQueryCacheLifetime(300);
$data = $q->getArrayResult();
$data = array_filter($data, static fn(array $item) => !in_array($cc, $item['hideCountries'] ?? []));
return array_map(function (array $item) {
$item['t'] = 'blog';
/** @var DateTime $date */
$date = $item['publishDate'];
$item['date'] = $date->getTimestamp();
return $item;
}, $data);
}
/**
* @param $ids
* @param array $param
* @return array
* @throws Exception
*/
public function getByIdsForShortShow($ids, $param = [])
{
$ids = is_array($ids) ? $ids : [$ids];
$lc = !empty($param['locale']) ? $param['locale'] : App::getCurLocale();
$cn = App::getCurCountry();
// блог по снижению ват показываем только для Германии
if ($cn != 'de') {
if ($idsx = array_search(2235, $ids)) {
unset($ids[$idsx]);
}
}
$idss = implode(',', $ids);
$sql = "SELECT
p.id,
p.enable,
p.unid,
p.view,
p.publish_date AS `publishDate`,
p.hide_countries AS `hideCountries`,
lcurl.{$lc} AS `url`,
lctitle.{$lc} AS `title`,
lchtml.{$lc} AS `body`,
lcssShow.{$lc} AS `statusShow`,
lchs.{$lc} AS `hideSingle`,
lcpw.def AS `preview.def`,
lcpw.en AS `preview.en`,
lcpw.{$lc} AS `preview.lc`,
COUNT(DISTINCT cmt.id) AS `commentCnt`
FROM
publication p
LEFT JOIN `publication_like` `plike` ON plike.publication_id = p.id
LEFT JOIN `locale_url` `lcurl` ON lcurl.publication_id = p.id
LEFT JOIN `locale_title` `lctitle` ON lctitle.publication_id = p.id
LEFT JOIN `locale_html` `lchtml` ON lchtml.publication_body_id = p.id
LEFT JOIN `locale_bool` `lcssShow` ON lcssShow.blog_show_id = p.id
LEFT JOIN `locale_bool` `lchs` ON lchs.blog_hide_single_id = p.id
LEFT JOIN `locale_preview` `lcpw` ON lcpw.publication_id = p.id
LEFT JOIN `comment_refact` `cmt` ON cmt.commentable_unid = p.unid AND cmt.locale = '{$lc}'
WHERE p.id IN ({$idss})
GROUP BY p.id;";
$conn = $this->_em->getConnection();
$rows = $conn->fetchAllAssociative($sql);
$res = [];
foreach ($rows as $row) {
if (!$row['url'] and !$row['title'] and !$row['body']) {
continue;
}
$preview = $row['preview.lc'];
if (!$preview) {
$preview = !empty($row['preview.def']) ? $row['preview.def'] : null;
if (!$preview) {
$preview = !empty($row['preview.en']) ? $row['preview.en'] : null;
}
}
$hideCountries = $row['hideCountries'];
if ($hideCountries) {
$hideCountries = json_decode($hideCountries, true);
} else {
$hideCountries = [];
}
$item = [
't' => 'blog',
'id' => $row['id'],
'unid' => $row['unid'],
'url' => $row['url'],
'title' => html_entity_decode($row['title']),
'body' => html_entity_decode(LocaleHelper::modifeLinkForLocales($row['body'])),
'preview' => $preview,
'enable' => boolval($row['enable']),
'statusShow' => boolval($row['statusShow']),
'hideSingle' => boolval($row['hideSingle']),
'hideCountries' => $hideCountries,
'commentCnt' => intval($row['commentCnt']),
'view' => intval($row['view']),
'publishDate' => DateTime::createFROMFormat('Y-m-d H:i:s', $row['publishDate']),
];
$res[$row['id']] = $item;
}
return $res;
}
/**
* Получение блогов для карты сайта
* @param string $lc
* @param string|null $cc
* @return array
* @throws Exception
*/
public function getPublicationsSEO(string $lc, ?string $cc = null)
{
$oMemcache = App::getMemcache();
$keyCache = $this->buildCacheId(__METHOD__, "blog.seo.{$lc}.{$cc}", $lc . $cc);
$rows = $oMemcache->get($keyCache);
if (!$rows) {
$hideIds = '2235';
if ($lc == 'ru') {
$hideIds .= ',2232';
}
$sql = "SELECT
p.id,
lcTitle.{$lc} AS title,
lcUrl.{$lc} AS url,
p.hide_countries AS hideCountries
FROM
publication p
LEFT JOIN `locale_title` `lcTitle` ON lcTitle.publication_id = p.id
LEFT JOIN `locale_url` `lcUrl` ON lcUrl.publication_id = p.id
LEFT JOIN `locale_bool` `lcShow` ON lcShow.blog_show_id = p.id
LEFT JOIN `locale_bool` `lcSingle` ON lcSingle.blog_hide_single_id = p.id
WHERE p.enable = 1
AND p.author IS NOT NULL
AND lcUrl.{$lc} IS NOT NULL
AND lcShow.{$lc} = 1
AND lcSingle.{$lc} != 1
AND p.id NOT IN ({$hideIds})
;
";
$conn = $this->_em->getConnection();
$rows = $conn->fetchAllAssociative($sql);
foreach ($rows as $i => $row) {
if ($row['hideCountries']) {
if ($c = json_decode($row['hideCountries'], true)) {
if ($cc) {
if (in_array($cc, $c)) {
unset($rows[$i]);
}
} else {
if (in_array($lc, $c)) {
unset($rows[$i]);
}
}
}
}
}
// кеш на неделю
$oMemcache->set($keyCache, $rows, MEMCACHE_COMPRESSED, (int) TimeConstant::WEEK);
}
return $rows;
}
/**
* Обновление статистики просмотров
* @param $id
* @throws \Doctrine\DBAL\Exception
*/
public function updView($id)
{
$conn = $this->getEntityManager()->getConnection();
$conn->executeStatement("UPDATE `publication` SET `view` = `view` + 1 WHERE `id` = {$id};");
}
public function getKey($id, $locale)
{
$q = $this->createQueryBuilder('p')
->select('u.' . $locale . ' url')
->leftJoin('p.url', 'u')
->andWhere('p.id = :id')
->setParameter('id', $id);
$r = $q->getQuery()
->useQueryCache(true)
->enableResultCache(3600);
$item = $r->getArrayResult();
return count($item) > 0 ? $item[0]['url'] : null;
}
/**
* @param $url
* @param null $locale
* @return array|null
*/
public function getBlogByUrlForDTO($url, $locale = null)
{
$q = $this->createQueryBuilder('p')
->select('p, url, body, title, description, keywords, statusShow, hideSingle, preview, likes, author')
->leftJoin('p.url', 'url')
->leftJoin('p.body', 'body')
->leftJoin('p.title', 'title')
->leftJoin('p.description', 'description')
->leftJoin('p.keywords', 'keywords')
->leftJoin('p.statusShow', 'statusShow')
->leftJoin('p.preview', 'preview')
->leftJoin('p.likes', 'likes')
->leftJoin('p.author', 'author')
->leftJoin('p.hideSingle', 'hideSingle');
if ($locale) {
$q->andWhere("url.{$locale} = :url")->setParameter('url', $url);
} else {
foreach (LocaleHelper::getList() as $lc => $item) {
$key = "url{$lc}";
$q->orWhere("url.{$lc} = :{$key}")->setParameter($key, $url);
}
}
$r = $q->getQuery();
$item = $r->getArrayResult();
if (count($item) == 1) {
$item = $item[0];
} else {
$item = null;
}
return $item;
}
/**
* @param $id
* @param null $locale
* @param bool $preview
* @return mixed|null
* @throws Exception
*/
public function getPublication($id, $locale = null, $preview = false)
{
$locale = $locale ? $locale : App::getCurLocale();
$oMemcache = App::getMemcache();
$keyCache = $this->buildCacheId(__METHOD__, $id, $locale);
$data = $oMemcache->get($keyCache);
// если $preview, то кеш не используем
if (!$preview) {
$data = null;
}
if (!$data) {
$s = $this
->joinQuery()
->setMaxResults(1);
if (App::isInt($id)) {
$s->andWhere('b.id = :id')->setParameters(['id' => $id]);
} else {
// если не ID, то значит urlKey и ведем поиск по нему
$s->andWhere("url.{$locale} = :id")->setParameter('id', $id);
}
if (!$preview) {
$s->andWhere('b.enable = true');
}
$q = $s->getQuery()->useQueryCache(true);
$data = ArrHelper::get($q->getArrayResult(), '0');
if (!$data) {
return null;
}
$url = ArrHelper::get($data, "url.{$locale}");
$title = ArrHelper::get($data, "title.{$locale}");
$body = ArrHelper::get($data, "body.{$locale}");
$description = ArrHelper::get($data, "description.{$locale}");
$keywords = ArrHelper::get($data, "keywords.{$locale}");
$statusShow = ArrHelper::get($data, "statusShow.{$locale}");
$statusTranslate = ArrHelper::get($data, "statusTranslate.{$locale}");
$icon = ArrHelper::get($data, "preview.{$locale}");
// если показ закрыт, либо не зватает переводов, то проводим дополнительные проверки
if (!$statusShow or !$body or !$title) {
$localeDef = LocaleHelper::getDefault();
if ($locale == $localeDef) {
// если локаль совпалает с дефолтной, то сразу выдаем NULL
return null;
} else {
// получаем тексты для дефолтной локали
$title = ArrHelper::get($data, "title.{$localeDef}");
$body = ArrHelper::get($data, "body.{$localeDef}");
$description = ArrHelper::get($data, "description.{$localeDef}");
$keywords = ArrHelper::get($data, "keywords.{$localeDef}");
$statusShow = ArrHelper::get($data, "statusShow.{$localeDef}");
$statusTranslate = ArrHelper::get($data, "statusTranslate.{$localeDef}");
$icon = ArrHelper::get($data, "preview.{$localeDef}");
}
}
if (!$icon) {
$icon = ArrHelper::get($data, "preview.default");
}
// дополнительная проверка
if (!$statusShow or !$body or !$title) {
return null;
}
$data['url'] = $url;
$data['title'] = html_entity_decode($title);
$data['body'] = html_entity_decode(LocaleHelper::modifeLinkForLocales($body));
$data['description'] = $description;
$data['keywords'] = $keywords;
$data['statusShow'] = $statusShow;
$data['statusTranslate'] = $statusTranslate;
$data['preview'] = $icon;
}
return $data;
}
/**
* Количество активных блогов по локали
* @param array $param
* @return int
* @throws Exception фильтрация должна быть одинаковая с
* @see PublicationRepository::getIdsForShortShow
*/
public function getPublicationsCount(array $param): int
{
$cc = App::getCurCountry();
$oMemcache = App::getMemcache();
$keyCache = $this->buildCacheId(__METHOD__, $cc, $param['locale']);
$cnt = $oMemcache->get($keyCache);
if (!$cnt) {
unset($param['offset'], $param['limit']);
$cnt = count($this->getIdsForShortShow($param));
// кеш на неделю
$oMemcache->set($keyCache, $cnt, MEMCACHE_COMPRESSED, (int) TimeConstant::WEEK);
}
return intval($cnt);
}
/**
* @param null $ids
* @param null $limit
* @return array|null
*/
public function getPublicationsParticipant($ids = null, $limit = null)
{
$q = $this
->createQueryBuilder('p');
if ($ids) {
$ids = TranslitHelper::replaceSpace($ids);
$IDS = explode(',', $ids);
$q->andWhere('p.id in (:ids)')
->setParameter('ids', $IDS);
}
if ($limit) {
$q->setMaxResults($limit);
}
$r = $q->getQuery();
return $r->getResult();
}
/**
* Получение списка для проверки на наличие кириллических символов
* @return array
*/
public function getCollectionsAdmForCheckCyrillic()
{
$q = $this->createQueryBuilder('p')
->select('p, body, title')
->leftJoin('p.body', 'body')
->leftJoin('p.title', 'title')
->andWhere("p.enable = true");
return $q->getQuery()->getArrayResult();
}
/**
* Получение списка для проверки на наличие кириллических символов
* @return array
* @throws \Doctrine\DBAL\Exception
*/
public function admGetListForLiMenuSelect()
{
$sql = "SELECT
p.id,
lc.ru AS name
FROM
publication p
LEFT JOIN `locale_title` `lc` ON `lc`.publication_id = `p`.id
ORDER BY lc.ru ;
";
$conn = $this->_em->getConnection();
$rows = $conn->fetchAllAssociative($sql);
$items = [];
foreach ($rows as $row) {
$items[$row['id']] = $row['name'];
}
return $items;
}
/**
* отдаем сразу URL или NULL
* @param bool|null $forPage
* @return string|null
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \Doctrine\DBAL\Exception
* @throws Exception
*/
public function getUrlBlogExpressSamples(?bool $forPage = false)
{
$lc = App::getCurLocale();
$cc = App::getCurCountry();
// для РФ блог не показываем
if (!$forPage and $cc == 'ru') {
return null;
}
$sql = "SELECT
lu.{$lc} AS slug
FROM
publication p
LEFT JOIN `locale_url` `lu` ON `lu`.publication_id = `p`.id
LEFT JOIN `locale_bool` `lp` ON `lp`.blog_show_id = `p`.id
LEFT JOIN `locale_status_translate` `lst` ON `lst`.publication_id = `p`.id
WHERE p.id = 2232 AND lp.{$lc} = 1 AND lst.{$lc} = 1;
";
$conn = $this->_em->getConnection();
$slug = $conn->executeQuery($sql)->fetchOne();
if ($slug) {
$url = App::generateUrl('app_publication_single', ['id' => $slug]);
} else {
$url = null;
}
return $url;
}
}