My Laravel pagination output is like laravel pagination used to be, but I need to change the data array for each object.
My output is:
As you can see, the data object has 2 items, which I need to change.
My code is:
$items = $this->items()
->where('position', '=', null)
->paginate(15);
Which returns the user items with pivot table, but I don't like the way the pivot table is shown in the JSON, so I decided to change the items and organize each item with the pivot before the item.
For this purpose, I tried to use foreach
foreach ($items->data as $item)
{
}
which giving my an error, for a reason I don't know:
Undefined property: Illuminate\Pagination\LengthAwarePaginator::$data"
status_code: 500
Any help?
The paginator's items is a collection. You can grab it and transform the data like so:
$paginator = $this->items()->where('position', '=', null)->paginate(15);
$paginator->getCollection()->transform(function ($value) {
// Your code here
return $value;
});
If you are familiar with tap helper here is the snippet that does exact same.
$paginator = tap($this->items()->where('position', '=', null)->paginate(15),function($paginatedInstance){
return $paginatedInstance->getCollection()->transform(function ($value) {
return $value;
});
});
We can't chain method getCollection to paginator instance because AbstractPaginator will return paginator's underlying collection. so the paginator instance will be transformed to Collection. So fix that we can use tap helper.
If you'd like to keep items paginated:
$itemsPaginated = $this->items()
->paginate(15);
$itemsTransformed = $itemsPaginated
->getCollection()
->map(function($item) {
return [
'id' => $item->id,
];
})->toArray();
$itemsTransformedAndPaginated = new \Illuminate\Pagination\LengthAwarePaginator(
$itemsTransformed,
$itemsPaginated->total(),
$itemsPaginated->perPage(),
$itemsPaginated->currentPage(), [
'path' => \Request::url(),
'query' => [
'page' => $itemsPaginated->currentPage()
]
]
);
There is a setCollection method for such purpose.
$items = Model::paginate(10);
$updatedItems = $items->getCollection();
// data manipulation
// ...
$items->setCollection($updateItems);
From the source code of /Illuminate/Pagination/AbstractPaginator.php
/**
* Set the paginator's underlying collection.
*
* #param \Illuminate\Support\Collection $collection
* #return $this
*/
public function setCollection(Collection $collection)
{
$this->items = $collection;
return $this;
}
Source
I could make shorter way. This returns edited $array instead of simple $paginated. This example modify file names.
This doc was useful for me.
$paginated=$query->paginate(12);
$array=$paginated->toArray();
foreach ($array['data'] as $r=>$record) {
$array['data'][$r]->gif=$array['data'][$r]->gif.".gif";
}
return $array;
Sample Example :
$franchiseData=[ 'id'=>1 ,'name'=>'PAnkaj'];
$models = $bookingsQuery->paginate(10);
$models->setCollection(collect($franchiseData));
return $models;
Note that $models->setCollection(collect($franchiseData)); you have to use collect() else you will get error.
getCollection
is one way to get the items. Another way is to use this
For ex- Assuming, user doesn't have name param and only have first_name and last_name
$userPaginatedData = User::paginate(15);
$users = $userPaginatedData->items();
foreach($users as $user) {
$user->name = $user->first_name . ' ' . $user->last_name;
}
return $userPaginatedData;
Now in the data key, you would see that each user has name param with it.
Laravel 8.9.0 has added the through method to AbstractPaginator.
It transforms each item in the slice of items using a callback, and keeps the items paginated.
$paginator = $this->items()->where('position', '=', null)->paginate(15);
$paginator->through(function ($value) {
// Your code here
return $value;
});
The source code:
/**
* Transform each item in the slice of items using a callback.
*
* #param callable $callback
* #return $this
*/
public function through(callable $callback)
{
$this->items->transform($callback);
return $this;
}
-Laravel 5.4
// example update column "photo"
// from "/path/to/photo.png"
// to "abc.com/path/to/photo.png"
foreach ($items as $item)
{
$path = $item->photo;
// Remove
$item->offsetUnset("photo");
// Set
$item->offsetSet("photo", url($path));
}
Laravel AbstractPaginator has methods setCollection() and getCollection()
<?php
$itemsPaginated = $this->items()->paginate(15);
$itemsPaginated->setCollection(
$itemsPaginated->getCollection()->transform(function ($item) {
// Your code here
return $item;
})
)
This is your paginated items...
$items = $this->items()
->where('position', '=', null)
->paginate(15);
I am using Laravel 8, can simply use each
$items->each(function ($item) {
// your code here
$item->custom_data = calcSomeData(); // sample
});
It does the same as this...
$items->getCollection()->transform(function ($item) {
// your code here
$item->custom_data = calcSomeData(); // sample
});
<?php
$itemsPaginated = $this->items()->paginate(15);
$itemsPaginated = json_encode($itemsPaginated);
foreach ($itemsPaginated->data as $key => $item) {
$results->data[$key]; //Modify
}
$itemsPaginated = json_encode($results);
you have to use below code in your blade
{!! $items->render() !!}
Ignore the pagination in laravel and hit the normal data
foreach ($items as $item)
{
}
Related
i have object given below and i wanted to pagination in this how can i get
$productListArray = array();
$productListObject = ((object)[
"id"=>$productList->id,
"title"=>$productList->title,
"slug"=>$productList->slug,
'categoryName'=>$categoryName[0]->cat_title,
'brand'=>$brandName[0]->brandname,
'minMrp'=>$minMrp,
'maxMrp' =>$maxMrp,
'minSellingPrice' => $minSellingPrice,
'maxSellingPrice' => $maxSellingPrice,
'rating'=>$productList->rating,
'rating_count' => $productList->rating_count,
'image' => $img[0]
])->paginate();
array_push($productListArray, $productListObject);
}
return response()->json($productListArray, 200);
Hi you can get the Current page using laravel paginator Paginator::currentPageResolver
public function index()
{
$currentPage = 3; // You can set this to any page you want to paginate to
// Make sure that you call the static method currentPageResolver()
// before querying users
Paginator::currentPageResolver(function () use ($currentPage) {
return $currentPage;
});
$users = \App\User::paginate(5);
return view('user.index', compact('users'));
}
thanks for your support i found solution,
first add on your header
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
then make an other function
public function paginate($items, $perPage = 5, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
after than call this function where you want in class
$data = $this->paginate($productListArray);
return response()->json($data, 200);
last 2 lines already mentioned in my questions
thanks again
I am new in Laraver, I am using Eloqunet model... deleteItem function, delete item with offer_in and nbr...When delete item I want to add a new nbr from each item with equal offer_id, starting from 1. I need to define counter = 1, and increase by 1 for every item.. I don't know how to write a for loop, or foreach loop, which pass through selected item, and change 'nbr' with the corresponding value of the counter?
my code is:
public function deleteItem(Request $request, $offer_id, $nbr) {
$item = OfferItem::select('id', 'offer_id', 'nbr', 'product', 'quantity', 'item_price', 'item_tax', 'item_total')
->where('offer_id', $offer_id)
->where('nbr', $nbr)
->first();
$item->delete();
//select new items for offer, after deleting item
$items = OfferItem::select('id', 'offer_id', 'nbr', 'product', 'quantity', 'item_price', 'item_tax', 'item_total')
->where('offer_id', $offer_id)
->get();
//todo
return response()->json($item);
}
Using the Laravel collections, you can just loop the collection and set new count to nbr. Using $count as a reference for the closure, to make the logic work.
$int = 1;
$items->each(function (OfferItem $item) use (&$count) {
$item->nbr = $count;
$item->save();
$count++;
});
You can achieve this purely in SQL like in these examples.
You can achieve what you want using Laravel by:
public function deleteItem(Request $request, $offer_id, $nbr) {
OfferItem::query()
->where('offer_id', $offer_id)
->where('nbr', $nbr)
->delete();
// Select new items for offer, after deleting item
$items = OfferItem::where('offer_id', $offer_id)
->where('nbr', '>', $nbr)
->get()
->sortBy('nbr')
->map(function ($item) use ($nbr) {
$update = [
'id' => $item->id,
'nbr' => $nbr,
];
$nbr++;
return $update;
});
OfferItem::query()->update($items);
return response()->json($item); // It is not clear from your question what you
// are trying to return here. Why would you
// return a deleted item?
}
So i work with Laravel, and i use Laravel excel to load excel/csv files, but my files contains empty rows and i want to delete every empty row.
this is my code :
Excel::selectSheetsByIndex(0)->load($path, function($reader){
$results = $reader->noHeading()->toArray();
foreach ($results as $row) {
//my code
}
}, 'UTF-8');
So please if someone has any idea how i can do that i will be very appreciative
I think you can do it in this way
/** #var LaravelExcelReader $data */
$data = \Excel::load('file.xls', function ($reader) {
$reader->limitRows(20);
$reader->ignoreEmpty();
})->get()->toArray();
# remove empty rows
$data = array_filter($data);
use ToCollection method the wrap everything within if($row->filter()->isNotEmpty())
public function collection(Collection $rows)
{
foreach($rows as $row) {
if($row->filter()->isNotEmpty()){
// you logic can go here
$user = User::create([
'name' => ucwords($row['name']),
'class' => $row['class'],
...
]);
}
}
}
I'm building an application using Laravel 4.2. I have a model for units and another for users and pivot table user_units. Every user in this application can select a unit and add it to his favorite list then he can publish this unit with his information as an ad.
I want to select all units published by all users
The user_units (pivot) table has the following columns:
id
user_id
unit_id
publish
adtype
addinfo
created_at
updated_at
With relations methods on models
public function users() {
return $this->belongsToMany('User', 'user_units')
->withPivot('id','publish', 'adtype', 'addinfo');
}
public function units() {
return $this->belongsToMany('Unit', 'user_units')
->withPivot('id','publish', 'adtype', 'addinfo');
}
My query to select all published units by all users
// Get all published units by users for sale.
$users = User::all();
$publishedSaleUnits = [];
foreach($users as $user){
$userUnits = $user->units()->orderBy('adtype', 'desc')->get();
if(count($userUnits)){
foreach($userUnits as $unit){
if($unit->pivot->publish == 1 && $unit->unit_purpose_id == 1){
if( $unit->pivot->adtype ){
//push all featured ads onto the beginning of array
array_unshift($publishedSaleUnits, $unit);
}else{
//push all normal ads onto the end of array
array_push($publishedSaleUnits, $unit);
}
}
}
}
}
Now I got the result but I can't use pagination with results because it's an array of objects.
So is there any better solution to get all published units by user with pagination?
according to this article
https://www.itsolutionstuff.com/post/how-to-create-pagination-from-array-in-laravelexample.html
you can paginate your array by creating a custom method and using LengthAwarePaginator
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
class PaginationController extends Controller
{
public function index()
{
$myArray = [
['id'=>1, 'title'=>'Laravel CRUD'],
['id'=>2, 'title'=>'Laravel Ajax CRUD'],
['id'=>3, 'title'=>'Laravel CORS Middleware'],
];
$data = $this->paginate($myArray);
return view('paginate', compact('data'));
}
public function paginate($items, $perPage = 5, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
}
Your approach to query the data is extremely inefficient. Fetch your data in one query. Nested traversing is not only hard to read but also a performance killer.
To the pagination problem:
Laravel provides a Pagignator Factory. With it you will be able to build your own Paginator with your own data.
It's as easy as
$units = Paginator::make($unit, count($unit), 10);
if you're using the Facade. Otherwise Illuminate\Pagination\Factory is the class you are looking for.
You can try my code with your own array,
$page = isset($request->page) ? $request->page : 1; // Get the page=1 from the url
$perPage = $pagination_num; // Number of items per page
$offset = ($page * $perPage) - $perPage;
$entries = new LengthAwarePaginator(
array_slice($contact_list, $offset, $perPage, true),
count($contact_list), // Total items
$perPage, // Items per page
$page, // Current page
['path' => $request->url(), 'query' => $request->query()] // We
need this so we can keep all old query parameters from the url
);
I got a better solution to paginate array result and I found the answer here
Paginator::make function we need to pass only the required values instead of all values. Because paginator::make function simply displays the data send to it. To send the correct offset paginated data to the paginator::make, the following method should be followed
$perPage = 5;
$page = Input::get('page', 1);
if ($page > count($publishedSaleUnits) or $page < 1) { $page = 1; }
$offset = ($page * $perPage) - $perPage;
$perPageUnits = array_slice($publishedSaleUnits,$offset,$perPage);
$pagination = Paginator::make($perPageUnits, count($publishedSaleUnits), $perPage);
this code work for me on laravel 8
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
public function paginate($items, $perPage = 5, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
according to this refrence https://www.itsolutionstuff.com/post/how-to-create-pagination-from-array-in-laravelexample.html
I been trying for hours now to successfully rewrite Magento's build-in Autosuggest Function so it displays productnames instead of query history entries. I want nothing fancy, no product pictures and whatnot, just plain product name suggestions.
So to get the productnames, I created under app/code/local/Aw the folder CatalogSearch/Model and there created a file named Query.php. Inside that file I have the following class and rewritten method:
class Aw_CatalogSearch_Model_Query
extends Mage_CatalogSearch_Model_Query {
public function getSuggestCollection() {
$collection = $this->getData('suggest_collection');
if (is_null($collection)) {
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('name', array('like' =>
'%'.$this->getQueryText().'%'))
->addExpressionAttributeToSelect('query_text', '{{name}}', 'name')
->addAttributeToSort('name', 'ASC')
->setPageSize(10)
->addStoreFilter($this->getStoreId());
$this->setData('suggest_collection', $collection);
}
return $collection;
}
};
I created the module xml file in app/etc/modules/ and the module configuration in app/code/local/Aw/CatalogSearch/etc/config.xml
All good so far, the overwritten method getSuggestCollection() is executed.
The problem comes in app/code/core/Mage/CatalogSearch/Block/Autocomplete.php, in the getSuggestData() method.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
When it iterates over the collection, I get a
Call to a member function getQueryText() on a non-object ...
The point I do not understand is that I have defined an alias field named 'query_text' in the collection query inside the getSuggestCollection() method. Even when I used something like getData('query_text') or $item->getQuery_text() to get the data of this field is not working.
I have the strong feeling, that the collection object is not valid as it supposed be within the getSuggestData() method of Mage_CatalogSearch_Block_Autocomplete class.
Can anybody point me out how to solve this issue? Is it not possible as above way to gather suggestions from the products collection and pass these to Autocomplete.php?
This is my first magento project, so please bear with me! I am really lost on this one!
Any hint is greatly apprecitated.
Using Magento 1.7.0.2 for this project.
Well, I found a solution. For anyone who might be interested in this, the problem stated in my question is located in the following lines
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection() ... // continue method chaining ...
I changed the code, so that the constructor and methods are chained all together, like this:
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('name') ... // continue method chaining
...
I added the filters for product_status, cataloginventory/stock and catalog/product_visibility with singleton calls right after the collection is available
In that way, everything works as expected.
For anyone else wanting to do something similar, I just rewrote app/code/core/Mage/CatalogSearch/Block/Autocomplete.php to my own module and made the search results query the sku and return product names. Your mileage may vary, however, my sku codes are sensible names rather than random digits so this worked for me.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
// Get products where the url matches the query in some meaningful way
$products = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('type_id', 'configurable')
->addAttributeToFilter('sku',array('like'=>'%'.$query.'%'))
->load();
foreach($products as $product) {
$_data = array(
'title' => $product->getName(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => 1
);
// if ($item->Name() == $query) {
// array_unshift($data, $_data);
// }
// else {
$data[] = $_data;
// }
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
I did not need to rewrite Mage_CatalogSearch_Model_Query, just the code for the suggestions.