How do I customize the pagination items in this Laravel 8 application? - php

I am working on a blogging application in Laravel 8.
The ArticlesController controller I have this method to display the paginated articles:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\ArticleCategory;
use App\Models\Article;
use App\Models\Comment;
class ArticlesController extends FrontendController {
// Articles per page
protected $per_page = 12;
public function index(Request $request) {
// Search query
$qry = $request->input('search');
$articlesQuery = Article::where('title', 'like', '%' . $qry . '%')
->orWhere('short_description', 'like', '%' . $qry . '%')
->orWhere('content', 'like', '%' . $qry . '%');
// Search results count
if ($qry) {
$article_count = $articlesQuery->count();
}
$articles = $articlesQuery->orderBy('id', 'desc')->paginate($this->per_page);
$featured_articles = Article::where('featured', 1)->orderBy('id', 'desc')->get();
return view('themes/' . $this->theme_directory . '/templates/index',
array_merge($this->data, [
'search_query' => $qry,
'articles' => $articles,
'featured_articles' => $featured_articles,
'article_count' => $article_count ?? null
])
);
}
}
The pagination, in the plain HTML template, looks like this:
<nav class="pgn">
<ul>
<li>
<a class="pgn__prev" href="#0">Prev</a>
</li>
<li><a class="pgn__num" href="#0">1</a></li>
<li><span class="pgn__num current">2</span></li>
<li><a class="pgn__num" href="#0">3</a></li>
<li><span class="pgn__num dots">…</span></li>
<li><a class="pgn__num" href="#0">4</a></li>
<li>
<a class="pgn__next" href="#0">Next</a>
</li>
</ul>
</nav>
The goal
The goal is to keep the pagination structure above, in Laravel's Blade.
The problem
The code below works for the "Next" and "Prev" buttons, but not the links in between.
<nav class="pgn">
<ul>
<li>
<a class="pgn__prev" href="{{ $articles->withQueryString()->previousPageUrl() }}">Prev</a>
</li>
{!! $articles->withQueryString()->links() !!}
<li>
<a class="pgn__next" href="{{ $articles->withQueryString()->nextPageUrl() }}">Next</a>
</li>
</ul>
</nav>
Questions
What causes this bug?
What is the easiest fix?

