В данной заметке будет рассмотрен вариант создания меню в фреймворке Laravel с помощью расширения lavary/laravel-menu. Ознакомиться со всем его функционалом можно по ссылке. Я приведу пример базового использования данного расширения для создания многоуровневого меню.
Сам вывод на экран пунктов меню без оформления стилей выглядит следующим образом:



Установка.

Процесс установки подробно описан тут. Для этого выполняем в консоли (перейдя в каталог проекта) команду
composer require lavary/laravel-menu

далее добавляем пункт в массив провайдеров (файл config/app.php)
'Lavary\Menu\ServiceProvider',
и в массив алиасов:
'Menu' => 'Lavary\Menu\Facade',


Базовое использование.

Расширение имеет много полезных методов, которые могут пригодиться при создании сложных меню. В моем примере будут описаны только самые важные.

Информацию относящуюся к меню лучше всего хранить в БД. То есть создаем таблицу «menus» с такой структурой (минимально):



для дочерних пунктов меню прописывается id их родительских пунктов в поле parent_id.
В поле path нужно прописать ссылки на страницы к которым относятся данные пункты.

Конечно нужно создать модель для работы с данной таблицей. Для этого в консоли:
php artisan make:model Menu

Функционал по созданию пунктов меню с помощью данного расширения лучше всего вынести в отдельный класс или в метод главного (наследуемого) контроллера. Т.к. меню должно формироваться не для одного контроллера, а для многих (возможно для всех).


Для того, чтобы использовать расширение, сначала получаем данные о пунктах меню из БД используя модель. Для этого в нужном методе контроллера (который должен вывести страницу с нашим меню) получаем данные из таблицы menus в таком формате:



и передаем их на обработку методу buildMenu().
То есть, действие контроллера будет содержать такой код:
public function index()
{
    $arrMenu = \App\Menu::all();
    $menu = $this->buildMenu($arrMenu);
    return view('home', ['menu' => $menu]);
}

Метод buildMenu() создающий пункты меню:
use Menu as LavMenu; //lavary/laravel-menu
...
/*
 * Формирование пунктов меню используя расширение
 * https://github.com/lavary/laravel-menu#installation
 */
public function buildMenu ($arrMenu){
    $mBuilder = LavMenu::make('MyNav', function($m) use ($arrMenu){
        foreach($arrMenu as $item){
            /*
             * Для родительского пункта меню формируем элемент меню в корне
             * и с помощью метода id присваиваем каждому пункту идентификатор
             */
            if($item->parent_id == 0){
                $m->add($item->title, $item->path)->id($item->id);
            }
            //иначе формируем дочерний пункт меню
            else {
                //ищем для текущего дочернего пункта меню в объекте меню ($m)
                //id родительского пункта (из БД)
                if($m->find($item->parent_id)){
                    $m->find($item->parent_id)->add($item->title, $item->path)->id($item->id);
               }
            }
        }
    });
    return $mBuilder;
}

Методу make(), в качестве первого аргумента, передается произвольное название меню. Название нужно для того, чтобы была возможность создавать дополнительные меню, например в боковой панели. В качестве второго аргумента передается анонимная функция. Чтобы получить доступ к данным полученным из модели, даем к ним доступ с помощью
use ($arrMenu)

Результат работы метода buildMenu() сохраняется в переменной $menu, которая будет содержать объект Builder, и далее передаем ее в шаблон наряду с другими переменными.



В данном действии контроллера (index) вызывается шаблон 'home' - файл resources\views\home.blade.php. В нем секция отвечающая за меню будет иметь такой вид:
@extends('layouts.app')
@section('menu')
    @if($menu)
    <div class="menu classic">
        <ul id="nav" class="menu">
       <!--$menu->roots() - получаем только родительские элементы меню-->
        @include('customMenuItems', ['items'=>$menu->roots()])
        </ul>
    </div>
    @endif
@endsection
где HTML код и классы можно настроить под оформление своего проекта.

Как тут видно, шаблон наследует от макета, который располагается в resources\views\layouts\app.blade.php
в макете секцию меню нужно подключить как и остальные блоки:
@yield('menu')

Пункты меню будем выводить в дополнительном, подключаемом шаблоне, это нужно для создания многоуровневого меню – шаблон будет рекурсивно вызывать сам себя для формирования дочерних пунктов меню неограниченной вложенности. Для подключение данного подшаблона прописана директива
@include('customMenuItems', ['items'=>$menu->roots()])
которая подключит шаблон resources\views\customMenuItems.blade.php и передаст в переменной items массив объектов только родительских пунктов меню.

<!--Шаблон для вывода меню с использованием рекурсии-->
@foreach($items as $item)
    <!--Добавляем класс active для активного пункта меню-->
    <li {{ (URL::current() == $item->url()) ? "class=active" : '' }}>
        <!-- метод url() получает ссылку на пункт меню (указана вторым параметром
        при создании объекта LavMenu)-->
        <a href="{{ $item->url() }}">{{ $item->title }}</a>
        <!--Формируем дочерние пункты меню
        метод haschildren() проверяет наличие дочерних пунктов меню-->
        @if($item->hasChildren())
            <ul class="sub-menu">
                <!--метод children() возвращает дочерние пункты меню для текущего пункта-->
                @include(env('THEME').'.customMenuItems', ['items'=>$item->children()])
            </ul>
        @endif
    </li>
@endforeach

Активному пункту меню присваивается класс active для того, чтобы придать ему определенное оформление, при надобности.
Для каждого пункта меню проверяется наличие дочерних элементов и если они есть, то шаблон подключается рекурсивно для формирования вложенности пунктов меню.