PDOを利用したDBアクセスクラス(自作ですけども)

最新ソースはコチラ

下記のソースは初期版です。

// PDOを利用したデータベースクラス
class pdbo{
	private static	$pdo;
	private static	$conf;

	private function __construct(){
	}

	public function Factory( $table ){
		if( is_null( pdbo::$conf ) ){
			$tmp = new Config( CONF_PATH.'db.ini' );
			$tmp = $tmp->Get();
			pdbo::$conf = $tmp['DataBase'];
		}
		if( is_null( pdbo::$pdo ) ){
			try{
				pdbo::$pdo = new PDO( pdbo::$conf['dns'],
					pdbo::$conf['user'], pdbo::$conf['password'] );
			} catch( PDOException $e ){
				echo $e->GetMessage();
				throw new Exception( $e->getMessage() );
			}
		}
		return new dbo( pdbo::$pdo, '', $table );
	}

}

class dbo{
	private $dbo;
	private $db_name;
	private $table_name;
	private $fileds;
	private $error_message;
	private $query_log = array();

	public function __construct( $pdbo, $db, $table ){
		$this->dbo		= $pdbo;
		$this->db_name	= $db;
		$this->table_name	= $table;

		//テーブル情報取得
		try{
			$ret = $pdbo->query( 'DESCRIBE '.$table );
		} catch( PDOException $e ){
			$this->error_message = $e->getMessage();
			throw new Exception( $this->error_message );
		}
		$tmp = $ret->fetchAll( PDO::FETCH_ASSOC );
		foreach( $tmp as $node ){
			$type = $this->getType( $node['Type'] );
			$this->fileds[$node['Field']]['type']= $type['type'];
			$this->fileds[$node['Field']]['size']= $type['size'];
			$this->fileds[$node['Field']]['option']= $type['option'];
			$this->fileds[$node['Field']]['null']= $node['Null'];
			$this->fileds[$node['Field']]['key']	= $node['Key'];
		}
	}

	public function DumpQuerys(){
		print_r( $this->query_log );
	}
	/**
	 * 一行だけレコードを取得する
	 *  $flagがtrueの時、条件配列にプライマリキーが存在しない場合エラーに
	 *  なります
	 * @param	array	$condition	条件配列
	 * @param	bool	$flag		プライマリキー存在チェック
	 */
	public function getOnce( $condition, $flag = true ){
		$table	= $this->table_name;
		$dbo	=& $this->dbo;
		if( $flag ){
			//プライマリーキーの存在チェック
			$primary = $this->getPrimary();
			$keys = array_keys( $condition );
			foreach( $primary as $name  ){
				if( !in_array( $name, $keys ) ){
					throw new Exception('プライマリーキーが設定されていません');
				}
			}
		}

		//検索条件生成
		$ret = null;
		try{
			$where = $this->makeWhere( $condition );

			$sql = "SELECT * FROM {$table}";
			if( strlen( $where ) > 0 ) $sql .= $where;
			$this->query_log[] = $sql;
			$ret = $dbo->query( $sql );

		} catch( PDOException $e ){
			$this->error_message = $e->getMessage();
			throw new Exception( $this->error_message );
		}

		//エラー処理
		if( $ret === false )  throw new Exception( "query error: {$sql}");

		//複数行検出
		if( $ret->rowCount() != 1 ) return false;

		return $ret->fetch(PDO::FETCH_ASSOC);
	}

	public function getAll($condition = array(), $order = array()){
		$table	= $this->table_name;
		$dbo	=& $this->dbo;

		//検索条件生成
		$ret = null;
		try{
			$where = $this->makeWhere( $condition );
			$_order = $this->makeOrder( $order );

			$sql = "SELECT * FROM {$table}";
			$sql .= $where;
			$sql .= $_order;
			$this->query_log[] = $sql;
			$ret = $dbo->query( $sql );

		} catch( PDOException $e ){
			$this->error_message = $e->getMessage();
			throw new Exception( $this->error_message );
		}

		//エラー処理
		if( $ret === false )  throw new Exception( "query error: {$sql}");

		return $ret->fetchAll(PDO::FETCH_ASSOC);
	}

