2.1 Create middleware get.menu (ok)

Phần 1: Gọi được menulist nhưng chưa có phần tử

Bản đã chạy dữ liệu dạng

C:\xampp82\htdocs\testvn\routes\web.php

<?php
use App\Http\Controllers\BannerController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group(['middleware' => ['get.menu']], function () {
  Route::get('/', function () {
    return view('dashboard.homepage');
  });
});

C:\xampp82\htdocs\testvn\app\Http\Middleware\GetMenu.php

<?php
namespace App\Http\Middleware;
use Closure;
use App\Http\Menus\GetSidebarMenu;
use App\Models\Menulist;
use Illuminate\Http\Request;
class GetMenu
{
  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
   * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
   */
  public function handle(Request $request, Closure $next)
  {
    $role = 'guest';
    $menus = new GetSidebarMenu();
    $menulists = Menulist::all();
    $result = array();
    foreach ($menulists as $menulist) {
      $result[$menulist->name] = $menus->get($role, $menulist->id);
    }
    view()->share('appMenus', $result);
    return $next($request);
  }
}

C:\xampp82\htdocs\testvn\app\Models\Menulist.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Menulist extends Model
{
  use HasFactory;
  protected $table = 'menulist';
}

C:\xampp82\htdocs\testvn\app\Models\Menus.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Menus extends Model
{
  use HasFactory;
  protected $table = 'menus';
}

C:\xampp82\htdocs\testvn\app\Http\Menus\MenuInterface.php

<?php
/*
*   07.11.2019
*   GuestMenu.php
*/
namespace App\Http\Menus;
use App\MenuBuilder;
interface MenuInterface
{
  public function get(string $roles);
}

C:\xampp82\htdocs\testvn\app\Http\Menus\GetSidebarMenu.php

<?php
/*
*   07.11.2019
*   MenusMenu.php
*/
namespace App\Http\Menus;
use App\MenuBuilder\MenuBuilder;
use Illuminate\Support\Facades\DB;
use App\Models\Menus;
use App\MenuBuilder\RenderFromDatabaseData;
class GetSidebarMenu implements MenuInterface
{
  private $mb; //menu builder
  private $menu;
  public function __construct()
  {
    $this->mb = new MenuBuilder();
  }
  private function getMenuFromDB($menuId, $menuName)
  {
    $this->menu = Menus::join('menu_role', 'menus.id', '=', 'menu_role.menus_id')
      ->select('menus.*')
      ->where('menus.menu_id', '=', $menuId)
      ->where('menu_role.role_name', '=', $menuName)
      ->orderBy('menus.sequence', 'asc')->get();
  }
  private function getGuestMenu($menuId)
  {
    $this->getMenuFromDB($menuId, 'guest');
  }
  private function getUserMenu($menuId)
  {
    $this->getMenuFromDB($menuId, 'user');
  }
  private function getAdminMenu($menuId)
  {
    $this->getMenuFromDB($menuId, 'admin');
  }
  public function get($role, $menuId = 2)
  {
    $this->getMenuFromDB($menuId, $role);
    $rfd = new RenderFromDatabaseData;
    return $rfd->render($this->menu);
  }
  public function getAll($menuId = 2)
  {
    $this->menu = Menus::select('menus.*')
      ->where('menus.menu_id', '=', $menuId)
      ->orderBy('menus.sequence', 'asc')->get();
    $rfd = new RenderFromDatabaseData;
    return $rfd->render($this->menu);
  }
}

C:\xampp82\htdocs\testvn\app\MenuBuilder\MenuBuilder.php

