Skip to content

Instantly share code, notes, and snippets.

@KaiCMueller
Created December 12, 2018 16:27
Show Gist options
  • Save KaiCMueller/3bd0570f115d709264972440d4a87b58 to your computer and use it in GitHub Desktop.
Save KaiCMueller/3bd0570f115d709264972440d4a87b58 to your computer and use it in GitHub Desktop.
EasyAdmin: Active entity menu items
{% macro render_menu_item(item, translation_domain) %}
{% if item.type == 'divider' %}
{{ item.label|trans(domain = translation_domain) }}
{% else %}
{% set menu_params = { menuIndex: item.menu_index, submenuIndex: item.submenu_index } %}
{% set path =
item.type == 'link' ? item.url :
item.type == 'route' ? path(item.route, item.params) :
item.type == 'entity' ? path('easyadmin', { entity: item.entity, action: 'list' }|merge(menu_params)|merge(item.params)) :
item.type == 'empty' ? '#' : ''
%}
{# if the URL generated for the route belongs to the backend, regenerate
the URL to include the menu_params to display the selected menu item
(this is checked comparing the beginning of the route URL with the backend homepage URL)
#}
{% if item.type == 'route' and (path starts with path('easyadmin')) %}
{% set path = path(item.route, menu_params|merge(item.params)) %}
{% endif %}
<a href="{{ path }}" {% if item.target|default(false) %}target="{{ item.target }}"{% endif %} class="{{ item.css_class|default('') }}">
{% if item.icon is not empty %}<i class="fa {{ item.icon }}"></i>{% endif %}
<span>{{ item.label|trans(domain = translation_domain) }}</span>
{% if item.children|default([]) is not empty %}<span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span>{% endif %}
</a>
{% endif %}
{% endmacro %}
{% macro menu_item_active_class(item, loop) %}
{% set active = false %}
{% if app.request.query.get('entity') and item.entity is defined %}
{% if app.request.query.get('entity')|default(-1) == item.entity %}
{% set active = true %}
{% endif %}
{% else %}
{% if app.request.query.get('menuIndex')|default(-1) == loop.index0 %}
{% set active = true %}
{% endif %}
{% endif %}
{% if item.children is defined %}
{% for subitem in item.children %}
{% if app.request.query.get('entity') and subitem.entity is defined %}
{% if app.request.query.get('entity')|default(-1) ==subitem.entity %}
{% set active = true %}
{% endif %}
{% else %}
{% if app.request.query.get('menuIndex')|default(-1) == loop.parent.loop.index0 and app.request.query.get('submenuIndex')|default(-1) == loop.index0 %}
{% set active = true %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{{ active == true ? "active" }}
{% endmacro %}
{% import _self as helper %}
{% block main_menu_before %}{% endblock %}
{% set _translation_domain = (_entity_config.translation_domain)|default(easyadmin_config('translation_domain'))|default('messages') %}
<ul class="sidebar-menu" data-widget="tree" data-animation-speed="250">
{% set _menu_items = easyadmin_config('design.menu') %}
{% block main_menu %}
{% for item in _menu_items %}
{% block menu_item %}
<li class="{{ item.type == 'divider' ? 'header' }} {{ item.children is not empty ? 'treeview' }} {{ helper.menu_item_active_class(item, loop) }} {{ app.request.query.get('submenuIndex')|default(-1) != -1 ? 'submenu-active' }}">
{{ helper.render_menu_item(item, _translation_domain) }}
{% if item.children|default([]) is not empty %}
<ul class="treeview-menu">
{% for subitem in item.children %}
{% block menu_subitem %}
<li class="{{ subitem.type == 'divider' ? 'header' }} {{ helper.menu_item_active_class(subitem, loop) }}">
{{ helper.render_menu_item(subitem, _translation_domain) }}
</li>
{% endblock menu_subitem %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endblock menu_item %}
{% endfor %}
{% endblock main_menu %}
</ul>
{% block main_menu_after %}{% endblock %}
@brizzz
Copy link

brizzz commented Apr 26, 2020

Little improved solution for EasyAdmin v2.x
Twig extension:

public function easyadmin_mark_selected(array $menu)
    {
        $request = $this->container->get(RequestStack::class)->getCurrentRequest();
        if ($request->query->has('menuIndex') && $request->query->has('submenuIndex')) {
            return $menu;
        }

        if (!$requestEntity = $request->query->get('entity')) {
            return $menu;
        }

        foreach ($menu as &$item) {

            if (isset($item['entity']) && $requestEntity === $item['entity']) {
                $item['active'] = true;
            }

            foreach ($item['children'] as &$subItem) {
                if (isset($subItem['entity']) && $requestEntity === $subItem['entity']) {
                    $item['active'] = true;
                    $item['subActive'] = true;
                    $subItem['active'] = true;
                }
            }
        }

        return $menu;
    }

Extended template:

{% extends '@!EasyAdmin/default/menu.html.twig' %}

{% import _self as helper %}

{% block main_menu %}
  {% set _menu_items = _menu_items|easyadmin_mark_selected %}
  {% for item in _menu_items %}
    {% block menu_item %}
      {% set is_selected_menu = app.request.query.get('menuIndex')|default(-1) == item.menu_index or item.active|default(false) %}
      {% set is_selected_submenu = is_selected_menu and app.request.query.get('submenuIndex')|default(-1) != -1 or item.subActive|default(false) %}

      {% if easyadmin_is_granted(item.permission) %}
        <li class="{{ item.type == 'divider' ? 'header' }} {{ item.children is not empty ? 'treeview' }} {{ is_selected_menu ? 'active' }} {{ is_selected_submenu ? 'submenu-active' }}">
          {{ helper.render_menu_item(item, _translation_domain) }}

          {% if item.children|default([]) is not empty %}
            <ul class="treeview-menu">
              {% for subitem in item.children %}
                {% block menu_subitem %}
                  {% if easyadmin_is_granted(subitem.permission) %}
                    <li class="{{ subitem.type == 'divider' ? 'header' }} {{ is_selected_menu and app.request.query.get('submenuIndex')|default(-1) == subitem.submenu_index or subitem.active|default(false) ? 'active' }}">
                      {{ helper.render_menu_item(subitem, _translation_domain) }}
                    </li>
                  {% endif %}
                {% endblock menu_subitem %}
              {% endfor %}
            </ul>
          {% endif %}
        </li>
      {% endif %}
    {% endblock menu_item %}
  {% endfor %}
{% endblock main_menu %}

@KaiCMueller
Copy link
Author

Hi @brizzz, thanks for your contribution! Can you please explain what the "improvements" are? Thank you!

@brizzz
Copy link

brizzz commented Apr 30, 2020

Thank you for starting point :) You version not work correctly on v2.x for me. And the base template of v2.x have some style changes. Improvements:

  1. less code duplication and better BC: extending base template and override only "main_menu" block
  2. move hard logic of defining active item to twig filter (by the way v3.x implemnts similiar approach)

@KaiCMueller
Copy link
Author

@brizzz good point! I think it makes sense to keep both approaches, while recommending your approach for EasyAdmin v2 and up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment