kazpgmの日記

『プログラム自動作成@自動生成』作成の日記

TOOL更新_DBマネージャクラス。うごいたので。ここに更新する。

TOOL更新_DBマネージャクラス。うごいたので。ここに更新する。まだ実験中なのでコーディング規約には沿っていないけど、徐々に、このページを直接直していくことにする。
■使い方はこんな感じ

■config.php
// データソース名(ZEND DB 接続情報)
if( $_ENV["OS"] == 'Windows_NT' ) { 
    $DSN_ZEND = 
        array(
         host=>'localhost', //接続先ホスト
         username=>'user',  //DBユーザ名
         password=>'user',  //DBパスワード
         dbname=>'dbname'   //DB名
        ); 
} else { 
    $DSN_ZEND = 
        array(
         host=>'localhost', //接続先ホスト
         username=>'user',  //DBユーザ名
         password=>'user',  //DBパスワード
         dbname=>'dbname'   //DB名
        ); 
}
Zend_Registry::set('DSN_ZEND',$DSN_ZEND);
■ControllerABase.php
        $DSN_ZEND  = Zend_Registry::get('DSN_ZEND');
        $this->_db = DbManager::getInstance($DSN_ZEND, 'uid'); // DB接続
■LogininfoUtil.php
        $sql = 'INSERT INTO ' . 'm_logininfo' . ' ( '.
            'login_id, ' . // ログインID
            'login_type, ' . // ログイン権限
            'pwd1, ' . // パスワード
            'yuko_flg, ' . // 有効フラグ
            'logininfo_insert, ' . // 登録日時
            'logininfo_update ' .  // 更新日時
            ' ) VALUES (?,?,?,?,?,?)'; 
        $valary = array();
        $valary[] = $o['login_id']; // ログインID
        $valary[] = $o['login_type']; // ログイン権限
        $valary[] = $o['pwd1']; // パスワード
        $valary[] = $o['yuko_flg']; // 有効フラグ
        $valary[] = date( 'Y/m/d H:i:s' ); // 登録日時
        $valary[] = date( 'Y/m/d H:i:s' ); // 更新日時
        
        $db->query($sql, $valary);

■DBマネージャクラスはこれ

■DbManager.php
<?php
//  =============================================================
//  2010 kaz PHP自動作成お助けTOOL.(http://kazpgm.ddo.jp/) Start
//  修正BSDライセンス。
//  =============================================================
require_once 'Zend/Config/Ini.php';
require_once 'Zend/Db.php';
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once('AppLogr.php');

// DBマネージャ
//  1.必ず1コネクション(シングルトン)とする
//  2.DBコネクションは、DBに最初にアクセスするときまで取得しない。
//   補足:アクセスしなければDBコネクションを取得しない
//      commit()、rollBack()はDBコネクションがない場合、何もしない。
//  3.デバックしやすくするためSQLログを出力する。
//   ・Zend_Dbを直接使わずに一度SQLを作成してから使う。
//  4.ControllerBaseクラスでExceptionを拾うのでここでは拾わない。
// 
class DbManager {
    protected $_db = null;          // DBコネクション
    protected $_logger = null;      // ログ出力オブジェクト
    protected $_uid = '';           // ユーザID
    protected $_dsn = '';           // データセットネーム
    protected $_logMark = '●';     // Log用に、コネクションを区別するためのマーク
    protected $_begin = '';         // 初期値=''、$_dbがnullのときでかつ、beginTransactionメソッドのとき'begin'を設定する。
                                    // DBアクセスがあったとき、$_begin='begin'のときはbeginしてからDBアクセスを行う。その後''に戻す。
    // シングルトンオブジェクトを格納する変数
    private static $_singleton = null;

    // コンストラクタをprivateにして直接newできないようにしています。
    // 「クラス名::getInstance();」を使用してください。
    // 「new クラス名();」だと「Fatal error: Call to private クラス名::__construct() ・・・」になります
    private function __construct() {
    }

    // インスタンスを生成する
    public static function getInstance($dsn=null, $uid='dummy') {
        if (self::_getSingleton() == null) {
            $obj = new self();
            self::_setSingleton($obj);
            $obj->_setLoggerEtc($dsn, $uid);
        }
        return self::_getSingleton();
    }

    /**
     * Singleton変数を取得する。<br>
     * @return    シングルトン変数
     */
    protected function _getSingleton() {
        return self::$_singleton;
    }

    /**
     * Singleton変数を設定する。<br>
     * @param    $singleton    シングルトン変数
     */
    protected function _setSingleton($singleton) {
        self::$_singleton = $singleton;
    }

    /**
     * Loggerなどを設定する。<br>
     * @param    $dsn    データセット
     * @param    $uid    ユーザID
     */
    protected function _setLoggerEtc(&$dsn, &$uid) {
        $this->_dsn = $dsn;  // DBコネクト情報
        $this->_uid = $uid;  // ユーザID
        // ログ
        $this->_logger = new AppLogr(DIR_LOG, DEBUG_FLG);
    }

    /**
     * DBコネクションを設定する。<br>
     */
    private function _getConnection() {
        if (empty($this->_db)) {
            if (empty($this->_dsn)) {
                // 例外をスローします。
                throw new SysException('Invalid $dsn. please call getInstance($dsn, $uid)');
            }
            $db = Zend_Db::factory('Pdo_Mysql', $this->_dsn);
            $db->getConnection();
            $db->setFetchMode(Zend_Db::FETCH_OBJ);
            $db->query('SET names utf8');
            $db->query("SET time_zone = '+9:00'");
            $db->query("set autocommit = 0");
            $this->_db = $db;
            if ($this->_begin == 'begin') {
                $this->beginTransaction(); // DBアクセスがあったとき$_begin='begin'のときはbeginしてからDBアクセスを行う。
                $this->_begin = '';        // ''に戻す。
            }
        }
    }

    // DBコネクションを戻す
    // SQLログを出力するため通常はDbManagerクラスを使用してください。
    // どうしても直接DBコネクションを使いたいときのみ使用してください。
    public function getDb() {
        $this->_getConnection();
        return $this->_db;
    }

   /**
     * getAll処理。<br>
     * @param    $sql    SQL文。値の置換文字は?で指定する。
     * @param    $ary    値の配列。
     * @return           結果
     */
    public function getAll($sql, $ary=array()) {
        $this->_getConnection();
        $sql = $this->_sqlAndValQuote($sql, $ary); // SQL文に値を埋めこむ。
        $this->_outSqlLog($sql, 'getAll');
        return $this->rtn2arr($this->_db->fetchAll($sql));

    }

   /**
     * getRow処理。<br>
     * @param    $sql    SQL文。値の置換文字は?で指定する。
     * @param    $ary    値の配列。
     * @return           結果
     */
    public function getRow($sql, $ary=array()) {
        $this->_getConnection();
        $sql = $this->_sqlAndValQuote($sql, $ary); // 値を埋めこんだSQL文。
        $this->_outSqlLog($sql, 'getRow');
        return $this->rtn2arr($this->_db->fetchRow($sql));
    }

   /**
     * getOne処理。<br>
     * @param    $sql    SQL文。値の置換文字は?で指定する。
     * @param    $ary    値の配列。
     * @return           結果
     */
    public function getOne($sql, $ary=array()) {
        $this->_getConnection();
        $sql = $this->_sqlAndValQuote($sql, $ary); // 値を埋めこんだSQL文。
        $this->_outSqlLog($sql, 'getOne');
        return $this->rtn2arr($this->_db->fetchOne($sql));
    }

   /**
     * Query処理(INSERT処理、UPDATE処理、DELETE処理、その他)。<br>
     * @param    $sql    SQL文。値の置換文字は?で指定する。
     * @param    $ary    値の配列。
     * @return           結果
     */
    public function query($sql, $ary=array()) {
        $this->_getConnection();
        $sql = $this->_sqlAndValQuote($sql, $ary); // 値を埋めこんだSQL文。
        $this->_outSqlLog($sql, 'query');
        return $this->_db->query($sql);
    }