<?php
/*
*   07.11.2019
*   MenuBuilder
*/
namespace App\MenuBuilder;
class MenuBuilder
{
  private $menu;
  private $dropdown;
  private $dropdownDeep;
  public function __construct()
  {
    $this->menu = array();
    $this->dropdown = false;
    $this->dropdownDeep = 0;
  }
  private function innerAddElementToMenuLastPosition(&$menu, $element, $offset)
  {
    $z = 1;
    $result = false;
    $menu = &$menu[count($menu) - 1];
    while (is_array($menu)) {
      if ($z == $this->dropdownDeep - $offset) {
        array_push($menu['elements'], $element);
        $result = true;
        break;
      }
      $menu = &$menu['elements'][count($menu['elements']) - 1];
      $z++;
    }
    return $result;
  }
  private function addElementToMenuLastPosition($element, $offset = 0)
  {
    return $this->innerAddElementToMenuLastPosition($this->menu, $element, $offset);
  }
  private function addRegularLink($id, $name, $href, $icon, $iconType, $sequence = 0)
  {
    $hasIcon = ($icon === false || strlen($icon) === 0) ? false : true;
    if ($hasIcon) {
      array_push($this->menu, array(
        'id' => $id,
        'slug' => 'link',
        'name' => $name,
        'href' => $href,
        'hasIcon' => $hasIcon,
        'icon' => $icon,
        'iconType' => $iconType,
        'sequence' => $sequence,
      ));
    } else {
      array_push($this->menu, array(
        'id' => $id,
        'slug' => 'link',
        'name' => $name,
        'href' => $href,
        'hasIcon' => $hasIcon,
        'sequence' => $sequence,
      ));
    }
  }
  private function addDropdownLink($id, $name, $href, $icon, $iconType, $sequence = 0)
  {
    $num = count($this->menu);
    $hasIcon = ($icon === false || strlen($icon) === 0) ? false : true;
    if ($hasIcon) {
      $this->addElementToMenuLastPosition(array(
        'id' => $id,
        'slug' => 'link',
        'name' => $name,
        'href' => $href,
        'hasIcon' => $hasIcon,
        'icon' => $icon,
        'iconType' => $iconType,
        'sequence' => $sequence,
      ));
    } else {
      $this->addElementToMenuLastPosition(array(
        'id' => $id,
        'slug' => 'link',
        'name' => $name,
        'href' => $href,
        'hasIcon' => $hasIcon,
        'sequence' => $sequence,
      ));
    }
  }
  public function addLink($id, $name, $href, $icon = false, $iconType = 'coreui', $sequence = 0)
  {
    if ($this->dropdown === true) {
      $this->addDropdownLink($id, $name, $href, $icon, $iconType, $sequence);
    } else {
      $this->addRegularLink($id, $name, $href, $icon, $iconType, $sequence);
    }
  }
  public function addTitle($id, $name, $icon = false, $iconType = 'coreui', $sequence = 0)
  {
    $hasIcon = ($icon === false || strlen($icon) === 0) ? false : true;
    if ($hasIcon) {
      array_push($this->menu, array(
        'id' => $id,
        'slug' => 'title',
        'name' => $name,
        'hasIcon' => $hasIcon,
        'icon' => $icon,
        'iconType' => $iconType,
        'sequence' => $sequence,
      ));
    } else {
      array_push($this->menu, array(
        'id' => $id,
        'slug' => 'title',
        'name' => $name,
        'hasIcon' => $hasIcon,
        'sequence' => $sequence,
      ));
    }
  }
  public function beginDropdown($id, $name, $icon = false, $iconType = 'coreui', $sequence = 0)
  {
    $this->dropdown = true;
    $this->dropdownDeep++;
    $hasIcon = ($icon === false || strlen($icon) === 0) ? false : true;
    if ($this->dropdownDeep === 1) {
      if ($hasIcon) {
        array_push($this->menu, array(
          'id' => $id,
          'slug' => 'dropdown',
          'name' => $name,
          'hasIcon' => $hasIcon,
          'icon' => $icon,
          'iconType' => $iconType,
          'elements' => array(),
          'sequence' => $sequence,
        ));
      } else {
        array_push($this->menu, array(
          'id' => $id,
          'slug' => 'dropdown',
          'name' => $name,
          'hasIcon' => $hasIcon,
          'elements' => array(),
          'sequence' => $sequence,
        ));
      }
    } else {
      if ($hasIcon) {
        $this->addElementToMenuLastPosition(array(
          'id' => $id,
          'slug' => 'dropdown',
          'name' => $name,
          'hasIcon' => $hasIcon,
          'icon' => $icon,
          'iconType' => $iconType,
          'elements' => array(),
          'sequence' => $sequence,
        ), 1);
      } else {
        $this->addElementToMenuLastPosition(array(
          'id' => $id,
          'slug' => 'dropdown',
          'name' => $name,
          'hasIcon' => $hasIcon,
          'elements' => array(),
          'sequence' => $sequence,
        ), 1);
      }
    }
  }
  public function endDropdown()
  {
    $this->dropdownDeep--;
    if ($this->dropdownDeep < 0) {
      $this->dropdownDeep = 0;
    }
    if ($this->dropdownDeep <= 0) {
      $this->dropdown = false;
    }
  }
  public function getResult()
  {
    return $this->menu;
  }
}

