Skip to content

Commit dbacf71

Browse files
authored
Merge pull request #540 from dotkernel/issue-539
Implemented dot-navigation package
2 parents c507c26 + d4fd07a commit dbacf71

File tree

11 files changed

+341
-32
lines changed

11 files changed

+341
-32
lines changed

config/autoload/navigation.global.php

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
'dot_navigation' => [
7+
//enable menu item active if any child is active
8+
'active_recursion' => true,
9+
'containers' => [
10+
'left_menu' => [
11+
'type' => 'ArrayProvider',
12+
'options' => [
13+
'items' => [
14+
[
15+
'options' => [
16+
'label' => 'Pages',
17+
'route' => [],
18+
],
19+
'attributes' => [
20+
'class' => 'nav-link dropdown-toggle',
21+
'href' => '#',
22+
],
23+
'pages' => [
24+
[
25+
'options' => [
26+
'label' => 'Home',
27+
'uri' => '/home',
28+
],
29+
'attributes' => [
30+
'class' => 'dropdown-item',
31+
],
32+
],
33+
[
34+
'options' => [
35+
'label' => 'About Us',
36+
'uri' => '/page/about-us',
37+
],
38+
'attributes' => [
39+
'class' => 'dropdown-item',
40+
],
41+
],
42+
[
43+
'options' => [
44+
'label' => 'Who We Are',
45+
'uri' => '/page/who-we-are',
46+
],
47+
'attributes' => [
48+
'class' => 'dropdown-item',
49+
],
50+
],
51+
[
52+
'options' => [
53+
'label' => 'Premium content',
54+
'uri' => '/page/premium-content',
55+
],
56+
'attributes' => [
57+
'class' => 'dropdown-item',
58+
],
59+
],
60+
],
61+
],
62+
[
63+
'options' => [
64+
'label' => 'Contribute',
65+
'uri' => 'https://github.com/dotkernel',
66+
],
67+
'attributes' => [
68+
'class' => 'nav-link',
69+
'target' => '_blank',
70+
],
71+
],
72+
[
73+
'options' => [
74+
'label' => 'Contact Us',
75+
'uri' => '/contact/form',
76+
],
77+
'attributes' => [
78+
'class' => 'nav-link',
79+
],
80+
],
81+
[
82+
'options' => [
83+
'label' => 'Disabled',
84+
'uri' => '/',
85+
],
86+
'attributes' => [
87+
'class' => 'nav-link disabled',
88+
],
89+
],
90+
],
91+
],
92+
],
93+
'guest_menu' => [
94+
'type' => 'ArrayProvider',
95+
'options' => [
96+
'items' => [
97+
[
98+
'options' => [
99+
'label' => 'Log in',
100+
'uri' => '/user/login',
101+
],
102+
'attributes' => [
103+
'class' => 'nav-link',
104+
],
105+
],
106+
],
107+
],
108+
],
109+
'user_menu' => [
110+
'type' => 'ArrayProvider',
111+
'options' => [
112+
'items' => [
113+
[
114+
'options' => [
115+
'label' => 'Profile',
116+
'uri' => '/account/details',
117+
],
118+
'attributes' => [
119+
'class' => 'nav-link',
120+
],
121+
],
122+
[
123+
'options' => [
124+
'label' => 'Log out',
125+
'uri' => '/user/logout',
126+
],
127+
'attributes' => [
128+
'class' => 'nav-link',
129+
],
130+
],
131+
],
132+
],
133+
],
134+
'user_profile_menu' => [
135+
'type' => 'ArrayProvider',
136+
'options' => [
137+
'items' => [
138+
[
139+
'options' => [
140+
'label' => 'Avatar',
141+
'uri' => '/account/avatar',
142+
],
143+
],
144+
[
145+
'options' => [
146+
'label' => 'Details',
147+
'uri' => '/account/details',
148+
],
149+
],
150+
[
151+
'options' => [
152+
'label' => 'Change password',
153+
'uri' => '/account/change-password',
154+
],
155+
],
156+
[
157+
'options' => [
158+
'label' => 'Delete account',
159+
'uri' => '/account/delete-account',
160+
],
161+
],
162+
],
163+
],
164+
],
165+
],
166+
//register custom providers here
167+
'provider_manager' => [],
168+
],
169+
];

config/autoload/templates.global.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types=1);
44

