Top > MyPage
 

PHPでのページャーの実装

Pear::Pagerについて

以前、DB_Pagerというのが、ページャーの実装の基本だったみたいだが、今ではだいぶ古いということで、Pear::Pagerを使うのが推奨されているよう。

Pear::Pagerの使用例

たとえば次のように使う。

require_once "DB.php";
require_once "Pager/Pager.php";

$dsn = 'pgsql://user:password@hostname/databasename';
$db = DB::connect($dsn);
if (PEAR::isError($db)) {
    die($db->getUserInfo());
}

while ($item =& $rs->fetchRow(DB_FETCHMODE_ASSOC)){
    $html[] = $item;
} 

$params = array(
"itemData"=>$html,  //アイテムの配列です。
"totalItems"=>$rs->numRows(), //合計アイテム数
"perPage"=>5, //1ページあたりの表示数
"delta"=>3,
"mode"=>"Sliding",
"altFirst"=>"", //以下、文字表示設定 1ページ目のalt表示
"altPrev"=>"", //前のalt
"prevImg"=>"<<", //前へ の文字表示
"altNext"=>"", //次へ のalt
"nextImg"=>">>", //次へ の文字表示
"altLast"=>"", //ラストのalt表示
"altPage"=>"",
"separator"=>" | ", //数字と数字の間の文字
"append"=>1,
"fileName"=>"viewpage.php",//リンクurl
"urlVar"=>"page",//get属性
);

$pagenum = $_GET["page"];  //現在のページを受け取る
$pager = & Pager::factory($params); //Pagerオブジェクトを作る。

$array = Array();
$array = $pager->getPageData($pagenum); //ページ番号からリストをもらう

foreach($array as $item){
    echo $item[TITLE];
    echo "";
}
echo "";
echo $pager->links;  //ページャーを表示

             

こうすると

title1                 
title2
title3
title4
title5
1 |  2 |  3 |  4 |  5 |   >> 

この様に表示される。

Pear::Pagerのオプション

Pear::Pagerは前例の$paramsのようにオプションを指定することで動作や表示を変えることができる。おもな属性は次の通り。

  • itemData:アイテムの配列。
  • totalItems:合計アイテム数
  • perPage:1ページあたりの表示数
  • linkClass: CSSを使うときのclassの指定
  • curPageLinkClassName:現在のページ表示にCSSを使うときのclassの指定
  • append: URLにリンクを自動的に加えるかどうか。falseにした場合"page.php?page=%d"のようにfileNameに書く必要がある。%dは現在のページに置換される。
  • httpMethod: GETとPOSTどちらで送るか。POSTにするとリンクにjavascriptが使われる模様
  • path:現在のページを抜いたpathの指定
  • fileName:ページの名前を指定。デフォルトは現在のページ
  • urlVar:ページを受け取るための変数名
  • alt***: altNextなど。リンクにつけるプレビューを設定。
  • ***Img: prevImgなど。リンクを表すイメージを指定。<img/>を使用可能
  • separator:リンクを区切る文字。<img/>を使用可能
  • firstPageText:最初のページ番号の文字を指定。<img/>を使用可能
  • clearIfVoid:一ページだけのときページャーを表示するかどうか
  • extraVars:その他必要なページ情報を連想配列で指定
  • mode:ページャーのモードを指定("Jumping"or"Sliding")
  • delta:ページャーの見せるページ数を指定。modeによって動作が異なる

最低限設定が必要なパラメータはitemDataかtotalItems、appendがfalseのときにfileNameが必要。

modeによってページャーの動作は多少異なり、Jumpingのときdeltaがページャーの一度に見せる数になり、deltaが3のとき

のようになる。Slidingの場合は、deltaは現在のページから前後いくつ見せるかになり

のようになる。

Pear::Pagerのメソッド

Pagerにはおもに次のようなメソッドがある。

  • factory($options = array()):オプションからページャーのオブジェクトを返す
  • getPageIdByOffset($offset): offsetが何ページ目かを返す
  • getPageData($pageID): pageIDのページのアイテムの配列を返す
  • getOffsetByPageId($pageID): pageIDのページのオフセットの配列を返す。(例:array(4, 6))
  • getPageRangeByPageId($pageID): pageIDのページのときページャーが表示するページの範囲を配列で返す。(例:array(1, 5))
  • getLinks():ページャーを表示するHTMLを返す
  • get***PageID(): getNextPageIDなど。ページの番号を返す。
  • getOption($name):オプションに設定した値を返す

PEARが使えない場合

Pear::Pagerを使うと楽にページャーが実装できるが、レンタルサーバなどで、気軽にPEARライブラリを入れられない場合は自前で実装する必要がある。

調べるとこのようなメソッドが見つかった。

<?php
// pager()関数関連の定義
// ページ情報となる変数名の設定
define(PAGE_VALUE , "id");
// ページをいくつで区切るか?
// 100件ごとに区切りたいなら100を指定
define(PER_PAGE,10);
// ページメニューの数の幅
// ページ総数 59 / VIEW_PAGE_MENU_WIDTH = 5の場合
// 26ページ目を表示しているときは下記のように表示される
// < 21 22 23 24 25 26 27 28 29 30 31 >
// 26 の前5つ分(21まで)と後ろ5つ分(31まで)を表示する
define(VIEW_PAGE_MENU_WIDTH , 5);
// 前に戻るときのマーク 「< (<)」とか「前」とか「←」とか指定
define(PREV_MARK , "");
// 次に行くときのマーク 「< (>)」とか「次」とか「→」とか指定
define(NEXT_MARK , ">");
// pager()関数ここから
function pager($idname,$countRe){
    // 現在のページ情報を取得
    $id =$_GET[$idname];
    // ページ情報以外のパラメータを補完し、$other_paramにセット
    foreach($_GET as $key => $value){
        // $idname 以外のGETメソッドのパラメータを $other_param に再構築
        if ($key != $idname){
            // リンクさせるためにurlencodeする.
            $other_param .= "&".$key."=".urlencode($value);
        }
    }
    // ページ数の指定がなければページ数を1にセット
    if($id=="") $id=1;
    // 最終ページを計算する
    // 総Hit数をページング単位で割ると総ページ数が計算される
    // ページング単位PER_PAGEを10とすると最終ページ数$maxPageは
    // 総Hit数 / PER_PAGEを切り上げたものとなる。
    // 検索結果205件 PER_PAGE:10の場合 $maxPage = ceil(205 / 10) = 21
    $maxPage=ceil($countRe / PER_PAGE);
    // maxPage=1の場合(PER_PAGEより少ない検索結果)
    // 選択したページ数(id)よりもmaxPageが小さいときはfalse
    if( ($maxPage == 1) or ($maxPage < $id) ) return false;
    // 選択したページ数がVIEW_PAGE_MENU_WIDTHより大きいとき
    if($id > VIEW_PAGE_MENU_WIDTH + 1){
        // スタートページは選択ページからVIEW_PAGE_MENU_WIDTHを
        // 引いたもの程度出せばよい
        $startPage = $id - VIEW_PAGE_MENU_WIDTH;
        // より小さいもの「 < 」の部分はさらにその$startPageから1を引いたもの
$startMore = " <a href="$PHP_SELF?".$idname."=".($startPage - \
    1).$other_param."\">".PREV_MARK." </a>";
    }else{
        // そうでなければ$startPage=1(一番はじめのページ = 1)になる
        $startPage = 1;
    }
    // 選択したページ数に5を足したものより、更に$maxPage
    // (最大ページ)が大きければ
    if($id + VIEW_PAGE_MENU_WIDTH < $maxPage){
        // 表示される最終ページは選択したページに
        // VIEW_PAGE_MENU_WIDTHを足したものになる
        $endPage = $id + VIEW_PAGE_MENU_WIDTH;
$endMore = " <a href=\"$PHP_SELF?".$idname."=".($endPage + \
    1).$other_param."\"> ".NEXT_MARK." </a>";
    }else{
        // そうでなければ、$endPageは最終ページになる
        $endPage = $maxPage;
    }
    // ここまでで、計算されたのは
    // $id        : 現在選択しているページ番号
    // $maxPage   : 検索の最終ページ
    // $startPage : 表示されるはじめのページ
    // $endPage   : 表示される最後のページ
    // $page_footer="" として$page_footerを初期化
    $page_footer="";
    // $startPage から $endPageまで繰り返し
    for($i = $startPage ; $i  <= $endPage ; $i++){
        // $i = $idだったら選択されたページなので、fontsizeを大きくする
        // その際、リンクはなし
        // そうでなければ、id=$iをリンクにセットする
$page_footer.= " ".(($id==$i)?" <span style='font-Size:120%'>$i </span>":" \
    <a href=\"$PHP_SELF?$idname=$i$other_param\">$i </a>");
    }
    // $startMoreと$endMoreを$page_footerの前後に付け足す
    $page_footer = $startMore.$page_footer.$endMore;
    // $page_footerを表示
    print $page_footer;
}
// pager()関数ここまで
?>
        