C:\xampp82\htdocs\testvn\app\MenuBuilder\RenderFromDatabaseData.php

<?php
/*
*   08.11.2019
*   RenderFromDatabaseData
*/
namespace App\MenuBuilder;
use App\MenuBuilder\MenuBuilder;
class RenderFromDatabaseData
{
  private $mb; // MenuBuilder
  private $data;
  public function __construct()
  {
    $this->mb = new MenuBuilder();
  }
  private function addTitle($data)
  {
    $this->mb->addTitle($data['id'], $data['name'], false, 'coreui', $data['sequence']);
  }
  private function addLink($data)
  {
    if ($data['parent_id'] === NULL) {
      $this->mb->addLink($data['id'], $data['name'], $data['href'], $data['icon'], 'coreui', $data['sequence']);
    }
  }
  private function dropdownLoop($id)
  {
    for ($i = 0; $i < count($this->data); $i++) {
      if ($this->data[$i]['parent_id'] == $id) {
        if ($this->data[$i]['slug'] === 'dropdown') {
          $this->addDropdown($this->data[$i]);
        } elseif ($this->data[$i]['slug'] === 'link') {
          $this->mb->addLink($this->data[$i]['id'], $this->data[$i]['name'], $this->data[$i]['href'], $this->data[$i]['icon'], 'coreui', $this->data[$i]['sequence']);
        } else {
          $this->addTitle($this->data[$i]);
        }
      }
    }
  }
  private function addDropdown($data)
  {
    $this->mb->beginDropdown($data['id'], $data['name'], $data['icon'], 'coreui', $data['sequence']);
    $this->dropdownLoop($data['id']);
    $this->mb->endDropdown();
  }
  private function mainLoop()
  {
    for ($i = 0; $i < count($this->data); $i++) {
      switch ($this->data[$i]['slug']) {
        case 'title':
          $this->addTitle($this->data[$i]);
          break;
        case 'link':
          $this->addLink($this->data[$i]);
          break;
        case 'dropdown':
          if ($this->data[$i]['parent_id'] == null) {
            $this->addDropdown($this->data[$i]);
          }
          break;
      }
    }
  }
  /***
   * $data - array
   * return - array
   */
  public function render($data)
  {
    if (!empty($data)) {
      $this->data = $data;
      $this->mainLoop();
    }
    return $this->mb->getResult();
  }
}

C:\xampp82\htdocs\testvn\app\MenuBuilder\FreelyPositionedMenus.php

<?php
/*
17.12.2019
FreelyPositionedMenus,php
*/
namespace App\MenuBuilder;
class FreelyPositionedMenus
{
  private static function renderDropdown($data, $prefixClass)
  {
    if (array_key_exists('slug', $data) && $data['slug'] === 'dropdown') {
      echo '<li class="' . $prefixClass . 'nav-item dropdown px-3">';
      echo '<a class="' . $prefixClass . 'nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" href="#">';
      if ($data['hasIcon'] === true && $data['iconType'] === 'coreui') {
        echo '<i class="' . $data['icon'] . ' ' . $prefixClass . 'nav-icon"></i>';
      }
      echo $data['name'] . '</a>';
      echo '<div class="dropdown-menu">';
      self::renderDropdown($data['elements'], $prefixClass);
      echo '</div></li>';
    } else {
      for ($i = 0; $i < count($data); $i++) {
        if ($data[$i]['slug'] === 'link') {
          echo '<a class="' . $prefixClass . 'nav-link dropdown-item" href="' . env('APP_URL', '') . $data[$i]['href'] . '">';
          echo '<span class="' . $prefixClass . 'nav-icon"></span>' . $data[$i]['name'] . '</a>';
        } elseif ($data[$i]['slug'] === 'dropdown') {
          self::renderDropdown($data[$i], $prefixClass);
        }
      }
    }
  }
  /**
   * Render menu nav
   * @param  $data - array, result of GetSidebarMenu->get function
   * @param  $prefixClass - prefix to be placed before detailed classes
   * @param  $navClass - class to be placed in nav 
   */
  public static function render($data, $prefixClass = '', $navClass = '')
  {
    echo '<ul class="' . $prefixClass . 'nav ' . $navClass . '">';
    foreach ($data as $d) {
      if ($d['slug'] === 'link') {
        echo '<li class="' . $prefixClass . 'nav-item px-3">';
        echo '<a class="' . $prefixClass . 'nav-link" href="' . env('APP_URL', '') . $d['href'] . '">';
        if ($d['hasIcon'] === true) {
          if ($d['iconType'] === 'coreui') {
            echo '<i class="' . $d['icon'] . ' ' . $prefixClass . 'nav-icon"></i>';
          }
        }
        echo $d['name'];
        echo '</a>';
        echo '</li>';
      } elseif ($d['slug'] === 'dropdown') {
        self::renderDropdown($d, $prefixClass);
      } elseif ($d['slug'] === 'title') {
        echo '<li class="' . $prefixClass . 'nav-title px-3">';
        if ($d['hasIcon'] === true) {
          if ($d['iconType'] === 'coreui') {
            echo '<i class="' . $d['icon'] . ' ' . $prefixClass . 'nav-icon"></i>';
          }
        }
        echo $d['name'];
        echo '</li>';
      }
    }
    echo '</ul>';
  }
}