55
use Dot\Twig\Extension\DateExtension;
6+
use Frontend\App\Twig\Extension\RouteExtension;
67
use Laminas\ServiceManager\Factory\InvokableFactory;
78
use Mezzio\Template\TemplateRendererInterface;
89
use Mezzio\Twig\TwigEnvironmentFactory;
@@ -29,12 +30,13 @@
2930
'cache_dir' => 'data/cache/twig',
3031
'extensions' => [
3132
DateExtension::class,
33+
RouteExtension::class,
3234
],
3335
'optimizations' => -1,
3436
'runtime_loaders' => [],
3537
//'timezone' => '',
3638
'globals' => [
37-
'appName' => $app['name'],
39+
'appName' => $app['name'] ?? '',
3840
],
3941
],
4042
];

config/config.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class_exists(\Mezzio\Swoole\ConfigProvider::class)
4545
\Dot\ResponseHeader\ConfigProvider::class,
4646
\Dot\DataFixtures\ConfigProvider::class,
4747
\Dot\Cache\ConfigProvider::class,
48+
\Dot\Helpers\ConfigProvider::class,
49+
\Dot\Navigation\ConfigProvider::class,
4850

4951
// Default App module config
5052
\Frontend\App\ConfigProvider::class,

config/pipeline.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types=1);
44

55
use Dot\ErrorHandler\ErrorHandlerInterface;
6+
use Dot\Navigation\NavigationMiddleware;
67
use Dot\Rbac\Guard\Middleware\ForbiddenHandler;
78
use Dot\Rbac\Guard\Middleware\RbacGuardMiddleware;
89
use Dot\ResponseHeader\Middleware\ResponseHeaderMiddleware;
@@ -77,6 +78,7 @@
7778
$app->pipe(AuthMiddleware::class);
7879
$app->pipe(ForbiddenHandler::class);
7980
$app->pipe(RbacGuardMiddleware::class);
81+
$app->pipe(NavigationMiddleware::class);
8082

8183
// Register the dispatch middleware in the middleware pipeline
8284
$app->pipe(DispatchMiddleware::class);

