How to use Paginator with pluck method in Laravel? - laravel

I have several columns that are plucked out of database and displayed in a table.I have been trying to paginate the table.Is there a way where I could paginate each and every column values that are plucked out of database?
return $this-> orderByDesc('date_added')->whereNull('deleted_at')->pluck('program');

Create a Paginator instance with the query results and return that to your view with the table:
$page = 1;
$perPage = 10;
$options = [];
$items = $this-> orderByDesc('date_added')->whereNull('deleted_at')->pluck('program');
return view('some.table', [
'items' => new LengthAwarePaginator($items->take($perPage), $items->count(), $perPage, $page, $options)
]);

$page_no = 1;
$no_of_data = 10;
$offset = ($page_no * $no_of_data) - $no_of_data;
return $this-> orderByDesc('date_added')->whereNull('deleted_at')->offset($offset)->limit($no_of_data)->pluck('program');

Related

Laravel 9 hasMany relationship not working

I have a model with a relationship with another model, when calling the relationship in the controller it gives me
Exception: Property [products] does not exist on the Eloquent builder instance.
model:
public function products(): HasMany
{
return $this->hasMany(CartProduct::class,'cart_id','id');
}
controller
public function showCartOfAuth()
{
$id =auth()->guard('customers')->user()->id;
$cart = Cart::where('customer_id',$id)->get();
$products = Cart::where('customer_id',$id)->products->get();
$response = [
'cart' => $cart,
'items' => $products
];
return response($response,200);
}
Can you try this, please: Cart::with('products')->where('customer_id',$id)->get();
The way you have implemented requires atleast two database queries.
One: $cart = Cart::where('customer_id',$id)->get();
Two: Cart::where('customer_id',$id)->first()->products; //maybe a third query to fetch the products
For better performance you should
public function showCartOfAuth()
{
$id =auth()->guard('customers')->user()->id;
// Either Option 1
// Possibly 2 database queries, one to fetch the Cart and another to fetch Products for the Cart
$cart = Cart::where('customer_id',$id)->first();
$products = $cart->products;
$response = [
'cart' => $cart,
'items' => $products
];
// OR Option 2
// One database query using eager loading
$cart = Cart::with('products')->where('customer_id', $id)->first();
$response = ['cart' => $cart];
return response($response,200);
}
If you use option 2 from above then instead of $items you can use $cart->products

Laravel pagination with problems

