I have a menu for my site that I only want to be able to display links based upon a users permissions.
Menu example:
<ul>
<li>Dashboard</li>
<li>Products</li>
<li>Suppliers</li>
</ul>
In Twig I am currently having to repeat code to accomplish what I am needing done. I DONT like doing this!
I first check to see if the user is an admin, if they are then then automatically get access to all the links...
{% set is_admin = false %}
{% if app.security.token.user.roles is iterable %}
{% for role in app.security.token.user.roles %}
{% if role == 'ROLE_ADMIN' or role == 'ROLE_SUPER_ADMIN' %}
{% set is_admin = true %}
{% endif %}
{% endfor %}
{% endif %}
This is my menu set up currently. I need to be able to authenticate whether the link can show up based upon the users roles and permissions. This is just mock up link, but in reality I could have upwards of 50 links, so as you can see this is just not a correct way to do this.
Any suggestions would be VERY welcome on how to perhaps create a function in Twig (not aware of any way to do this) or any other possible way recommended. I just need to have a reusable function.
<ul>
{% set is_dashboard = false %}
{% for role in app.user.roles %}
{% for roleAuth in role.appRoleAuthorizations %}
{% for roleAuthRoute in roleAuth.appRoleAuthorizationRoute %}
{% if roleAuthRoute.name == "dashboard" or is_admin %}
{% set is_dashboard = true %}
{% endif %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if is_dashboard == true %}
<li>Dashboard</li>
{% endif %}
{% set is_products = false %}
{% for role in app.user.roles %}
{% for roleAuth in role.appRoleAuthorizations %}
{% for roleAuthRoute in roleAuth.appRoleAuthorizationRoute %}
{% if roleAuthRoute.name == "product" or is_admin %}
{% set is_products = true %}
{% endif %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if is_products == true %}
<li>Products</li>
{% endif %}
{% set is_suppliers = false %}
{% for role in app.user.roles %}
{% for roleAuth in role.appRoleAuthorizations %}
{% for roleAuthRoute in roleAuth.appRoleAuthorizationRoute %}
{% if roleAuthRoute.name == "supplier" or is_admin %}
{% set is_suppliers = true %}
{% endif %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% if is_suppliers == true %}
<li>Suppliers</li>
{% endif %}
</ul>
Why don't you use Symfony's built-in {% is_granted() %}
Twig function? Here's the doc. Using it should make your templates a bit more clean.
As for building menus, there's no need to do this in your templates, as this would break the single responsibility principle.
First, you should consider using KnpMenuBundle, as it allows you to dynamically build menus that could depend on basically any parameter that's accessible through the Service Container. The menu itself is usually built with EventListener
s, which gives you a lot of flexibility.
If adding a bundle is not an option for you, then why don't you extract the checks you make in your template into a service itself? It could have access to virtually any value in your project. You could just pass the current context and user there, and get an array or object of booleans that can be then used in your template.