How to paginate ítems inside relationship in Laravel? - php

I have model Category with relation products:
public function products()
{
return $this->hasMany(Product::class);
}
In MainController I have code:
$products = Category::with('products')->whereNull('parent_id')->paginate(15);
Method paginate only paginate categories, but How I can paginate products?

It's not a good idea to use pagination inside another pagination, but if you want to do this, you should create manual pagination for products of each category:
use Illuminate\Pagination\LengthAwarePaginator as Paginator;
use Illuminate\Http\Request;
$categories = Category::with('products')->whereNull('parent_id')->paginate(15);
foreach ($categories as $category) {
$count = $category->products->count(); // total count of products in this category
$limit = 10; // count of products per page in child pagination
$page = $request->input('category'.$category->id.'page', 1); // current page of this category's pagination
$offset = ($page * $limit) - $limit; // offset for array_slice()
$itemsForCurrentPage = array_slice($category->products->toArray(), $offset, $limit, true);
$paginator = new Paginator($itemsForCurrentPage, $count, $limit, $page, [
'path' => $request->url(),
'query' => $request->query(),
]);
$paginator->setPageName('category'.$category->id.'page');
$category->paginator = $paginator;
}
return view('categories.index', ['categories' => $categories]);
And then in your categories\index.blade.php:
<ul>
#foreach ($categories as $category)
<li>
<h3>{{ $category->title }}</h3>
#if ($category->paginator)
<ul>
#foreach ($category->paginator->items() as $product)
<li>{{ $product['title'] }}</li>
#endforeach
</ul>
{{ $category->paginator->links() }}
#endif
</li>
#endforeach
</ul>
{{ $categories->links() }}
I hope this helps, but I say it again, it's not a good idea to use pagination inside another pagination.

Related

Laravel how to add pagination on categorized posts

