<?php
namespace Moka\Cms\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Moka\Cms\Bridge\Doctrine\QueryBuilder\EntryQueryBuilder;
use Moka\Cms\Entity\EntryInterface;
use Moka\Cms\Exception\EntryRouteException;
use Moka\Cms\Exception\NotPublishedHttpException;
use Moka\Cms\Exception\RendererException;
use Moka\Cms\Model\EntryMetadata;
use Moka\Cms\Model\Model;
use Moka\Cms\Renderer\RendererManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class EntryController extends AbstractController
{
public function __construct(private Model $model, private RendererManager $rendererManager, private ManagerRegistry $managerRegistry)
{
}
public function show(Request $request)
{
if (!$type = $request->attributes->get('_type')) {
throw new EntryRouteException('Route attribute "_type" is required');
}
$entryMetadata = $this->model->getEntryMetadata($type);
$renderer = $request->attributes->get('_renderer') ?? $entryMetadata->getDefaultRendererName();
if (!$renderer) {
throw new RendererException('Default entry renderer or route attribute "_renderer" is required');
}
$rendererContext = $request->attributes->get('_renderer_context') ?? $entryMetadata->getDefaultRendererContext();
$rendererContext['locale'] ??= $request->getLocale();
$attributes = array_filter($request->attributes->all(), fn ($name) => !str_starts_with($name, '_'), ARRAY_FILTER_USE_KEY);
if (!$entryMetadata->isSingle() && 0 === count($attributes)) {
throw new EntryRouteException('You must declare a route attribute');
}
/** @var null|EntryInterface $entry */
$entry = $entryMetadata->isSingle()
? $this->getSingleEntry($entryMetadata, $request->getLocale())
: $this->getEntry($entryMetadata, $request->getLocale(), $attributes);
if (!$entry) {
throw $this->createNotFoundException();
}
if (!$entry->isPublished() || !$entry->hasLocale($request->getLocale())) {
throw new NotPublishedHttpException('Entry is not published');
}
$rs = $this->rendererManager->get($renderer)->render($entry, $rendererContext);
if ($rs instanceof Response) {
return $rs;
}
return new Response($rs);
}
protected function getEntry(EntryMetadata $entryMetadata, string $locale, array $attributes): ?EntryInterface
{
$qb = $this->createQueryBuilder($entryMetadata, $locale);
foreach ($attributes as $name => $value) {
if ($entryMetadata->hasField($name)) {
$qb->addWhereFieldEqual($name, $value);
}
}
return $qb->getQuery()->getOneOrNullResult();
}
protected function getSingleEntry(EntryMetadata $entryMetadata, string $locale): ?EntryInterface
{
return $this->createQueryBuilder($entryMetadata, $locale)->getQuery()->getOneOrNullResult();
}
protected function createQueryBuilder(EntryMetadata $entryMetadata, string $locale): EntryQueryBuilder
{
/** @var EntityManagerInterface $entityManager */
$entityManager = $this->managerRegistry->getManagerForClass($entryMetadata->getClassName());
return (new EntryQueryBuilder($entityManager, $entryMetadata))
->select('entry')
->from($entryMetadata->getClassName(), 'entry')
->setLocale($locale)
->whereIsMain()
->joinTranslation();
}
}