<?php
namespace Elements\Bundle\BlogBundle\Controller;
use Carbon\Carbon;
use Elements\Bundle\BlogBundle\Tools\BlogBundleGenerator;
use Pimcore\Controller\FrontendController;
use Pimcore\Google\Cse;
use Pimcore\Logger;
use Pimcore\Model\DataObject\BlogBundleArticle;
use Pimcore\Model\DataObject\BlogBundleAuthor;
use Pimcore\Model\DataObject\BlogBundleCategory;
use Pimcore\Model\DataObject\BlogBundleConfig;
use Pimcore\Model\Document\Page;
use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Knp\Component\Pager\Paginator;
use Knp\Component\Pager\PaginatorInterface;
use Doctrine\DBAL\Query\QueryBuilder;
class BlogController extends FrontendController
{
/**
* @param Request $request
* @throws \Exception
*/
public function overviewAction(Request $request, PaginatorInterface $paginator): \Symfony\Component\HttpFoundation\JsonResponse|Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$sorting = null;
$articles = new BlogBundleArticle\Listing();
$articles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
if ($request->get('from', false)) {
$articles->addConditionParam('publishDate > :from', ['from' => Carbon::createFromTimeString($request->get('from'))->getTimestamp()]);
}
if ($request->get('to', false)) {
$articles->addConditionParam('publishDate < :to', ['to' => Carbon::createFromTimeString($request->get('to'))->getTimestamp()]);
}
if ($request->get('q', '') != '') {
$articles->addConditionParam('(title LIKE :search OR shortDescription LIKE :search)', ['search' => '%' . $request->get('q') . '%'] );
}
if ($request->get('category')){
$articles->addConditionParam('categories LIKE "%,' . intval($request->get('category')) . ',%"');
}
if ($request->get('categories', [])) {
$orCondition = [];
foreach ($request->get('categories', []) as $category) {
if($category) {
$orCondition[] = 'categories LIKE "%,' . intval($category) . ',%"';
}
}
if(!empty($orCondition)) {
$articles->addConditionParam('(' . implode(' OR ', $orCondition) . ')');
}
}
if ($config) {
if ($config->getIsMultiSite()) {
$articles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getSorting();
}
if (!$sorting) {
$sorting = 'topArticle DESC, publishDate DESC';
}
$articles->setOrderKey($sorting, false);
$params = [
'config' => $config
];
$eventParams = [
'articleListing' => $articles,
'params' => $params
];
$eventDispatcher = \Pimcore::getEventDispatcher();
/** @var GenericEvent $articleListingEvent */
$articleListingEvent = $eventDispatcher->dispatch(new GenericEvent('articleListing', $eventParams), 'articleListing');
if ($articleListingEvent->hasArgument('articleListing')) {
$articles = $articleListingEvent->getArgument('articleListing');
}
if ($articleListingEvent->hasArgument('params')) {
$params = $articleListingEvent->getArgument('params');
}
$paginator = $paginator->paginate($articles, $request->get('page', 1), $config && $config->getItemsPerPage() ? $config->getItemsPerPage() : 4);
if ($config) {
if ($config->getPageRange()) {
$paginator->setPageRange($config->getPageRange());
}
}
$params['paginator'] = $paginator;
if ($request->isXmlHttpRequest()) {
$html = $this->renderView('@ElementsBlog/Includes/articlesContainer.html.twig', $params);
return $this->json(['success' => true, 'html' => $html]);
}
return $this->render('@ElementsBlog/Blog/overview.html.twig', $params);
}
/**
* @param Request $request
* @throws \Exception
*/
public function detailAction(Request $request): \Symfony\Component\HttpFoundation\Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$article = BlogBundleArticle::getById($request->get('id'));
if ($request->get('pimcore_object_preview') == '' || !$article instanceof BlogBundleArticle) {
if (!$article instanceof BlogBundleArticle || !$article->isPublished() || $article->getPublishDate()->timestamp > time()) {
throw new NotFoundHttpException('The requested Article doesn\'t exist (anymore)');
}
}
if ($request->get('pimcore_object_preview') != '') {
$this->addResponseHeader( 'x-robots-tag', 'noindex,nofollow');
}
$relatedArticlesCount = $config ? $config->getRelatedArticlesCount() : null;
if ($relatedArticlesCount === null) {
$relatedArticlesCount = 3;
}
$sorting = $config ? $config->getSorting() : 'topArticle DESC, publishDate DESC';
if(empty($article->getRelatedArticles())) {
$relatedArticles = new BlogBundleArticle\Listing();
$relatedArticles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
$relatedArticles->addConditionParam('o_id != :id', ['id' => $article->getId()]);
$condition = [];
foreach ($article->getCategories() ?? [] as $category) {
$ignoreCategory = false;
if($config
&& method_exists($category, 'getSite')
&& !empty($category->getSite())
&& !in_array($config->getId(), $category->getSite())
) {
$ignoreCategory = true;
}
if(!$ignoreCategory) {
$condition[] = 'categories LIKE "%,' . $category->getId() . ',%"';
}
}
if (count($condition)) {
$relatedArticles->addConditionParam('(' . implode(' OR ', $condition) . ')');
}
if ($config) {
if ($config->getIsMultiSite()) {
$relatedArticles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
}
$relatedArticles->setOrderKey($sorting, false);
$relatedArticles->setLimit($relatedArticlesCount * 3);
$relatedArticles->setOrderKey('RAND(' . Carbon::now()->hour . ')', false);
$count = $relatedArticles->getCount();
$relatedArticles->setOrderKey('RAND(' . Carbon::now()->hour . ')', false);
$relatedArticles = $relatedArticles->load();
} else { // use manual articles
$relatedArticles = $article->getRelatedArticles();
$count = count($relatedArticles);
}
$articles = [];
if ($count > $relatedArticlesCount) {
$articlesArray = $relatedArticles;
for ($i = 0; $i < $relatedArticlesCount; $i++) {
$articles[] = $articlesArray[$i];
}
} else {
$notIds = [$article->getId()];
foreach ($relatedArticles as $relatedArticle) {
$articles[] = $relatedArticle;
$notIds[] = $relatedArticle->getId();
}
if (!$article->getNotfillWithRandomTeaser() && $count < $relatedArticlesCount) {
$fillArticles = new BlogBundleArticle\Listing();
$fillArticles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
$fillArticles->addConditionParam('o_id NOT IN (' . implode(',', $notIds) . ')');
if ($config) {
$fillArticles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$fillArticles->setOrderKey($sorting, false);
$fillArticles->setLimit($relatedArticlesCount - $count);
foreach ($fillArticles as $fillArticle) {
$articles[] = $fillArticle;
}
}
}
return $this->render('@ElementsBlog/Blog/detail.html.twig', [
'article' => $article,
'articles' => $articles,
'config' => $config
]);
}
/**
* @param Request $request
* @return array
* @throws \Exception
*/
public function categoryAction(Request $request, PaginatorInterface $paginator): \Symfony\Component\HttpFoundation\JsonResponse|Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$category = BlogBundleCategory::getById($request->get('id'));
if (!$category instanceof BlogBundleCategory || !$category->isPublished()) {
throw new NotFoundHttpException('The requested Category doesn\'t exist (anymore)');
}
$articles = new BlogBundleArticle\Listing();
$articles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
if ($request->get('from', false)) {
$articles->addConditionParam('publishDate > :from', ['from' => Carbon::createFromTimeString($request->get('from'))->getTimestamp()]);
}
if ($request->get('to', false)) {
$articles->addConditionParam('publishDate < :to', ['to' => Carbon::createFromTimeString($request->get('to'))->getTimestamp()]);
}
if ($request->get('q', '') != '') {
$articles->addConditionParam('(title LIKE :search OR shortDescription LIKE :search)', ['search' => '%' . $request->get('q') . '%'] );
}
$articles->addConditionParam('categories LIKE :categoryId', ['categoryId' => "%," . $category->getId() . ",%"]);
if ($config) {
if ($config->getIsMultiSite()) {
$articles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getSorting();
}
if (!$sorting) {
$sorting = 'topArticle DESC, publishDate DESC';
}
$articles->setOrderKey($sorting, false);
$paginator = $paginator->paginate($articles, $request->get('page', 1),$config->getItemsPerPage() ?? 4);
if ($config){
if ($config->getPageRange()) {
$paginator->setPageRange($config->getPageRange());
}
}
$params['paginator'] = $paginator;
$params['category'] = $category;
$params['config'] = $config;
if ($request->isXmlHttpRequest()) {
$html = $this->renderView('@ElementsBlog/Includes/articlesContainer.html.twig', $params);
return $this->json(['success' => true, 'html' => $html]);
}
return $this->render('@ElementsBlog/Blog/category.html.twig', $params);
}
/**
* @param Request $request
* @return array
* @throws \Exception
*/
public function archiveAction(Request $request, PaginatorInterface $paginator): \Symfony\Component\HttpFoundation\Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
if (!intval($request->get('year'))) {
throw new NotFoundHttpException('The requested Archive date is invalid');
}
if (intval($request->get('month'))) {
$dateFrom = Carbon::createFromDate($request->get('year'), $request->get('month'));
$dateFrom->startOfMonth();
$dateTo = clone $dateFrom;
$dateTo->endOfMonth();
} else {
$dateFrom = Carbon::createFromDate($request->get('year'));
$dateFrom->startOfYear();
$dateTo = clone $dateFrom;
$dateTo->endOfYear();
}
$articles = new BlogBundleArticle\Listing();
$articles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
$articles->addConditionParam('publishDate > :dateFrom AND publishDate < :dateTo', ['dateTo' => $dateTo->timestamp, 'dateFrom' => $dateFrom->timestamp] );
if ($config) {
if ($config->getIsMultiSite()) {
$articles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getSorting();
}
if (!$sorting) {
$sorting = 'topArticle DESC, publishDate DESC';
}
$articles->setOrderKey($sorting, false);
$paginator = $paginator->paginate($articles, $request->get('page', 1), $config->getItemsPerPage() ?? 4);
if ($config){
if ($config->getPageRange()) {
$paginator->setPageRange($config->getPageRange());
}
}
return $this->render('@ElementsBlog/Blog/archive.html.twig', [
"paginator" => $paginator,
'config' => $config
]);
}
/**
* @param Request $request
* @return array
* @throws \Exception
*/
public function authorOverviewAction(Request $request, PaginatorInterface $paginator): \Symfony\Component\HttpFoundation\Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$authors = new BlogBundleAuthor\Listing();
$authors->onCreateQueryBuilder(function (\Doctrine\DBAL\Query\QueryBuilder $query) use ($authors, $request) {
$query->distinct()->leftJoin(
'object_localized_' . $authors->getClassId() . '_' . $request->getLocale(),
'object_localized_' . \Pimcore\Model\DataObject\BlogBundleArticle::classId() . '_' . $request->getLocale(),
'articles',
'articles.author__id = object_localized_' . $authors->getClassId() . '_' . $request->getLocale() . '.o_id AND articles.o_published = 1 AND IFNULL(articles.title,"") != "" AND articles.publishDate < ' . time()
);
});
if ($config) {
if ($config->getIsMultiSite()) {
$authors->addConditionParam('articles.site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getAuthorSorting();
}
if (!$sorting) {
$sorting = 'lastname ASC, firstname ASC';
// Todo: COUNT(articles.o_id) --> einbauen
// $sorting = 'articleCount DESC, lastname ASC, firstname ASC';
}
$authors->setOrderKey($sorting, false);
$paginator = $paginator->paginate($authors, $request->get('page', 1), $config->getItemsPerPage() ?? 4);
if ($config) {
if ($config->getPageRange()) {
$paginator->setPageRange($config->getPageRange());
}
}
return $this->render('@ElementsBlog/Blog/authorOverview.html.twig', [
"paginator" => $paginator,
'config' => $config
]);
}
/**
* @param Request $request
* @return array
* @throws \Exception
*/
public function authorDetailAction( PaginatorInterface $paginator, Request $request): \Symfony\Component\HttpFoundation\Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$author = BlogBundleAuthor::getById($request->get('id'));
if (!$author instanceof BlogBundleAuthor || !$author->isPublished()) {
throw new NotFoundHttpException('The requested Author doesn\'t exist (anymore)');
}
if ($request->get('pimcore_object_preview') != '') {
$this->addResponseHeader( 'x-robots-tag', 'noindex,nofollow');
}
$articles = new BlogBundleArticle\Listing();
$articles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
$articles->addConditionParam('author__id = :authorId', ['authorId' => $author->getId()]);
if ($config) {
if ($config->getIsMultiSite()) {
$articles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getSorting();
}
if (!$sorting) {
$sorting = 'topArticle DESC, publishDate DESC';
}
$articles->setOrderKey($sorting, false);
$paginator = $paginator->paginate($articles, $request->get('page', 1), $config->getAuthorItemsPerPage() ?? 4);
if ($config){
if ($config->getPageRange()) {
$paginator->setPageRange($config->getPageRange());
}
}
return $this->render('@ElementsBlog/Blog/authorDetail.html.twig', [
'author' => $author,
'paginator' => $paginator,
'config' => $config
]);
}
public function cseAction (Request $request, PaginatorInterface $paginator): \Symfony\Component\HttpFoundation\Response
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
if ($request->get('q')) {
try {
$page = $request->get('page', 1);
$perPage = $config->getSearchResultCount() ?? 10;
$search = $request->get('q') . ' site:' . \Pimcore\Tool::getHostUrl() . $config->getOverviewDocument();
$result = Cse::search($search, (($page - 1) * $perPage), null, [
'cx' => $config->getGoogleCseCx()
], $request->get('facet'));
$paginator = $paginator->paginate($result, $page, $perPage);
return $this->render('@ElementsBlog/Blog/cse.html.twig', [
'paginator' => $paginator,
'config' => $config
]);
} catch (\Exception $e) {
Logger::err($e->getMessage());
}
}
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function languageRedirectAction(Request $request)
{
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
if (!in_array($language, \Pimcore\Tool::getValidLanguages()) || !$config->getOverviewDocument($language) instanceof Page) {
if ($config->getOverviewDocument('en') instanceof Page) {
$language = 'en';
} else {
$language = 'de';
}
}
return $this->redirect($config->getOverviewDocument($language)->getFullPath());
}
public function rssAction(Request $request, BlogBundleGenerator $blogBundleGenerator) {
if ($this->document) {
$config = $this->document->getProperty('blog_config');
}
if (!$config) {
$configListing = new BlogBundleConfig\Listing();
$config = $configListing->current();
}
$articles = new BlogBundleArticle\Listing();
$articles->addConditionParam('IFNULL(title,"") != "" AND publishDate < :now', ['now' => time()]);
if ($config) {
if ($config->getIsMultiSite()) {
$articles->addConditionParam('site LIKE :site', ['site' => '%,' . $config->getId() . ',%']);
}
$sorting = $config->getSorting();
}
if (!$sorting) {
$sorting = 'topArticle DESC, publishDate DESC';
}
$articles->setOrderKey($sorting, false);
$rssString = '<?xml version="1.0" encoding="ISO-8859-1"?><rss version="2.0"><channel>';
$rssString .= '<title>' . $this->config ? $this->config->getRssTitle() : '' . '</title>';
$rssString .= '<link>' . \Pimcore\Tool::getHostUrl() . $this->config->getOverviewDocument() . '</link>';
$rssString .= '<description>' . $this->config ? $this->config->getRssDescription() : '' . '</description>';
$rssString .= '<language>' . $request->getLocale() . '</language>';
$rssString .= '<copyright>' . $this->config ? $this->config->getCopyright() : '' . '</copyright>';
foreach ($articles as $article) {
$articleString = '<item>';
$articleString .= '<title>' . $article->getTitle() . '</title>';
$articleString .= '<description>' . $article->getShortDescription() . '</description>';
$articleString .= '<link>' . \Pimcore\Tool::getHostUrl() . $blogBundleGenerator->generate($article) . '</link>';
$articleString .= '<pubDate>' . $article->getPublishDate()->toIso8601String() . '</pubDate>';
$articleString .= '</item>';
$rssString .= $articleString;
}
$rssString .= '</channel></rss>';
return new Response($rssString, 200, [
'Content-Type' => 'application/rss+xml; charset=UTF8'
]);
}
}