How to create a database-driven multi-level navigation menu using Laravel
So after doing much more searching and reading from different sources this is what I came up with and it's working fine:
/app/models/Navigation.php
<?php
class Navigation extends Eloquent {
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'navigation';
public function parent() {
return $this->hasOne('navigation', 'id', 'parent_id');
}
public function children() {
return $this->hasMany('navigation', 'parent_id', 'id');
}
public static function tree() {
return static::with(implode('.', array_fill(0, 4, 'children')))->where('parent_id', '=', NULL)->get();
}
}
/app/controllers/HomeController.php
<?php
class HomeController extends BaseController {
protected $layout = "layouts.main";
public function showWelcome()
{
$items = Navigation::tree();
$this->layout->content = View::make('layouts.home.index')->withItems($items);
}
}
/app/views/layouts/home/index.blade.php
<ul>
@foreach($items as $item)
<li>{{ $item->title }}
@foreach($item['children'] as $child)
<li>{{ $child->title }}</li>
@endforeach
</li>
@endforeach
</ul>
Laravel multilevel menus with sorting
Here are the step by step I'm using to get multilevel menus :
Table "menus"
id, title, order, parent_id
Model
class Menu extends Model
{
public function children()
{
return $this->hasMany(self::class , 'parent_id', 'id')->orderBy('order');
}
}
Controller
class MenuController extends Controller
{
public function index()
{
$menus = Menu::where('parent_id', 0)->orderBy('order', 'ASC')->get();
return view('menu', compact('menus'));
}
}
View
@foreach($menus as $menu)
@foreach($menu->children => $child)
<h4>{{ $child->title }}</h4>
@endforeach
@endforeach
How to list select option with multi level categories in Laravel 5
For the ul
you can create a recursive function using blade e.g.
@include('partials.menu', $items)
Then in that view something like:
<ul>
{{-- You would have to provide your own logic to decide which class name the ul should have --}}
@foreach($items as $item)
{{ $item->name }}
@if(!empty($item->children)) {{-- Or however you want to check for children --}}
@include('partials.menu', ['items' => $item->children]) {{-- Here I am just telling blade to treat the children as $items where they are passed through --}}
@endif
@endforeach
</ul>
This is a basic implementation of a recursive function with blade.
You can use a similar approach for the select
as well.
Hope this helps!
Laravel : Storing navigation in cache but want to set active class based on current url
You may add
a new macro
in HTML
class, simply add this in a file (macros.php
) and store it inside app/start
directory then include it from the app/startglobal.php
file using require/include
:
HTML::macro('menuItem', function($name, $title = null, $parameters = array(), $attributes = array()){
$currentUrl = URL::current() == url() ? url('home') : URL::current();
$active = ( $currentUrl == URL::route($name, $parameters) ) ? ' class="active"':'';
return '<li'.$active.'>' . HTML::linkRoute($name, $title, $parameters, $attributes) . '</li>';
});
In your view
you may generate the menu items using something like this:
<ul>
{{ HTML::menuItem('page.home', 'Home', array('home')) }}
</ul>
Here page.home
is the route name assigned to /
when declaring the route
and yes in this case routes should have name
, for example:
Route::get('/', array('uses' => 'PageController@home', 'as' => 'page.home'));
In the menuItem
macro the second parameter (Home
) is the menu title to show and the third parameter is an optional parameter if has any. So for example, your About Us
page has the parameter about-us
and to create the menu item you may use this:
{{ HTML::menuItem('page.about', 'About Us', array('about-us')) }}
This is a possible solution and there may be other ways.
If else statement based on database row
You need to do this in a controller.
Route::get('letters', ['uses' => 'LettersController@index']);
And then in your letters controller
public function index()
{
// Grab letters for the user. You need to be sure that the user is logged in
$letters = Letter::forUser(Auth::user())->get();
$data = [
'letters' => $letters
];
// You will be able to call $letters->count() in your view
return View::make('letters.index', $data);
}
In your letter Model
public function scopeForUser(User $u)
{
return $query->where('user_id', '=', $u->id);
}
Related Topics
How to Make Short Random Unique Keys, Like Youtube Video Ids, in PHP
How to Create a .Gz File Using PHP
Use Keyword in Functions - PHP
Laravel: Where to Store Global Arrays Data and Constants
Laravel Middleware with Multiple Roles
Laravel Eloquent: How to Get Only Certain Columns from Joined Tables
How to Use Imagick to Merge and Mask Images
Adding 1 Day to a Datetime Format Value
Is Header('Content-Type:Text/Plain'); Necessary at All
PHP Warning: Unknown: Failed to Open Stream
PHP Date Time Greater Than Today