diff --git a/config/forms/event_details.xml b/config/forms/event_details.xml
index 7c624dcc..bd4e4871 100644
--- a/config/forms/event_details.xml
+++ b/config/forms/event_details.xml
@@ -14,6 +14,19 @@
+
+
+
+
+
+
+ sulu_admin.url
+
+
+
+
+
+
diff --git a/config/services.yaml b/config/services.yaml
index 3877d370..831db81b 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -44,3 +44,6 @@ services:
App\Content\Type\AlbumSelection:
tags: [{name: 'sulu.content.type', alias: 'album_selection'}]
+
+ App\Routing\EventRouteDefaultsProvider:
+ tags: [{ name: 'sulu_route.defaults_provider' }]
diff --git a/src/Controller/Admin/EventController.php b/src/Controller/Admin/EventController.php
index c0c4077d..345a81aa 100644
--- a/src/Controller/Admin/EventController.php
+++ b/src/Controller/Admin/EventController.php
@@ -8,7 +8,10 @@
use App\Entity\Event;
use Doctrine\ORM\EntityManagerInterface;
use Sulu\Bundle\MediaBundle\Media\Manager\MediaManagerInterface;
+use Sulu\Bundle\RouteBundle\Entity\RouteRepositoryInterface;
+use Sulu\Bundle\RouteBundle\Manager\RouteManagerInterface;
use Sulu\Component\Security\SecuredControllerInterface;
+use Sulu\Component\Webspace\Manager\WebspaceManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,6 +22,7 @@
* @phpstan-type EventData array{
* id: int|null,
* name: string,
+ * routePath: string,
* image: array{id: int}|null,
* startDate: string|null,
* endDate: string|null,
@@ -29,15 +33,24 @@ class EventController extends AbstractController implements SecuredControllerInt
private DoctrineListRepresentationFactory $doctrineListRepresentationFactory;
private EntityManagerInterface $entityManager;
private MediaManagerInterface $mediaManager;
+ private WebspaceManagerInterface $webspaceManager;
+ private RouteManagerInterface $routeManager;
+ private RouteRepositoryInterface $routeRepository;
public function __construct(
DoctrineListRepresentationFactory $doctrineListRepresentationFactory,
EntityManagerInterface $entityManager,
- MediaManagerInterface $mediaManager
+ MediaManagerInterface $mediaManager,
+ WebspaceManagerInterface $webspaceManager,
+ RouteManagerInterface $routeManager,
+ RouteRepositoryInterface $routeRepository
) {
$this->doctrineListRepresentationFactory = $doctrineListRepresentationFactory;
$this->entityManager = $entityManager;
$this->mediaManager = $mediaManager;
+ $this->webspaceManager = $webspaceManager;
+ $this->routeManager = $routeManager;
+ $this->routeRepository = $routeRepository;
}
/**
@@ -66,6 +79,7 @@ public function putAction(Request $request, int $id): Response
/** @var EventData $data */
$data = $request->toArray();
$this->mapDataToEntity($data, $event);
+ $this->updateRoutesForEntity($event);
$this->entityManager->flush();
return $this->json($this->getDataForEntity($event));
@@ -84,6 +98,9 @@ public function postAction(Request $request): Response
$this->entityManager->persist($event);
$this->entityManager->flush();
+ $this->updateRoutesForEntity($event);
+ $this->entityManager->flush();
+
return $this->json($this->getDataForEntity($event), 201);
}
@@ -94,6 +111,7 @@ public function deleteAction(int $id): Response
{
/** @var Event $event */
$event = $this->entityManager->getReference(Event::class, $id);
+ $this->removeRoutesForEntity($event);
$this->entityManager->remove($event);
$this->entityManager->flush();
@@ -124,6 +142,7 @@ protected function getDataForEntity(Event $entity): array
return [
'id' => $entity->getId(),
'name' => $entity->getName(),
+ 'routePath' => $entity->getRoutePath(),
'image' => $image
? ['id' => $image->getId()]
: null,
@@ -140,11 +159,41 @@ protected function mapDataToEntity(array $data, Event $entity): void
$imageId = $data['image']['id'] ?? null;
$entity->setName($data['name']);
+ $entity->setRoutePath($data['routePath']);
$entity->setImage($imageId ? $this->mediaManager->getEntityById($imageId) : null);
$entity->setStartDate($data['startDate'] ? new \DateTimeImmutable($data['startDate']) : null);
$entity->setEndDate($data['endDate'] ? new \DateTimeImmutable($data['endDate']) : null);
}
+ protected function updateRoutesForEntity(Event $entity): void
+ {
+ // create route for all locales of the application because event entity is not localized
+ foreach ($this->webspaceManager->getAllLocales() as $locale) {
+ $this->routeManager->createOrUpdateByAttributes(
+ Event::class,
+ (string) $entity->getId(),
+ $locale,
+ $entity->getRoutePath(),
+ );
+ }
+ }
+
+ protected function removeRoutesForEntity(Event $entity): void
+ {
+ // remove route for all locales of the application because event entity is not localized
+ foreach ($this->webspaceManager->getAllLocales() as $locale) {
+ $routes = $this->routeRepository->findAllByEntity(
+ Event::class,
+ (string) $entity->getId(),
+ $locale
+ );
+
+ foreach ($routes as $route) {
+ $this->routeRepository->remove($route);
+ }
+ }
+ }
+
public function getSecurityContext(): string
{
return Event::SECURITY_CONTEXT;
diff --git a/src/Controller/Website/EventController.php b/src/Controller/Website/EventController.php
new file mode 100644
index 00000000..d47b071f
--- /dev/null
+++ b/src/Controller/Website/EventController.php
@@ -0,0 +1,60 @@
+webspaceManager = $webspaceManager;
+ $this->routeRepository = $routeRepository;
+ $this->templateAttributeResolver = $templateAttributeResolver;
+ }
+
+ public function indexAction(Event $event): Response
+ {
+ $parameters = $this->templateAttributeResolver->resolve([
+ 'event' => $event,
+ 'localizations' => $this->getLocalizationsArrayForEntity($event),
+ ]);
+
+ return $this->render('events/event.html.twig', $parameters);
+ }
+
+ /**
+ * @return array
+ */
+ protected function getLocalizationsArrayForEntity(Event $entity): array
+ {
+ $routes = $this->routeRepository->findAllByEntity(Event::class, (string) $entity->getId());
+
+ $localizations = [];
+ foreach ($routes as $route) {
+ $url = $this->webspaceManager->findUrlByResourceLocator(
+ $route->getPath(),
+ null,
+ $route->getLocale()
+ );
+
+ $localizations[$route->getLocale()] = ['locale' => $route->getLocale(), 'url' => $url];
+ }
+
+ return $localizations;
+ }
+}
diff --git a/src/Entity/Event.php b/src/Entity/Event.php
index b85c5117..6e15343d 100644
--- a/src/Entity/Event.php
+++ b/src/Entity/Event.php
@@ -28,6 +28,11 @@ class Event
*/
private string $name;
+ /**
+ * @ORM\Column(type="string", length=255)
+ */
+ private string $routePath;
+
/**
* @ORM\ManyToOne(targetEntity=MediaInterface::class)
* @ORM\JoinColumn(onDelete="SET NULL")
@@ -59,6 +64,16 @@ public function setName(string $name): void
$this->name = $name;
}
+ public function getRoutePath(): string
+ {
+ return $this->routePath ?? '';
+ }
+
+ public function setRoutePath(string $routePath): void
+ {
+ $this->routePath = $routePath;
+ }
+
public function getImage(): ?MediaInterface
{
return $this->image;
diff --git a/src/Routing/EventRouteDefaultsProvider.php b/src/Routing/EventRouteDefaultsProvider.php
new file mode 100644
index 00000000..0fc06c6e
--- /dev/null
+++ b/src/Routing/EventRouteDefaultsProvider.php
@@ -0,0 +1,40 @@
+entityManager = $entityManager;
+ }
+
+ /**
+ * @return mixed[]
+ */
+ public function getByEntity($entityClass, $id, $locale, $object = null)
+ {
+ return [
+ '_controller' => EventController::class . '::indexAction',
+ 'event' => $object ?: $this->entityManager->getRepository(Event::class)->find($id),
+ ];
+ }
+
+ public function isPublished($entityClass, $id, $locale)
+ {
+ return true;
+ }
+
+ public function supports($entityClass)
+ {
+ return Event::class === $entityClass;
+ }
+}
diff --git a/templates/events/event.html.twig b/templates/events/event.html.twig
new file mode 100644
index 00000000..429821b0
--- /dev/null
+++ b/templates/events/event.html.twig
@@ -0,0 +1,5 @@
+{% extends 'base.html.twig' %}
+
+{% block contentBody %}
+ {{ event.name }}
+{% endblock %}