   /**
     * SQL文に値配列を埋め込んでquote処理する。<br>
     * @param    $sql    SQL文。値の置換文字は?で指定する。
     * @param    $ary    値の配列。
     * @return           値を埋めこんだSQL文
     */
    protected function _sqlAndValQuote(&$sql, &$ary=array()) {
        $sqls = preg_split("/(\?)/", $sql, -1, PREG_SPLIT_DELIM_CAPTURE ); // ”?”で分割。”?”も配列に含める。
        $i = 0;
        foreach((array)$sqls as $key => $sqlValue) {
            if ($sqlValue == "?") { // ”?”の場合
                if (is_null($ary[$i])) {
                    $sqls[$key] = 'null'; // 値埋め込む。
                } else {
                    $sqls[$key] = $this->_db->quote($ary[$i]); // 値埋め込む。
                }
                $i++;
            }
        }
        $rtnSql = join('', $sqls); // 値を埋めこんだSQL文。
        return $rtnSql;
    }

//    // ---------------------------------------------------------
//    // ここから お助けTOOLVer0.1互換用。非推奨。              -
//    // ---------------------------------------------------------
//    // $this->_db->quote() 対応:お助けTOOLVer0.1互換用。非推奨。
//    public function dbQuote($column) {
//        $this->_getConnection();
//        $tmp = $this->_db->quote($column);
//        return $tmp;
//    }
//
//    // $this->_db->quote() 配列対応版:お助けTOOLVer0.1互換用。非推奨。
//    public function dbQuotes($columns) {
//        $this->_getConnection();
//        $tmp = array();
//        foreach((array)$columns as $colName => $colValue) {
//            $tmp[$colName] = $this->_db->quote($colValue);
//        }
//        return $tmp;
//    }
//
//    // fetchAll処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbFetchAll($sql) {
//        $this->_getConnection();
//        $this->_outSqlLog($sql, 'dbFetchAll');
//        return $this->rtn2arr($this->_db->fetchAll($sql));
//    }
//
//    // 1件read処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbFetchRow($sql) {
//        $this->_getConnection();
//        $this->_outSqlLog($sql, 'dbFetchOne');
//        return $this->rtn2arr($this->_db->fetchRow($sql));
//    }
//
//    // fetchOne処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbFetchOne($sql) {
//        $this->_getConnection();
//        $this->_outSqlLog($sql, 'dbFetchOne');
//        return $this->rtn2arr($this->_db->fetchOne($sql));
//    }
//
//    // INSERT処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbInsert($tableName, $columns) {
//        $this->_getConnection();
//        $columns = $this->dbQuotes($columns);
//        $sql = 'INSERT INTO '.$tableName.' ('.join(', ', array_keys((array)$columns)).') VALUES ('.join(', ', array_values((array)$columns)).')';
//        $this->_outSqlLog($sql, 'dbInsert');
//        return $this->_db->query($sql)->rowCount();
//    }
//
//    // UPDATE処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbUpdate($tableName, $columns, $conditions = array()) {
//        $this->_getConnection();
//        $sets = array();
//
//        $columns = $this->dbQuotes($columns);
//        foreach($columns as $key => $val) {
//            $sets[] = $key . ' = ' . $val;
//        }
//        $sql = 'UPDATE '.$tableName.' SET ' .join(', ', $sets);
//        if($conditions) {
//            $sql .= ' WHERE ' . join(' AND ', $conditions);
//        }
//
//        $this->_outSqlLog($sql, 'dbUpdate');
//        return $this->_db->query($sql)->rowCount();
//    }
//
//    // DELETE処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbDelete($tableName, $conditions = array()) {
//        $this->_getConnection();
//        $sqlWhere = $conditions;
//
//        $sql = 'DELETE FROM ' . $tableName;
//        if($sqlWhere) {
//            $sql .= ' WHERE ' . join(' AND ', (array)$sqlWhere);
//        }
//
//        $this->_outSqlLog($sql, 'dbDelete');
//        return $this->_db->query($sql)->rowCount();
//    }
//
//    // Query処理:お助けTOOLVer0.1互換用。非推奨。
//    public function dbQuery($sql) {
//        $this->_getConnection();
//        $this->_outSqlLog($sql, 'dbQuery');
//        return $this->_db->query($sql);
//    }
//    // ---------------------------------------------------------
//    // ここまで お助けTOOLVer0.1互換用。非推奨。              -
//    // ---------------------------------------------------------