i have a simple question as i do not know which line i should add into to get laravel pagination. (->paginate(5).
public function index(Request $request)
{
$codeSearch = $request->get('code');
$descriptionSearch = $request->get('description');
//$tmp = Category::all()->toArray();
$tmp = Category::where('code','like','%' .$codeSearch. '%')->where('description','like','%' .$codeSearch. '%')->get()->toArray();
$category = array();
foreach ($tmp as $key => $row) {
$policy = Category::find($row['parent_id']);
$tmpResult = new Category();
$tmpResult->id = $row['id'];
$tmpResult->code = $row['code'];
$tmpResult->description = $row['description'];
$tmpResult->parent_id = $policy['description'];
$tmpResult->status = $row['status'];
array_push($category, $tmpResult);
}
return view('category.index', compact('category'));
}
Paginate can't be called on the collection, so you have to run it on the query, by simply replace ->get() with ->paginate(5) like this
$tmp = Category::where('code','like','%' .$codeSearch. '%')
->where('description','like','%' .$codeSearch. '%')
->paginate(5)
->toArray();
Try
$tmp = Category::where('code','like','%' .$codeSearch. '%')->where('description','like','%' .$codeSearch. '%')->paginate(5);
In view
#foreach($tmp as $tm)
//whatever operation you like to do
#endforeach
{{$tmp->links()}}
The following ->get(), ->first(), all() get the results from the database and so does ->paginate(5), so I would suggest that you replace ->get() with paginate(5) an you can get rid of toArray() because the result will be a collection with which you can use foreach() or get a value by index.
As you need an array in your condition, then you can simply convert the final array into a collection object and use the pagination concept.
$items = [
'item1',
'item2',
'item3',
'item4',
'item5',
'item6',
'item7',
'item8',
'item9',
'item10'
];
// Get current page form url e.x. &page=1
$currentPage = LengthAwarePaginator::resolveCurrentPage();
// Create a new Laravel collection from the array data
$itemCollection = collect($items);
// Define how many items we want to be visible in each page
$perPage = 1;
// Slice the collection to get the items to display in current page
$currentPageItems = $itemCollection->slice(($currentPage * $perPage) - $perPage, $perPage)->all();
// Create our paginator and pass it to the view
$paginatedItems= new LengthAwarePaginator($currentPageItems , count($itemCollection), $perPage);
// set url path for generted links
$paginatedItems->setPath($request->url());
return view('items_view', ['items' => $paginatedItems]);
It would probably be easier to have a relationship setup for a Category's parent. Then you can load the parent when you retrieve the categories.
class Category extends Model
{
...
public function parent()
{
return $this->belongsTo(self::class);
}
}
I feel like your search is probably trying to do an OR WHERE, search the code field for this value or the description:
$categories = Category::with('parent')
->where('code', 'like', '%' .$codeSearch. '%')
->orWhere('description', 'like', '%' .$codeSearch. '%')
->paginate(5);
Then in your view if you want the parent category's description you can get it through the relationship:
#foreach ($categories as $category)
parent description: {{ $category->parent->description }}
#endforeach

How to use transform in paginated collection in laravel

I want to use map or transform in paginated collection in laravel 5.5 but I am struggling it work
This is what I was trying to do but getCollection is not available in LengthAwarePaginator as what we used to do in previous laravel versions see: How to transform paginated collection
$query = User::filter($request->all()
->with('applications');
$users = $query->paginate(config('app.defaults.pageSize'))
->transform(function ($user, $key) {
$user['picture'] = $user->avatar;
return $user;
});
This is what I receive but there is no pagination details in my result
How can I return transformed collection with pagination details?
For Laraval >= 8.x: if you want to perform the transform() on the collection of the paginated query builder result instead of doing the pagination on the full collection, one can use the method through():
User::filter($request->all()
->with('applications')
->paginate(config('app.defaults.pageSize'))
// through() will call transform() on the $items in the pagination object
->through(function ($user, $key) {
$user['picture'] = $user->avatar;
return $user;
});
I have ended up building custom paginate function in AppServiceProvider
use Illuminate\Support\Collection;
In register of AppServiceProvider
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: \Illuminate\Pagination\LengthAwarePaginator::resolveCurrentPage($pageName);
return new \Illuminate\Pagination\LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => \Illuminate\Pagination\LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
You should paginate before retrieving the collection and transforming as follows:
$query = User::filter($request->all())->with('applications')->paginate(50);
$users = $query->getCollection()->transform(function ($user, $key) {
//your code here
});
dd($users);
It should give you your desired result.
Your problem is that you are printing the $users variable that hold the array of the users in the current page. To get the paginated list try to return/print $query instead.
So your code should be as following:
$query = User::filter($request->all()
->with('applications');
$users = $query->paginate(config('app.defaults.pageSize'))
->transform(function ($user, $key) {
$user['picture'] = $user->avatar;
return $user;
});
return response()->json($query);
Happy Coding!
You can use method setCollection from Paginator class:
https://laravel.com/api/8.x/Illuminate/Pagination/Paginator.html#method_setCollection
$messages = $chat->messages()->paginate(15);
$messages->setCollection($messages->getCollection()->transform(function($item){
$item->created = $item->created_at->formatLocalized('%d %B %Y %H:%M');
return $item;
}));

Laravel merge logic

In my case i need to use collections together. But also i need that model too. I decided to merge eloquents. Like this:
$products = Product::orderBy('created_at', 'desc')->get();
$sliders = Slider::orderBy('order', 'asc')->get();
$news = News::orderBy('order', 'asc')->get();
$collection = new ModelCollection();
$result = $collection->merge($products)->merge($news)->merge($sliders)->sortByDesc('created_at');
dd($result);
$products has 4 data, $slider also has 4 data, $news has 3 data.
But i am allways get 4 data by sorting created_at. Why i can't get 11 data from the collection?
https://laravel.com/docs/5.6/collections#method-merge
in this case there is no limit or rules.
in the interest of brevity i am trying to make an array with my selected models. If its a collection it keeps model. If its just an array also i need to add the model name for each data collections.
array(
Products > product1,product2,product3,product4
News > news1, news2, news3
Slider > slider1, slider2, slider3
)
If you want all collections in one array you can do by this,
$products = Product::orderBy('created_at', 'desc')->get();
$sliders = Slider::orderBy('order', 'asc')->get();
$news = News::orderBy('order', 'asc')->get();
$result = array();
$result['products'] = $products;
$result['sliders'] = $sliders;
$result['news'] = $news;
This will create collection $result like you want,
array(
products > product1,product2,product3,product4
news > news1, news2, news3
sliders > slider1, slider2, slider3
)
Hope this will help you. Comment if any doubts.

How to paginate a collection after get() in Laravel?

I have a merge on two query results which works fine:
$events1 = \App\Event::Where('valid_to','>=',$today)->orderByRaw('valid_to','ASC')->get();
$events2 = \App\Event::Where('valid_to','<',$today)>orderByRaw('valid_to','ASC')->get();
$events = $events1->merge($events2);
Now I need to paginate this new collection and as suggestted I added this piece:
$page = 1;
$perPage = 60;
$pagination = new \Illuminate\Pagination\LengthAwarePaginator(
$events->forPage($page, $perPage),
$events->count(),
$perPage,
$page
);
EDIT: For future readers, patricus's answer works great and I did that.
best way for paginate collection:
1- add this to boot function in \app\Providers\AppServiceProvider
/**
* Paginate a standard Laravel Collection.
*
* #param int $perPage
* #param int $total
* #param int $page
* #param string $pageName
* #return array
*/
Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
2-From hereafter for all collection you can paginate like this
$events1 = \App\Event::Where('valid_to','>=',$today)->orderByRaw('valid_to','ASC')->get();
$events2 = \App\Event::Where('valid_to','<',$today)>orderByRaw('valid_to','ASC')->get();
$events = $events1->merge($events2);
$events->paginate(5)
You're calling links() and render() on the wrong object. You've assigned the paginator to the $pagination variable. You should be calling
$pagination->links()
or
$pagination->render()
Also, if you'd like to clean this up a little bit, you can modify your query so that you only have one query and don't need to combine two different result sets. You just need to first order on the result of the date comparison, and then order on your valid_to field.
$events = \App\Event::orderByRaw('valid_to < ?', [$today])->orderBy('valid_to')->get();
The date comparison will return a true/false result. In ASC order (default when not specified), true results will come after false results, so rows where the valid_to is less than $today (expired) will come after the rows where valid_to is greater than or equal to $today.
That result set will then be ordered by the valid_to field itself. This one query gives you the same results as the two queries you've manually merged. And, of course, you can just paginate this one query:
$events = \App\Event::orderByRaw('valid_to < ?', [$today])->orderBy('valid_to')->paginate(60);
Now, it is your $events object that is paginated, so you would want to use $events->links() and $events->render().

Resources