DB周りの処理を書いた

  • テーブルと1対1対応し、そのテーブルへの入出力を担当するDaoオブジェクト
  • テーブルの行と(だいたい)1対1対応し、行データを保持するBeanオブジェクト

を作る。アプリケーション内ではBeanにデータを載せて処理を行い、DBへ保存したり更新したりするときにはBeanがDaoに処理を委譲する。

各テーブルのDao,Beanは抽象Dao,抽象Beanクラスを継承して作る。親クラスには単純なテーブルを想定した処理を書いておき、子クラスでは親クラスの単純な処理では対応しきれないところをオーバーライドする。

抽象DAO。各テーブルのDAOはこれを継承して作る。

/**
 * Ethna_DB_ADODB専用の抽象DAO
 *
 */
abstract class Dao
{
    public $db;

    /**
     * コンストラクタ
     *
     * @param Ethna_DB_ADODB $db
     */
    public function __construct($db)
    {
        $this->db = $db;
    }

    /**
     * $objの内容をDBに保存する
     *
     * @param Bean $obj
     * @return true/false
     */
    public function insert($obj)
    {
        return $this->db->autoExecute($this->getTable(),
get_object_vars($obj), 'INSERT');
    }

    /**
     * $objの内容でDBを更新する
     *
     * @param Bean $obj
     * @return true/false
     */
    public function update($obj)
    {
        $prKey = $this->getPrKey();
        $where = $this->getPrKey() . '=' . addslashes($obj->$prKey);
        return $this->db->db->autoExecute($this->getTable(),
get_object_vars($obj), 'UPDATE', $where);
    }

    /**
     * $objをデータベースから削除する
     *
     * @param Bean $obj
     * @return true/false
     */
    public function delete($obj)
    {
        $prKey = $this->getPrKey();
        $sql = "DELETE FROM " . $this->getTable() . " WHERE " . $prKey
. "=" . addslashes($obj->$prKey);
        return $this->db->Execute($sql);
    }

    /**
     * テーブル名を返す
     *
     * @return string テーブル名
     */
    abstract protected function getTable();

    /**
     * プライマリキーの列名を返す
     *
     * @return string プライマリキーの列名
     */
    abstract protected function getPrKey();
}
?>

UsersテーブルのDAO。Usersテーブルは単純なつくりなので処理のほとんどは親クラスに任せてしまう。

<?php
require_once('Dao.php');

class UsersDao extends Dao
{
    protected function getTable()
    {
        return 'users';
    }

    protected function getPrKey()
    {
        return 'user_id';
    }
}
?>

各種Beanの親クラスになる抽象Bean。生成時にDAOを渡してもらって保持しておき、データベース処理を頼まれたらDAOに丸投げする。(12/15 returnを追加)

<?php
abstract class Bean
{
    protected $dao;

    public function __construct($dao)
    {
        $this->dao = $dao;
    }

    public function insert()
    {
        return $this->dao->insert($this);
    }

    public function update()
    {
        return $this->dao->update($this);
    }

    public function delete()
    {
        return $this->dao->delete($this);
    }
}
?>

Usersテーブルの行を表すBean。アプリケーションの中でデータコンテナのような役目を果たし、ビジネスロジックが実装されたりする。MVCのM。Beanとか言いながらメンバ変数はpublic。

<?php
require_once('Bean.php');

class User extends Bean
{
    public $user_id;
    public $email;
    public $pass;
}
?>

で、これらを使ってUsersテーブルに新規レコードを挿入する。セッションに各カラムの値が連想配列でセットされているとして、

        // セッションデータからUserオブジェクトを作成
        $sd = $this->session->get('USER_REGIST');
        $user = new User(new UsersDao($this->backend->getDB()));
        foreach($sd as $key => $value) {
            $user->$key = $value;
        }

        // UserオブジェクトをDBに保存
        if ($user->insert()) {
           throw new Exception('DBへの挿入エラー');
        }

というように使う。

課題は、

  1. ADOdbのautoExecuteがSQL文の成功/失敗にかかわらずNULLを返す。true/falseを返してくれるはずなんだけど。調査必要。(Beanにreturn文を書いていないだけでした。)
  2. Actionなどのクライアントが欲しいのは「DBに保存する機能を持ったUserオブジェクト」という1つのものなのに、DaoとBeanで2回newしてるのがなんかかっこ悪いような気がする。
  3. これも根は同じことかもしれないけど、require_onceの量をもうちょっと減らせないものか。

といったところ。