WebTecNote

[PHP5] OOPで掲示板を作ってみる – Step8:ページング

オブジェクト指向プログラミングでフレームワークを使わずに掲示板を作るよその8。
ページングって面倒だよね。

目次

投稿者による編集と削除が出来るようになった掲示板。

投稿し続けるとログが延々表示される症状が出ているからページングをつけませう。
ページングについては ページング機能の仕組みとか作り方とか に書いたのとそんなに変わらない。
問題はどこで何をするかってことですー。

ページ番号をGETとかで保持しながら番号に応じたログを表示します。
ログを表示するには表示の始点と終点が必要です。その計算はページ番号×1ページあたりの表示件数で出せます。
GETをあれこれするのはコントローラーの仕事なのでその辺の計算はコントローラーにおきます。
始点と終点が出せたらその値をモデルに投げてログを切り取らせます。ログを切り取れたら後はビューにそのログを投げる。
ビューはログの他にページングリンクとかを表示する仕事もあります。
ページングリンクを作るのに必要な値はコントローラーが持っているので、コントローラーから受け取ってリンクを作成します。
リンクの作成をビュークラスに入れてしまうと雑多になりすぎるので、クラスファイルを別に作ることにします。
コントローラーから受け取った値をページングクラスに渡してインスタンスを作成すれば
テンプレートでメソッドを使うだけでリンクとかが表示されるようになるっていう寸法ですー。

extract

下準備としてViewのセッターをちょっと変えとく。
今まで$logdataとか$messageみたいなテンプレートで使う変数をdisplayメソッドでゲッターとセットで書いてたんだけど、
もっとフリーダムに変数が作れた方が便利なのでextractを使うことにします。

新しく$viewVarsというプロパティをViewに追加します。

private $viewVars = array();

入れ替わりに$_logs$_tokenは削除。

ログデータのセッターを$viewVarsのセッターに変更。値は連想配列です。

/**
 * プロパティセッター
 */
public function set($property, $value)
{
	$this->viewVars[$property] = $value;
}

/**
 * プロパティのゲッター
 */
public function get($property)
{
	return $this->viewVars[$property];
}

displayメソッドにextractを入れる。

public function display()
{
	$class = empty($this->_systemMessage['type']) ? '' : ' ' . $this->_systemMessage['type'];
	$message = $this->getSystemMessage();
   
	if(isset($message)){
		if( is_array($message) ){
		   $message = implode('<br />', $message);
		}
		
		$message = '<p class="message' . $class . '">' . $message . '</p>';
	}
	
	extract($this->viewVars);
	
	ob_start();
	include($this->getTemplateName());
	echo ob_get_clean();
}

バッファリングもついでに書いてみた 😀

この変更によりコントローラー内のセッターが次のように変わります。

$this->view->setLog($log);//before
$this->view->set('logdata', $log);//after

トークンの作成はcreateToken()だけ残してViewに移し、Viewのコンストラクタ内で変数にセットするようにしました。

$this->set('token', $this->createToken());//トークン

なんかテンプレートに渡したいというものがあったとき、setを使うだけで変数の作成が出来るので便利です。

Controller

コントローラーにページネーションメソッドを追加します。
メソッドの引数はページ番号と1ページあたりの表示件数です。
表示件数はiniに入れたりGETで渡してもいいかなーと思うんだけど説明が長引くので直書きにしておく。

protected function paginate($page, $disp)
{
	$page = empty($page) ? 1:$page;
	$start = ($page == 1)? 0 : ($page-1) * $disp;
	$end   = ($page * $disp);
	$count = count($this->model->getLogData());
	$pageCount =  floor($count / $disp);
	
	$this->view->paginate(array('page'=>$page, 'pageCount'=>$pageCount, 'dataCount'=>$count, 'limit'=>$disp ));

	return $this->model->paginate($start, $end);
	
}

ページ番号と表示件数を元に始点・終点を計算してModelの同名メソッドに渡します。
Viewへはログの件数と総ページ数をセットにして渡します。

ページングが必要なのはログが表示されるインデックスページだけなので、修正するのはindexViewメソッドです。

lib/controller.php (class Controller)

//インデックス
private function indexView()
{
    $this->view->set('logdata', $this->paginate(@$_GET['page'], 5));//Viewにログを渡す
    $this->view->display();//表示
}

Model

モデルのpaginateメソッドはforで始点から終点までを切り取ってreturnするだけです。
この程度なら別にコントローラー内でやっつけても…とか思うんだけどね。

lib/model.php (class Model)

/**
 * 部分的にログを取り出す
 */
public function paginate($start, $end)
{
	$logdata = $this->getLogData();
	$limit = count($logdata);
	$result = array();
	
	for($i = $start; $i < $end; $i++){
		if($i >=  $limit){ break; }
		$result[] = $logdata[$i];
	}
	
	return $result;
}

View

ビューメソッドはPaginationクラスのインスタンス作ってセットするだけ。
lib/view.php (class View)

public function paginate($params)
{
	include('pagination.php');
	$this->set('pagination', new Pagination($params));
}

Paginationクラス

CakePHPを真似して書きましたお。
ページ番号、最大ページ数、データ件数、表示件数を元にナビゲーションを作成します。
さすがに300行近くあるものは張れないので全文はダウンロードして見てください。
ライブラリを探して使うのもアリだと思います。

Template

Viewで作成されたインスタンスはテンプレートで$pagenationから使えるようになってます。
index.tplにソースを追加するだけで表示のことはクラスが勝手に処理してくれます。
メソッドはだいたいCakeのと同じです。

<p><?php $pagination->counter('合計 %pages% ページ中の %page% ページ目です。 全 %count% 件のうち、 %start% 件目から %end% 件目までの  %current% 件を表示しています。'); ?></p>
<p class="pagenation"><?php
	$pagination->prev();
	$pagination->numbers();
	$pagination->next();
?></p>

これでログが増えても安心ね!

実用するには色々と足りてないところがあるけど、オブジェクト指向らしい掲示板は作れたと思いますー。
でもオブジェクト指向の本領発揮にはまだまだ遠い…。

Step8 Download

動作確認とかはローカルでやってください。ライセンスはCreative Commons BY-NCです。

“OOPでBBS Step8” をダウンロード

oop-bbs-step8.zip – 1308 回のダウンロード – 18.90 KB
モバイルバージョンを終了