	public function getPaging( $condition = array(), $order, &$page ){
		$table	= $this->table_name;
		$dbo	=& $this->dbo;

		//検索条件生成
		$res = null;
		try{
			$where = $this->makeWhere( $condition );
			$_order = $this->makeOrder( $order );

			$sql = "SELECT * FROM {$table}";
			$sql .= $where;
			$sql .= $_order;
			$this->query_log[] = $sql;
			$res = $dbo->query( $sql );

		} catch( PDOException $e ){
			$this->error_message = $e->getMessage();
			throw new Exception( $this->error_message );
		}

		//エラー処理
		if( $res === false )  throw new Exception( "query error: {$sql}");

		$page['rowCount'] = $res->rowCount();
		$page['pageMax'] = ceil( $page['rowCount'] / $page['limit'] );
		$page['start']	= ($page['now'] - 1 )* $page['limit'] + 1;
		$page['end']	= $page['now'] * $page['limit'];
		if( $page['end'] > $page['rowCount'] ) $page['end'] = $page['rowCount'];
		$ret = array();
		for( $n = $page['start']; $n fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_ABS, $n );
		}
		return $ret;
	}

	/**
	 * 唯一のレコード更新
	 */
	public function updateOnce( $data ){
		$table	= $this->table_name;
		$dbo	=& $this->dbo;
		$fileds =& $this->fileds;

		//更新データ
		$up_data = array();
		//条件データ
		$condition = array();
		foreach( $data as $name => $val ){
			list( $nm ) = $this->getFiledName( $name );
			if( $fileds[$nm]['key'] == 'PRI' ){
				$condition[$name] = $val;
			} else {
				$up_data[$name] = $val;
			}
		}

		return $this->update( $up_data, $condition );
	}

	/**
	 * 複数更新
	 */
	public function update( $data, $condition ){
		$table	= $this->table_name;
		$dbo	=& $this->dbo;
		$fileds =& $this->fileds;
		$node = array();
		try{
			$where = $this->makeWhere( $condition );
			foreach( $data as $name => $val){
				$val = addslashes($val);
				//日付時にクォートをつける
				if( $this->isDate($fileds[$name]['type']) ) {
					if( $val == $val * 1 ){
						$val = "'".date( 'Y-m-d H:i:s', $val )."'";
					}
				}
				//文字型にシングルクォートをつける
				if( $this->isString($fileds[$name]['type']) ) {
					$val = "'{$val}'";
				}
				$node[] = "{$name} = {$val}";
		   	}
			$sql = "UPDATE {$table} SET ".implode( ' , ', $node )." {$where}";
			$this->query_log[] = $sql;
			$dbo->query( $sql );
		} catch( Exception $e){
			echo $e->getMessage();
			return false;
		}
		return true;
	}

	/**
	 * 一行だけレコードを取得する
	 *  $flagがtrueの時、条件配列にプライマリキーが存在しない場合エラーに
	 *  なります
	 * @param	array	$data		登録情報
	 * @param	bool	$flag		プライマリキー存在チェック
	 */
	public function insert( $data, $flag = true ){
		if( count( $data ) == 0 ) return false;
		//インサートチェック
		if( ($name = dbo::existsFiled($data,$this->getNotNull())) !== true ){
			throw new Exception(
				"{$name}はnot nullのフィールドですが、存在していませんでした。"
		   	);
		}
		$fileds =& $this->fileds;
		//文字列次処理
		foreach( $data as $name => $val ){
			//文字列時にクォートをつける
			if( $this->isString($fileds[$name]['type']) ){
				$val = "'".addslashes($val)."'";
			}
			//日付時にクォートをつける
			if( $this->isDate($fileds[$name]['type']) ) {
				if( is_int( $val ) ){
					$val = date( 'Y-m-d H:i:s', $val );
				}
				$val = "'".addslashes($val)."'";
			}
			$data[$name] = $val;
		}

		$tmp = array();
		foreach( $data as $name => $val ) $tmp[] = "{$val}";

		$sql = "INSERT INTO {$this->table_name} ( ".
			implode( ' , ', array_keys($data) )." ) VALUES ( ";
		$sql .= implode( ', ', $tmp )." ); ";
		try{
			$this->query_log[] = $sql;
			$ret = $this->dbo->query( $sql );
		} catch( PDOException $e ) {
			throw new Exception( 'Insert Error:'.$e->getMessage() );
		}
		if( $ret === false ){
			throw new Exception( 'Insert Error: '.$sql );
		}
		return true;
	}

	public function delete( $condition = array() ){
	}

	/**
	 * 条件削除
	 */
	public function deleteSearch( $condition ){
		if( count( $condition ) == 0 ) return false;

		$sql = "DELETE FROM {$this->table_name} ".$this->makeWhere($condition);

		try{
			$this->query_log[] = $sql;
			$ret = $this->dbo->query( $sql );
		} catch( PDOException $e ) {
			throw new Exception( 'Insert Error:'.$e->getMessage() );
		}
		return true;
	}

	/**
	 * Where句の生成
	 */
	private function makeWhere( $condition ){
		if( count( $condition ) == 0 ) return '';
		$fileds = $this->fileds;
		$where = array();
		foreach( $condition as $key => $val ){
			$val = addslashes( $val );
			$option = '';
			//オプション検出
			if( strpos( $key, ':' )  !== false ){
				//オプション取得
				$tmp = $key;
				list( $key, $option ) = explode( ':', $tmp );

				//テーブルにカラムが存在するか
				if( !isset( $fileds[$key] ) ){
					throw new Exception(
						"{$key}は{$this->table_name}に存在しないカラムです"
				   	);
				}

				//文字列 日付型 の場合の処理
				if( $this->isString( $fileds[$key]['type'] ) ||
					$this->isDate( $fileds[$key]['type'] )
				) {
					$val = "'{$val}'";
				}

				switch( $option ){
					case 'not':
						$where[] = "{$key} <> {$val}";
						break;

					case 'begin':
						$where[] = "{$key} >= {$val}";
						break;
					case 'quit':
						$where[] = "{$key}  {$val}";
						break;

					case 'end':
						$where[] = "{$key} < {$val}"; 						break; 					case '--': 						$where[] = "{$key} {$val}"; 						break; 					case 'like': 						$where[] = "{$key} LIKE {$val}"; 						break; 					case 'eq': 						$where[] = "{$key} = {$val}"; 						break; 					case 'neq': 						$where[] = "{$key} = {$val}"; 						break; 					default: 						throw  new Exception( 'makeWhere error: '. 							'指定されないオプションを検出しました' 					   	); 				} 			} else { 				//オプションが無いとき 				//テーブルにカラムが存在するか 				if( !isset( $this->fileds[$key] ) ){
					throw new Exception(
						"{$key}は{$this->table_name}に存在しないカラムです"
				   	);
				}

				if( $this->isString($fileds[$key]['type'] ) ) {
					$where[] = "{$key} LIKE '%{$val}%'";
				} else {
					$where[] = "{$key} = {$val}";
				}
			}
		}
		return " WHERE ".implode( ' AND ', $where );
	}

	/**
	 *
	 */
	protected function makeOrder( $order ){
		if( count( $order ) == 0 ) return '';

		$ret = array();
		$fileds = $this->fileds;
		$kyes = array_keys( $order );
		//テーブルにカラムが存在するか
		foreach( $order as $name => $val ){
			if( !isset( $fileds[$name] ) ){
				throw new Exception(
					"{$key}は{$this->table_name}に存在しないカラムです"
		   		);
			}
			$ret[] = "{$name} {$val}";
		}
		return " ORDER BY ".implode( " , ", $ret );
	}

	/**
	 * 文字型かを判別する
	 */
	protected function isString( $type ){
		switch( strtolower($type) ){
			case 'char':
			case 'varchar':
			case 'text':
				return true;
		}
		return false;
	}

	/**
	 * 日付型かを判別する
	 */
	protected function isDate( $type ){
		switch( strtolower($type) ){
			case 'date':
			case 'datetime':
			case 'timestamp':
				return true;
		}
		return false;
	}

	/**
	 * Mysqlのカラムタイプから型とサイズ、オプション属性を切り離す
	 */
	private function getType( $type ){
		$ret = array(
			'size'	=> '',
			'type'	=> '',
			'option'=> '',
		);
		$st	= 0;
		$end= 0;
		$st = strpos( $type, '(' );
		if( $st === false ){
			$ret['type'] = $type;
			return $ret;
		}
		$ret['type'] = substr( $type, 0, $st );
		$end = strpos( $type, ')' );
		$ret['size'] = substr( $type, $st+1, $end-$st-1 );
		$tmp = explode( ' ', $type );
		if( count( $tmp ) > 1 ) $ret['option'] = $tmp[1];
		return $ret;
	}

	/**
	 * プライマリーキー配列の取得
	 */
	private function getPrimary(){
		$ret = array();
		foreach( $this->fileds as $name => $node ){
			if( $node['key'] == 'PRI' ){
				$ret[] = $name;
			}
		}
		return $ret;
	}

	private function getNotNull(){
		$ret = array();
		foreach( $this->fileds as $name => $node ){
			if( $node['null'] == 'No' ){
				$ret[] = $name;
			}
		}
		return $ret;
	}

	/**
	 * $list配列内のフィールドが$filedsに含まれているかチェックする
	 */
	private function existsFiled( $fileds, $list ){
		$keys = array_keys( $fileds );
		foreach( $list as $name ){
			if( !in_array( $name, $keys ) ) return $name;
		}
		return true;
	}

	private function getFiledName( $name ){
		if( strpos(  $name, ':' )  === false ) return array( $name, '' );
		return explode( ':', $name );
	}
}