페이지네이션
CodeIgniter는 테마 적용이 간단하고, 모델과 함께 동작하며, 단일 페이지에서 여러 페이지네이터를 지원할 수 있는 매우 간단하지만 유연한 페이지네이션 라이브러리를 제공합니다.
라이브러리 로드
CodeIgniter의 모든 서비스와 마찬가지로 Config\Services를 통해 로드할 수 있지만, 일반적으로 수동으로 로드할 필요는 없습니다:
<?php
$pager = service('pager');
모델과 함께 페이지네이션
대부분의 경우 데이터베이스에서 가져온 결과를 페이지네이션하기 위해 Pager 라이브러리를 사용합니다. Model 클래스를 사용할 때 내장된 paginate() 메서드를 사용하여 현재 배치의 결과를 자동으로 가져오고 컨트롤러에서 사용할 수 있도록 Pager 라이브러리를 설정할 수 있습니다. 심지어 page=X 쿼리 변수를 통해 현재 URL에서 표시해야 할 현재 페이지를 읽습니다.
애플리케이션에서 페이지네이션된 사용자 목록을 제공하려면 컨트롤러 메서드는 다음과 같이 구성됩니다:
<?php
namespace App\Controllers;
use App\Models\UserModel;
class UserController extends BaseController
{
public function index()
{
$model = model(UserModel::class);
$data = [
'users' => $model->paginate(10),
'pager' => $model->pager,
];
return view('users/index', $data);
}
}
이 예시에서는 먼저 UserModel의 새 인스턴스를 생성합니다. 그런 다음 뷰로 보낼 데이터를 채웁니다. 첫 번째 요소는 데이터베이스에서 가져온 users 결과로, 올바른 페이지를 위해 페이지당 10명의 사용자를 반환합니다. 뷰에 전달해야 하는 두 번째 항목은 Pager 인스턴스 자체입니다. 편의를 위해 모델은 사용한 인스턴스를 유지하여 공개 속성 $pager에 저장합니다. 따라서 해당 값을 가져와 뷰의 $pager 변수에 할당합니다.
페이지네이션을 위한 쿼리 사용자 정의
모델에서 페이지네이션을 위한 쿼리를 사용자 정의하려면 paginate() 메서드 전에 쿼리 빌더 메서드를 추가할 수 있습니다.
WHERE 추가
WHERE 조건을 추가하려면 조건을 직접 지정할 수 있습니다:
use App\Models\UserModel;
// In your Controller.
$model = model(UserModel::class);
$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.
}
}
use App\Models\UserModel;
// In your Controller.
$model = model(UserModel::class);
$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 및 Query Builder 인스턴스를 사용한다는 점을 이해하는 것이 중요합니다. 따라서 $db->query()는 쿼리를 즉시 실행하고 쿼리 빌더와 연관되지 않으므로 $db->query()와 함께 Model::paginate()를 사용하려고 하면 동작하지 않습니다.
쿼리 빌더로 작성할 수 없는 복잡한 SQL 쿼리가 필요한 경우 $db->query()와 Manual Pagination을 사용해 보십시오.
페이저 링크 표시
뷰 내에서 결과 링크를 표시할 위치를 지정해야 합니다:
<?= $pager->links() ?>
이것으로 충분합니다. Pager 클래스는 현재 페이지 양쪽으로 두 페이지 이상 떨어진 페이지에 대해 첫 페이지 및 마지막 페이지 링크와 다음 및 이전 링크를 렌더링합니다.
다음 및 이전에 대한 라이브러리 패턴은 결과를 페이징하는 전통적인 방식과 다르다는 점에 유의하는 것이 중요합니다.
여기서 다음 및 이전은 레코드의 다음 또는 이전 페이지가 아니라 페이지네이션 구조에 표시될 링크 그룹과 연결됩니다.
더 간단한 출력을 원하면 세부 페이지네이션 링크 대신 “이전” 및 “최신” 링크만 사용하는 simpleLinks() 메서드를 사용할 수 있습니다:
<?= $pager->simpleLinks() ?>
내부적으로 라이브러리는 링크 형식을 결정하는 뷰 파일을 로드하므로 필요에 맞게 수정하기 쉽습니다. 출력을 완전히 사용자 정의하는 방법에 대한 자세한 내용은 아래를 참조하십시오.
여러 결과 페이지네이션
두 개의 다른 결과 집합에서 링크를 제공해야 하는 경우 데이터를 분리하여 유지하기 위해 대부분의 페이지네이션 메서드에 그룹 이름을 전달할 수 있습니다:
<?php
namespace App\Controllers;
use App\Models\PageModel;
use App\Models\UserModel;
class UserController extends BaseController
{
public function index()
{
$userModel = model(UserModel::class);
$pageModel = model(PageModel::class);
$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
use App\Models\UserModel;
$userModel = model(UserModel::class);
$page = 3;
$users = $userModel->paginate(10, 'group1', $page);
페이지의 URI 세그먼트 지정
페이지 쿼리 파라미터 대신 페이지 번호에 URI 세그먼트를 사용할 수도 있습니다. 네 번째 인수로 사용할 세그먼트 번호를 지정하면 됩니다. 그러면 페이저가 생성하는 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() 메서드로 링크를 수동으로 생성할 수 있으며, 각각 첫 번째, 두 번째, 세 번째 파라미터로 현재 페이지, 페이지당 결과 수, 전체 항목 수를 받습니다:
<?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 ?>
기본적으로 링크를 일반적인 방식으로 일련의 링크로 표시하지만, 네 번째 파라미터로 템플릿 이름을 전달하여 사용되는 표시 템플릿을 변경할 수 있습니다. 자세한 내용은 다음 섹션에서 확인할 수 있습니다:
$pager->makeLinks($page, $perPage, $total, 'template_name');
이전 섹션에서 설명한 대로 페이지 쿼리 파라미터 대신 페이지 번호에 URI 세그먼트를 사용할 수도 있습니다. makeLinks()의 다섯 번째 파라미터로 사용할 세그먼트 번호를 지정합니다:
$pager->makeLinks($page, $perPage, $total, 'template_name', $segment);
참고: $segment 값은 URI 세그먼트 수에 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() 메서드는 현재 페이지 링크 양쪽에 두 개의 링크를 표시하도록 지정합니다. 허용되는 유일한 파라미터는 표시할 링크 수입니다.
참고
올바른 페이지네이션 링크를 생성하려면 이 메서드를 먼저 호출해야 합니다.
hasPrevious() & hasNext()
이 메서드들은 setSurroundCount()에 전달된 값을 기반으로 현재 페이지 양쪽에 표시할 수 있는 링크가 더 있으면 불리언 true를 반환합니다.
예를 들어 데이터가 20페이지 있고 현재 페이지가 3페이지라고 가정합니다. 주변 개수가 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() 메서드는 각각 이전 및 다음 페이지네이션 그룹의 링크를 얻는 데 사용됩니다.
prev 및 next가 현재 페이지를 기준으로 이전 및 다음 페이지의 링크가 되는 페이지네이션 구조를 사용하려면 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페이지라고 가정합니다. 주변 개수가 2이면 다음 링크가 이렇게 표시됩니다:
1 | 2 | 3 | 4 | 5
2페이지가 있으므로 hasPreviousPage()는 true를 반환합니다. 그리고 4페이지가 있으므로 hasNextPage()도 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()
이 메서드는 전체 페이지 수를 반환합니다.
페이지의 항목 수 표시
Added in version 4.6.0.
When paginating items, it’s often helpful to display the total number of items and the range of items shown on the current page. To simplify this task, new methods have been added. These methods make it easier to manage and display pagination details. Here’s an example:
<?php $pager->setSurroundCount(1) ?>
<p>
Showing <span class="font-medium"><?= $pager->getPerPageStart() ?></span>
to <span class="font-medium"><?= $pager->getPerPageEnd() ?></span>
of <span class="font-medium"><?= $pager->getTotal() ?></span> results
</p>
getTotal()
페이지의 전체 항목 수를 반환합니다.
getPerPage()
페이지당 표시될 항목 수를 반환합니다.
getPerPageStart()
페이지가 시작하는 항목 번호를 반환합니다.
getPerPageEnd()
페이지가 끝나는 항목 번호를 반환합니다.