| 
<?phpnamespace Jackbooted\DB;
 
 use \Jackbooted\Config\Cfg;
 use \Jackbooted\Util\Log4PHP;
 /**
 * @copyright Confidential and copyright (c) 2016 Jackbooted Software. All rights reserved.
 *
 * Written by Brett Dutton of Jackbooted Software
 * brett at brettdutton dot com
 *
 * This software is written and distributed under the GNU General Public
 * License which means that its source code is freely-distributed and
 * available to the general public.
 */
 
 abstract class DAO extends \Jackbooted\Util\JB {
 private static $log;
 private static $tableList =  [];
 
 protected $db             = null;
 public    $primaryKey     = null;
 public    $tableName      = null;
 protected $tableStructure = null;
 public    $orm            = []; // Mapping of the variable to the column name. automatically adds 0 and 'id' => primaryKey
 public    $titles         = []; // Array of all the column titles Automatically replaces ID for primary key
 public    $keyFormat      = 'XX000000';
 public    $ignoreCols     = [];
 
 /**
 * @return void
 */
 public static function init () {
 self::$log = Log4PHP::logFactory ( __CLASS__ );
 }
 
 /**
 * @return void
 */
 public function __construct() {
 parent::__construct();
 if ( Cfg::get( 'jb_audit_tables', true ) ) {
 $this->auditTable ();
 }
 
 if ( ! isset( $this->orm[0] ) )    $this->orm[0]    = $this->primaryKey;
 if ( ! isset( $this->orm['id'] ) ) $this->orm['id'] = $this->primaryKey;
 
 if ( ! isset( $this->titles[$this->primaryKey] ) ) $this->titles[$this->primaryKey] = 'ID';
 
 // Could automatically populate the titles based on the column names
 // But at this stage it is "YAGNI" reference CRUD::jbCol2Title
 }
 
 /**
 * @param  $row
 * @return mixed
 */
 public function getRowCount ( $where=null ) {
 $sql = 'SELECT COUNT(*) FROM ' . $this->tableName;
 
 $params = null;
 $sql .= $this->toWhere ( $where, $params );
 
 return DB::oneValue ( $this->db, $sql, $params );
 }
 
 private function toWhere ( $where, &$params=null ) {
 if ( is_array ( $where ) && count ( $where ) > 0 ) {
 $where = $this->objToRel ( $where );
 $sql = '';
 $params = [];
 foreach ( $where as $key => $value ) {
 
 // This allows for dummy columns to be part of the object without the
 // DAO automatically accessing them in the queries.
 if ( $this->ignoreCols != null && array_key_exists( $key, $this->ignoreCols ) ) continue;
 
 if ( $sql == '' ) {
 $sql .= ' WHERE ';
 }
 else {
 $sql .= ' AND ';
 }
 
 if ( $value == null ) {
 $sql .= $key . ' IS NULL';
 }
 else if ( stripos( $value, '%' ) !== false ) {
 $sql .= $key . ' LIKE ?';
 $params[] = $value;
 }
 else {
 $sql .= $key . '=?';
 $params[] = $value;
 }
 }
 
 return $sql;
 }
 else if ( is_string ( $where ) ) {
 return ' WHERE ' . $where;
 }
 else {
 return '';
 }
 }
 
 /**
 * @param  $id
 * @param int $fetch
 * @return array
 */
 public function oneRow ( $id, $fetch=DB::FETCH_ASSOC ) {
 $sql = 'SELECT * FROM ' . $this->tableName . ' WHERE ' . $this->primaryKey . '=?';
 return DB::oneRow ( $this->db, $sql, $id, $fetch );
 }
 
 /**
 * @param  $sets
 * @param  $where
 * @return int
 */
 public function update ( $sets, $where ) {
 DBTable::clearCache();
 
 $sets  = $this->objToRel ( $sets );
 
 // This allows for dummy columns to be part of the object without the
 // DAO automatically accessing them in the queries.
 if ( $this->ignoreCols != null ) {
 foreach ( $this->ignoreCols as $ignoreCol ) {
 unset( $sets[$ignoreCol] );
 }
 }
 
 $params =  [];
 $sql = 'UPDATE ' . $this->tableName . ' ' .
 'SET '    . join ( '=?, ',    array_keys ( $sets  ) ) . '=? ' .
 $this->toWhere ( $where, $params );
 
 return DB::exec ( $this->db, $sql,  array_merge ( array_values ( $sets ), $params ) );
 }
 
 /**
 * @param  $sets
 * @param  $where
 * @return int
 */
 public function search ( $params, $fetch=DB::FETCH_ASSOC ) {
 
 $sql = 'SELECT';
 if ( ! isset ( $params['columns'] ) || $params['columns']== null || $params['columns']=='' ) {
 $sql .= ' *';
 }
 else if ( is_array ( $params['columns'] ) ) {
 $sql .= ' ' . join ( ',',  array_keys ( $this->objToRel ( $params['columns'] ) ) );
 }
 else if ( is_string ( $params['columns'] ) ) {
 $sql .= ' ' . $params['columns'];
 }
 
 $whereParams = null;
 $sql .= ' FROM ' . $this->tableName . $this->toWhere ( $params['where'], $whereParams );
 
 if ( ! isset ( $params['order'] ) || $params['order']== null || $params['order']=='' ) {
 $sql .= '';
 }
 else if ( is_array ( $params['order'] ) ) {
 $order = '';
 foreach ( $this->objToRel ( $params['order'] ) as $key => $value ) {
 if ( $order != '' ) $order .= ', ';
 $order .= $key;
 $value = strtoupper( $value );
 if ( $value == 'ASC' || $value == 'DESC' ) $order .= ' ' . $value;
 }
 $sql .= ' ORDER BY ' . $order;
 }
 else if ( is_string ( $params['order'] ) ) {
 if ( preg_match ( '/^\s*ORDER BY\s+(.*)$/', $params['order'], $match ) ) {
 $order = $match[1];
 }
 else {
 $order = $params['order'];
 }
 $sql .= ' ORDER BY ' . $order;
 }
 
 if ( ! isset ( $params['limit'] ) || $params['limit']== null || $params['limit']=='' ) {
 $sql .= '';
 }
 else if ( is_array ( $params['limit'] ) ) {
 $sql .= ' LIMIT ' . join ( ',',  $params['limit'] );
 }
 else if ( is_integer ( $params['limit'] ) ) {
 $sql .= ' LIMIT ' . $params['limit'];
 }
 return new DBTable ( $this->db, $sql, $whereParams, $fetch );
 }
 
 /**
 * @param  $row
 * @return int
 */
 public function delete ( $row ) {
 $sql = 'DELETE FROM ' . $this->tableName . $this->toWhere ( $row, $params );
 //echo $sql . "\n";
 //print_r ( $params );
 return DB::exec ( $this->db, $sql, $params );
 }
 
 /**
 * @param  $row
 * @return bool|mixed
 */
 public function insert ( $row, $insertMethod='INSERT' ) {
 $row    = $this->objToRel ( $row );
 
 // This allows for dummy columns to be part of the object without the
 // DAO automatically accessing them in the queries.
 if ( $this->ignoreCols != null ) {
 foreach ( $this->ignoreCols as $ignoreCol ) {
 unset( $row[$ignoreCol] );
 }
 }
 
 if ( Cfg::get ( 'jb_db', false ) ) {
 $pKey = DBMaintenance::dbNextNumber ( $this->db, $this->tableName );
 $row[$this->primaryKey] = $pKey;
 }
 
 $keys   = array_keys ( $row );
 $values = array_values ( $row );
 
 $sql = $insertMethod . ' INTO ' . $this->tableName . ' (' . join ( ',', $keys ) . ') VALUES (' . DB::in ( $values )  . ')';
 if ( DB::exec ( $this->db, $sql, $values ) != 1 ) return false;
 
 if ( ! Cfg::get ( 'jb_db', false ) ) {
 $pKey = DB::lastInsertId ( $this->db );
 }
 
 return $pKey;
 }
 
 /**
 * @param  $object
 * @return array
 */
 public function objToRel ( $object ) {
 $relational =  [];
 if ( is_array ( $object ) ) {
 foreach ( $object as $key => $val ) {
 if ( isset ( $this->orm[$key] ) ) $key = $this->orm[$key];
 $relational[$key] = $val;
 }
 }
 return $relational;
 }
 
 public function auditTable () {
 if ( in_array ( null,   [ $this->db, $this->tableName, $this->tableStructure ] ) ) {
 return false;
 }
 
 if ( ! isset ( self::$tableList[$this->db] ) ) {
 self::$tableList[$this->db] = array_flip ( DBMaintenance::getTableList() );
 }
 
 if ( ! isset ( self::$tableList[$this->db][$this->tableName] ) ) {
 DB::exec ( $this->db, $this->tableStructure );
 DBMaintenance::addTableToNextNumber ( $this->tableName, $this->keyFormat, $this->tableName );
 self::$tableList[$this->db][$this->tableName] = 1;
 }
 
 return true;
 }
 
 public function __toString()
 {
 return $this->tableStructure;
 }
 }
 
 |