To create a custom pagination, I'd recommend to make use of a custom "view".
Basically, what would you have to do (which you have already done), is define a limit, and then basically do the following:
you create your view file (which will be the custom paginator) - name it however you want to name it. I'll name it custom.blade.php
This view has to be created after running the command: php artisan vendor:publish --tag=laravel-pagination
here you can find a bit more in the documentation about it: https://laravel.com/docs/9.x/pagination#customizing-the-pagination-view
#if ($paginator->onFirstPage())
<li class="disabled"><span>← Previous</span></li>
#else
<li>
<a class="pgn__prev" href="{{ $articles->withQueryString()->previousPageUrl() }}">Prev</a>
</li>
#endif
#foreach ($elements as $element)
#if (is_string($element))
<li class="disabled"><span>{{ $element }}</span></li>
#endif
#if (is_array($element))
#foreach ($element as $page => $url)
#if ($page == $paginator->currentPage())
<li class="active my-active"><span>{{ $page }}</span></li>
#else
<li>{{ $page }}</li>
#endif
#endforeach
#endif
#endforeach
#if ($paginator->hasMorePages())
<li>
<a class="pgn__next" href="{{ $articles->withQueryString()->nextPageUrl() }}">Next</a>
</li>
#else
<li class="disabled"><span>Next</span></li>
#endif
And finally, on the view where you want to make use of the custom pagination:
{{ $articles->links(‘path.pagination.custom') }}
(just make sure to have the correct path)
edit: It's a bit hard for me to give a definitive answer without looking at the project itself, but I hope this at least helps somehow.

Related

How to use orWhere to combine results in Laravel?

I'm trying to find the slugs complete and incomplete model TaskboardColumn, then I only want the values of the user and the project.
Here is what I've tried:
Model
public static function projectOpenTasks($projectId, $userID=null)
{
$taskBoardColumn = \App\TaskboardColumn::where('slug', 'incomplete')->first();
$taskBoardColumn2 = \App\TaskboardColumn::where('slug', 'inprogress')->first();
$projectTask = \App\Task::where('tasks.board_column_id', $taskBoardColumn->id)->orWhere('tasks.board_column_id', $taskBoardColumn2->id);
if($userID)
{
$projectIssue = $projectTask->where('user_id', '=', $userID);
}
$projectIssue = $projectTask->where('project_id', $projectId)
->get();
return $projectIssue;
}
Controller
$this->openTasks = Task::projectOpenTasks($this->project->id);
View
<ul class="list-task list-group" data-role="tasklist">
<li class="list-group-item" data-role="task">
<strong>#lang('app.title')</strong>
<span class="pull-right"><strong>#lang('app.dueDate')</strong></span>
</li>
#forelse($openTasks as $key=>$task)
<li class="list-group-item row" data-role="task">
<div class="col-xs-8">
{{ ($key+1).'. '.ucfirst($task->heading) }}
</div>
<label class="label label-danger pull-right col-xs-4">{{ $task->due_date->format($global->date_format) }}</label>
</li>
#empty
<li class="list-group-item" data-role="task">
#lang('messages.noOpenTasks')
</li>
#endforelse
</ul>
With this code I'm getting all the tasks, and I need just this project's tasks.
You can use grouping to achieve this
$projectTask = \App\Task::where(function($q) {
$q->where('tasks.board_column_id', $taskBoardColumn->id);
$q->orWhere('tasks.board_column_id', $taskBoardColumn2->id)
})->get();
Thanks
orwhere is used in places where only one of the query has to run. just like and keyword in programming orwhere is used in sense of query.
following is the code snippet -
$projectTask = $query->where('tasks.board_column_id', $taskBoardColumn->id)
->orWhere('tasks.board_column_id', $taskBoardColumn2->id)
->get();

Get datas from one to many (inverse ) relation laravel

I have 2 models 'Trips.php'
public function region()
{
return $this->belongsTo('App\Region');
}
Region.php
public function trips()
{
return $this->hasMany('App\Trip');
}
I'm trying to show the trips that are in one one specific region. For example: I have a region named Lake Side and I want to show all trips that are in Lake Side region in list.
I tried the following:
In controller:
$trips = Trip::all();
In view:
#foreach($trips as $trip)
<li><a href="#">
{{$trip->region->name}}</a>
<ul class="dropdown">
<li><a href="#">
{{$trip->title}}</a>
</li>
</ul>
</li>
#endforeach
This gives me region name and trip name but repeats region name if more than one trip is made in same region.
And tried another way around (inverse):
<ul class="dropdown">
#foreach($regions as $region)
<li><a href="#">
{{$region->tour->title}}</a>
</li>
#endforeach
</ul>
And getting error Trying to get property of non-object
One way to do that is to use whereHas():
$trips = Trip::whereHas('region', function($q) use ($regionName) {
$q->where('name', $regionName);
})->get();
Pass $trips and $regionName to the view:
#foreach ($trips as $trip)
<li>{{ $regionName }}
<ul class="dropdown">
<li><a href="#">
{{ $trip->title }}</a>
</li>
</ul>
</li>
#endforeach
Alternatively, you can use eager loading:
$region = Region::where('name', $regionName)->with('trips')->first();
And in the view:
#foreach ($region->trips as $trip)
<li>{{ $region->name }}
<ul class="dropdown">
<li><a href="#">
{{ $trip->title }}</a>
</li>
</ul>
</li>
#endforeach
By getting trips with regions, what you're essentially getting is every trip with a region property.
Instead do the reverse Region::with('trips')->where('id', $regionId)->get() and you'll get regions with their trips. So now every region result has a trips property which contains many trips.
Alternatively don't use eager load. So Region::firstOrFail($regionId) then just use $region->trips.
And you can loop through them like
// Can print region here
#foreach($region->trips as $trip)
// Can print region's trips here
#endforeach

Multi-level menu in laravel 5.1 - loops

I am a little bit new with laravel 5.1 framework. Last couple of days I create my database (insert, update, delete) for dynamic menu I want to create. I connect with default layout in which i put menu. From route code looks like this.
View::composer('layouts.default',function($view){
$menus = Menu::where('parent_id',0)->orderBy('order')->get();
$submenus = Menu::where('parent_id','!=',0)->get();
$view->with(compact('menus','submenus'));
});
In main menu are items with parent_id = 0. Submenu items have parent_id = id, and soo on.
I want to display correct but when I hover main menu items that dont have items, css block appear, becouse i didnt make good if condition. Is there any way to do this?
Code in view look like this.
#foreach($menus as $menu)
<li class="dropdown {!! (Request::is('typography') || Request::is('advancedfeatures') || Request::is('grid') ? 'active' : '') !!}"> {!! $menu->title !!}
<ul class="dropdown-menu" role="menu">
#foreach($submenus as $submenu)
#if($submenu->parent_id === $menu->id)
<li>{!! $submenu->title !!}
#foreach($submenus as $smenu)
#if($smenu->parent_id === $submenu->id)
<ul class="dropdown-submenu" role="menu">
<li>{!! $smenu->title !!}
</li>
</ul>
#endif
#endforeach
</li>
#endif
#endforeach
</ul>
</li>
#endforeach
One more question is how to take only one value from Menu model for example id that can be used to point only one submenu.
Best regards!
You can do it simply by using recursion. I removed html classes for readability.
Note: Set NULL parent_id for root items.
Add this relation to your Menu Model.
function childs()
{
return $this->hasMany('Namespace\Menu','parent_id', 'id');
}
In your controller get the menus who has no parent.
$menus = Menu::whereNull('parent_id')->orderBy('order')->get();
Then display them in your view.
<ul>
#foreach($menus as $menu)
<li>
{!! $menu->title !!}
#include('childItems')//recursion view
</li>
#endforeach
</ul>
And this is what your childItems.blade.php will look like.
<ul>
#foreach($menu->childs as $menu)
<li>
{!! $menu->title !!}
#include('childItems')//call itself for deeper relations.
</li>
#endforeach
</ul>
That's it.

How to make menu and submenu dynamic Laravel

I want to make menu and submenu dynamic .I made menu with their link but unable to make submenu,please help me my database structure
table name:menu
id menu_name url timestamps
table:sub_menu
id submenu_name link menu_id timestamps
my query is like this
public function menu()
{
$sql=\DB::table('menu')->rightjoin('sub_menu','menu.id','=','sub_menu.menu_id')
->select('submenu_name','link','url','menu_id','menu_name','menu.id')->get();
return view('products.show.menu',compact('sql'));
}
view
<ul>
#foreach($sql as $key => $nav)
#if($key > 0)
<li>
{{$nav->menu_name}}
#if (count($nav->submenu_name) > 0 )
<ul>
#foreach($nav->submenu_name as $child)
<li>{{$child->submenu_name}}</li>
#endforeach
#endif
</ul>
</li>
#endif
#endforeach
</ul>
Have you set up models for these tables? Your query will return multiple rows for each menu/submenu combination, meaning you can't just iterate over it as you are. There's no need to use the query builder here.
Assuming your models are set up as follows (you will need to check the namespace used in the relationships):
class Menu extends Eloquent
{
protected $table = 'menu';
public function submenu()
{
return $this->hasMany('App\SubMenu');
}
}
class SubMenu extends Eloquent
{
protected $table = 'sub_menu';
public function menu()
{
return $this->belongsTo('App\Menu');
}
}
In your controller, you can do:
public function menu()
{
$menu = Menu::with('submenu')->get();
return view('products.show.menu', compact('menu'));
}
Then in your view:
<ul>
#foreach($menu as $menuItem)
<li>
{{ $menuItem->menu_name }}
#if( ! $menuItem->submenu->isEmpty())
<ul>
#foreach($menuItem->submenu as $subMenuItem)
<li>{{ $subMenuItem->submenu_name }}</li>
#endforeach
</ul>
#endif
</li>
#endforeach
</ul>
You can use it without controller
`#foreach(App\Menu::get() as $menuItem)
#if( ! $menuItem->submenu->isEmpty() )
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
{{ $menuItem->menu_name }}
</a>
#else
<li>
{{ $menuItem->menu_name }}
#endif
#if( ! $menuItem->submenu->isEmpty())
<ul class="dropdown-menu" role="menu">
#foreach($menuItem->submenu as $subMenuItem)
<li>{{ $subMenuItem->submenu_name }}</li>
#endforeach
</ul>
#endif
</li>
#endforeach`

Dynamic menu laravel

I am starting with laravel, and made an integration with bootstrap. I want to make a menu bar to access to the information by year, the menu is made I this way to the view
<li class="dropdown-submenu">
<a tabindex="-1" href="#">2007</a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="<?php echo url('/convenios/2007/registrar', $parameters = array(), $secure = null); ?>">Registrar</a></li>
<li>Consultar</li>
</ul>
</li>
I made this on a view called base.blade.php, there is a better way to make the menus or I made this in the right way?
menus table
id - parent_id - title - url - order - created_at - updated_at
Make Menu model
class Menu extends Model
{
public $timestamps = false;
protected $table = 'menus';
protected $fillable = array('parent_id','title','url','order');
public function parent()
{
return $this->belongsTo('App\Menu', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Menu', 'parent_id');
}
}
in View
#foreach(App\Menu::orderBy('order','asc')->get() as $menuItem)
#if( $menuItem->parent_id == 0 )
<li {{ $menuItem->url ? '' : "class=dropdown" }}>
<a href="{{ $menuItem->children->isEmpty() ? $menuItem->url : "#" }}"{{ $menuItem->children->isEmpty() ? '' : "class=dropdown-toggle data-toggle=dropdown role=button aria-expanded=false" }}>
{{ $menuItem->title }}
</a>
#endif
#if( ! $menuItem->children->isEmpty() )
<ul class="dropdown-menu" role="menu">
#foreach($menuItem->children as $subMenuItem)
<li>{{ $subMenuItem->title }}</li>
#endforeach
</ul>
#endif
</li>
#endforeach
you can make controller as you like
this way i spent all day trying to get this working code, when i finished i decide to search for anybody ask for that issue
Have fun :)

Categories