ページネーション
CodeIgniterは、シンプルながらも柔軟なページネーションライブラリを提供します。テーマ設定が容易で、モデルと連携し、単一ページで複数のページネーターをサポートできます。
ライブラリの読み込み
CodeIgniterの他のサービスと同様に、Config\Services
を介して読み込むことができますが、通常は手動で読み込む必要はありません。
<?php
$pager = \Config\Services::pager();
モデルを使用したページネーション
ほとんどの場合、データベースから取得した結果をページネーションするために、Pagerライブラリを使用します。Modelクラスを使用する場合、組み込みのpaginate()
メソッドを使用して、現在のバッチの結果を自動的に取得し、Pagerライブラリを設定してコントローラーで使用できるようにすることができます。page=X
クエリ変数を使用して、現在のURLから表示する必要がある現在のページを読み取ります。
アプリケーションにユーザーのページネーションされたリストを提供するには、コントローラーのメソッドは次のようになります。
<?php
namespace App\Controllers;
class UserController extends BaseController
{
public function index()
{
$model = new \App\Models\UserModel();
$data = [
'users' => $model->paginate(10),
'pager' => $model->pager,
];
return view('users/index', $data);
}
}
この例では、最初にUserModel
の新しいインスタンスを作成します。次に、ビューに送信するデータを準備します。最初の要素はデータベースからの結果、**users**で、正しいページのデータが取得され、ページごとに10人のユーザーが返されます。ビューに送信する必要がある2番目のアイテムは、Pagerインスタンス自体です。便宜上、Modelは使用したインスタンスを保持し、公開プロパティ$pager
に格納します。そのため、それを取得してビューの$pager
変数に代入します。
ページネーションのクエリのカスタマイズ
モデルでページネーションのクエリをカスタマイズするには、paginate()
メソッドの前にQuery Builderメソッドを追加できます。
WHERE句の追加
WHERE条件を追加する場合は、条件を直接指定できます。
// In your Controller.
$model = new \App\Models\UserModel();
$data = [
'users' => $model->where('ban', 1)->paginate(10),
'pager' => $model->pager,
];
条件を別のメソッドに移動することもできます。
<?php
namespace App\Models;
use CodeIgniter\Model;
class UserModel extends Model
{
// ...
public function banned()
{
$this->builder()->where('ban', 1);
return $this; // This will allow the call chain to be used.
}
}
// In your Controller.
$model = new \App\Models\UserModel();
$data = [
'users' => $model->banned()->paginate(10),
'pager' => $model->pager,
];
JOIN句の追加
別のテーブルを結合できます。
<?php
namespace App\Models;
use CodeIgniter\Model;
class NewsModel extends Model
{
protected $table = 'news';
// ...
public function getPagination(?int $perPage = null): array
{
$this->builder()
->select('news.*, category.name')
->join('category', 'news.category_id = category.id');
return [
'news' => $this->paginate($perPage),
'pager' => $this->pager,
];
}
}
重要
Model::paginate()
メソッドは、**Model**と**Model**内の**Query Builder**インスタンスを使用します。したがって、$db->query()と共にModel::paginate()
を使用しようとすると、$db->query()
はクエリをすぐに実行し、Query Builderに関連付けられていないため、**機能しません**。
Query Builderで記述できない複雑なSQLクエリが必要な場合は、$db->query()と手動ページネーションを使用してみてください。
ページャーリンクの表示
ビュー内で、結果のリンクを表示する場所を指定する必要があります。
<?= $pager->links() ?>
これだけです。Pagerクラスは、最初のページと最後のページのリンク、および現在のページのどちらかの側に2ページ以上のページがある場合の次のページと前のページのリンクをレンダリングします。
次のページと前のページのライブラリパターンは、従来のページング方法とは異なることに注意することが重要です。
ここでの次のページと前のページは、ページネーション構造に表示されるリンクのグループにリンクされており、レコードの次のページまたは前のページにリンクされていません。
よりシンプルな出力を希望する場合は、詳細なページネーションリンクの代わりに「Older」と「Newer」リンクのみを使用するsimpleLinks()
メソッドを使用できます。
<?= $pager->simpleLinks() ?>
内部的には、ライブラリはリンクのフォーマットを決定するビューファイルを読み込み、ニーズに合わせて簡単に変更できます。出力の完全なカスタマイズ方法の詳細については、以下を参照してください。
複数の結果のページネーション
2つの異なる結果セットからリンクを提供する必要がある場合は、データを分離するために、ほとんどのページネーションメソッドにグループ名を渡すことができます。
<?php
namespace App\Controllers;
class UserController extends BaseController
{
public function index()
{
$userModel = new \App\Models\UserModel();
$pageModel = new \App\Models\PageModel();
$data = [
'users' => $userModel->paginate(10, 'group1'),
'pages' => $pageModel->paginate(15, 'group2'),
'pager' => $userModel->pager,
];
echo view('users/index', $data);
}
}
?>
<!-- In your view file: -->
<?= $pager->links('group1') ?>
<?= $pager->simpleLinks('group2') ?>
ページの手動設定
返す結果のページを指定する必要がある場合は、3番目の引数としてページを指定できます。これは、表示するページを制御するデフォルトの$_GET
変数とは異なる方法がある場合に便利です。
<?php
$userModel = new \App\Models\UserModel();
$page = 3;
$users = $userModel->paginate(10, 'group1', $page);
ページのURIセグメントの指定
ページクエリパラメータの代わりに、ページ番号にURIセグメントを使用することもできます。使用するセグメント番号を4番目の引数として指定するだけです。ページャーによって生成されるURIは、**https://domain.tld/foo/bar?page=[pageNumber]**ではなく、**https://domain.tld/foo/bar/[pageNumber]**のようになります。
<?php
$users = $userModel->paginate(10, 'group1', null, $segment);
注:$segment
の値は、URIセグメントの数プラス1より大きくすることはできません。
手動ページネーション
既知のデータに基づいてページネーションを作成する必要がある場合があります。makeLinks()
メソッドを使用して手動でリンクを作成できます。このメソッドは、現在のページ、1ページあたりの結果数、アイテムの総数をそれぞれ最初の、2番目の、3番目のパラメータとして取得します。
<?php
namespace App\Controllers;
class UserController extends BaseController
{
public function index()
{
// ...
$pager = service('pager');
$page = (int) ($this->request->getGet('page') ?? 1);
$perPage = 20;
$total = 200;
// Call makeLinks() to make pagination links.
$pager_links = $pager->makeLinks($page, $perPage, $total);
$data = [
// ...
'pager_links' => $pager_links,
];
return view('users/index', $data);
}
}
?>
<!-- In your view file: -->
<?= $pager_links ?>
これはデフォルトでリンクを通常の方法(一連のリンクとして)で表示しますが、4番目のパラメータとしてテンプレートの名前を渡すことで、使用される表示テンプレートを変更できます。詳細については、次のセクションを参照してください。
$pager->makeLinks($page, $perPage, $total, 'template_name');
前のセクションで説明したように、ページクエリパラメータの代わりに、ページ番号にURIセグメントを使用することもできます。makeLinks()
の5番目のパラメータとして使用するセグメント番号を指定します。
$pager->makeLinks($page, $perPage, $total, 'template_name', $segment);
注:$segment
の値は、URIセグメントの数プラス1より大きくすることはできません。
1ページに多くのページャーを表示する必要がある場合は、グループを定義する追加のパラメータが役立ちます。
<?php
$pager = service('pager');
$pager->setPath('path/for/my-group', 'my-group'); // Additionally you could define path for every group.
$pager->makeLinks($page, $perPage, $total, 'template_name', $segment, 'my-group');
ページネーションライブラリは、デフォルトでHTTPクエリに**page**クエリパラメータを使用します(グループ名がない場合、またはdefault
グループ名が指定されていない場合)。カスタムグループ名についてはpage_[groupName]
を使用します。
期待されるクエリのみを使用したページネーション
デフォルトでは、すべてのGETクエリがページネーションリンクに表示されます。
たとえば、URL **https://domain.tld?search=foo&order=asc&hello=i+am+here&page=2**にアクセスする場合、ページ3のリンクは、他のリンクと共に次のように生成できます。
<?php
echo $pager->links();
// Page 3 link: https://domain.tld?search=foo&order=asc&hello=i+am+here&page=3
only()
メソッドを使用すると、既に想定されているクエリにのみ制限することができます。
<?php
echo $pager->only(['search', 'order'])->links();
// Page 3 link: https://domain.tld?search=foo&order=asc&page=3
page クエリはデフォルトで有効になっています。そして、only()
はすべてのページネーションリンクで機能します。
リンクのカスタマイズ
ビューの設定
リンクがページにレンダリングされるときは、HTML を記述するビューファイルを使用します。app/Config/Pager.php を編集することで、使用されるビューを簡単に変更できます。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Pager extends BaseConfig
{
public $templates = [
'default_full' => 'CodeIgniter\Pager\Views\default_full',
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
];
// ...
}
この設定は、使用するビューのエイリアスと名前空間付きビューパスを格納します。default_full
と default_simple
ビューは、それぞれ links()
と simpleLinks()
メソッドで使用されます。それらの表示方法をアプリケーション全体で変更するには、ここで新しいビューを割り当てることができます。
例えば、Foundation CSS フレームワークで動作する新しいビューファイルを作成し、それをapp/Views/Pagers/foundation_full.phpに配置したとします。application ディレクトリは App
として名前空間化されており、その下にあるすべてのディレクトリは名前空間のセグメントに直接マップされるため、名前空間を通じてビューファイルを見つけることができます。
'default_full' => 'App\Views\Pagers\foundation_full'
ただし、標準のapp/Views ディレクトリの下にあるため、view()
メソッドはファイル名でそれを特定できるため、名前空間化する必要はありません。その場合、サブディレクトリとファイル名を指定するだけで済みます。
'default_full' => 'Pagers/foundation_full'
ビューを作成して設定したら、自動的に使用されます。既存のテンプレートを置き換える必要はありません。設定ファイルに必要な数の追加テンプレートを作成できます。よくある状況としては、アプリケーションのフロントエンドとバックエンドで異なるスタイルが必要になることです。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Pager extends BaseConfig
{
public $templates = [
'default_full' => 'CodeIgniter\Pager\Views\default_full',
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
'front_full' => 'App\Views\Pagers\foundation_full',
];
// ...
}
設定後、links()
、simpleLinks()
、makeLinks()
メソッドの最後のパラメーターとして指定できます。
<?= $pager->links('group1', 'front_full') ?>
<?= $pager->simpleLinks('group2', 'front_full') ?>
<?= $pager->makeLinks($page, $perPage, $total, 'front_full') ?>
ビューの作成
新しいビューを作成する場合、ページネーションリンク自体の作成に必要なコードのみを作成する必要があります。複数の場所で使用する可能性があり、有用性を制限するだけであるため、不要なラッピングdivを作成しないでください。新しいビューの作成を説明する最も簡単な方法は、既存のdefault_full
テンプレートを示すことです。
<?php $pager->setSurroundCount(2) ?>
<nav aria-label="Page navigation">
<ul class="pagination">
<?php if ($pager->hasPrevious()) : ?>
<li>
<a href="<?= $pager->getFirst() ?>" aria-label="<?= lang('Pager.first') ?>">
<span aria-hidden="true"><?= lang('Pager.first') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getPrevious() ?>" aria-label="<?= lang('Pager.previous') ?>">
<span aria-hidden="true"><?= lang('Pager.previous') ?></span>
</a>
</li>
<?php endif ?>
<?php foreach ($pager->links() as $link): ?>
<li <?= $link['active'] ? 'class="active"' : '' ?>>
<a href="<?= $link['uri'] ?>">
<?= $link['title'] ?>
</a>
</li>
<?php endforeach ?>
<?php if ($pager->hasNext()) : ?>
<li>
<a href="<?= $pager->getNext() ?>" aria-label="<?= lang('Pager.next') ?>">
<span aria-hidden="true"><?= lang('Pager.next') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getLast() ?>" aria-label="<?= lang('Pager.last') ?>">
<span aria-hidden="true"><?= lang('Pager.last') ?></span>
</a>
</li>
<?php endif ?>
</ul>
</nav>
setSurroundCount()
最初の行で、setSurroundCount()
メソッドは、現在のページリンクの両側に2つのリンクを表示することを指定します。受け入れるパラメーターは、表示するリンクの数だけです。
注記
正しいページネーションリンクを生成するには、このメソッドを最初に呼び出す必要があります。
hasPrevious() & hasNext()
これらのメソッドは、setSurroundCount() に渡された値に基づいて、現在のページの両側に表示できるリンクがさらに存在する場合、ブール値 true
を返します。
たとえば、20ページのデータがあるとします。現在のページは3ページ目です。周囲の数(surroundCount)が2の場合、次のリンクは次のように表示されます。
1 | 2 | 3 | 4 | 5
最初に表示されるリンクは1ページ目であるため、0ページがないため、hasPrevious()
はfalse
を返します。ただし、5ページ目以降に15ページの追加の結果があるため、hasNext()
はtrue
を返します。
getPrevious() & getNext()
これらのメソッドは、番号付きリンクの両側にある前後のページの結果のURL を返します。
たとえば、現在のページが5ページ目に設定されていて、前後(surroundCount)のリンクをそれぞれ2つにしたい場合、次のようになります。
3 | 4 | 5 | 6 | 7
getPrevious()
は2ページ目のURLを返します。getNext()
は8ページ目のURLを返します。
4ページ目と6ページ目を取得したい場合は、代わりにgetPreviousPage() & getNextPage() を使用してください。
getFirst() & getLast()
getPrevious() & getNext() と同様に、これらのメソッドは結果セットの最初と最後のページへのURL を返します。
links()
すべての番号付きリンクに関するデータの配列を返します。各リンクの配列には、リンクのuri、タイトル(数字のみ)、リンクが現在/アクティブなリンクかどうかを示すブール値が含まれています。
<?php
$link = [
'active' => false,
'uri' => 'https://example.com/foo?page=2',
'title' => 1,
];
標準のページネーション構造について示されたコードでは、getPrevious() & getNext() メソッドを使用して、それぞれ前後のページネーショングループへのリンクを取得しています。
前と次のページが現在のページに基づいて前後のページへのリンクになるページネーション構造を使用する場合は、getPrevious() & getNext() メソッドをgetPreviousPage() & getNextPage() に、hasPrevious() & hasNext() メソッドをhasPreviousPage() & hasNextPage() にそれぞれ置き換えるだけです。
これらの変更を加えた例を以下に示します。
<nav aria-label="<?= lang('Pager.pageNavigation') ?>">
<ul class="pagination">
<?php if ($pager->hasPreviousPage()) : ?>
<li>
<a href="<?= $pager->getFirst() ?>" aria-label="<?= lang('Pager.first') ?>">
<span aria-hidden="true"><?= lang('Pager.first') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getPreviousPage() ?>" aria-label="<?= lang('Pager.previous') ?>">
<span aria-hidden="true"><?= lang('Pager.previous') ?></span>
</a>
</li>
<?php endif ?>
<?php foreach ($pager->links() as $link): ?>
<li <?= $link['active'] ? 'class="active"' : '' ?>>
<a href="<?= $link['uri'] ?>">
<?= $link['title'] ?>
</a>
</li>
<?php endforeach ?>
<?php if ($pager->hasNextPage()) : ?>
<li>
<a href="<?= $pager->getNextPage() ?>" aria-label="<?= lang('Pager.next') ?>">
<span aria-hidden="true"><?= lang('Pager.next') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getLast() ?>" aria-label="<?= lang('Pager.last') ?>">
<span aria-hidden="true"><?= lang('Pager.last') ?></span>
</a>
</li>
<?php endif ?>
</ul>
</nav>
hasPreviousPage() & hasNextPage()
このメソッドは、表示されている現在のページの前後にページへのリンクがある場合、ブール値 true
を返します。
たとえば、20ページのデータがあるとします。現在のページは3ページ目です。周囲の数(surroundCount)が2の場合、次のリンクは次のように表示されます。
1 | 2 | 3 | 4 | 5
hasPreviousPage()
は2ページ目があるためtrue
を返し、hasNextPage()
は4ページ目があるためtrue
を返します。
注記
hasPrevious() & hasNext() との違いは、hasPrevious() & hasNext() がsetSurroundCount() に渡された値に基づいて、現在のページの前後に表示されるリンクのセットに基づいているのに対し、こちらは現在のページに基づいていることです。
getPreviousPage() & getNextPage()
これらのメソッドは、表示されている現在のページに関連する前後のページのURL を返します。
たとえば、現在のページが5ページ目に設定されていて、前後(surroundCount)のリンクをそれぞれ2つにしたい場合、次のようになります。
3 | 4 | 5 | 6 | 7
getPreviousPage()
は4ページ目のURLを返します。getNextPage()
は6ページ目のURLを返します。
注記
getPrevious() & getNext() は、番号付きリンクの両側にある前後のページの結果のURLを返します。
URLではなくページ番号を使用したい場合は、次のメソッドを使用できます。
getPreviousPageNumber() & getNextPageNumber()
これらのメソッドは、表示されている現在のページに関連する前後のページのページ番号を返します。
getFirstPageNumber() & getLastPageNumber()
これらのメソッドは、表示されるリンクのセットの最初のページと最後のページのページ番号を返します。たとえば、表示されるリンクのセットが次のようになっている場合
3 | 4 | 5 | 6 | 7
getFirstPageNumber()
は3を返し、getLastPageNumber()
は7を返します。
注記
結果セット全体の最初のページと最後のページのページ番号を取得するには、次の方法を使用できます。最初のページ番号は常に1であり、getPageCount() を使用して最後のページ番号を取得できます。
getCurrentPageNumber()
このメソッドは、現在のページのページ番号を返します。
getPageCount()
このメソッドは、ページの総数を返します。