صفحه بندی در لاراول

350

صفحه بندی (pagination)

  1. مقدمه
  2. کاربرد پایه
    • صفحه بندی نتایج Query Builder
    • صفحه بندی نتایج Eloquent
    • نحوه ی ایجاد یک Paginator به صورت دستی
  3. نمایش نتایج در یک view
  4. تبدیل نتایج به فرمت JSON

مقدمه

صفحه بندی یا Pagination در اغلب framework ها بسیار دشوار می باشد. Laravel این عملیات را به صورت چشم گیری آسان می سازد، به گونه ای که قادر است با سرعت باور نکردنی یک سری لینک هوشمند بر اساس صفحه ی جاری ایجاد کنید. HTML خروجی با فریم ورک bootstrap کاملا سازگار خواهد بود.

کاربرد پایه

صفحه بندی نتایج Query Builder

روش های مختلفی برای صفحه بندی (paginate) آیتم ها وجود دارد که آسان ترین آن فراخوانی متد paginate در query builder یا یک کوئریEloquent است. این متد که توسط Laravel ارائه می شود خود به صورت اتوماتیک عملیات تنظیم limit (محدوده) و offset (فاصله ی صفحه ی اول تا صفحه ی جاری) را بر مبنای صفحه ی جاری (مورد مشاهده ی کاربر) بر عهده می گیرد. به صورت پیش فرض، صفحه ی جاری با توجه به مقدار آرگومان کوئری استرینگ ?page در درخواست HTTP تشخیص داده می شود. ناگفته مشخص است که این مقدار به صورت خودکار توسط Laravel شناسایی شده و به نیز به صورت اتوماتیک داخل لینک های تولید شده توسط paginator درج می گردد.
ابتدا توجه خود را به فراخوانی متد paginate در یک کوئری ساده جلب می کنیم. در این مثال تنها آرگومان ارسالی به متد paginate تعداد آیتم هایی است که شما می خواهید به ازای هر صفحه نمایش داده شود. در نمونه ی زیر مقدار 15 را به عنوان آرگومان پاس می دهیم که نشانگر نمایش 15 آیتم در هر صفحه می باشد:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
namespace App\Http\Controllers;
use DB;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
   /**
    * Show all of the users for the application.
    *
    * @return Response
    */
   public function index()
   {
       $users = DB::table('users')->paginate(15);
  
       return view('user.index', ['users' => $users]);
   }
}
نکته:

در حال حاضر عملیات pagination که از دستور groupBy استفاده می کنند به راحتی و روشی بهینه توسط Laravel قابل اجرا نیستند. اگر که بایستی دستور groupBy را برای گروه بندی مجموعه ننتایج صفحه گذاری شده اجرا نمایید، توصیه می شود از پایگاه داده کوئری گرفته و سپس یکpaginator به صورت دستی ایجاد نمایید.

" صفحه بندی ساده "

اگر می خواهید فقط لینک های "Next" و "Previous" را در view مربوط به صفحه بندی (pagination view) خود نمایش دهید، در آن صورت می توانید متد simplePaginate را برای تنظیم و اجرای یک query بهینه تر فراخوانی نمایید. این امکان به خصوص در زمان کار با dataset های بزرگ و در شرایطی که لزومی ندارد به هنگام اجرای view، به ازای هر شماره صفحه یک لینک نمایش داده شود، مفید واقع می شود:

1
$users = DB::table('users')->simplePaginate(15);

صفحه بندی نتایج Eloquent

می توانید کوئری های Eloquent را صفحه بندی (paginate) نمایید. در این مثال مدل User را با 15 آیتم به ازای هر صفحه paginate می کنیم. همان طور که می بینید، سینتکس این مثال تفاوت چندانی با سینتکس صفحه بندی نتایج query builder ندارد:

1
$users = App\User::paginate(15);

البته می توانید متد paginate را پس از اعمال دیگر constraint ها (قیود و محدودیت ها) در کوئری مربوطه همچون عبارت where، صدا بزنید:

1
$users = User::where('votes', '>', 100)->paginate(15);

همچنین می توانید متد simplePaginate را در زمان صفحه بندی مدل های Eloquent مانند زیر فرابخوانید:

1
$users = User::where('votes', '>', 100)->simplePaginate(15);

نحوه ی ایجاد یک paginator به صورت دستی

گاهی با توجه نیاز خود ممکن است لازم شود یک نمونه pagination به صورت دستی ایجاد نموده و آرایه ای از آیتم ها را به عنون پارامتر به آن پاس دهید. برای این منظور کافی است بر اساس نیاز خود یک نمونه از کلاس Illuminate\Pagination\Paginator یاIlluminate\Pagination\LengthAwarePaginator ایجاد نمایید.
لزومی ندارد کلاس Paginator از تعداد کل آیتم های موجود در مجموعه نتایج آگاهی داشته باشد. اما به همین خاطر هم کلاس مورد نظر نیز هیچ متدی برای بدست آوردن شماره (اندیس) آخرین صفحه ندارد. LengthAwarePaginator تقریبا همان آرگومان هایی را که به Paginator ارسال می شود را به عنوان ورودی دریافت می کند، اما علاوه بر آن تعداد کل آیتم های موجود در مجموعه نتایج را نیز می طلبد.
به عبارت دیگر، می توان گفت که Paginator به گونه ای معادل متد simplePaginate در query builder و Eloquent بوده و با آن همخوانی دارد. این در حالی است که LengthAwarePaginator به نحوی معادل متد paginate تلقی می شود.
در زمان ایجاد یک نمونه از paginator به صورت دستی، توصیه می شود حتما تابع array slice را بر روی نتایج که به صورت آرایه به عنوان آرگومان به نمونه ارسال می کنید، فراخوانی نموده و نتایج را به صورت دستی " slice " کنید (این تابع بخشی از یک آرایه را برش داده و در خروجی برمی گرداند).

