diff --git a/config/forms/event_details.xml b/config/forms/event_details.xml index 40d88648..87ad09f9 100644 --- a/config/forms/event_details.xml +++ b/config/forms/event_details.xml @@ -14,6 +14,14 @@ + + + + + + + sulu_admin.url + diff --git a/config/packages/app_event_admin.yaml b/config/packages/app_event_admin.yaml index 3e0a60c1..63311681 100644 --- a/config/packages/app_event_admin.yaml +++ b/config/packages/app_event_admin.yaml @@ -4,3 +4,11 @@ sulu_admin: routes: list: 'app.get_events' detail: 'app.get_event' + +sulu_route: + mappings: + App\Entity\Event: + generator: schema + options: + route_schema: /events/{implode("-", object)} + resource_key: events diff --git a/config/services.yaml b/config/services.yaml index bd73083f..9d831d35 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -13,6 +13,7 @@ services: Sulu\Bundle\SnippetBundle\Snippet\DefaultSnippetManagerInterface: '@sulu_snippet.default_snippet.manager' Sulu\Component\PHPCR\PathCleanupInterface: '@sulu.content.path_cleaner' Doctrine\ORM\EntityManagerInterface: '@doctrine.orm.entity_manager' + Sulu\Bundle\RouteBundle\Entity\RouteRepositoryInterface: '@sulu.repository.route' # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name @@ -47,3 +48,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 4a596a9b..4f1d8935 100644 --- a/src/Controller/Admin/EventController.php +++ b/src/Controller/Admin/EventController.php @@ -10,8 +10,11 @@ use FOS\RestBundle\View\ViewHandlerInterface; use HandcraftedInTheAlps\RestRoutingBundle\Controller\Annotations\RouteResource; use HandcraftedInTheAlps\RestRoutingBundle\Routing\ClassResourceInterface; +use Sulu\Bundle\RouteBundle\Entity\RouteRepositoryInterface; +use Sulu\Bundle\RouteBundle\Manager\RouteManagerInterface; use Sulu\Component\Rest\AbstractRestController; use Sulu\Component\Security\SecuredControllerInterface; +use Sulu\Component\Webspace\Manager\WebspaceManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -24,15 +27,24 @@ class EventController extends AbstractRestController implements ClassResourceInt { private DoctrineListRepresentationFactory $doctrineListRepresentationFactory; private EntityManagerInterface $entityManager; + private WebspaceManagerInterface $webspaceManager; + private RouteManagerInterface $routeManager; + private RouteRepositoryInterface $routeRepository; public function __construct( DoctrineListRepresentationFactory $doctrineListRepresentationFactory, EntityManagerInterface $entityManager, + WebspaceManagerInterface $webspaceManager, + RouteManagerInterface $routeManager, + RouteRepositoryInterface $routeRepository, ViewHandlerInterface $viewHandler, ?TokenStorageInterface $tokenStorage = null ) { $this->doctrineListRepresentationFactory = $doctrineListRepresentationFactory; $this->entityManager = $entityManager; + $this->webspaceManager = $webspaceManager; + $this->routeManager = $routeManager; + $this->routeRepository = $routeRepository; parent::__construct($viewHandler, $tokenStorage); } @@ -64,6 +76,7 @@ public function putAction(Request $request, int $id): Response } $this->mapDataToEntity($request->request->all(), $event); + $this->updateRoutesForEntity($event); $this->entityManager->flush(); return $this->handleView($this->view($event)); @@ -77,13 +90,17 @@ public function postAction(Request $request): Response $this->entityManager->persist($event); $this->entityManager->flush(); + $this->updateRoutesForEntity($event); + $this->entityManager->flush(); + return $this->handleView($this->view($event, 201)); } - public function deleteAction(int $id): Response + public function deleteAction(Request $request, int $id): Response { /** @var Event $event */ $event = $this->entityManager->getReference(Event::class, $id); + $this->removeRoutesForEntity($event); $this->entityManager->remove($event); $this->entityManager->flush(); @@ -96,10 +113,40 @@ public function deleteAction(int $id): Response protected function mapDataToEntity(array $data, Event $entity): void { $entity->setName($data['name']); + $entity->setRoutePath($data['routePath']); $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..1c87efda --- /dev/null +++ b/src/Controller/Website/EventController.php @@ -0,0 +1,60 @@ +get('sulu_website.resolver.template_attribute')->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->get('sulu.repository.route')->findAllByEntity(Event::class, (string) $entity->getId()); + + $localizations = []; + foreach ($routes as $route) { + $url = $this->get('sulu_core.webspace.webspace_manager')->findUrlByResourceLocator( + $route->getPath(), + null, + $route->getLocale() + ); + + $localizations[$route->getLocale()] = ['locale' => $route->getLocale(), 'url' => $url]; + } + + return $localizations; + } + + /** + * @return string[] + */ + public static function getSubscribedServices() + { + $subscribedServices = parent::getSubscribedServices(); + + $subscribedServices['sulu_core.webspace.webspace_manager'] = WebspaceManagerInterface::class; + $subscribedServices['sulu.repository.route'] = RouteRepositoryInterface::class; + $subscribedServices['sulu_website.resolver.template_attribute'] = TemplateAttributeResolverInterface::class; + + return $subscribedServices; + } +} diff --git a/src/Entity/Event.php b/src/Entity/Event.php index 459ed141..a1e8a01d 100644 --- a/src/Entity/Event.php +++ b/src/Entity/Event.php @@ -33,6 +33,13 @@ class Event */ private string $name; + /** + * @ORM\Column(type="string", length=255) + * + * @Serializer\Expose() + */ + private string $routePath; + /** * @ORM\Column(type="datetime_immutable", nullable=true) * @@ -62,6 +69,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 getStartDate(): ?\DateTimeImmutable { return $this->startDate; 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 %}