    /**
     * ログ出力処理<br>
     * 
     * @param    $sql    SQL文
     * @param    $func   'fetchAll'、'fetchOne'など
     * @return            文字種を表す定数
     */
    protected function _outSqlLog($sql, $func) {
        $this->_logger->outSqlLog("[$this->_logMark $this->_uid $func ]", $sql);    // ユーザID + メソッド名 + SQL
    }

    /**
     * 結果を配列で返す<br>
     * 
     * @param    $obj    obj
     * @return   配列
     */
    public function rtn2arr($arr)  
    {  
        if (is_object($arr)) { // OBJECTのとき
            return (array)$arr;
        } else if (!is_array($arr)) { // 配列以外のとき
            return $arr;
        }
        // 配列のとき
        $rtns = array();
        for ($i = 0; $i < count($arr); $i++) {
            if (is_object($arr[$i])) {
                $rtns[$i] = (array)$arr[$i];
            } else {
                $rtns[$i] = $arr[$i];
            }
        }  
        return $rtns;  
    }  

    // DB begin
    public function beginTransaction()
    {
        if (empty($this->_db)) {
            $this->_begin = 'begin'; // $_dbがnullのとき'begin'を設定する。
            return null;
        }
        $sql = 'begin';
        $this->_outSqlLog($sql, 'beginTransaction');
        return $this->_db->query($sql);
    }

    // DB commit
    public function commit()
    {
        if (empty($this->_db)) {
            $this->_begin = ''; // $_dbはnullに戻す。
            return null;
        }
        $sql = 'commit';
        $this->_outSqlLog($sql, 'commit');
        return $this->_db->query($sql);
    }

    // DB rollback
    public function rollBack()
    {
        if (empty($this->_db)) {
            $this->_begin = ''; // $_dbはnullに戻す。
            return null;
        }
        $sql = 'rollback';
        $this->_outSqlLog($sql, 'rollBack');
        return $this->_db->query($sql);
    }


}
//  =============================================================
//  2010 kaz PHP自動作成お助けTOOL.(http://kazpgm.ddo.jp/) End
//  修正BSDライセンス。
//  =============================================================

■シーケンス作成用DBマネージャクラスはこれ

■DbManagerForSeq.php
<?php
//  =============================================================
//  2010 kaz PHP自動作成お助けTOOL.(http://kazpgm.ddo.jp/) Start
//  修正BSDライセンス。
//  =============================================================

// シーケンス作成用DBマネージャ。DbManagerを継承しただけ。
// ただし、static $_singleton2にシングルトンobjを格納するためgetInstanceを書き換えている。
//    書き換えないとDbManagerにあるselfはDbManagerのことなので$_singleton2を使ってくれない。
//  シーケンス作成時にコミットするために使う。
//  1.必ず1コネクション(シングルトン)とする
//  2.DBコネクションは、DBに最初にアクセスするときまで取得しない。
//   補足:アクセスしなければDBコネクションを取得しない
//      commit()、rollBack()はDBコネクションがない場合、何もしない。
//  3.デバックしやすくするためSQLログを出力する。
//   ・Zend_Dbを直接使わずに一度SQLを作成してから使う。
//  4.ControllerBaseクラスでExceptionを拾うのでここでは拾わない。
// 
class DbManagerForSeq extends DbManager {
    // シングルトンオブジェクトを格納する変数
    private static $_singleton2 = null;

    // コンストラクタをprivateにして直接newできないようにしています。
    // 「クラス名::getInstance();」を使用してください。
    // 「new クラス名();」だと「Fatal error: Call to private クラス名::__construct() ・・・」になります
    private function __construct() {
    }

    // インスタンスを生成する
    public static function getInstance($dsn=null, $uid='dummy') {
        if (self::_getSingleton() == null) {
            $obj = new self();
            self::_setSingleton($obj);
            $obj->_logMark = '△'; // Log用に、コネクションを区別するためのマーク
            $obj->_setLoggerEtc($dsn, $uid);
        }
        return self::_getSingleton();
    }

