<?php
namespace App\Controller;
use App\Service\CanonicalRedirectHelper;
use App\Service\FormHelper;
use App\Service\MagazinHelper;
use Carbon\Carbon;
use Elements\Bundle\HashCashBundle\Service\HashCashService;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\DataObject\Consent\Service;
use Pimcore\File;
use Pimcore\Mail;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\BlogArticle;
use Pimcore\Model\DataObject\BlogAuthor;
use Pimcore\Model\DataObject\BlogCategory;
use Pimcore\Model\DataObject\BlogSubscriber;
use Pimcore\Model\DataObject\BlogTheme;
use Pimcore\Translation\Translator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class MagazineController extends AbstractController
{
public function portalAction(Request $request, Service $consentService, Translator $translator, HashCashService $hashCashService) {
$portal = $this->document->getProperty('blogPortal');
//2 top artikel
$topArticleListing = new BlogArticle\Listing();
$topArticleListing->addConditionParam('topArticle = 1 AND portals LIKE :portal', ['portal' => '%,' . $portal->getId() . ',%']); //add later, currently there are no top articles
$topArticleListing->setLimit(2);
$topArticleListing->addConditionParam('teaserImage IS NOT NULL AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)');
$topArticleListing->setOrderKey('articleDate');
$topArticleListing->setOrder('DESC');
//Teaser Grid Articles
$gridArticleListing = new BlogArticle\Listing();
//ignore the two top articles
if ($topArticleListing->count()) {
$gridArticleListing->addConditionParam('oo_id NOT IN (' . implode(',', (clone $topArticleListing)->loadIdList()) . ')');
}
$gridArticleListing->addConditionParam('teaserImage IS NOT NULL AND portals LIKE :portal AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)', ['portal' => '%,' . $portal->getId() . ',%']);
$gridArticleListing->setOrderKey('articleDate');
$gridArticleListing->setOrder('DESC');
$gridArticleListing->setLimit(12);
$subscribeResult = $this->subscriberAction($request, $consentService, $translator, $hashCashService);
return $this->renderTemplate('Magazine/portal.html.twig', [
'gridArticles' => $gridArticleListing,
'topArticles' => $topArticleListing,
'subscribeSuccess' => $subscribeResult['subscribeSuccess'],
'errors' => $subscribeResult['errors']
]);
}
public function topicAction(Request $request, PaginatorInterface $paginator, Service $consentService, Translator $translator, HashCashService $hashCashService)
{
$blogTheme = $this->getDocumentEditable('relation', 'blogTheme')->getElement();
if ($blogTheme instanceof BlogTheme) {
$orCondition = [];
foreach ($blogTheme->getBlogCategories() as $category){
$orCondition[] = 'categories LIKE "%,' . $category->getId() . ',%"';
}
$orCondition[] = 'blogThemes LIKE "%,' . $blogTheme->getId() . ',%"';
if (!empty($orCondition)) {
/*//2 top artikel
$topArticleListing = new BlogArticle\Listing();
$topArticleListing->addConditionParam('topArticle = 1 AND portals LIKE :portal', ['portal' => '%,' . $this->document->getProperty('blogPortal')->getId() . ',%']); //add later, currently there are no top articles
$topArticleListing->addConditionParam(implode(' OR ' , $orCondition)); //add later, currently there are no top articles
if ($articleRelation = $this->getDocumentEditable('relation', 'mainArticle')->getElement()){
$topArticleListing->addConditionParam('oo_id != ' . $articleRelation->getId());
}
$topArticleListing->setLimit(2);
$topArticleListing->addConditionParam('teaserImage IS NOT NULL');
$topArticleListing->setOrderKey('articleDate');
$topArticleListing->setOrder('DESC');*/
$articleListing = new BlogArticle\Listing();
$articleListing->addConditionParam(implode(' OR ' , $orCondition)); //add later, currently there are no top articles
if ($articleRelation = $this->getDocumentEditable('relation', 'mainArticle')->getElement()){
$articleListing->addConditionParam('oo_id != ' . $articleRelation->getId());
}
$articleListing->addConditionParam('teaserImage IS NOT NULL AND portals LIKE :portal AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)', ['portal' => '%,' . $this->document->getProperty('blogPortal')->getId() . ',%']);
/*//ignore the two top articles
if ($topArticleListing->count()) {
$articleListing->addConditionParam('oo_id NOT IN (' . implode(',', (clone $topArticleListing)->loadIdList()) . ')');
}*/
$articleListing->setOrderKey('articleDate');
$articleListing->setOrder('DESC');
$pagination = $paginator->paginate($articleListing, $request->get('page', 1), $blogTheme->getArticlesPerPage() ?: 6);
$pagination->setPageRange(3);
}
}
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Magazine/Includes/articleTeaserGrid.html.twig', ['paginator' => $pagination, 'document' => $this->document])
]);
}
$subscribeResult = $this->subscriberAction($request, $consentService, $translator, $hashCashService);
return $this->renderTemplate('Magazine/topic.html.twig', [
'blogTheme' => $blogTheme,
// 'topArticles' => $topArticleListing,
'paginator' => $pagination,
'subscribeSuccess' => $subscribeResult['subscribeSuccess'],
'errors' => $subscribeResult['errors']
]);
}
public function archiveAction(Request $request, Translator $translator, PaginatorInterface $paginator){
$articleListing = new BlogArticle\Listing();
$articleListing->setOrderKey('articleDate');
$articleListing->setOrder('DESC');
$currentYear = $request->get('timeline') ?: Carbon::today()->format('Y');
$firstDayOfYear = Carbon::createFromFormat("Y-m-d H:i:s", $currentYear."-01-01 00:00:00")->timestamp;
$lastDayOfYear = Carbon::createFromFormat("Y-m-d H:i:s", $currentYear."-12-31 23:59:59")->timestamp;
$articleListing->addConditionParam('(articleDate < "' . $lastDayOfYear . '") AND (articleDate > "' . $firstDayOfYear . '")');
$articleListing->addConditionParam('teaserImage IS NOT NULL AND portals LIKE :portal AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)', ['portal' => '%,' . $this->document->getProperty('blogPortal')->getId() . ',%']);
$paginator = $paginator->paginate($articleListing, $request->get('page', 1), $this->getDocumentEditable('numeric', 'per_page')->getData() ? $this->getDocumentEditable('numeric', 'per_page')->getData() : 9);
$paginator->setPageRange(3);
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Magazine/Includes/archiveContainer.html.twig', [
'paginator' => $paginator,
'currentYear' => $currentYear,
'document' => $this->document
])
]);
}
$archiveYears = new BlogArticle\Listing();
$archiveYears->addConditionParam('teaserImage IS NOT NULL AND portals LIKE :portal AND articleDate != "" AND articleDate IS NOT NULL AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)', ['portal' => '%,' . $this->document->getProperty('blogPortal')->getId() . ',%']);
$archiveYears->setOrderKey('articleDate');
$archiveYears->setOrder('DESC');
$archiveYears->setGroupBy('YEAR(FROM_UNIXTIME(articleDate))', false);
return $this->renderTemplate('Magazine/archive.html.twig', [
'archiveYears' => $archiveYears,
'currentYear' => $currentYear,
'paginator' => $paginator
]);
}
public function searchAction(Request $request, PaginatorInterface $paginator)
{
$articleListing = new BlogArticle\Listing();
$articleListing->addConditionParam('teaserImage IS NOT NULL AND portals LIKE :portal AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)', ['portal' => '%,' . $this->document->getProperty('blogPortal')->getId() . ',%']);
if ($request->get('category')){
$articleListing->addConditionParam("categories LIKE :category", ["category" => "%," .$request->get('category') . ",%"]);
}
if ($searchParam = $request->get('nav-search')){
$articleListing->addConditionParam("title LIKE :query OR keywords LIKE :queryComma", ["query" => "%" . $searchParam . "%", "queryComma" => "%" . $searchParam . ",%"]);
}
$articleListing->setOrderKey('articleDate');
$articleListing->setOrder('DESC');
$paginator = $paginator->paginate($articleListing, $request->get('page', 1), $this->getDocumentEditable('numeric', 'per_page')->getData() ? $this->getDocumentEditable('numeric', 'per_page')->getData() : 9);
$paginator->setPageRange(3);
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Magazine/Includes/articleTeaserGrid.html.twig', ['paginator' => $paginator, 'document' => $this->document])
]);
}
return $this->renderTemplate('Magazine/search.html.twig', [
'magazine' => true,
'paginator' => $paginator,
'category' => BlogCategory::getById($request->get('category'))
]);
}
public function detailAction(Request $request, CanonicalRedirectHelper $redirectHelper, Service $consentService, Translator $translator, HashCashService $hashCashService)
{
$article = BlogArticle::getById($request->get('id',0));
if (!$article || ($article->getSubmitted() && !$article->getVerified())){
throw new NotFoundHttpException("the requested object doesn't exist anymore");
}
if (CanonicalRedirectHelper::ENABLE_CANONICAL_REDIRECT && $redirect = $redirectHelper->canonicalRedirect($article)) {
return $redirect;
}
$subscribeResult = $this->subscriberAction($request, $consentService, $translator, $hashCashService);
return $this->renderTemplate('Magazine/detail.html.twig', [
'article' => $article,
'subscribeSuccess' => $subscribeResult['subscribeSuccess'],
'errors' => $subscribeResult['errors']
]);
}
public function authorOverviewAction(Request $request, PaginatorInterface $paginator){
$portalId = $this->document->getProperty('blogPortal')->getId();
$authorListing = new BlogAuthor\Listing();
$authorListing->addConditionParam('image != "" AND image IS NOT NULL AND name IS NOT NULL AND name != ""');
$authorListing->addConditionParam('portals LIKE :portal', ['portal' => '%,' . $portalId . ',%']);
$authorListing->setOrderKey('name');
$authorListing->setOrder('ASC');
$paginator = $paginator->paginate($authorListing, $request->get('page', 1), $this->getDocumentEditable('numeric', 'per_page')->getData() ? $this->getDocumentEditable('numeric', 'per_page')->getData() : 6);
$paginator->setPageRange(3);
$db = \Pimcore\Db::get();
$sql = <<<EOT
SELECT oo_id,
(SELECT COUNT(*) FROM object_BlogArticle WHERE author__id = object_BlogAuthor.oo_id AND object_BlogArticle.teaserImage IS NOT NULL AND o_published = 1) as counter
FROM object_BlogAuthor WHERE portals LIKE "%,$portalId,%"
EOT;
$results = $db->fetchAll($sql);
$articleCount = [];
foreach ($results as $result){
$articleCount[$result['oo_id']] = $result;
}
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Magazine/Includes/authorTeaserGrid.html.twig', [
'paginator' => $paginator,
'articleCount' => $articleCount,
'document' => $this->document
])
]);
}
return $this->renderTemplate('Magazine/authorOverview.html.twig', [
'paginator' => $paginator,
'articleCount' => $articleCount,
]);
}
public function authorDetailAction(Request $request, PaginatorInterface $paginator, CanonicalRedirectHelper $redirectHelper)
{
$author = BlogAuthor::getById($request->get('id',0));
if (!$author){
throw new NotFoundHttpException("the requested object doesn't exist anymore");
}
if (CanonicalRedirectHelper::ENABLE_CANONICAL_REDIRECT && $redirect = $redirectHelper->canonicalRedirect($author)) {
return $redirect;
}
$articleListing = new BlogArticle\Listing();
$articleListing->addConditionParam("author__id = " . $author->getId());
$articleListing->addConditionParam('teaserImage IS NOT NULL AND (IFNULL(submitted, 0) = 0 OR IFNULL(verified, 0) = 1)');
$articleListing->setOrderKey('articleDate');
$articleListing->setOrder('DESC');
$paginator = $paginator->paginate($articleListing, $request->get('page', 1), 6);
$paginator->setPageRange(3);
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Magazine/Includes/articleTeaserGrid.html.twig', [
'paginator' => $paginator,
'notRelative' => true,
'document' => $this->document
])
]);
}
return $this->renderTemplate('Magazine/authorDetail.html.twig', [
'author' => $author,
'paginator' => $paginator
]);
}
public function subscriberAction(Request $request, Service $consentService, Translator $translator, HashCashService $hashCashService){
$portal = $this->document->getProperty('blogPortal');
$subscribeSuccess = false;
if ($request->isMethod('POST') && $request->get('subscribeMagazine', false)) {
if ($hashCashService->validateProcessFrom()) {
$email = $request->get('email');
$errors = [];
if ($email == '') {
$errors[] = 'email must not be empty';
} else {
if (!FormHelper::isValidEmailAddress($email)) {
$errors[] = 'email must be valid';
} else {
$subscriber = BlogSubscriber::getByEmail($email);
$subscriber->addConditionParam('portal__id = :portal', ['portal' => $portal->getId()]);
$subscriber->setLimit(1);
$subscriber = $subscriber->current();
if ($subscriber instanceof BlogSubscriber && $subscriber->getConfirmed()) {
$errors[] = 'subscriber already exists';
}
}
}
} else {
$errors[] = 'hashcash not valid';
}
if (empty($errors)) {
if (!$subscriber instanceof BlogSubscriber) {
$subscriber = new BlogSubscriber();
$subscriber->setKey(File::getValidFilename($email));
$subscriber->setPublished(true);
$subscriber->setParent(DataObject\Service::createFolderByPath('/Blog/Subscribers/' . $portal->getKey()));
$subscriber->setEmail($email);
$subscriber->setSubscriberLanguage($request->getLocale());
}
$token = md5($portal->getKey() . '_' . $email . time());
$validUntil = Carbon::now()->addDays(30);
$subscriber->setToken($token);
$subscriber->setValidUntil($validUntil);
$subscriber->setSubscriberLanguage($request->getLocale());
$metaData = [
'ip' => $request->getClientIp()
];
$subscriber->setPortal($portal);
$subscriber->save();
$consentService->giveConsent($subscriber, 'consent', $translator->trans('magazin.subscribe.' . $portal->getKey() . '.gdpr'), $metaData);
$subscriber->save();
if ($mailDoc = $this->document->getProperty('blogPortal')->getSubscribeMail()) {
$mail = new Mail();
$mail->setDocument($mailDoc);
$mail->setParams([
'email' => $email,
'url' => $this->document->getProperty('blogPortal')->getSubscribeConfirmDocument() . '?token=' . $token,
'token' => $token
]);
$mail->addTo($email);
$mail->send();
}
$subscribeSuccess = true;
}
}
return [
'subscribeSuccess' => $subscribeSuccess,
'errors' => $errors ?? []
];
}
public function confirmSubscriptionAction(Request $request) {
$success = false;
$errors = [];
if (!$this->editmode) {
$subscriber = BlogSubscriber::getByToken($request->get('token'), 1);
if ($subscriber instanceof BlogSubscriber) {
if ($subscriber->getValidUntil() >= Carbon::now()) {
$subscriber->setConfirmed(true);
$subscriber->setActive(true);
$subscriber->setToken('');
try {
$subscriber->save();
$success = true;
} catch (\Exception $e) {
if (\Pimcore::inDebugMode()) {
p_r($e);
}
$errors[] = 'general error';
}
} else {
$errors[] = 'token expired';
}
} else {
$errors[] = 'token invalid';
}
}
return $this->renderTemplate('Magazine/confirmSubscription.html.twig', [
'success' => $success,
'errors' => $errors,
]);
}
/**
* @param Request $request
* @param string $id
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Exception
*/
public function unsubscribeSubscriptionAction(Request $request) {
$subscriber = BlogSubscriber::getById($request->get('id'));
$unsubscribed = false;
if ($subscriber instanceof BlogSubscriber && $request->isMethod('POST') && $request->get('pot-number') == '') {
$subscriber->setActive(false);
$subscriber->save();
$unsubscribed = true;
}
return $this->renderTemplate('Magazine/unsubscribeSubscription.html.twig', [
'unsubscribed' => $unsubscribed
]);
}
}