페이지네이션
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.
항목을 페이지네이션할 때 총 항목 수와 현재 페이지에 표시된 항목 범위를 표시하는 것이 유용한 경우가 많습니다. 이 작업을 단순화하기 위해 새로운 메서드가 추가되었습니다. 이 메서드들을 통해 페이지네이션 세부 정보를 더 쉽게 관리하고 표시할 수 있습니다. 다음은 예시입니다:
<?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()
페이지가 끝나는 항목 번호를 반환합니다.