<?php
namespace Cms\Modules\NewsBundle\Service;
use App\Doctrine\Repository\Content\ObjectSearch;
use App\Doctrine\Repository\Content\Posts\Post\PostObjectRepository;
use App\Entity\Content\Posts\Post\PostObject;
use App\Enum\ChannelEnum;
use App\Util\Ulids;
use Cms\AssetsBundle\Model\Structure\TitleStructure;
use Cms\CoreBundle\Model\Search\AbstractSearcher;
use Cms\CoreBundle\Util\DateTimeUtils;
use Cms\FrontendBundle\Model\FrontendGlobals;
use Cms\ModuleBundle\Entity\ModuleEntity;
use Cms\ModuleBundle\Entity\Proxy;
use Cms\ModuleBundle\Exception\ModuleConfigException;
use Cms\ModuleBundle\Model\ModuleConfig;
use Cms\ModuleBundle\Model\Traits\FrontendActions\CascadingSharesTrait;
use Cms\ModuleBundle\Model\Traits\FrontendActions\FeedSecurityTrait;
use Cms\ModuleBundle\Model\Traits\FrontendActions\FeedTrait;
use Cms\ModuleBundle\Model\Traits\FrontendActions\RssFeedTrait;
use Cms\ModuleBundle\Model\Traits\FrontendActions\SocialMetaTrait;
use Cms\Modules\NewsBundle\Doctrine\Article\ArticleProxyRepository;
use Cms\Modules\NewsBundle\Entity\Article\ArticleProxy;
use Cms\Modules\NewsBundle\Entity\ModuleSettings;
use Cms\Modules\NewsBundle\Service\Search\ArticleSearcher;
use Cms\Widgets\Html\Html;
use Common\Util\Strings;
use Doctrine\Common\Util\ClassUtils;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class NewsModuleConfig
* @package Cms\Modules\NewsBundle\Service
*/
final class NewsModuleConfig extends ModuleConfig
{
const NAME = 'News';
use RssFeedTrait;
use FeedTrait;
use FeedSecurityTrait;
use SocialMetaTrait;
use CascadingSharesTrait;
/**
* @return ArticleProxyRepository
*/
private function getProxyRepository(): ArticleProxyRepository
{
return $this->getEntityManager()->getRepository(ArticleProxy::class);
}
/**
* @return PostObjectRepository
*/
private function getObjectRepository(): PostObjectRepository
{
return $this->getEntityManager()->getRepository(PostObject::class);
}
/**
* {@inheritdoc}
* @param ArticleProxy $proxy
*/
public function urlify(Proxy $proxy = null)
{
if ($proxy === null) {
return '/' . $this->key();
}
return sprintf(
'/%s/%s/%s',
$this->key(),
$proxy->getId(),
$proxy->getData()->getSlug()
);
}
/**
* {@inheritdoc}
*/
public function frontend(FrontendGlobals $globals)
{
$extra = $globals->getExtra();
//override inner layout from module settings
/** @var ModuleSettings $settings */
$settings = $globals->getModuleSettings();
if ( ! empty($settings->getInnerLayout())) {
$globals->setInnerLayout(
$settings->getInnerLayout(),
true
);
}
switch (true) {
case preg_match('/^\\/$/', $extra, $matches):
return $this->frontendList($globals, array(
'page' => 1,
));
case preg_match('/^\\/page\\/([1-9]\\d*)$/', $extra, $matches):
return $this->frontendList($globals, array(
'page' => $matches[1],
));
// SCHOOLNOW: modify regex to allow for ulid values
case preg_match('/^\\/([0-9]+|[0-7][0-9a-hA-HjJkKmMnNp-tP-Tv-zV-Z]{25})\\/([-a-zA-Z0-9]+)$/', $extra, $matches):
return $this->frontendView($globals, array(
'id' => $matches[1],
'slug' => $matches[2],
));
case $this->isPrivateFeed($globals->getContainer(), $this->name()):
return $this->loginRedirect($globals->getRequest());
case preg_match('/\\/subscribe$/', $extra):
return $this->frontendSubscribe($globals);
case preg_match('/\\/feed\\/(rss)$/', $extra, $matches):
return $this->rssFeed(
$this->getFeedBuilder(),
$globals,
$matches[1]
);
default:
throw new NotFoundHttpException();
}
}
/**
* @param FrontendGlobals $globals
* @param array $params
* @return array
* @throws ModuleConfigException
*/
private function frontendList(FrontendGlobals $globals, array $params)
{
// SCHOOLNOW: handle schoolnow
if ($this->isSchoolNow($globals->getContainer())) {
return $this->frontendListSchoolNow($globals, $params);
}
// query for objects, apply paging
$items = $this->paginationResults(
$this->getProxyRepository()->createQueryBuilder('items')
->andWhere('items.container IN (:container)')
->setParameter('container', $this->flattenContainers($globals->getContainer(), ModuleSettings::class))
->andWhere('items.data_timestamp <= :now')
->setParameter('now', DateTimeUtils::current())
->addOrderBy('items.data_timestamp', 'DESC')
,
$params['page']
);
// handle paging math
$pagination = $this->pagination($items, $params['page']);
// set title, do this after query, so we can attach page number for ada compliance
if ( ! empty($globals->getModuleSettings()->getTitle())) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getModuleSettings()->getTitle()));
if ( ! empty($pagination)) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure('Page ' . $pagination['current']));
}
} else {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getModule()->name()));
if ( ! empty($pagination)) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure('Page ' . $pagination['current']));
}
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getContainer()->getName()));
}
// render the content
$content = $this->getTwig()->render(
$this->getDatabaseLoader()->determine(
$globals->getTheme(),
sprintf(
'/modules/%s/List/build/tpl.html.twig',
$globals->getModule()->name()
)
),
array(
'globals' => $globals,
'items' => $items,
'pagination' => $pagination,
)
);
// pass back as we need it
return array(
array(
'content' => array(
(new Html())
->setContent($content),
),
),
);
}
/**
* @param FrontendGlobals $globals
* @param array $params
* @return array
* @throws ModuleConfigException
*/
private function frontendListSchoolNow(FrontendGlobals $globals, array $params)
{
// set things we are looking for
$globals->setThingClasses([
PostObject::class,
]);
// query for objects, apply paging
/** @var PostObjectRepository $postObjectRepository */
$postObjectRepository = $this->getEntityManager()->getRepository(PostObject::class);
$items = $postObjectRepository
->findBySearch(
(new ObjectSearch())
->setContainer($globals->getContainer())
->setChannels(ChannelEnum::WEBSITE)
,
self::PAGINATION_SIZE + 1,
($params['page'] - 1) * self::PAGINATION_SIZE
)
->getIterator()
->getArrayCopy()
;
// handle paging math
$pagination = $this->pagination($items, $params['page']);
// set title, do this after query, so we can attach page number for ada compliance
if ( ! empty($globals->getModuleSettings()->getTitle())) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getModuleSettings()->getTitle()));
if ( ! empty($pagination)) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure('Page ' . $pagination['current']));
}
} else {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getModule()->name()));
if ( ! empty($pagination)) {
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure('Page ' . $pagination['current']));
}
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($globals->getContainer()->getName()));
}
// render the content
$content = $this->getTwig()->render(
$this->getDatabaseLoader()->determine(
$globals->getTheme(),
sprintf(
'/modules/%s/List/build/sn.html.twig',
$globals->getModule()->name()
)
),
array(
'globals' => $globals,
'items' => $items,
'pagination' => $pagination,
)
);
// pass back as we need it
return array(
array(
'content' => array(
(new Html())
->setContent($content),
),
),
);
}
/**
* @param FrontendGlobals $globals
* @param array $params
* @return array|RedirectResponse
* @throws ModuleConfigException
*/
private function frontendView(FrontendGlobals $globals, array $params)
{
// SCHOOLNOW: handle schoolnow
if ($this->isSchoolNow($globals->getContainer())) {
return $this->frontendViewSchoolNow($globals, $params);
}
/** @var ArticleProxy $item */
$item = $this->getEntityManager()->getRepository(ArticleProxy::class)->find($params['id']);
// check for item, if none, throw 404
if ( ! $item) {
throw new NotFoundHttpException();
}
// set the thing on the globals
$globals->setThing($item);
// handle non-proxy preview
if ($globals->getThingOverride() instanceof ModuleEntity) {
$globals->setThing($item->setData(
$globals->getThingOverride()->getData()
));
}
// set social meta tags
$this->setSocialMeta(
$globals,
$item->getData()->getSocialMetadata()
);
// set title
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($item->getData()->getTitle()))
->add(new TitleStructure($globals->getContainer()->getName()));
// check to see if we have an external link set; if so return a redirect, and only do if not logged in
if ( ! empty($item->getData()->getExternalLink()) && empty($globals->getMimic())) {
return new RedirectResponse($item->getData()->getExternalLink());
}
// check slugs, and if incorrect, redirect to proper url with slug
if ($item->getData()->getSlug() !== $params['slug']) {
return new RedirectResponse(sprintf(
'%s/%s/%s/%s',
$globals->pathPrefix(),
$globals->getModule()->key(),
$item->getId(),
$item->getData()->getSlug()
));
}
// render the content
$content = $this->getTwig()->render(
$this->getDatabaseLoader()->determine(
$globals->getTheme(),
sprintf(
'/modules/%s/View/build/tpl.html.twig',
$globals->getModule()->name()
)
),
array(
'globals' => $globals,
'item' => $item,
)
);
// pass back as we need it
return array(
array(
'content' => array(
(new Html())
->setContent($content),
),
),
);
}
/**
* @param FrontendGlobals $globals
* @param array $params
* @return array|RedirectResponse
* @throws ModuleConfigException
*/
private function frontendViewSchoolNow(FrontendGlobals $globals, array $params)
{
if ( ! Ulids::test($params['id'])) {
throw new NotFoundHttpException();
}
/** @var PostObject $item */
$item = $this->getEntityManager()->getRepository(PostObject::class)->find($params['id']);
// check for item, if none, throw 404
if ( ! $item) {
throw new NotFoundHttpException();
}
// check if it has website channel
if ( ! $item->hasChannel(ChannelEnum::WEBSITE)) {
throw new NotFoundHttpException();
}
// set the thing on the globals
$globals
->setThing($item)
->setThingClasses([ClassUtils::getClass($item)])
;
// handle non-proxy preview
// if ($globals->getThingOverride() instanceof ModuleEntity) {
// $globals->setThing($item->setData(
// $globals->getThingOverride()->getData()
// ));
// }
// set social meta tags
$this->setSocialMeta(
$globals,
[
'og:type' => 'article',
'title' => $item->getHeadline(),
'image' => $item->getMedia()->getFeature(),
// 'cs:image-presized' => ( ! empty($this->getSocialImage())),
'description' => Strings::htmltidytrim($item->getHtml()),
]
);
// set title
$globals->getAssetsOrganizer()->getTitles()
->add(new TitleStructure($item->getHeadline()))
->add(new TitleStructure($globals->getContainer()->getName()));
// check to see if we have an external link set; if so return a redirect, and only do if not logged in
// if ( ! empty($item->getData()->getExternalLink()) && empty($globals->getMimic())) {
// return new RedirectResponse($item->getData()->getExternalLink());
// }
// check slugs, and if incorrect, redirect to proper url with slug
if ($item->getSlug() !== $params['slug']) {
return new RedirectResponse(sprintf(
'%s/%s/%s/%s',
$globals->pathPrefix(),
$globals->getModule()->key(),
$item->getId(),
$item->getSlug()
));
}
// render the content
$content = $this->getTwig()->render(
$this->getDatabaseLoader()->determine(
$globals->getTheme(),
sprintf(
'/modules/%s/View/build/sn.html.twig',
$globals->getModule()->name()
)
),
array(
'globals' => $globals,
'item' => $item,
)
);
// pass back as we need it
return array(
array(
'content' => array(
(new Html())
->setContent($content),
),
),
);
}
/**
* {@inheritdoc}
*/
public function types()
{
return array(ArticleProxy::TYPE);
}
/**
* {@inheritdoc}
*/
public function typesRoots()
{
return array(ArticleProxy::TYPE);
}
/**
* {@inheritdoc}
*/
public function typesChildren($type)
{
return [];
}
/**
* {@inheritdoc}
*/
public function collectionClass($classname)
{
}
/**
* @return ArticleSearcher|object
*/
public function getArticleSearcher(): ArticleSearcher
{
return $this->container->get(__METHOD__);
}
/**
* {@inheritDoc}
* @return ArticleSearcher
*/
public function getSearcher(): AbstractSearcher
{
return $this->getArticleSearcher();
}
}