I have an laravel-application where I want to add pagination to my "blog-posts"-section. I can make it work when I return all blog_posts, but since they are categorized, the pagination does not work anymore.
Here is my controller
public function index() {
$blog_posts = Blog::where("publishes_on", "<=", Carbon::now())
->orderBy('publishes_on', 'desc')
->where('blog_status_id', '=', '2')
->with('blog_category')
->paginate(4);
$blog_categories = BlogCategory::get();
return view('blog.index', compact('blog_categories', 'blog_posts'));
}
and the blade view
#foreach($blog_categories as $category)
#foreach($category->blog_posts as $blog)
<div>
{{ $blog->title }}
</div>
#endforeach
#endforeach
Before I added the categories, my blade view looked like this
#foreach($blog_posts as $blog)
<div style="border-top: 2px solid red; padding: 4px;">
{{ $blog->title }}
</div>
#endforeach
<div>
{{ $blog_posts->links() }}
</div>
but now, I don't know how to add the pagination?
can someone help me out
You can use setRelation to override blog_posts relationship and have it return a paginated collection instead:
<?php
$blog_categories = BlogCategory::get()
->map(function($blogCategory) {
return $blogCategory
->setRelation( 'blog_posts', $blogCategory->blog_posts()->paginate(10) );
});
Calling paginate() returns an instance of Illuminate\Pagination\LengthAwarePaginator
To get collection of blog posts, use this:
$category->blog_posts->getCollection()
To get pagination links view:
$category->blog_posts->links()
It's all untested, so let me know if it doesn't work
You can create your custom pagination: (https://laravel.com/api/5.8/Illuminate/Pagination/LengthAwarePaginator.html)
$all_posts = Blog::where("publishes_on", "<=", Carbon::now())
->orderBy('publishes_on', 'desc')
->where('blog_status_id', '=', '2')
->with('blog_category')
->get();
$blog_categories = BlogCategory::get();
$count = count($all_posts);
$page = (request('page'))?:1;
$rpp = 4; //(request('perPage'))?:10;
$offset = $rpp * ($page - 1);
$paginator = new LengthAwarePaginator(
$all_posts->slice($offset,$rpp),$count,$rpp,$page,[
'path' => request()->url(),
'query' => request()->query(),
]);
$blog_posts = $paginator;
return view('blog.index', ['blog_posts' => $blog_posts,
'blog_categories' => $blog_categories]);

having laravel category (slug based) posts with pagination

I have this function, where i get my categories base on their slug
public function postcategoryposts($slug){
$category = PostCategory::where('slug','=',$slug)->firstOrFail();
return view('front.postcategory-posts', compact('category'));
}
Currently i'm getting my each category posts in blade like:
#foreach($category->posts as $post)
{{$post->title}}
#endforeach
until here everything is normal, the problem is how to divide my posts into pages? I am not able to use:
$category = PostCategory::where('slug','=',$slug)->paginate(10);
because I'm using
firstOrFail();
any idea?
You need to add a function to your model to get posts and then paginate.
In your controller
public function postcategoryposts($slug)
{
$category = PostCategory::where('slug','=',$slug)->firstOrFail();
$posts = $category->getPaginatedPosts(10);
return view('front.postcategory-posts', compact('posts'));
}
In your model
// PostCategory model
public function getPaginatedPosts($limit = 10)
{
// Get category posts using laravel pagination method
return Post::where('category_id', '=', $this->id)->paginate($limit);
}
In your blade view
<div class="container">
#foreach ($posts as $post)
{{ $post->title }}
#endforeach
</div>
{{ $posts->render() }}
More informations about Laravel pagination here
Hope it's helps you :)

Troubles with getting sub-categories of main category in Laravel

I'm trying to learn Laravel while writing some common features. Now what I'm trying to make is when I click on main category link to open new page and display all sub-categories assigned to this category. Sounds pretty simple but I can't display them.
This is what I have in my Category Model
public function parent()
{
return $this->belongsTo('App\Category', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Category', 'parent_id');
}
And in controller
public function categoryListing( $category_id )
{
$categories = Category::with('children')->get();
$category = Category::find($category_id);
if($category->parent_id == 0) {
$ids = Category::select('id')->where('parent_id', '!=',0)->get();
$array = array();
foreach ($ids as $id) {
$array[] = (int) $id->id;
}
} else {
$items = Item::where('category_id' ,$category_id)->paginate(5);
}
return view('category_list', compact('categories','items'));
}
The idea here is to display Main Category and all sub-categories (childs) of this main category.
And this is the loop on the page
#foreach($categories as $category)
<a href="{!!route('list',array($category->id))!!}">
<span><strong>{!!$category->title!!}</strong> ({!! $category->itemCount!!})</span>
</a>
<ul class="list-group">
#foreach($category as $subcategory)
{!!$subcategory->title!!}
<span class="badge badge-primary badge-pill">{!! $subcategory->itemCount !!}</span>
</li>
#endforeach
</ul>
#endforeach
Current error is
Trying to get property of non-object
on the inside foreach.
Just try this is 'cleaner'.. if it works, start adding your links and other content so you will know what does not work.
#foreach($categories as $category)
<span><strong>{!!$category->title!!}</strong></span>
<ul class="list-group">
#foreach($category as $subcategory)
<li>{!!$subcategory->title!!}</li>
#endforeach
</ul>
#endforeach
Make sure the variables you try to print exist in each object.
You can try to dd($categories); in your controller before the return view('category_list', compact('categories','items')); statement to see whats inside $categories

laravel 5 custom paginator not working

im trying to implement a view like sphinx documentation where you can click on next and previous to navigate between pages. not sure if im using the custom paginator on array right, i cant get page navigation links to display on a view page. this is the code:
public function paginate($array, $perPage, $pageStart=1) {
$offset = ($pageStart * $perPage) - $perPage;
return new Paginator(array_slice($array, $offset, $perPage, true), $perPage, $pageStart);
}
view()->composer('layouts.book', function($view)
{
//some other code
$pages = [];
foreach($book->textsection_pages as $textsection) {
$pages[] = $textsection->alias;
}
foreach($book->task_pages as $task) {
$pages[] = $task->alias;
}
foreach($book->tutor_pages as $tutor) {
$pages[] = $tutor->alias;
}
foreach($book->eval_pages as $eval) {
$pages[] = $eval->alias;
}
$chapters = $book->chapters()->orderBy('weight', 'asc')->get();
$paginated = $this->paginate($pages, 1);
$view->with(['chapters' => $chapters, 'book' => $book, 'paginated' => $paginated]);
});
and in the view i called {!! $paginated->render() !!}, but no navigation link was displayed.
Here is how I handle custom Pagination in my application (Laravel 5.1). I create a partial view resources/views/partials/pagination.blade.php
#if ($paginator->lastPage() > 1)
<ul id="pagination">
<li>
#if ($paginator->currentPage() > 1)
<a class="prev" href="{{ $paginator->url($paginator->currentPage()-1) }}">Previous</a>
#else
<span class="disabled">Previous</span>
#endif
</li>
<li>
#if ($paginator->currentPage() !== $paginator->lastPage())
<a class="next" href="{{ $paginator->url($paginator->currentPage()+1) }}" >Next</a>
#else
<span class="disabled">Next</span>
#endif
</li>
</ul>
#endif
In my controller, I pass the usual $model->paginate(10) method. Then finally in my view where I want to use the Paginator, resources/views/list.blade.php I do this:
#foreach ($objects as $object)
// Here we list the object properties
#endforeach
#include("partials.pagination", ['paginator' => $objects])

How to get calculated data from Controller to View and display it (laravel)?

i have a question again.. So, this time I need to send calculated data from my controller to view.
I have no problem with send simple data, like:
// Controller
public function index() {
$page = Page::whereAlias('products');
$products = Product::all();
$data = compact('page', 'products');
return View::make('products', $data);
}
//View
#foreach ($products as $product)
{{ $product->title }}
#endforeach
But in my project I need calculate for every products discount, if discounts date is correct, show it as discounted product.
Also calculate rating of this product, reviews count and so on. I have all correct relations and models.
And in my project I have next code (i think it's not correct):
// Controller
public function index() {
$page = Page::whereAlias('products');
$products = Product::all();
$data = compact('page', 'products');
return View::make('products', $data);
}
//View
<?php
$discount_count = 0;
$rating_count = 0;
$reviews_count = 0;
?>
#foreach ($products as $product)
{{ $product->title }}
<?php
foreach ($product->rating as $rating) { $rating_count++; }
?>
{{ $rating_count }}
<?php
foreach ($product->reviews as $review) { $review_count++; }
?>
{{ $review_count }}
#if ($product->discount_date_start > $current_date < $discount_date_end)
{{ $product->price - $product-discount }}
{{ round($product->discount / ($product->price / 100)); }}% // discount in percents
#else
{{ $product->price }}
#endif
#endforeach
As I understand all calculations must be in controller? But how..?
Thank you.
All calculations actually should not be in the controller or the view, but an additional class most would refer to as a repository, but that's probably outside of the scope of the question. It would work in the view or the controller as well, but if you don't have a repository class for handling this logic, into the controller it goes!
Just loop through the products in your controller and add properties to each product you have for the data you need. This is untested, but it should be close to what you need.
// Controller
public function index() {
$page = Page::whereAlias('products');
$products = Product::all();
foreach($products as $product) {
if($product->dicount_rate_start > $current_date < $discount_date_end) {
$product->total = $product->price - $product->discount;
$product->round = round($product->discount / $product->price / 100);
} else {
$product->total = $product->price;
$product->round = '';
}
}
$data = compact('page', 'products');
return View::make('products', $data);
}
//View
#foreach ($products as $product)
{{ $product->title }}
{{ $product->rating->count() }}
{{ $product->reviews->count() }}
{{ $product->total }}
{{ $product->round }}
#endforeach
You can also simplify your logic for adding up reviews and ratings as well using the count() method.

Categories