    /**
     * Singleton変数を取得する。<br>
     * @return    シングルトン変数
     */
    protected function _getSingleton() {
        return self::$_singleton2;
    }

    /**
     * Singleton変数を設定する。<br>
     * @param    $singleton    シングルトン変数
     */
    protected function _setSingleton($singleton) {
        self::$_singleton2 = $singleton;
    }

}
//  =============================================================
//  2010 kaz PHP自動作成お助けTOOL.(http://kazpgm.ddo.jp/) End
//  修正BSDライセンス。
//  =============================================================

 ■サイト:http://kazpgm.ddo.jp/

03/09 20:00-02:00 ちょと面白いのは、結果を配列で返す「rtn2arr」メソッドで元のロジックに対応するようにした。Zend_Dbの結果では配列の中にオブジェクトが入っていたりするのでハンドリングが今までと変わってしまう。そこで、配列の配列に変換した。PHP5でもarrayはポインター渡しにならない。ということを考えるとarrayにしないで使うのがいいのだろうが、使いづらい。ので。まだ&つけてポインターにしたほうが使い勝手がいい。
DSNをiniを使わずにArrayを使ったのは、WinNTとLinuxでDBを切り分ける既存ロジックが使い心地いいので。それに、config.phpをクラスにしてここに固定データをまとめる予定なので。

3/11 01:30-01:30 delete、insert、updateはquaryメソッドで処理している。queryメソッドは「Zend_Db_Statement_Pdo Object」(PDOStatement)を戻してくる。「rowCount()」メソッドで更新件数を取得た。 dbQueryメソッドでrtn2arrメソッドを通すのはやめた。queryメソッドの戻りは「Zend_Db_Statement_Pdo Object」(PDOStatement)だったので、rtn2arrするのはNGだった。直接修正。コメントなし。

6/3 23:00-0:00 DBマネージャクラスを前面修正。SQLは?を置換する方法(見かけはprepareメソッドのやり方。でも、使えるのは?のみにした。)に変えた。Quote忘れを完全に防止する。という強い気持ち。お助けTOOLVer0.1互換用のメソッドも今回コメントアウトした。あと2ヶ月ぐらい様子見て、問題ないようならコメントアウトを削除する予定。

6/5 15:00-15:30 DbManagerForSeq.phpのために_getSingletonメソッド、_setSingletonメソッドをつくって関連修正した。DbManagerForSeq.phpのDBインスタンスはDbManagerのものを見ていた。2つのコネクションになっていなかった。ので、修正した。http://d.hatena.ne.jp/kazpgm/20100315/1268667599 (TOOL更新_DBマネージャクラス。に、置き換えている。「AppDbFunctions」(DB関数群)クラス作成した。ここに更新する。)でテストしている。ついでにこのページにDbManagerForSeq.phpも載せておく。

6/5 17:30-18:30 DbManagerForSeq.phpとDbManager.phpの共通部分を_setLoggerEtc($dsn, $uid)にまとめた。『$obj = new self();』にして$objにインスタンスいれて$thisで使ってみた。全体的にうまくいっている。

6/8 20:30-21:00 DBコネクションは、DBに最初にアクセスするとき取得する。補足:アクセスしなければDBコネクションを取得しない。commit()、rollBack()はDBコネクションがない場合、何もしない。とした。

6/8 23:30-0:00 beginTransactionメソッドのとき、すぐにDBコネクション作らないようにした。実際にDBアクセスする前にコネクションを取る。

6/9 20:30 21:00 commit()、 rollBack()のときで『empty($this->_db)』のとき『$this->_begin = '';』するようにした。
6/10 20:30-20:40 ■LogininfoUtil.phpのサンプルをinsert文(?が入っている)の箇所に差し替えた。
8/9 10:00-10:30 http://d.hatena.ne.jp/kazpgm/20100809/1281315402の内容を反映した。
20/21 20:30-22:30 パラメータがnullのときの作成SQLが間違っていた。ので修正した。(http://d.hatena.ne.jp/kazpgm/20101021/1287667279 参照)