C:\xampp82\htdocs\testvn\app\Http\Kernel.php

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \App\Http\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    'get.menu' => \App\Http\Middleware\GetMenu::class
];

C:\xampp82\htdocs\testvn\resources\views\layouts\sidebar.blade.php

<div class="sidebar sidebar-dark sidebar-fixed" id="sidebar">
  <div class="sidebar-brand d-none d-md-flex">
    <svg class="sidebar-brand-full" width="118" height="46" alt="CoreUI Logo">
      <use xlink:href="{{secure_asset('dist/assets/brand/coreui.svg#full')}}"></use>
    </svg>
    <svg class="sidebar-brand-narrow" width="46" height="46" alt="CoreUI Logo">
      <use xlink:href="{{secure_asset('dist/assets/brand/coreui.svg#signet')}}"></use>
    </svg>
  </div>
  @include('dashboard.shared.nav-builder')
  <button class="sidebar-toggler" type="button" data-coreui-toggle="unfoldable"></button>
</div>

C:\xampp82\htdocs\testvn\resources\views\dashboard\shared\nav-builder.blade.php

<?php
/*
$data = $menuel['elements']
 */
if (!function_exists('renderDropdown')) {
  function renderDropdown($data)
  {
    if (array_key_exists('slug', $data) && $data['slug'] === 'dropdown') {
      echo '<li class="sidebar-nav-dropdown">';
      echo '<a class="nav-link" href="#">';
      if ($data['hasIcon'] === true && $data['iconType'] === 'coreui') {
        echo '<i class="' . $data['icon'] . ' sidebar-nav-icon"></i>';
      }
      echo $data['name'] . '</a>';
      echo '<ul class="sidebar-nav-dropdown-items">';
      renderDropdown($data['elements']);
      echo '</ul></li>';
    } else {
      for ($i = 0; $i < count($data); $i++) {
        if ($data[$i]['slug'] === 'link') {
          echo '<li class="sidebar-nav-item">';
          echo '<a class="nav-link" href="' . url($data[$i]['href']) . '">';
          echo '<span class="sidebar-nav-icon"></span>' . $data[$i]['name'] . '</a></li>';
        } elseif ($data[$i]['slug'] === 'dropdown') {
          renderDropdown($data[$i]);
        }
      }
    }
  }
}
?>
<ul class="sidebar-nav aaa2">
  @foreach($appMenus['sidebar menu'] as $menuel)
    @if($menuel['target'] === 'link')
      <li class="sidebar-nav-item">
        <a class="nav-link" href="{{ url($menuel['slug']) }}">
          @if($menuel['hasIcon'] === true)
          @if($menuel['iconType'] === 'coreui')
          <i class="{{ $menuel['icon'] }} sidebar-nav-icon"></i>
          @endif
          @endif
          {{ $menuel['name'] }}
        </a>
      </li>
    @endif
  @endforeach
</ul>

Last updated