Laravel Pagination the data not change with the render() in the blade - php

I have this problem, when i manually create a paginator in laravel for show 100 products, in the view the page displays the data and it is fine, but if i put a limit , example i want 10 element per page, he show the ten elements in the firs page, when i click in next the second page show me the same ten elements, the data don't changes , why?
Controller:
public function show()
{
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'http://www.mocky.io/v2/59bec4d926000046015261a7',
// You can set any number of default request options.
'timeout' => 2.0,
]);
$response = $client->request('GET', '');
$code = $response->getStatusCode()
$products = json_decode($response->getBody()->getContents());
}
$products = new Paginator($products, 10 ,
Paginator::resolveCurrentPage(),
['path' => Paginator::resolveCurrentPath()]);
return view('products/list', compact('products'));
}
View
#extends('layout.master')
#section('content')
<h2> Products</h2>
<ul>
#if($products)
#foreach($products as $product)
<li> {{ $product->name}} - {{ $product->value}}</li>
#endforeach
#endif
</ul>
{{$products->render()}}
#endsection
Example of Result with array of ten element , 3 per page
// this is a example with invented information.
array {0,1,2,3,4,5,6,7,8,9}
Page 1
0 - 0
1 - 1
2 - 2
Page 2 // the data dont change , why ?
0 - 0
1 - 1
2 - 2

No magic, paginators will call your controller function for every page. The request will have the pagination information in it. It is your job to actually select and slice the page. The paginator simply presents it... which is a big part of the work...
// DB::select returns an array, thus we have to build the paginator ourselves...
$comm = DB::select('select bla bla bla from comments where this and that...
order by approved ASC');
// this basically gets the request's page variable... or defaults to 1
$page = Paginator::resolveCurrentPage('page') ?: 1;
// Assume 15 items per page... so start index to slice our array
$startIndex = ($page - 1) * 15;
// Length aware paginator needs a total count of items... to paginate properly
$total = count($comm);
// Eliminate the non relevant items...
$results = array_slice($comm, $startIndex, 15);
$comments = new LengthAwarePaginator($results, $total, 15, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => 'page',
]);
return view('backend/comments', compact('comments'));

You need to add your page name (the name of the request param denoting the page number) like so:
$products = new Paginator($products, 10, null,
['path' => Paginator::resolveCurrentPath(),
'pageName' => 'page']);

I had the same problem, where the data was not changing. I solved it by passing a page number to my guzzle call. Whenever a link is clicked, a request is sent therefore, you can get the page number from the request object. Pass the page number to the guzzle call so that the page number changes. Hope It helps

Related

Google Cloud Storage paginate objects in a bucket (PHP)

I want to iterate over the objects in a bucket. I REALLY need to paginate this - we have 100's of thousands of objects in the bucket. Our bucket looks like:
bucket/MLS ID/file 1
bucket/MLS ID/file 2
bucket/MLS ID/file 3
... etc
Simplest version of my code follows. I know the value I'm setting into $params['nextToken'] is wrong, I can't figure out how or where to get the right one. $file_objects is a 'Google\Cloud\Storage\ObjectIterator', right?
// temp: pages of 10, out of a total of 100. I really want pages of 100
// out of all (in my test bucket, I have about 700 objects)
$params = [
'prefix' => $mls_id,
'maxResults' => 10,
'resultLimit' => 100,
'fields' => 'items/id,items/name,items/updated,nextPageToken',
'pageToken' => NULL
];
while ( $file_objects = $bucket->objects($params) )
{
foreach ( $file_objects as $object )
{
print "NAME: {$object->name()}\n";
}
// I think that this might need to be encoded somehow?
// or how do I get the requested nextPageToken???
$params['pageToken'] = $file_objects->nextResultToken();
}
So - I don't understand maxResults vs resultLimit. It would seem that resultLimit would be the total that I want to see from my bucket, and maxResults the size of my page. But maxResults doesn't seem to affect anything, while resultLimit does.
maxResults = 100
resultLimit = 10
produces 10 objects.
maxResults = 10
resultLimit = 100
spits out 100 objects.
maxResults = 10
resultLimit = 0
dumps out all 702 in the bucket, with maxResults having no effect at all. And at no point does "$file_objects->nextResultToken();" give me anything.
What am I missing?
The objects method automatically handles pagination for you. It returns an ObjectIterator object.
The resultLimit parameter limits the total number of objects to return across all pages. The maxResults parameter sets the maximum number to return per page.
If you use a foreach over the ObjectIterator object, it'll iterate through all objects, but note that there are also other methods in ObjectIterator, like iterateByPage.
Ok, I think I got it. I found the documentation far too sparse and misleading. The code I came up with:
$params = [
'prefix' => <my prefix here>,
'maxResults' => 100,
//'resultLimit' => 0,
'fields' => 'items/id,items/name,items/updated,nextPageToken',
'pageToken' => NULL
];
// Note: setting 'resultLimit' to 0 does not work, I found the
// docs misleading. If you want all results, don't set it at all
// Get the first set of objects per those parameters
$object_iterator = $bucket->objects($params);
// in order to get the next_result_token, I had to get the current
// object first. If you don't, nextResultToken() always returns
// NULL
$current = $object_iterator->current();
$next_result_token = $object_iterator->nextResultToken();
while ($next_result_token)
{
$object_page_iterator = $object_iterator->iterateByPage();
foreach ($object_page_iterator->current() as $file_object )
{
print " -- {$file_object->name()}\n";
}
// here is where you use the page token retrieved earlier - get
// a new set of objects
$params['pageToken'] = $next_result_token;
$object_iterator = $bucket->objects($params);
// Once again, get the current object before trying to get the
// next result token
$current = $object_iterator->current();
$next_result_token = $object_iterator->nextResultToken();
print "NEXT RESULT TOKEN: {$next_result_token}\n";
}
This seems to work for me, so now I can get to the actual problem. Hope this helps someone.