نمایش نتایج در یک view

با فراخوانی متدهای paginate یا simplePaginate در query builder یا کوئری Eloquent، یک نمونه از کلاس paginator در خروجی دریافت می کنید. با فراخوانی متد paginate نمونه ای از Illuminate\Pagination\LengthAwarePaginator را به عنوان خروجی دریافت می کنید. با فراخوانی متد simplePaginate یک نمونه شی از کلاس Illuminate\Pagination\Paginator دریافت می کنید. این نمونه اشیا توابع متعددی را ارائه می کنند که توصیفی از مجموعه نتایج در اختیار قرار می دهد. علاوه بر این توابع کمکی (helper function)، نمونه های ایجاد شده ازpaginator در واقع iterator هستند و می توان مانند آرایه در آن ها حلقه زد.
پس از بازیابی نتایج، می توان به واسطه ی موتور Blade آن ها را در view نمایش داده و لینک های صفحه را render کرد:

1
2
3
4
5
6
<div class="container">
   @foreach ($users as $user)
       {{ $user->name }}
   @endforeach
</div>
{!! $users->links() !!}

متد links در مثال بالا لینک ها را در بقیه ی صفحات موجود در مجموعه نتایج نمایش می دهد (render می کند). تمامی این لینک ها از قبل متغیر کوئری استرینگ ?page مربوطه را دارند. لازم به تکرار نیست که HTML خروجی متد یاد شده کاملا با فریم ورک Bootstrap سی اس اس سازگار می باشد.

تنظیم URI مورد استفاده ی paginator

متد setPath به شما امکان می دهد تا URI مورد استفاده ی paginator(به هنگام لینک سازی) را سفارشی تنظیم نمایید. به عنوان مثال، اگر می خواهید paginator لینک هایی مثل http://example.com/custom/url?page=N تولید کند، لازم استcustom/url را به عنوان آرگومان به متد setPath ارسال نمایید:

1
2
3
4
5
Route::get('users', function () {
   $users = App\User::paginate(15);
   $users->setPath('custom/url');
   //
});

الحاق کردن query string به لینک های صفحه بندی

می توان با بهره گیری از متد appends متغیر query string جدید به لینک ها پویست نمود. به عنوان مثال به منظور افزودن متغیر &sort=votesبه تک تک لینک های صفحه بندی، می بایست متد appends را به صورت زیر فراخوانی نمایید:

1
{!! $users->appends(['sort' => 'votes'])->links() !!}

برای افزودن یک "hash fragment" به یو آر ال paginator بایستی متد fragment را صدا بزنید. به عنوان نمونه می خواهیم #foo را به انتهای هر یک از لینک های صفحه بندی الصاق کنیم. برای این منظور کافی است تابع fragment را مانند زیر فراخوانی کنید:

1
{!! $users->fragment('foo')->links() !!}

دیگر توابع کمکی

برای دسترسی به اطلاعات بیشتر در خصوص pagination می توان توابع helper زیر را در نمونه های paginator فراخوانی کرد:

1
2
3
4
5
6
7
8
9
10
11
$results->count()
$results->currentPage()
$results->firstItem()
$results->hasMorePages()
$results->lastItem()
$results->lastPage() (Not available when using simplePaginate)
$results->nextPageUrl()
$results->perPage()
$results->previousPageUrl()
$results->total() (Not available when using simplePaginate)
$results->url($page)

تبدیل نتایج به فرمت JSON

کلاس های صفحه بندی نتایج (paginator result) لاراول همگی، کانترکت (contract)Illuminate\Contracts\Support\JsonableInterface را پیاده سازی کرده و متد tojson را در اختیار ما قرار می دهند (expose می کنند). از این رو به راحتی می توان نتایج pagination را به فرمت JSON تبدیل کرد.
همچنین می توان یک نمونه از کلاس paginator را به JSON تبدیل کرد. برای این منظور کافی است نمونه ی paginator را از یک route یا متد اکشن controller به عنوان خروجی برگردانید:

1
2
3
Route::get('users', function () {
   return App\User::paginate();
});

نسخه ی تبدیل شده به جیسون paginator حاوی meta information هایی نظیر total (تعداد کل آیتم ها)، current page (صفحه ی جاری)،last page (آخرین صفحه) و غیره ... خواهد بود. برای دسترسی به خود اشیا می بایست از کلید data در آرایه ی JSON بهره گرفت.در زیر نمونه ای از کلاس مزبور را که به فرمت json تبدیل شده، مشاهده می کنید:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "total": 50,
  "per_page": 15,
  "current_page": 1,
  "last_page": 4,
  "next_page_url": "http://laravel.app?page=2",
  "prev_page_url": null,
  "from": 1,
  "to": 15,
  "data":[
       {
           // Result Object
       },
       {
           // Result Object
       }
  ]
}



از مجموع 1 رأی

فاقد نظر