Laravel pagination pretty URL

后端 未结 6 1029
孤街浪徒
孤街浪徒 2020-11-27 19:35

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

相关标签:
6条回答
  • 2020-11-27 20:02

    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

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-11-27 20:09

    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;
    
    
    0 讨论(0)
  • 2020-11-27 20:20

    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');
        }
    }
    
    0 讨论(0)
  • 2020-11-27 20:21

    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')

    0 讨论(0)
  • 2020-11-27 20:23

    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));

    0 讨论(0)
提交回复
热议问题