src/App/src/ConfigProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function getDependencies(): array
3636
RecaptchaService::class => AttributedServiceFactory::class,
3737
CookieService::class => AttributedServiceFactory::class,
3838
RememberMeMiddleware::class => AttributedServiceFactory::class,
39+
Twig\Extension\RouteExtension::class => AttributedServiceFactory::class,
3940
],
4041
'aliases' => [
4142
EntityManager::class => 'doctrine.entity_manager.orm_default',
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Frontend\App\Twig\Extension;
6+
7+
use Dot\DependencyInjection\Attribute\Inject;
8+
use Mezzio\Helper\UrlHelper;
9+
use Twig\Extension\AbstractExtension;
10+
use Twig\TwigFunction;
11+
12+
class RouteExtension extends AbstractExtension
13+
{
14+
#[Inject(UrlHelper::class)]
15+
public function __construct(
16+
private readonly UrlHelper $urlHelper,
17+
) {
18+
}
19+
20+
public function getFunctions(): array
21+
{
22+
return [
23+
new TwigFunction('getCurrentRoute', [$this, 'getCurrentRoute']),
24+
new TwigFunction('isRoute', [$this, 'isRoute']),
25+
];
26+
}
27+
28+
public function getCurrentRoute(): ?string
29+
{
30+
return $this->urlHelper->getRequest()?->getUri()?->getPath();
31+
}
32+
33+
public function isRoute(?string $route): bool
34+
{
35+
if (null === $route) {
36+
return false;
37+
}
38+
39+
$currentRoute = $this->getCurrentRoute();
40+
if (null === $currentRoute) {
41+
return false;
42+
}
43+
44+
return $currentRoute === $route;
45+
}
46+
}

src/App/templates/layout/default.html.twig

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,37 +42,14 @@
4242

4343
<div class="collapse navbar-collapse" id="navbarHeader">
4444
<ul class="navbar-nav mr-auto">
45-
<li class="nav-item dropdown">
46-
<a class="nav-link dropdown-toggle" href="#" id="pageDropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Pages</a>
47-
<div class="dropdown-menu" aria-labelledby="pageDropdown">
48-
<a class="dropdown-item" href="{{ url('page', {action: 'home'}) }}">Home</a>
49-
<a class="dropdown-item" href="{{ url('page', {action: 'about-us'}) }}">About Us</a>
50-
<a class="dropdown-item" href="{{ url('page', {action: 'who-we-are'}) }}">Who We Are</a>
51-
<a class="dropdown-item" href="{{ url('page', {action: 'premium-content'}) }}">Protected Content</a>
52-
</div>
53-
</li>
54-
<li class="nav-item">
55-
<a class="nav-link" href="https://github.com/dotkernel" target="_blank">Contribute</a>
56-
</li>
57-
<li class="nav-item">
58-
<a class="nav-link" href="{{ url('contact', {action: 'form'}) }}">Contact Us</a>
59-
</li>
60-
<li class="nav-item">
61-
<a class="nav-link disabled" href="{{ url('page', {action: 'index'}) }}">Disabled</a>
62-
</li>
45+
{{ navigationPartial('left_menu', 'partial::menu') }}
6346
</ul>
47+
6448
<ul class="navbar-nav ms-auto">
6549
{% if hasIdentity() %}
66-
<li class="nav-item">
67-
<a class="nav-link" href="{{ url('account', {action: 'details'}) }}">Profile</a>
68-
</li>
69-
<li class="nav-item">
70-
<a class="nav-link" href="{{ url('user', {action: 'logout'}) }}">Log out</a>
71-
</li>
50+
{{ navigationPartial('user_menu', 'partial::menu') }}
7251
{% else %}
73-
<li class="nav-item">
74-
<a class="nav-link" href="{{ url('user', {action: 'login'}) }}">Log in</a>
75-
</li>
52+
{{ navigationPartial('guest_menu', 'partial::menu') }}
7653
{% endif %}
7754
</ul>
7855
</div>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% set extraAttributes = '' %}
2+
{% if page is defined %}
3+
<ul class="navbar-nav mr-auto">
4+
{% endif %}
5+
{% for page in container %}
6+
{% if navigation.isAllowed(page) %}
7+
{% if page.hasChildren() %}
8+
<li class="nav-item dropdown">
9+
<a {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %} id="pageDropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ page.getOption('label') }}</a>
10+
<div class="dropdown-menu" aria-labelledby="pageDropdown">
11+
{{ navigationPartial(page, 'partial::menu') }}
12+
</div>
13+
</li>
14+
{% else %}
15+
{% if page.hasParent() %}
16+
<a {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %} href="{{ navigation.getHref(page) }}" {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %}>{{ page.getOption('label') }}</a>
17+
{% else %}
18+
<li class="nav-item">
19+
<a {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %} href="{{ navigation.getHref(page) }}" {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %}>{{ page.getOption('label') }}</a>
20+
</li>
21+
{% endif %}
22+
{% endif %}
23+
{% endif %}
24+
{% endfor %}
25+
{% if page is defined %}
26+
</ul>
27+
{% endif %}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{% set extraAttributes = '' %}
2+
{% for page in container %}
3+
{% if navigation.isAllowed(page) %}
4+
<li class="{% if isRoute(page.getOption('uri')) %}active{% endif %}">
5+
<a href="{{ navigation.getHref(page) }}" class="text-decoration-none" {% autoescape false %}{{ pageAttributes(page) ~ extraAttributes }}{% endautoescape %}>{{ page.getOption('label') }}</a>
6+
</li>
7+
{% endif %}
8+
{% endfor %}

src/User/templates/user/profile.html.twig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222
<i class="fas fa-bars"></i>
2323
</div>
2424
<ul class="profile-action-menu">
25-
<li class="{% if action is defined and action is same as ('avatar') %}active{% endif %}"><a href="{{ path('account', {action: 'avatar'}) }}" class="text-decoration-none">Avatar</a></li>
26-
<li class="{% if action is defined and action is same as ('details') %}active{% endif %}"><a href="{{ path('account', {action: 'details'}) }}" class="text-decoration-none">Details</a></li>
27-
<li class="{% if action is defined and action is same as ('change-password') %}active{% endif %}"><a href="{{ path('account', {action: 'change-password'}) }}" class="text-decoration-none">Change password</a></li>
28-
<li class="{% if action is defined and action is same as ('delete-account') %}active{% endif %}"><a href="{{ path('account', {action: 'delete-account'}) }}" class="text-decoration-none">Delete account</a></li>
25+
{{ navigationPartial('user_profile_menu', 'partial::user_profile_menu') }}
2926
</ul>
3027
</div>
3128
<div class="col-md-8">

0 commit comments

Comments
 (0)