Hi everyone, it’s my first post on here and I’m quite new to laminas so excuse me in advance if I ask something boring.
Since it’s my first post I’ll include the full story to give as much info as possible on what I’m working on, I’ll spoiler the stuff that isn’t too relevant for the question to keep it ontopic.
What I'm working on and what I made so far.
I’ve been working for a while on a laminas project (an old zend v1 website written by someone else that I’m rebuilding from scratch)
I’ve started from the laminas skeleton application, and adapted it into what I needed.
Basically at the moment I have built the full structure of the website with the main application module and 5 modules containing each a main website feature (one for users/accounts, one for authentication and authorization and the remaining 3 for the website content)
The authentication code is working (it may need some tweaks) and properly using bcrypt.
The authorization part is handled with the acl package but I’m still struggling a bit to set it up.
I was setting up the ACL package when I noticed the existence of the mysterious AclListener, according to what I could find, if properly implemented it can handle the showing/hiding of the various navigation elements according to the ACL permisions of the user.
Sadly I’m new both to Laminas listeners and to Laminas Acl (to Laminas in general to be honest)
and all i could find is THIS documentation of the class on GitHub.
EDIT 3: Doing more resarch it seems like I don’t need to setup the AclListener and that I should instead configure the Navigation Helper with setAcl and setRole.
here is what I’ve set up so far:
Navigation config in module/application/config/module.config.php
'navigation' => [
'default' => [
[
'label' => 'Home',
'route' => 'home',
'resource' => 'home',
],
[
'label' => 'User management',
'route' => 'users',
'resource' => 'users',
'pages' => [
[
'label' => 'New user',
'route' => 'users',
'action' => 'add',
],
... // and so on for the other pages and sub pages
Acl config in module/Auth/config/module.config.php
'acl' => [
'roles' => [
"none" => [],
"anonymous" =>["none"],
...
],
'resources' => [
new Resource('users'),
new Resource('auth'),
...
],
'rules' => [
[
'type' => 'allow',
'roles' => ['none'],
'resources' => ['home'],
],
....
Acl and AuthenticationService factories in module/Auth/config/module.config.php
'service_manager' => [
'factories'=>[
AuthenticationService::class => function($container){
return new AuthenticationService(null,$container->get(AuthAdapter::class));
},
Acl::class => function($container) {
$config = $container->get('config');
$aclConfig = $config['acl'] ?? [];
$acl = new Acl();
foreach ($aclConfig['roles'] ?? [] as $role => $parents) {
$acl->addRole($role,$parents);
}
foreach ($aclConfig['resources'] ?? [] as $resource) {
$acl->addResource($resource);
}
foreach ($aclConfig['rules'] ?? [] as $rule) {
$acl->{$rule['type']}(
$rule['roles'],
$rule['resources']
);
}
return $acl;
},
]
],
REMOVED AclListenerand injection in module/application/src/module.php
public function onBootstrap(MvcEvent $e)
{
$acl = $e->getApplication()->getServiceManager()->get(Acl::class);
$authService = $e->getApplication()->getServiceManager()->get(AuthenticationService::class);
$navigation = $e->getApplication()->getServiceManager()->get('ViewHelperManager')->get('Navigation');
$aclListener = new AclListener($acl, $authService, $navigation);
$e->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, [$aclListener, 'accept']);
}
Navbar element in module/application/view/layout/layout.phtml
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<?php $this->navigation()->menu()->setPartial('partial/navmenu'); ?>
<?= $this->navigation('navigation')
->menu()
->setMinDepth()
->setMaxDepth()
->setUlClass('nav navbar-nav') ?>
</div>
navmenu custom partial in module/application/view/partials/navmenu.phtml
(forgive me for the horrible code, is a temporary solution to get a decent looking navbar, I plan to come back and rewrite it once i finish the main stuff)
<ul class="nav navbar-nav">
<?php
foreach ($this->container as $page) {
if($page->hasPages()){
echo '<li class="nav-item dropdown">';
echo '<div class="btn-group">';
echo '<a class="nav-link';
if($page->isActive()) echo " active";
echo '" href="'.$page->getHref().'">'.$page->getLabel().'</a>';
echo '<a class="nav-link dropdown-toggle dropdown-toggle-split" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
</a> <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">';
foreach ($page->pages as $subpage){
echo '<a class="dropdown-item" href="'.$subpage->getHref().'">'.$subpage->getLabel().'</a>';
}
echo'</div></div></li>';
}else{
echo '<li class="nav-item "><a href="'.$page->getHref().'"class="nav-link';
if($page->isActive()) echo " active";
echo '">'.$this->escapeHtml($page->getLabel()).'</a></li>';
}
}
?>
</ul>
View Helper configuration in module/auth/src/module.php
public function getViewHelperConfig()
{
return [
'factories' => [
// This will overwrite the native navigation helper
'navigation' => function(HelperPluginManager $pm) {
// Setup ACL:
$acl = $container->get(Acl::class);
$auth = $container->get(AuthenticationService::class);
// Get an instance of the proxy helper
$navigation = $pm->get('Laminas\View\Helper\Navigation');
// Store ACL and role in the proxy helper:
$navigation->setAcl($acl);
$navigation->setRole($auth->getIdentity->role);
// Return the new navigation helper instance
return $navigation;
}
]
];
}```
I should have posted all the relevant code, my problem is that I simply don’t understand where to go from here, It’s clear that I have to setup something with the navigation config to tell the acllistener which elements should be hidden, and I’m also quite sure that the acl configuration isn’t correct but I couldn’t find much and so I decided to post here while I look for a solution my self.
Edit, to get the role for the ACL I’m using AuthenticationService->getStorage()->write([$username, $role]) so that i can then grab it with the getIdentity() method
Edit2: I fixed the acl config
Edit3: removed the AclListener stuff and added the ViewHelperConfiguration
at this point the navigation still doesn’t hide the elements that should be hidden to a role