CakePHP 3 giving wrong pagination output when limit is changed for a custom finder

CakePHP 3.7.7
I'm using the Paginator (https://book.cakephp.org/3.0/en/views/helpers/paginator.html) to display pagination for a query that has 972 rows.
In my Controller method I am loading the Paginator component and using a custom finder called findFilters() to return the data that I want paginated.
public function initialize()
{
parent::initialize();
$this->loadComponent('Paginator');
}
public $paginate = [
'finder' => 'filters', // uses custom finder, findFilters() in src/Model/Table/FiltersTable.php
];
/*
* Called via ajax. Renders the data and pagination to a template.
*/
public function getFilters()
{
$this->viewBuilder()->setLayout('ajax');
$this->loadModel('Filters');
$rf_keywords = '';
$rf_keywords = trim($this->request->getData('rf_keywords'));
// Pagination settings (relevant to the question).
$page = $this->request->getData('page') ? (int)$this->request->getData('page') : 1;
$this->paginate = ['limit' => 200, 'page' => $page];
$finder = $this
->Filters
->find('filters' , [
'rf_keywords' => $rf_keywords
]);
$data = $this
->paginate($finder)
->toArray();
$this->set('data', $data);
}
In my template (get_filters.ctp) I have the following to output the pagination numbers (links to be clicked to go between pages) and the total counts:
<?= $this->Paginator->numbers(); ?>
<?= $this->Paginator->counter([
'format' => 'Page {{page}} of {{pages}}, showing {{current}} records out of
{{count}} total, starting on record {{start}}, ending on {{end}}'
]) ?>
The problem is that changing the limit in the Controller...
$this->paginate = ['limit' => 200];
... is not updating the output of the Pagination correctly. See examples below:
'limit' => 20:
Shows page numbers 1 - 9 and:
Page 1 of 49, showing 20 records out of 972 total, starting on record 1, ending on 20
'limit' => 100:
Shows page numbers 1 - 9 and:
Page 1 of 10, showing 100 records out of 972 total, starting on record 1, ending on 100
'limit' => 500:
Shows page numbers 1 - 9 and:
Page 1 of 10, showing 100 records out of 972 total, starting on record 1, ending on 100
'limit' => 1000 (more than there are rows in the DB!):
Shows page numbers 1 - 9 and:
Page 1 of 10, showing 100 records out of 972 total, starting on record 1, ending on 100
So there are 2 problems:
It doesn't work with any limit value >100. Nothing changes in terms of the pagination output in the template. The behaviour is as though it is ignoring anything supplied as the limit and defaulting to 100.
The page number links ($this->Paginator->numbers();) are always 1 - 9 when the limit is >100. That is to say they stay the same irrespective of whether I use a limit of 100, 200, 500, 1000. I'm guessing this is due to problem (1) where it seems to ignore the actual limit set if it's >100.
I thought this was some caching issue. The ajax requests to getFilters() are being made via jquery so I have set cache: false on them to ensure each request appends a timestamp to the URL to ensure it's not using some old cached response.
I have cleared the files in tmp/cache/models/*
I've a force refresh in the browser. Tried an incognito/private browsing window to make sure it's not some session issue.
None of these things solve the problem.
The issue is also consistent if the page part of Pagination is altered. For example using page => 3 will give the correct rows from the database for page 3. But the Pagination HTML will still be exactly the same as where the problem occurs.
Why isn't this working?
Edit - the custom Finder returns the correct data so I don't think this is an issue. The signature is below and it returns a Query object which is executed via Pagination:
// src/Model/Table/FiltersTable.php
public function findFilters(Query $query, array $options)
{
// $query->find() ...
// ...
return $query;
}
Bit late, but the problem is with default maxLimit settings for CakePHP 3 pagination, what is set to 100 by default (reference below).
https://book.cakephp.org/3/en/controllers/components/pagination.html#limit-the-maximum-number-of-rows-per-page
When you update settings in Controller to, it should do the trick.
public $paginate = [
// Other keys here.
'maxLimit' => 1000
];

Laravel 5 pagination links

I have a laravel 5 application in which I`m trying to do a pagination for certain results (array of results not collection).
This is my code:
$paginator = new LengthAwarePaginator(
$l_aResponse['body'],
count($l_aResponse['body']),
'2',
Paginator::resolveCurrentPage(),
['path' => Paginator::resolveCurrentPath()]
);
return str_replace('/?', '?', $paginator->render());
My question is: is there a way to modify the way in which the "page" parameter is setup in the URL for pages? EG: I don't want this format: http://localsite/articles?page=3 but I want http://localsite/articles/3
I`ll appreciate any answer. Thanks!
The __construct() function of the LengthAwarePaginator class has a few parameters:
$items
$total
$perPage
$currentPage = null
array $options = []
As you can see the fourth parameter represents the current page.
So you can use a custom desired current page which has been retrieved from the last parameter from the url. An example would be:
// http://localsite/articles/3
$currentPage = ... // Get parameter from url
$paginator = new LengthAwarePaginator(
$l_aResponse['body'],
count($l_aResponse['body']),
'2',
$currentPage, // Current page as fourth parameter
['path' => Paginator::resolveCurrentPath()]
);
return str_replace('/?', '?', $paginator->render());
Have not tested this. Hope it helps :)

Use of manual pagination "$perPage" parameter

So I've been working on a pagination system that pulls data externally, after finally figuring out through trial and error I got the solution that works. While going through it something struck me as odd, as per the documentation $paginator = Paginator::make($items, $totalItems, $perPage);
I was wondering what's the actual use of the $perPage parameter? You would think that what ever number is specified would show that many items. But with manual pagination you have to limit the results that are passed into $items in order for it to work, otherwise you get the output of all items (as shown in code block below). Is manual pagination flawed? because if $perPage doesn't match the total number of items in the array $items it shows everything.
Example: Paginator::make( array('10xarray') ), 10, 2); it would show 5 pages with 2 items per page? where in reality it actually shows 10 items with 5 pages that all show the same 10 items.
<?php
class MainController extends BaseController {
public function library()
{
$this->layout->title = 'testing';
$this->layout->main = View::make('library/layout');
// Pagination data
$media = array(
array('title' => 'test'),
array('title' => 'test'),
array('title' => 'test'),
array('title' => 'test')
);
$perPage = 2;
$currentPage = Input::get('page', 1);
$pagedData = array_slice($media, ($currentPage - 1) * $perPage, $perPage);
$this->layout->main->paginated = Paginator::make($pagedData, count($media), $perPage);
if(Request::ajax()) {
return Response::json(
View::make(
'library/layout',
array('paginated' => $this->layout->main->paginated)
)->render()
);
}
}
}
it isn't flawed. it is intended behavior.
this manual paginator is just a container. nothing more, nothing less. how you implement it, is upon you.
without a LIMIT query, you can never do a pagination. when you use pagination(), laravel does the work under the hood. when you go for manual, you have to do it manually and get greater control.
why do you think it is called manual pagination in the first place?

cakePHP, page to a certain record

Is there a way to open directly the page in which a record appears?
Example:
function index($id){
$this->paginate = array(
'limit'=>12,
'page' => ????
);
$items = $this->Item->paginate();
/**
How can i calculate the page number, by the $id?
*/
}
If you got the ID, and you are auto_incrementing the ID in your database, you can count row before this ID:
$nbRow = $this->Item->find('count', array('conditions' => array('id <=' => $id))) ;
Then to find the page, you just have to divide (int division) by the number of item per page:
$page = ceil($nbRow / 12) ; // 12 or whatever item per page you have

Categories