KnpMenuBundle: строим меню для категорий и подкатегорий в symfony 4

Меню-билдер в лучших традициях симфони лучше объявить как сервис.

Создаем сервис app.knp.sidebar_menu в файле config/packages/knp_menu.yaml:

Содержимое config/packages/knp_menu.yaml:

knp_menu:
    twig:
        template: custom_knp_menu.html.twig

parameters:
    knp_menu.renderer.twig.options:
        currentClass: sel

services:
    app.knp.sidebar_menu:
        class: Knp\Menu\MenuItem
        factory: ['@App\Menu\MenuBuilder', createSidebarMenu]
        arguments: ["@request_stack"]
        tags:
            - { name: knp_menu.menu, alias: sidebar_menu }

Естественно, в knp_menu.yaml кастомный темлейт (knp_menu.twig.template) и css-класс для активного меню (currentClass) - это все опционально. Если поведение вашего меню совпадает с настройками kmpMenu по умолчанию, то кастомный темлейт нет смысла определять.

alias - указывает имя меня, которое можно будет передать при вызове knp_menu_render.

Благодаря autowiring, в конструкторе MenuBuilder мы можем прописать все зависимости, не создавая явно сервисы под каждую из зависимостей. В данном случае я внедрил 2 зависимости в MenuBuilder: MenuFactory и CategoryRepository, не создавая никаких дополнительных сервисов для них в yaml-файлах.

Содержимое билдера src/Menu/MenuBuilder.php:

<?php

namespace App\Menu;

use App\Entity\Category;
use App\Repository\CategoryRepository;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class MenuBuilder
{
    /**
     * @var FactoryInterface
     */
    private $factory;

    /**
     * @var CategoryRepository
     */
    private $categoryRepository;

    /**
     * @param FactoryInterface $factory
     * @param CategoryRepository $categoryRepository
     */
    public function __construct(
        FactoryInterface $factory,
        CategoryRepository $categoryRepository
    ) {
        $this->factory = $factory;
        $this->categoryRepository = $categoryRepository;
    }

    public function createSidebarMenu(RequestStack $requestStack): ItemInterface
    {
        $activeParentCategories = $this->categoryRepository
            ->findActiveParentCategories();

        $menu = $this->factory
            ->createItem('root')
            ->setChildrenAttribute('class', 'vertical_nav categories_nav');

        foreach ($activeParentCategories as $category) {
            $categoryMenuItem = $this->createMenuItemByCategory($category);

            $this->addCategoryChildrenMenu($category, $categoryMenuItem);

            $menu->addChild($categoryMenuItem);
        }

        return $menu;
    }

    /**
     * Create menu item using route whether for parent or child category as route is the same for both
     *
     * @param Category $category
     * @return ItemInterface
     */
    private function createMenuItemByCategory(Category $category): ItemInterface
    {
        return $this->factory->createItem($category->getName(), [
            'route' => 'category_show',
            'routeParameters' => ['category' => $category->getUri()],
        ]);
    }

    private function addCategoryChildrenMenu(Category $category, ItemInterface $categoryMenuItem): void
    {
        foreach ($category->getChildren() as $childCategory) {
            if (!$childCategory->isVisibleInMenu()) {
                continue;
            }

            $childCategoryMenuItem = $this->createMenuItemByCategory($childCategory);

            $categoryMenuItem->addChild($childCategoryMenuItem);
        }
    }
}

В моем случае у пунктов меню верхнего уровня могут быть только дети первого уровня. У потомков (детей) не может быть потомков.

Для рендеринга меню в twig-шаблоне достаточно указать:

{{ knp_menu_render('sidebar_menu') }}

где sidebar_menu - алиас, указанный в сервисе app.knp.sidebar_menu в knp_menu.yaml.

В результате будет сгенерировано меню следующего вида:

  • Category 1
    - SubCategory 1.1
    - SubCategory 1.2
    - SubCategory 1.3
  • Category 2
  • Category 3
    - SubCategory 3.1
    - SubCategory 3.2
    - SubCategory 3.3

 

 
 
 

icon Комментарии 0

Ваш комментарий к статье.. (для авторизованных)

ctrl+enter

icon Вход в систему

зарегистрироваться
НОВЫЕ ПОЛЬЗОВАТЕЛИ