From 5e669869a5905e5d36c8262564bb7779f7f73814 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Sun, 16 May 2021 19:55:23 +0200 Subject: [PATCH] backports murph-skeleton --- core/Controller/Site/NodeAdminController.php | 13 +- core/Entity/Site/Node.php | 77 +++++++++++ core/Entity/Site/Page/CollectionBlock.php | 22 +++ .../Site/NodeEventSubscriber.php | 128 +++++++++--------- core/Form/Site/NodeType.php | 34 +++++ core/Form/Site/Page/CollectionBlockType.php | 51 +++++++ core/Resources/translations/messages.fr.yaml | 2 + .../form/bootstrap_4_form_theme.html.twig | 39 ++++++ .../views/site/node_admin/_form.html.twig | 41 +++++- .../site/tree_admin/navigation.html.twig | 6 +- core/Router/SiteRouteLoader.php | 4 + core/Sitemap/SitemapBuilder.php | 4 + 12 files changed, 351 insertions(+), 70 deletions(-) create mode 100644 core/Entity/Site/Page/CollectionBlock.php create mode 100644 core/Form/Site/Page/CollectionBlockType.php diff --git a/core/Controller/Site/NodeAdminController.php b/core/Controller/Site/NodeAdminController.php index ec7dd59..f9da5e5 100644 --- a/core/Controller/Site/NodeAdminController.php +++ b/core/Controller/Site/NodeAdminController.php @@ -41,6 +41,7 @@ class NodeAdminController extends AdminController $entity = $factory->create($node->getMenu()); $form = $this->createForm(EntityType::class, $entity, [ 'pages' => $pageLocator->getPages(), + 'navigation' => $node->getMenu()->getNavigation(), ]); if ($request->isMethod('POST')) { @@ -108,6 +109,7 @@ class NodeAdminController extends AdminController ): Response { $form = $this->createForm(EntityType::class, $entity, [ 'pages' => $pageLocator->getPages(), + 'navigation' => $entity->getMenu()->getNavigation(), ]); if ($request->isMethod('POST')) { @@ -269,15 +271,22 @@ class NodeAdminController extends AdminController $page = $pageFactory->create($pageType, $entity->getLabel()); $page->setTemplate($pageConfiguration->getTemplates()[0]['file']); - $entity->setPage($page); + $entity + ->setPage($page) + ->setAliasNode(null); } elseif ('existing' === $pageAction) { if ($pageEntity) { $entity->setPage($pageEntity); } else { $this->addFlash('info', 'Aucun changement de page effectué.'); } - } elseif ('none' === $pageAction) { + $entity->setAliasNode(null); + } elseif ('alias' === $pageAction) { $entity->setPage(null); + } elseif ('none' === $pageAction) { + $entity + ->setPage(null) + ->setAliasNode(null); } } } diff --git a/core/Entity/Site/Node.php b/core/Entity/Site/Node.php index 3e43c56..4ca798f 100644 --- a/core/Entity/Site/Node.php +++ b/core/Entity/Site/Node.php @@ -123,9 +123,20 @@ class Node implements EntityInterface */ private $sitemapParameters = []; + /** + * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="aliasNodes") + */ + private $aliasNode; + + /** + * @ORM\OneToMany(targetEntity=Node::class, mappedBy="aliasNode") + */ + private $aliasNodes; + public function __construct() { $this->children = new ArrayCollection(); + $this->aliasNodes = new ArrayCollection(); } public function getId(): ?int @@ -324,6 +335,10 @@ class Node implements EntityInterface public function getPage(): ?Page { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getPage(); + } + return $this->page; } @@ -336,11 +351,19 @@ class Node implements EntityInterface public function getRouteName(): string { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getRouteName(); + } + return $this->getMenu()->getRouteName().'_'.($this->getCode() ? $this->getCode() : $this->getId()); } public function getCode(): ?string { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getCode(); + } + return $this->code; } @@ -353,6 +376,10 @@ class Node implements EntityInterface public function getParameters(): ?array { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getParameters(); + } + if (!is_array($this->parameters)) { $this->parameters = []; } @@ -385,6 +412,10 @@ class Node implements EntityInterface public function getController(): ?string { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getController(); + } + return $this->controller; } @@ -397,6 +428,10 @@ class Node implements EntityInterface public function getSitemapParameters(): ?array { + if ($this->getAliasNode()) { + return $this->getAliasNode()->getSitemapParameters(); + } + if (!is_array($this->sitemapParameters)) { $this->sitemapParameters = [ 'isVisible' => false, @@ -414,4 +449,46 @@ class Node implements EntityInterface return $this; } + + public function getAliasNode(): ?self + { + return $this->aliasNode; + } + + public function setAliasNode(?self $aliasNode): self + { + $this->aliasNode = $aliasNode; + + return $this; + } + + /** + * @return Collection|self[] + */ + public function getAliasNodes(): Collection + { + return $this->aliasNodes; + } + + public function addAliasNode(self $aliasNode): self + { + if (!$this->aliasNodes->contains($aliasNode)) { + $this->aliasNodes[] = $aliasNode; + $aliasNode->setAliasNode($this); + } + + return $this; + } + + public function removeAliasNode(self $aliasNode): self + { + if ($this->aliasNodes->removeElement($aliasNode)) { + // set the owning side to null (unless already changed) + if ($aliasNode->getAliasNode() === $this) { + $aliasNode->setAliasNode(null); + } + } + + return $this; + } } diff --git a/core/Entity/Site/Page/CollectionBlock.php b/core/Entity/Site/Page/CollectionBlock.php new file mode 100644 index 0000000..323eb90 --- /dev/null +++ b/core/Entity/Site/Page/CollectionBlock.php @@ -0,0 +1,22 @@ +getDisableUrl()) { $node->setUrl(null); - - return; - } - - if ($node->getUrl()) { - $generatedUrl = $node->getUrl(); } else { - $path = []; - $parent = $node->getParent(); + if ($node->getUrl()) { + $generatedUrl = $node->getUrl(); + } else { + $path = []; + $parent = $node->getParent(); - if ($parent && $parent->getUrl()) { - $pPath = trim($parent->getUrl(), '/'); + if ($parent && $parent->getUrl()) { + $pPath = trim($parent->getUrl(), '/'); - if ($pPath) { - $path[] = $pPath; + if ($pPath) { + $path[] = $pPath; + } + } + + $path[] = $this->slugify->slugify($node->getLabel()); + + $generatedUrl = '/'.implode('/', $path); + } + + if ('/' !== $generatedUrl) { + $generatedUrl = rtrim($generatedUrl, '/'); + } + + $parameters = $node->getParameters(); + $routeParameters = []; + + foreach ($parameters as $key => $parameter) { + $parameter['name'] = $this->routeParameterSlugify->slugify($parameter['name']); + $routeParameter = sprintf('{%s}', $parameter['name']); + $regex = '/'.preg_quote($routeParameter).'/'; + $routeParameters[] = $parameter['name']; + + if (!preg_match($regex, $generatedUrl)) { + $generatedUrl .= '/'.$routeParameter; + } + + $parameters[$key] = $parameter; + } + + preg_match_all('/\{(.*)\}/isU', $generatedUrl, $matches, PREG_SET_ORDER); + + foreach ($matches as $match) { + if (!in_array($match[1], $routeParameters)) { + $parameters[] = [ + 'name' => $this->routeParameterSlugify->slugify($match[1]), + 'defaultValue' => null, + 'requirement' => null, + ]; } } - $path[] = $this->slugify->slugify($node->getLabel()); - - $generatedUrl = '/'.implode('/', $path); - } - - if ('/' !== $generatedUrl) { - $generatedUrl = rtrim($generatedUrl, '/'); - } - - $parameters = $node->getParameters(); - $routeParameters = []; - - foreach ($parameters as $key => $parameter) { - $parameter['name'] = $this->routeParameterSlugify->slugify($parameter['name']); - $routeParameter = sprintf('{%s}', $parameter['name']); - $regex = '/'.preg_quote($routeParameter).'/'; - $routeParameters[] = $parameter['name']; - - if (!preg_match($regex, $generatedUrl)) { - $generatedUrl .= '/'.$routeParameter; + if (!u($generatedUrl)->startsWith('https://') && !u($generatedUrl)->startsWith('http://')) { + $generatedUrl = str_replace('//', '/', $generatedUrl); } - $parameters[$key] = $parameter; - } + $node->setParameters($parameters); - preg_match_all('/\{(.*)\}/isU', $generatedUrl, $matches, PREG_SET_ORDER); + $urlExists = $this->nodeRepository->urlExists($generatedUrl, $node); - foreach ($matches as $match) { - if (!in_array($match[1], $routeParameters)) { - $parameters[] = [ - 'name' => $this->routeParameterSlugify->slugify($match[1]), - 'defaultValue' => null, - 'requirement' => null, - ]; + if ($urlExists) { + $number = 1; + + while ($this->nodeRepository->urlExists($generatedUrl.'-'.$number, $node)) { + ++$number; + } + + $generatedUrl = $generatedUrl.'-'.$number; } - } - if (!u($generatedUrl)->startsWith('https://') && !u($generatedUrl)->startsWith('http://')) { - $generatedUrl = str_replace('//', '/', $generatedUrl); - } + if (!u($generatedUrl)->startsWith('/')) { + $generatedUrl = '/'.$generatedUrl; + } - $node->setParameters($parameters); + $node->setUrl($generatedUrl); + } $attributes = $node->getAttributes(); $realAttributes = []; @@ -131,24 +147,6 @@ class NodeEventSubscriber extends EntityManagerEventSubscriber } $node->setAttributes($realAttributes); - - $urlExists = $this->nodeRepository->urlExists($generatedUrl, $node); - - if ($urlExists) { - $number = 1; - - while ($this->nodeRepository->urlExists($generatedUrl.'-'.$number, $node)) { - ++$number; - } - - $generatedUrl = $generatedUrl.'-'.$number; - } - - if (!u($generatedUrl)->startsWith('/')) { - $generatedUrl = '/'.$generatedUrl; - } - - $node->setUrl($generatedUrl); } public function onDelete(EntityManagerEvent $event) diff --git a/core/Form/Site/NodeType.php b/core/Form/Site/NodeType.php index 21a91e2..7d8cde7 100644 --- a/core/Form/Site/NodeType.php +++ b/core/Form/Site/NodeType.php @@ -90,6 +90,7 @@ class NodeType extends AbstractType $actions = [ 'New page' => 'new', 'Use an existing page' => 'existing', + 'Alias element' => 'alias', 'No page' => 'none', ]; @@ -153,6 +154,38 @@ class NodeType extends AbstractType ] ); + $builder->add( + 'aliasNode', + EntityType::class, + [ + 'label' => false, + 'required' => true, + 'mapped' => true, + 'class' => Node::class, + 'choice_label' => 'label', + 'choices' => call_user_func(function() use ($options, $builder) { + $nodes = []; + + foreach ($options['navigation']->getMenus() as $menu) { + $nodes = array_merge( + $nodes, + $menu->getRootNode()->getAllChildren()->toArray() + ); + } + + foreach ($nodes as $k => $value) { + if ($value->getId() === $builder->getData()->getId()) { + unset($nodes[$k]); + } + } + + return $nodes; + }), + 'constraints' => [ + ], + ] + ); + $builder->add( 'parameters', CollectionType::class, @@ -213,6 +246,7 @@ class NodeType extends AbstractType $resolver->setDefaults([ 'data_class' => Node::class, 'pages' => [], + 'navigation' => null, ]); } } diff --git a/core/Form/Site/Page/CollectionBlockType.php b/core/Form/Site/Page/CollectionBlockType.php new file mode 100644 index 0000000..a42b71c --- /dev/null +++ b/core/Form/Site/Page/CollectionBlockType.php @@ -0,0 +1,51 @@ +add( + 'value', + CollectionType::class, + array_merge([ + 'required' => false, + 'label' => false, + ], $options['options']), + ); + } + + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars = array_replace($view->vars, [ + 'collection_name' => $options['collection_name'], + 'label_add' => $options['label_add'], + 'label_delete' => $options['label_delete'], + ]); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Block::class, + 'collection_name' => '', + 'label_add' => 'Add', + 'label_delete' => 'Delete', + 'options' => [], + ]); + } +} diff --git a/core/Resources/translations/messages.fr.yaml b/core/Resources/translations/messages.fr.yaml index 41a9af4..d45621a 100644 --- a/core/Resources/translations/messages.fr.yaml +++ b/core/Resources/translations/messages.fr.yaml @@ -71,6 +71,8 @@ "New menu": "Nouveau menu" "New": "Nouveau" "No action": "Aucune action" +"Alias element": "Élement alias" +"This element is an alias so the next configuration is ignored.": "Cet élement est un alias donc cette configuration sera ignorée" "Route name: %routeName%": "Nom de la route : %routeName%" "Content": "Contenu" "Routing": "Routage" diff --git a/core/Resources/views/form/bootstrap_4_form_theme.html.twig b/core/Resources/views/form/bootstrap_4_form_theme.html.twig index 8f05398..10ab5c0 100644 --- a/core/Resources/views/form/bootstrap_4_form_theme.html.twig +++ b/core/Resources/views/form/bootstrap_4_form_theme.html.twig @@ -36,3 +36,42 @@ {% endblock %} + +{% block collection_block_widget %} + +
+ {% for item in form.value %} +
+ {% for child in item %} + {{ form_row(child) }} + {% endfor %} +
+ +
+ + + {{ label_delete|trans }} + + +
+ {% endfor %} +
+ +
+ + {{ label_add|trans }} + +
+ + +{% endblock %} diff --git a/core/Resources/views/site/node_admin/_form.html.twig b/core/Resources/views/site/node_admin/_form.html.twig index fb6c1fe..9a0c36f 100644 --- a/core/Resources/views/site/node_admin/_form.html.twig +++ b/core/Resources/views/site/node_admin/_form.html.twig @@ -96,14 +96,39 @@
- Aucune action + {{ form_row(form.aliasNode) }} +
+
+ + +
+ {% set action = form.pageAction[3] %} + {% set options = {'attr': {'checked': 'checked'}} %} + +
+

+ + +
+ {{ form_row(action, options) }} +
+

+
+
+
+ {{ 'No action'|trans }}
{% if entity.id %}
- {% set action = form.pageAction[3] %} + {% set action = form.pageAction[4] %} {% set options = {'attr': {'checked': 'checked'}} %}
@@ -138,6 +163,12 @@
{% endif %} + {% if entity.aliasNode %} +
+ {{ 'This element is an alias so the next configuration is ignored.'|trans }} +
+ {% endif %} + {{ form_row(form.url) }}
@@ -215,6 +246,12 @@
+ {% if entity.aliasNode %} +
+ {{ 'This element is an alias so the next configuration is ignored.'|trans }} +
+ {% endif %} + {{ form_row(form.sitemapParameters) }}
diff --git a/core/Resources/views/site/tree_admin/navigation.html.twig b/core/Resources/views/site/tree_admin/navigation.html.twig index 60607f9..1d67993 100644 --- a/core/Resources/views/site/tree_admin/navigation.html.twig +++ b/core/Resources/views/site/tree_admin/navigation.html.twig @@ -79,7 +79,11 @@ {{ node.label }} - {% if node.hasExternalUrl %} + {% if node.aliasNode %} + + + + {% elseif node.hasExternalUrl %} diff --git a/core/Router/SiteRouteLoader.php b/core/Router/SiteRouteLoader.php index bbe5f25..662d61b 100644 --- a/core/Router/SiteRouteLoader.php +++ b/core/Router/SiteRouteLoader.php @@ -57,6 +57,10 @@ class SiteRouteLoader extends Loader continue; } + if (null !== $node->getAliasNode()) { + continue; + } + $requirements = []; $defaults = [ diff --git a/core/Sitemap/SitemapBuilder.php b/core/Sitemap/SitemapBuilder.php index ba6f02a..0e1750b 100644 --- a/core/Sitemap/SitemapBuilder.php +++ b/core/Sitemap/SitemapBuilder.php @@ -46,6 +46,10 @@ class SitemapBuilder continue; } + if ($node->getAliasNode()) { + continue; + } + $nodeItems = []; foreach ($this->getNodeUrls($node) as $url) {