Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel pagination pretty URL

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.

like image 918
jOpacic Avatar asked Jan 07 '14 14:01

jOpacic


3 Answers

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');
    }
}
like image 93
bitlather Avatar answered Sep 20 '22 10:09

bitlather


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.

like image 31
Marcin Nabiałek Avatar answered Sep 17 '22 10:09

Marcin Nabiałek


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

like image 30
Felice Ostuni Avatar answered Sep 19 '22 10:09

Felice Ostuni