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 %}
+
+