[PHP5] OOPで掲示板を作ってみる – Step4: ログの表示

オブジェクト指向プログラミングでフレームワークを使わずに掲示板作成その4。
書き込んだ内容を表示して初めて掲示板となるのだ!フーハハー

目次

  • 序章
  • Step1 : MVCを揃える
  • Step2 : テンプレート作成
  • Step3 : 書き込み
  • Step4: ログの表示 ← 今ここ
  • Step5: 設定ファイルと細かな修正
  • Step6: 編集&削除画面
  • Step7: 編集&削除機能
  • Step8: ページング

このエントリーで掲示板の基本完成。

Step4

Step3で書き込み出来るようになったからログを読み込んで掲示板っぽく表示させるよ!

step3-logdata

ログもメッセージと同じでModel→Controller→Viewと流す。

ログの読み込み

CSVだからfgetcsv使う。
ソースはマニュアルの例文をちょっと変えて使わせてもらう。

lib/model.php (class Model)

/**
 * ログファイルからログデータを読み込む
 */
public function readLog()
{
    $logs = array();
        
    if (($handle = fopen($this->_getLogfileName(), "r")) !== FALSE) {
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
            $logs[] = $data;
        }
        fclose($handle);
    }else{
        return false;
    }
        
    $this->setLogData($logs);//メンバ変数にセット
        
    return true;
}

Step3のsetPostdataと同じくセッターを使ってメンバ変数に保存。
ControllerはreadLogを実行してからgetLogDataで掲示板のログを得る。

lib/controller.php (class Controller – function execute)

$modelInstance->readLog();
$log = $modelInstance->getLogData();

配列で返されるから$logは当然こうなるんだけど…

step4-logdata

Viewに渡してからのこと考えると扱い辛い代物だと思う。
テンプレートエンジン使わないならWordPressのPostオブジェクトみたいな感じの方がいいよねえ…。
ログをオブジェクトにすればフォームにつけたnameをキーとして使えるから分かりやすいし、並び順が変わっても安心。
fgetcsvの配列がそのままオブジェクトになればいいのだから、
Modelのメンバ変数にあるフォーム要素の名前を使うことができる。

オブジェクトにするのに思いついた方法は2つ。

  1. array_combineしてオブジェクト型に変更
  2. 新しくクラスを作ってそれのインスタンスにする

array_combineの場合はこんな感じ。

$label = $this->_inputs;
array_unshift($label, 'date');
$array = array_combine($label, $logs);
(object) $array;

型変換したオブジェクトをvar_dumpとかするとobject(stdClass)っていう名前が出る。
これはstdClassっていうPHPに内臓されているクラスのインスタンスになるかららしい。

配列を型変換する方が簡単だけど、ちょっと試したいこともあることだし後者でやってみることにする。

Logクラス作成

新しくlog.phpを作ってLogというクラスを作る。
コンストラクタで$this->_inputsとログ1行のデータ(timestamp, name, comment)を受け取る。
Step3で作ったControllerから丸投げされた$_POSTを仕分けするsetPostdataメソッドにより
フォームから送られた配列は$this->_inputsと同じ順番に並んでいるから、
forでループさせるだけでフォーム要素のメンバ変数を全部作ることが出来る。

lib/bbs_log.php

class Log {
    
    function __construct($label, $line)
    {
        $num = count($line);
        for ($i=0; $i < $num ; $i++) {
             $varname = $label[$i];
             $this->{$varname} = $line[$i];  
        }
    }
}

ModelクラスのreadLogメソッドをちょっと修正。
setLogDataに渡す配列に入れるものをLogクラスのインスタンスにする。

lib/model.php (class Model)

/**
 * ログファイルからログデータを読み込む
 */
public function readLog()
{
    $logs = array();
    $label = $this->_inputs;
    array_unshift($label, 'date');
        
    if (($handle = fopen($this->_getLogfileName(), "r")) !== FALSE) {
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
            $logs[] = new Log($label, $data);
        }
        fclose($handle);
    }else{
        return false;
    }
        
    $this->setLogData($logs);
        
    return true;
}

実行結果 😀

step4-object

キーがあると俄然何の値なのか分かりやすい!

よーしあとはViewに投げるだけだぞ。

Controllerの修正

コントローラーにModelから受け取ったログをViewに渡すべく、上で書いたgetLogDataのところをちょっと変更。

lib/controller.php (class Controll – function execute)

$viewInstance->setLog($modelInstance->getLogData());

渡す時に使うのはセッターだと思うから、Viewに新しくsetLogというメソッドを作ります。

Viewの修正

Viewに新しく$_logsというメンバ変数を追加。これにControllerを介して渡されたログデータを入れる。

lib/view.php (class View)

/**
 * ログデータのセッター
 */
public function setLog($log)
{
    $this->_logs = $log;
}
    
/**
 * ログデータのゲッター
 */
public function getLog()
{
    return $this->_logs;
}

テンプレートにはLogオブジェクトが入った配列をそのまま渡すので、displayメソッドでゲッターを使う。

lib/view.php (class View – display)

$logdata = $this->getLog();

テンプレートの修正

この時点で実行すると Model→Controller→View→index.tpl という順にログが渡るが、
テンプレートで$logdataを print しているのでArrayという文字列しか出ない。

配列にLogオブジェクトが入っているならforeachすればいいよね。

template/index.tpl

<div id="main">
    <?php foreach($logdata as $log): ?>
    <div class="log">
    <p><strong class="name"><?php print($log->name); ?></strong> <span class="date"><?php print($log->date); ?></span></p>
    <p class="comment"><?php print($log->comment); ?></p>
    </div>
    <?php endforeach; ?>
</div>

オブジェクトにしたからテンプレートも書きやすい 😀
Wordpressやテンプレートエンジンのタグもこんな感じだよね。

だがちょっと待って欲しい。テンプレートでもゲッターを通すべきじゃないか?
いちいちprintって書くのも面倒くさいし、Wordpressのthe_title()みたいなのがあれば便利そう。
Logクラスにそういうメソッドを仕込んでおけば出来るよね。

Logクラスの修正

Logクラスにテンプレートタグみたいなゲッターを作成する。

lib/bbs_log.php (class Log)

public function the_($name, $option=NULL)
{
    print $this->getThe_($name, $option);  
}
    
public function getThe_($name, $option=NULL)
{
    $data = $this->{$name};
        
    if(!empty($option)){
        if($name=='date'){
        return date($option, $data);
        }
    }else{
        return $this->{$name};
    }
}

dateだけオプションでフォーマットできるようにしといた。

そしてテンプレートで使う。

template/index.tpl

<p><strong class="name"><?php $log->the_('name'); ?></strong> <span class="date"><?php $log->the_('date','Y/m/d H:i'); ?></span></p>
<p class="comment"><?php $log->the_('comment'); ?></p>

printやechoまみれになるよりはこっちの方が見やすいと思う。
この方法は存在しないキーを指定した時にエラーが出るから、__getを追加しておく。

lib/bbs_log.php (class Log)

public function __get($name)
{
}

Preview

書いて表示するだけのw掲示板完成! 😀
ログを表示するところのCSSを適当に書けば掲示板らしさマシマシ。

step4-preview

Step5に続きます。

Step4 Download

ソースファイルのライセンスは Creative Commons BY-NC です。
ローカルサーバーでテストしてください。

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

oop-bbs-step4.zip – 1061 回のダウンロード – 10.26 KB

XAMPPでXdebugを有効にする

ONにしとくと便利だと思う。

  1. xampp->apache->binにあるphp.iniを開く
  2. extension=php_xdebug.dllのセミコロンを外す
  3. Apatch再起動

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください