#native_company# #native_desc#
#native_cta#

MySQL Abstraction Class

By Vyacheslav Yanson
on April 3, 2007

Version: 0.3

Type: Class

Category: Databases

License: GNU General Public License

Description: Database abstraction class
Version 0.3

<?php

/*

Database abstraction class
Version 0.3

TODO for v1.0:
- Add functionality to create custom modifiers without having to hard-code them into class
- Eliminate the need to write SQL queries in asset definition
- Make class work with different database engines (like Propel does)

*/

class asset
{
	public function __construct($def, $db = null)
	{
		$this->db = is_null($db) ? $GLOBALS['db'] : $db;
		
		// list of elements
		$this->elements = $def['elements'];
		
		// sql queries
		$this->list_sql = $def['list_sql'];
		$this->edit_sql = $def['edit_sql'];
		$this->save_sql = $def['save_sql'];
		$this->add_sql = $def['add_sql'];
		$this->delete_sql = $def['delete_sql'];
		
		// primary key element
		$this->param_element = $def['primaryKey'];
	}
	
	// this goes through list of elements and formats it based on parameters
	// (array) $values
	private function parseValues($values = array())
	{
		$return = array();
		
		// loop through elements
		foreach ($this->elements as $n => $element)
		{
			$value = $values[$n];
			
			if (is_array($element['modifiers']))
			{
				foreach($element['modifiers'] as $pn => $pv)
				{
					// do something with $value based on params
					switch ($pn)
					{
						case 'date_format':
							$value = date($pv, $value);
							break;
						
						case 'toUnixTime':
							$value = strtotime($value);
							break;
						
						case 'encode':
							if ($pv === 'html')
							{
								$value = htmlspecialchars($value);
							} else {
								$value = urlencode($value);
							}
							break;
					}
				}
			}
				
			$return[$n] = $value;
		}
		
		return $return;
	}
	
	// get value from database by primary key
	// (string) $pkValue; (bool) $skipParce
	private function getOne($pkValue, $skipParce)
	{
		// fill in primary key value
		$q = preg_replace('~%param%~i', mysql_real_escape_string($pkValue), $this->edit_sql);
		$s = $this->db->query($q);
		
		return $skipParce ? $s[0] : $this->parseValues($s[0]);
	}
	
	// add new record
	// (array) $values
	public function add($values)
	{
		$sql = array();
		$sql_left = array();
		$sql_right = array();
		
		foreach ($this->elements as $n => $element)
		{
			$value = isset($values[$n]) ? stripslashes($values[$n]) : $element['default'];
			$sql[] = array($element['sql_path'], $value);
		}
		
		if (!empty($sql))
		{
			foreach($sql as $n => $v)
			{
				array_push($sql_left, "`" . $v[0] . "`");
				array_push($sql_right, "'" . mysql_real_escape_string($v[1]) . "'");
			}
			
			$search = array();
			$search[] = '~%sql_left%~i';
			$search[] = '~%sql_right%~i';
			
			$replace = array();
			$replace[] = implode(',', $sql_left);
			$replace[] = implode(',', $sql_right);
			
			$q = preg_replace($search, $replace, $this->add_sql);
			$this->db->query($q);
			
			return true;
		}
		
		return false;
	}
	
	// save values
	// (array) $values; (string) $pkValue
	public function save($values, $pkValue)
	{
		$sql = array();
		$sql_left = array();
		$sql_right = array();
		
		foreach ($this->elements as $n => $element)
		{
			if (isset($values[$n]))
			{
				$value = stripslashes($values[$n]);
				$sql[] = array($element['sql_path'], $value);
			}
		}
		
		$sql_upd = '';
		$i = 0;
		$total = count($sql) - 1;
		
		if ($total > -1)
		{
			foreach($sql as $n => $v)
			{
				$sql_upd .= "`" . $v[0] . "`='" . mysql_real_escape_string($v[1]) . "'";
				if ($i < $total) $sql_upd .= ",";
				$i++;
			}
			
			if(!empty($sql_upd))
			{
				$search = array();
				$search[] = '~%update_sql%~i';
				$search[] = '~%param%~i';
				
				$replace = array();
				$replace[] = $sql_upd;
				$replace[] = mysql_real_escape_string($pkValue); // primary key value
				
				// save
				$q = preg_replace($search, $replace, $this->save_sql);
				$this->db->query($q);
				
				return true;
			}
		}
		
		return false;
	}
	