クラスではなくメソッドなので、好きなファイルのところに置いて使う。使い方は次のように。

$num = count($array);  #データ配列の大きさを取得            
pager("page", $num);            
        

これで、次のようにページャーが表示される。

しかしDBなどと連携する際は、一覧を表示させたりするのは自分で $_GET["page"] などして現在のページから作る必要がある。

Ethnaでのページャー

Ethnaには次のようなメソッドが用意されているよう。

Google風リンクリストを返す

array getDirectLinkList (int $total, int $offset, int $count)

int $total: 検索総件数

int $offset: 表示オフセット

int $count: 表示件数

return: リンク情報を格納した配列

例としては次のようにするとページャーが作れる。

function perform()
{
    $this->total = 100;
$this->offset = $this->af->get('start') == null ? 0 : \
    $this->af->get('start');
    $this->count = 10;

    $this->getPager();
    return 'index';
}

/**
*
* ページャの作成
*
* @access  public
* @return  void
*/
function getPager(){
$pager = Ethna_Util::getDirectLinkList($this->total, $this->offset, \
    $this->count);
    $next = $this->offset + $this->count;
    if($next < $this->total){
        $last = ceil($this->total / $this->count);
        $this->af->setApp('hasnext', true);
        $this->af->setApp('next', $next);
        $this->af->setApp('last', ($last * $this->count) - $this->count);
    }
    $prev = $this->offset - $this->count;
    if($this->offset - $this->count >= 0){
        $this->af->setApp('hasprev', true);
        $this->af->setApp('prev', $prev);
    }
    $this->af->setApp('current', $this->offset);
    $this->af->setApp('link', 'localhost');
    $this->af->setApp('pager', $pager);
}

テンプレートでは表示のために次のようにする。

{if $app.hasprev}
<a href="{$app.link}?start=0">最初 </a> <a \
    href="{$app.link}?start={$app.prev}"><< </a>
{else}
最初 <<
{/if}
{foreach from=$app.pager item=page}
{if $page.offset == $app.current}
<strong>{$page.index} </strong>
{else}
 <a href="{$app.link}?start={$page.offset}">{$page.index} </a>
{/if}
{/foreach}
{if $app.hasnext}
 <a href="{$app.link}?start={$app.next}">>> </a>
 <a href="{$app.link}?start={$app.last}">最後 </a>
{else}
>>最後
{/if}

これで、

のようにページャーが表示される。

一覧の表示は自分で実装しなければいけないが、$this->af->get('start')でとれる値はページ番号ではなくオフセットで、アイテムのインデックスであることに注意。