<?php
class dbAccess{
	private $pdo = null;
	//pdoを作成し、保持する。
	public function __construct( $strDbPath ){
		if (! file_exists( $strDbPath )) {
			return;
			errLog(
				'DB FILE NOT FOUND' ."\t".
				'DB PATH:'.$strDbPath."\r\n"
			);
		};
		try{
			$this->pdo = new PDO( 'sqlite:' . $strDbPath );
    			$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
		}catch( PDOException $e ){
			errLog(
				'PDO CREATE ERROR' ."\t".
				'DB PATH:'.$strDbPath."\t".
				'Exception:'.$e->getMessage( )."\r\n" 
			);
		};
	}
	//pdoが作成されたかを確認し、boolで状態を返す。
	public function isEnable(){
		return $this->pdo !== null;
	}
	private function setSql( $strSql ){
		return $this->pdo->prepare( $strSql );
	}
	private function bind( &$stmt , $aryParams ){
		if( ! is_array( $aryParams ) ){
			errLog(
				'PARAM IS NOT ARRAY' ."\t".
				'PARAM:'.json_encode( $aryParams )."\r\n" 
			);
			throw new Exception();
		}

		foreach($aryParams as $key => $data ){
			$value = $data['value'];
			$type = $data['type'];
			$stmt->bindValue( $key , $value, $type );
		};
	}

	//selectの発行で利用する。第二引数がnullまたは空であれば、PDO::queryで発行する。
	public function select( $strSql , $aryPrams = null ){
		$haveToBind = true;
		if( $aryPrams === null || $aryPrams ===[] ){
			$haveToBind = false;
		};
		$ret = [ 'rows' => [] ,  'error' => null ];
		try {
			if( $haveToBind ){
				$stmt = $this->setSql( $strSql );
				$this->bind( $stmt , $aryPrams );
				$stmt->execute( );
			}else{
			    $stmt = $this->pdo->query($strSql);
			};

			$ret[ 'rows' ] =  $stmt->fetchAll();
		} catch (PDOException $e) {
			$ret[ 'error' ] = $e;
			if( $haveToBind ){
				errLog(
					'SELECT ERROR' ."\t".
					'SQL:'.$strSql."\t".
					'params:'.json_encode($aryPrams)."\t".
					'Exception:'.$e->getMessage( )."\r\n" 
				);
			}else{
				errLog(
					'SELECT ERROR' ."\t".
					'SQL:'.$strSql."\t".
					'Exception:'.$e->getMessage( )."\r\n" 
				);
			}
		};
		return $ret;
	}
	public function query( $strSql ){
		return $this->select( $strSql , null );
	}
	//insert,delete,updateの発行で利用する。尚、第二引数がnullまたは空であれば、PDO::execで発行する。
	//第２引数は2重配列とし、外側にはkeyは設定しないこと。※要は1から始まる配列であること、を期待する。
	public function write( $strSql , $aryAryParams  = null ){
		$haveToBind = true;
		if( $aryAryParams === null ){
			$haveToBind = false;
		}else if( $aryAryParams ===[] ){
			return ['row' =>[],'error' => null ];
		};
		$ret = [ 'error' => null ];
		if( $haveToBind ){
			$ret[ 'row' ] = [];
			try{
				$stmt = $this->setSql( $strSql );
			}catch( PDOException $e ){
				$ret[ 'error' ] = $e;
				errLog(
					'SETSQL ERROR' ."\t".
					'SQL:'.$strSql."\t".
					'Exception:'.$e->getMessage( )."\r\n"
				);
				return $ret;
			};
			foreach( $aryAryParams as $key => $aryParams ){
				try{
					$this->bind( $stmt , $aryParams );
					$stmt->execute( );
					$ret[ 'row' ][]= $stmt->rowCount();
				}catch( PDOException $e ){
					if( ! is_array( $ret[ 'error' ] ) ){
						$ret[ 'error' ] = [];
					};
					$ret[ 'error' ][$key] = $e;
					errLog(
						'EXEC ERROR' ."\t".
						'SQL:'.$strSql."\t".
						'params:'.json_encode($aryParams)."\t".
						'Exception:'.$e->getMessage( )."\r\n"
					);
				};
			};
		}else{
			try{
				$ret[ 'row' ] = $this->pdo->exec( $strSql );
			}catch( PDOException $e ){
				$ret[ 'error' ] = $e;
				errLog(
					'EXEC ERROR' ."\t".
					'SQL:'.$strSql."\t".
					'Exception:'.$e->getMessage( )."\r\n"
				);
				return $ret;
			};
		};
		return $ret;
	}
	//引数をexecする。create、drop等はこちらを用いる。
	public function exec( $strSql ){
		$ret = [ 'error' => null , 'row' => null ];
		try{
			$ret[ 'row' ] = $this->pdo->exec( $strSql );
		}catch( PDOException $e ){
			$ret[ 'error' ] = $e;
			errLog(
				'EXEC ERROR' ."\t".
				'SQL:'.$strSql."\t".
				'Exception:'.$e->getMessage( )."\r\n"
			);
		};
		return $ret;
	}
	//トランザクションを開始する。尚、これはIMMEDIATEで発行する。
	public function begin( ){
		return $this->exec( 'BEGIN IMMEDIATE' );
	}
	public function commit( ){
		return $this->exec( 'COMMIT' );
	}
	public function rollback( ){
		return $this->exec( 'ROLLBACK' );
	}


}

