Reputation: 9521
Is there a way to get a pagination pretty URL in Laravel 4?
For example, by default:
http://example.com/something/?page=3
And what I would like to get:
http://example.com/something/page/3
Also, the pagination should render this way, and appending to the pagination should appear in this way.
Upvotes: 23
Views: 35591
Reputation: 1147
For Laravel 5.8 use this solution in blade.php where you generate links:
$links = $data->links();
$patterns = '#\?page=#';
$replacements = '/page/';
$one = preg_replace($patterns, $replacements, $links);
$pattern2 = '#page/([1-9]+[0-9]*)/page/([1-9]+[0-9]*)#';
$replacements2 = 'page/$2';
$paginate_links = preg_replace($pattern2, $replacements2, $one);
echo $paginate_links;
Upvotes: 1
Reputation: 9
For anyone that is using laravel version 5.6+
You can pass additional parameters to set the page number.
According to: https://laravel.com/api/5.6/Illuminate/Database/Eloquent/Builder.html#method_paginate
Example:
StoreController.php
/**
* Show sale item based on given page
*
* @param int $page
* @return \Illuminate\Http\Response
*/
public function showPage($page = 1)
{
$saleItems = SaleItem::paginate(10, array('*'), 'page', $page);
...
}
Then, in your blade template. You can just route( ... , array('page' => $page));
Upvotes: 0
Reputation: 1080
hope this is helpful for someone, I've made a trait to be used in models. The idea is that this custom method can detect current route and adjust links to use correct segment position for {page} parameter:
https://gist.github.com/zofe/ced0054e6ac6eff1ea95
Upvotes: 1
Reputation: 111829
It's possible but you need to code a bit.
First you need to change in app/config/app.php
pagination service provider - you need to write your own.
Comment:
// 'Illuminate\Pagination\PaginationServiceProvider',
and add
'Providers\PaginationServiceProvider',
in providers section.
Now you need to create your PaginationServiceProvider to use custom pagination factory:
model/Providers/PaginationServiceProvider.php
file:
<?php
namespace Providers;
use Illuminate\Support\ServiceProvider;
class PaginationServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->bindShared('paginator', function ($app) {
$paginator = new PaginationFactory($app['request'], $app['view'],
$app['translator']);
$paginator->setViewName($app['config']['view.pagination']);
$app->refresh('request', $paginator, 'setRequest');
return $paginator;
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('paginator');
}
}
Above you create Providers\PaginationFactory
object, so now we need to create this file:
model/providers/PaginationFactory.php
file:
<?php
namespace Providers;
use Illuminate\Pagination\Factory;
class PaginationFactory extends Factory {
/**
* Get a new paginator instance.
*
* @param array $items
* @param int $total
* @param int|null $perPage
* @return \Illuminate\Pagination\Paginator
*/
public function make(array $items, $total, $perPage = null)
{
$paginator = new \Utils\Paginator($this, $items, $total, $perPage);
return $paginator->setupPaginationContext();
}
}
Here you create only \Utils\Paginator
object so now let's create it:
model/Utils/Paginator.php
file:
<?php
namespace Utils;
class Paginator extends \Illuminate\Pagination\Paginator {
/**
* Get a URL for a given page number.
*
* @param int $page
* @return string
*/
public function getUrl($page)
{
$routeParameters = array();
if ($page > 1) { // if $page == 1 don't add it to url
$routeParameters[$this->factory->getPageName()] = $page;
}
return \URL::route($this->factory->getCurrentUrl(), $routeParameters);
}
}
In this file we finally override default method for creating pagination urls.
Let's assume you have route defined this way:
Route::get('/categories/{page?}',
['as' => 'categories',
'uses' => 'CategoryController@displayList'
])->where('page', '[1-9]+[0-9]*');
As you see we defined here route name using as
(it's important because of Paginator implementation above - but you can do it of course in different way).
Now in method displayList
of CategoryController
class you can do:
public function displayList($categories, $page = 1) // default 1 is needed here
{
Paginator::setCurrentPage($page);
Paginator::setBaseUrl('categories'); // use here route name and not the url
Paginator::setPageName('page');
$categories = Category::paginate(15);
return View::make('admin.category')->with(
['categories' => $categories]
);
}
When in your view you add:
<?php echo $categories->links(); ?>
you will get generated urls this way:
http://localhost/categories
http://localhost/categories/2
http://localhost/categories/3
http://localhost/categories/4
http://localhost/categories/5
without ? in query string
However in my opinion something like this should be added by default or at least it should be enough to extend one class and not to create 3 classes just to implement one method.
Upvotes: 8
Reputation: 640
Here's a hacky workaround. I am using Laravel v4.1.23. It assumes page number is the last bit of your url. Haven't tested it deeply so I'm interested in any bugs people can find. I'm even more interested in a better solution :-)
Route:
Route::get('/articles/page/{page_number?}', function($page_number=1){
$per_page = 1;
Articles::resolveConnection()->getPaginator()->setCurrentPage($page_number);
$articles = Articles::orderBy('created_at', 'desc')->paginate($per_page);
return View::make('pages/articles')->with('articles', $articles);
});
View:
<?php
$links = $articles->links();
$patterns = array();
$patterns[] = '/'.$articles->getCurrentPage().'\?page=/';
$replacements = array();
$replacements[] = '';
echo preg_replace($patterns, $replacements, $links);
?>
Model:
<?php
class Articles extends Eloquent {
protected $table = 'articles';
}
Migration:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateArticlesTable extends Migration {
public function up()
{
Schema::create('articles', function($table){
$table->increments('id');
$table->string('slug');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
public function down()
{
Schema::drop('articles');
}
}
Upvotes: 14
Reputation: 9007
The only way I can think of doing this is by extending the Paginator class to do the matching. However, just know that it may conflict with third-party packages and other classes/libraries. The current method is designed to work with nearly all classes/libraries/packages.
Perhaps you could try the following:
http://packalyst.com/packages/package/desmart/pagination ('pagination' by 'desmart')
Upvotes: 0