	// delete record
	// (array|string) $sel
	public function delete($sel)
	{
		// sel could be an array of primary key values or string if you want to delete just one record
		if (is_array($sel) && count($sel) > 0)
		{
			$p = $sel;
		} else {
			$p = array(0 => $sel);
		}
		
		$q = preg_replace('~%param%~i', implode(',', $p), $this->delete_sql);
		$this->db->query($q);
		
		return true;
	}
	
	// get records. if second parameter is not an array - assume user wants to get one record by primary key
	// (bool) $skipParce; (string|array) $limit; (string) $order_by; (string) $order_how
	public function get($skipParce = false, $limit = array(), $order_by = '', $order_how = '')
	{
		// make sure $skipParce is boolean
		$skipParce = (bool) $skipParce;
		
		// check if we want to display one record or not
		if (is_array($limit))
		{
			$dList = array();
			
			foreach ($this->elements as $n => $element)
			{
				$dList[] = array('name' => $n, 'sql_path' => $element['sql_path']);
			}
			
			// what do we sort by? we need correct sql paths to columns
			$order_by_sql = $this->elements[$order_by]['sql_path'];
			
			// there is only asc and desc ordering
			$order_how = $order_how === 'desc' ? 'desc' : 'asc';
			
			// check if user wants to limit amount of records
			$limit_sql = '';
			if (isset($limit[0]) && (int) $limit[0] > 0)
			{
				$limit_sql = 'limit ' . (int) $limit[0];
				if (isset($limit[1]) && (int) $limit[1] > 0)
				{
					$limit_sql .= ', ' . (int) $limit[1];
				}
			}
			
			$search = array();
			$search[] = '~%sql_val%~i';
			$search[] = '~%sql_order%~i';
			$search[] = '~%sql_limit%~i';
			
			$replace = array();
			$replace[] = '*';
			$replace[] = empty($order_by_sql) ? '' : "order by `" . $order_by_sql . "` " . $order_how;
			$replace[] = $limit_sql;
			
			$query = preg_replace($search, $replace, $this->list_sql);
			$val = $this->db->query($query);
			
			if (!$skipParce)
			{
				foreach ($val as $n => $v)
				{
					$val[$n] = $this->parseValues($v);
				}
			}
			
			return $val;
		} else {
			// return single record
			return $this->getOne($limit, $skipParce);
		}
	}
}

// example usage:

include_once('class.mysql.php');

$db_conf = array(
	'host'	=>	'localhost',
	'user'	=>	'undefine_tester',
	'pass'	=>	'tester',
	'db'	=>	'undefine_tester',
	'pers'	=>	false // persistent connection?
);
$db = new mysql($db_conf);

$table = 'tester';
$tester_definition = array(
	'primaryKey'	=>	'id', // primary key column
	
	'elements'	=> array(
		/*
			please use the following format for element definitions:
			
			'unique name of element'	=>	array(
				'default'	=>	'default value (if not specified upon adding new record)',
				'sql_path'	=>	'column name in table',
				'modifiers'	=>	array(
					'encode'	=>	'html',
					'encode'	=>	'url'
				)
			)
		*/
		
		'id'	=>	array(
			'sql_path'	=>	'id'
		),
		
		'date'	=>	array(
			'default'	=>	time(),
			'sql_path'	=>	'date',
			'modifiers'	=>	array(
				'date_format'	=>	'F j, Y, g:i a'
			)
		),
		
		'title'	=> array(
			'sql_path'	=>	'title'
		)
	),
	
	// templated sql queries
	'list_sql'	=>	"select %sql_val% from `" . $table . "` %sql_order% %sql_limit%", // get all values
	'edit_sql'	=>	"select * from `" . $table . "` where `" . $param . "`='%param%' limit 1", // get single value
	'save_sql'	=>	"update `" . $table . "` set %update_sql% where `" . $param . "`='%param%' limit 1", // save
	'add_sql'	=>	"insert into `" . $table . "` (%sql_left%) values (%sql_right%)", // add
	'delete_sql'	=>	"delete from `" . $table . "` where `" . $param . "` in (%param%)" // delete
);

$tester_asset = new asset($tester_definition, $db);

$test_add = array(
	'title'	=>	'test'
);
$tester_asset->add($test_add);

$list = $tester_asset->get();
print_r($list);

?>