<?php
// $Id: object_handler.php,v 1.5 2006/09/27 02:59:06 ohwada Exp $

// 2006-09-20 K.OHWADA
// add set_cache_by_obj()
// add clean() get_objects_asc()
// add drop_table()
// add get_row_by_sql()
// same bugs

// 2006-07-10 K.OHWADA
// this is new file
// porting from weblinks_object_handler.php

//=========================================================
// Happy Linux Framework Module
// 2006-07-10 K.OHWADA
//=========================================================

//=========================================================
// class happy_linux_object_generic_handler
// support XC2.1 CriteriaElement class
//=========================================================
class happy_linux_object_handler extends happy_linux_error
{
	var $_DIRNAME;

	var $_DEBUG_INSERT = true;
	var $_DEBUG_UPDATE = true;
	var $_DEBUG_DELETE = true;

	var $_db;
	var $_table;
	var $_id_name;
	var $_class_name;

	var $_criteria_class_name = 'criteriaelement';

	var $_MODE_CRITERIA = 0;	// 0: XOOPS 2.0, 1: XC2.1

	var $_STRING_TYPES = array(
		XOBJ_DTYPE_TXTBOX, XOBJ_DTYPE_TXTAREA, XOBJ_DTYPE_URL
	);

	var $_cached = array();

	var $_magic_word;

//---------------------------------------------------------
// constructor
//---------------------------------------------------------
function happy_linux_object_handler( $dirname, $table_name, $id_name, $class_name )
{
	$this->happy_linux_error();

	$this->_db =& Database::getInstance();

	$this->_DIRNAME    = $dirname;
	$this->_id_name    = $id_name;
	$this->_class_name = $class_name;
	$this->_table      = $this->prefix( $table_name );

	$this->_magic_word = xoops_makepass();
}

function prefix($name)
{
	$ret = $this->db_prefix( $this->_DIRNAME."_".$name );
	return $ret;
}

//---------------------------------------------------------
// create
//---------------------------------------------------------
function &create($isNew = true)
{
	$obj = null;
	if (class_exists($this->_class_name)) 
	{
		$obj =& new $this->_class_name();
		if($isNew)
		{	$obj->setNew();	}
	}
	return $obj;
}

function _check_class( &$obj )
{
	if ( strtolower(get_class($obj)) == strtolower($this->_class_name) )
	{
		return true;
	}

	return false;
}

function _class_name()
{
	return $this->_class_name;
}

//---------------------------------------------------------
// pubilic function
//---------------------------------------------------------
function is_exist($id)
{
	$obj =& $this->get($id);
	if ( is_object($obj) )
	{
		return true;
	}
	return false;
}

function &get($id)
{
	$ret = null;

	$id  = intval($id);
	$sql = 'SELECT * FROM '. $this->_table .' WHERE '. $this->_id_name .'='.$id;

	$result =& $this->query($sql);

	if (!$result) 
	{	return $ret;	}

	if ($this->getRowsNum($result) == 1) 
	{
		$ret =& $this->create();
		$ret->assignVars( $this->fetchArray($result) );
		$ret->unsetNew();
	}

	return $ret;
}

function &getCache($id)
{
	if ( isset($this->_cached[$id]) )
	{
		return $this->_cached[$id];
	}

	$obj =& $this->get($id);
	if ( is_object($obj) )
	{
		$this->_cached[$id] = $obj;
	}

	return $obj;
}

function set_cache_by_obj( &$obj )
{
	$id = $this->_get_id_value_by_obj( $obj );
	if ( $id ) 
	{
		$this->_cached[$id] = $obj;
	}
}

function &getVarAll($id, $format='n')
{
	$arr = array();
	$obj = $this->get($id);
	if ( is_object($obj) )
	{
		$arr =& $obj->getVarAll($format);
	}
	return $arr;
}

function &getObjects( $criteria = null, $param1 = false, $param2 = false, $param3 = false )
{
	$ret = array();

	if( $this->_check_criteria_class($criteria) ) 
	{
		if ($this->_MODE_CRITERIA)
		{
			$sql = $this->_build_object_sql_new($criteria);
		}
		else
		{
			$sql = $this->_build_object_sql($criteria);
		}

		$limit = $criteria->getLimit();
		$start = $criteria->getStart();

		$ret =& $this->get_objects_by_sql($sql, $limit, $start, $param1);
	}
	else
	{
		$sql  = "SELECT * FROM " . $this->_table;
		$sql .= " ORDER BY ".$this->_id_name." ASC";

		$ret =& $this->get_objects_by_sql($sql, $param1, $param2, $param3);
	}

	return $ret;
}

function &getList( $criteria = null )
{
	$ret = array();
	$limit = $start = 0;

	$sql = "SELECT ".$this->_id_name." FROM ".$this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		if ($this->_MODE_CRITERIA)
		{
			$sql = $this->_build_object_sql_new($criteria);
		}
		else
		{
			$sql = $this->_build_object_sql($criteria);
		}

		$limit = $criteria->getLimit();
		$start = $criteria->getStart();
	}
	else 
	{
		$sql .= ' ORDER BY '.$this->_id_name;
	}

	$ret =& $this->get_first_rows_by_sql($sql, $limit, $start);
	return $ret;
}

function getCount( $criteria = null )
{
	$ret = array();

	$sql = "SELECT COUNT(*) FROM " . $this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		if ($this->_MODE_CRITERIA)
		{
			$sql = $this->_build_count_sql_new($criteria);
		}
		else
		{
			$sql = $this->_build_count_sql($criteria);
		}
	}

	return $this->get_count_by_sql($sql);
}

function insert(&$obj, $force=false)
{
	if ( $this->_DEBUG_INSERT )
	{
		return $this->_insert($obj, $force);
	}
	return true;
}

function _insert(&$obj, $force = false)
{
	if( !$this->_check_class($obj) ) 
	{
		$this->_set_errors( $this->_table.': not match class');
		return false;
	}

	if ( !$obj->isNew() ) 
	{
		$this->_set_errors( $this->_table.': not new object');
		return false;	
	}

	if ($this->_MODE_CRITERIA)
	{
		$sql = $this->_build_insert_sql_new($obj);
	}
	else
	{
		$sql = $this->_build_insert_sql($obj);
	}

	$result = $force ? $this->queryF($sql) : $this->query($sql);
	if (!$result)
	{	return false;	}

	$newid = $this->getInsertId();
	$obj->setVar($this->_id_name, $newid);

	return $newid;
}

function update(&$obj, $force=false)
{
	if ( $this->_DEBUG_UPDATE )
	{
		return $this->_update($obj, $force);
	}
	return true;
}

function _update(&$obj, $force = false)
{
	if( !$this->_check_class($obj) ) 
	{
		$this->_set_errors( $this->_table.': not match class');
		return false;
	}

	$id = $this->_get_id_value_by_obj( $obj );
	if ( empty($id) ) 
	{
		$this->_set_errors( $this->_table.': not exist primary id');
		return false;
	}

	if ($this->_MODE_CRITERIA)
	{
		$sql = $this->_build_update_sql_new($obj);
	}
	else
	{
		$sql = $this->_build_update_sql($obj);
	}

	$ret = $force ? $this->queryF($sql) : $this->query($sql);

	if ( isset($this->_cached[$id]) )
	{
		unset( $this->_cached[$id] );
	}

	return $ret;
}

function _get_id_value_by_obj( &$obj )
{
	$val = false;
	if ( is_object($obj) )
	{
		$val = intval( $obj->get($this->_id_name) );
	}
	return $val;
}

function delete(&$obj, $force=false)
{
	if ( $this->_DEBUG_DELETE )
	{
		return $this->_delete($obj, $force);
	}
	return true;
}

function _delete(&$obj, $force=false)
{
	$id  = $this->_get_id_value_by_obj( $obj );
	$sql = "DELETE FROM " . $this->_table . " WHERE " . $this->_id_name . "=".$id;
	$ret = $force ? $this->queryF($sql) : $this->query($sql);

	if ( isset($this->_cached[$id]) )
	{
		unset( $this->_cached[$id] );
	}

	return $ret;
}

function deleteAll(&$obj, $force=false)
{
	return $this->_delete_all($obj, $force);
}

function _delete_all($criteria, $force=false)
{
	$objs =& $this->getObjects($criteria);

	$flag = true;

	foreach ($objs as $obj) 
	{
		$flag &= $this->delete($obj, $force);
	}

	return $flag;
}

function existsFieldName($name)
{
	$sql = "SELECT * FROM ".$this->_table;

	$res =& $this->query($sql); 
	if ( !$res ) 
	{	return false;	}

	$num = $this->getFieldsNum( $res );

	for ( $i=0; $i<$num; $i++ ) 
	{
		$meta = mysql_fetch_field($res);

		if ($meta) 
		{
			if ( $meta->name == $name )
			{
				return true;
			}
		}
	}

	return false;
}

function existsTable()
{
	$sql = "SHOW TABLES";

	$res =& $this->queryF($sql); 
	if ( !$res ) 
	{	return false;	}

	$table_name = strtolower( $this->_table );

	while ($myrow =& $this->fetchRow($res)) 
	{
		$name = strtolower( $myrow[0] );

		if ( $name == $table_name )
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------
// create & drop table
//---------------------------------------------------------
function drop_table( $magic )
{
	$ret = false;
	if ( $magic === $this->_magic_word )
	{
		$sql = "DROP TABLE ".$this->_table;
		$ret = $this->query($sql);
	}
	return $ret;
}

function clean_table( $magic )
{
	$ret = false;
	if ( $magic === $this->_magic_word )
	{
		$sql = "DELETE FROM ".$this->_table;
		$ret = $this->query($sql);
	}
	return $ret;
}

function get_magic_word()
{
	return $this->_magic_word;
}

//---------------------------------------------------------
// execute query
//---------------------------------------------------------
function &get_objects_asc($limit=0, $start=0)
{
	$criteria = new CriteriaCompo();
	$criteria->setStart($start);
	$criteria->setLimit($limit);
	$objs =& $this->getObjects($criteria);
	return $objs;
}

function &get_objects_desc($limit=0, $start=0)
{
	$sort = $this->_id_name.' DESC';
	$criteria = new CriteriaCompo();
	$criteria->setSort($sort);
	$criteria->setStart($start);
	$criteria->setLimit($limit);
	$objs =& $this->getObjects($criteria);
	return $objs;
}

//---------------------------------------------------------
// execute query by sql
//---------------------------------------------------------
function get_count_by_sql($sql = null)
{
	$result = $this->query($sql);

	if (!$result) 
	{	return false;	}

	list($count) = $this->fetchRow($result);
	return $count;
}

function &get_objects_by_sql($sql = null, $limit = 0, $start = 0, $id_as_key = false)
{
	$ret = array();

	$result =& $this->query($sql, $limit, $start);

	if (!$result) 
	{	return $ret;	}

	while( $row =& $this->fetchArray($result) ) 
	{
		$obj =& new $this->_class_name();
		$obj->assignVars($row);
		$obj->unsetNew();

		if ($id_as_key)
		{
			$id = $this->_get_id_value_by_obj( $obj );
			$ret[$id] =& $obj;
		}
		else
		{
			$ret[] =& $obj;
		}

		unset($obj);
	}

	return $ret;
}

function &get_row_by_sql($sql)
{
	$res =& $this->query($sql);
	$arr =& $this->fetchArray( $res );
	return $arr;
}

function &get_rows_by_sql($sql, $limit=0, $offset=0)
{
	$res =& $this->query($sql, $limit, $offset);
	if ( !$res )
	{	return $res;	}

	$arr = array();

	while ( $row =& $this->fetchArray($res) ) 
	{
		$arr[] = $row;
	}

	return $arr;
}

function &get_first_rows_by_sql($sql, $limit=0, $start=0)
{
	$res =& $this->query($sql, $limit, $start);
	if ( !$res ) 
	{	return $res;	}

	$arr = array();

	while ( $row =& $this->fetchRow($res) ) 
	{
		$arr[] = $row[0];
	}

	return $arr;
}



function _check_criteria_class( $criteria )
{
	if ( isset($criteria) && is_a($criteria, $this->_criteria_class_name) )
	{
		return true;
	}
	return false;
}

//---------------------------------------------------------
// database class
//---------------------------------------------------------
function &query($sql, $limit=0, $offset=0, $force=false)
{
	$limit  = intval($limit);
	$offset = intval($offset);

	if ( $force )
	{
		$res =& $this->_db->queryF($sql, $limit, $offset);
	}
	else
	{
		$res =& $this->_db->query($sql, $limit, $offset);
	}

	$this->_print_db_sql($sql, $limit, $offset);

	if ( !$res ) 
	{
		$this->_set_db_error($sql, $limit, $offset);
	}

	return $res;
}

function &queryF($sql, $limit=0, $offset=0)
{
	$limit  = intval($limit);
	$offset = intval($offset);

	$res =& $this->_db->queryF($sql, $limit, $offset);

	$this->_print_db_sql($sql, $limit, $offset);

	if ( !$res ) 
	{
		$this->_set_db_error($sql, $limit, $offset);
	}

	return $res;
}

function getRowsNum($res)
{
	$ret = $this->_db->getRowsNum($res);
	return $ret;
}

function getFieldsNum($res)
{
	$ret = $this->_db->getFieldsNum($res);
	return $ret;
}

function &fetchArray($res)
{
	$ret = $this->_db->fetchArray($res);
	return $ret;
}

function &fetchRow($res)
{
	$ret = $this->_db->fetchRow($res);
	return $ret;
}

function getInsertId()
{
	$ret = $this->_db->getInsertId();
	return $ret;
}

function freeRecordSet($result)
{
	$ret = $this->_db->freeRecordSet($result);
	return $ret;
}

function db_prefix($tablename='')
{
// if tablename is empty, only prefix will be returned
	$ret = $this->_db->prefix($tablename);
	return $ret;
}

function get_db_error()
{
	$err = $this->_db->error();
	return $err;
}

// strip GPC slashes when set object by serVar();
function quoteString($str)
{
	$str = $this->quote($str);
	return $str;
}

function quote($str)
{
	$str = "'".addslashes($str)."'";
	return $str;
}

//---------------------------------------------------------
// build sql
// require XOOPS 2.0 CriteriaElement class
//---------------------------------------------------------
function _build_object_sql( $criteria = null ) 
{
	$sql = 'SELECT * FROM '.$this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$sql .= ' '.$criteria->renderWhere();

		$sort = $criteria->getSort();

		if ($sort)
		{
			$sql .= ' ORDER BY '.$sort;
		}
		else
		{
			$sql .= ' ORDER BY '.$this->_id_name.' '.$criteria->getOrder();
		}
	}

	return $sql;
}

function _build_list_sql( $criteria = null )
{
	$sql = "SELECT ".$this->_id_name." FROM ".$this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$sql .= ' '.$criteria->renderWhere();

		$sort = $criteria->getSort();

		if ($sort)
		{
			$sql .= ' ORDER BY '.$sort;
		}
		else
		{
			$sql .= ' ORDER BY '.$this->_id_name.' '.$criteria->getOrder();
		}
	}

	return $sql;
}

function _build_count_sql( $criteria = null ) 
{
	$sql = 'SELECT COUNT(*) FROM '.$this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$sql .= ' '.$criteria->renderWhere();
	}

	return $sql;
}

// override this function
function _build_insert_sql(&$obj) 
{
	// dummy
}

// override this function
function _build_update_sql(&$obj) 
{
	// dummy
}

//---------------------------------------------------------
// build sql
// require XC2.1 CriteriaElement class
//---------------------------------------------------------
function _build_object_sql_new( $criteria = null ) 
{
	$sql = "SELECT * FROM " . $this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$sql .= $this->_build_object_sql_addtion($criteria);
	}

	return $sql;
}

function _build_list_sql_new( $criteria = null )
{
	$sql = "SELECT ".$this->_id_name." FROM ".$this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$sql .= $this->_build_object_sql_addtion($criteria);
	}

	return $sql;
}

function _build_object_sql_addtion( $criteria ) 
{
	$sql = '';

	$where = $this->_makeCriteria4sql($criteria);

	if (trim($where)) 
	{
		$sql .= " WHERE ".$where;
	}

	$sorts = array();

	foreach ($criteria->getSorts() as $sort) 
	{
		$sorts[] = $sort['sort'] . ' ' . $sort['order'];
	}

	if ($criteria->getSort() != '') 
	{
		$sql .= " ORDER BY " . implode(',', $sorts);
	}

	return $sql;
}

function _build_count_sql_new( $criteria = null ) 
{
	$sql="SELECT COUNT(*) FROM " . $this->_table;

	if( $this->_check_criteria_class($criteria) ) 
	{
		$where = $this->_build_count_sql_where($criteria);

		if ($where) 
		{
			$sql .= " WHERE " . $where;
		}
	}

	return $sql;
}

function _build_insert_sql_new(&$obj) 
{
	$fileds=array();
	$values=array();

	$arr = $this->_makeVars4sql($obj);

	foreach($arr as $_name => $_value) 
	{
		$fields[]=$_name;
		$values[]=$_value;
	}

	$sql = @sprintf("INSERT INTO " . $this->_table . " ( %s ) VALUES ( %s )", implode(",", $fields), implode(",", $values));
	return $sql;
}

function _build_update_sql_new(&$obj) 
{
	$set_lists=array();
	$where = "";

	$arr = $this->_makeVars4sql($obj);

	foreach ($arr as $_name => $_value) 
	{
		if ($_name == $this->_id_name) 
		{
			$where = "${_name}=${_value}";
		}
		else 
		{
			$set_lists[] = "${_name}=${_value}";
		}
	}

	$sql = @sprintf("UPDATE " . $this->_table . " SET %s WHERE %s", implode(",",$set_lists), $where);

	return $sql;
}

function _makeVars4sql(&$obj)
{
	$ret = array();

	foreach ($obj->gets() as $key => $value) 
	{
		$dataType = $obj->mVars[$key]['data_type'];

		if ( in_array($dataType, $this->_STRING_TYPES) )
		{
			$ret[$key] = $this->db->quoteString($value);
		}
		else
		{
			$ret[$key] = $value;
		}
	}

	return $ret;
}

function _makeCriteria4sql($criteria)
{
	$dmmyObj =& $this->create();
	return $this->_makeCriteriaElement4sql($criteria, $dmmyObj);
}

function _makeCriteriaElement4sql($criteria, &$obj)
{
	if (is_a($criteria, $this->_criteria_class_name)) 
	{
		if ($criteria->hasChildElements()) 
		{
			$queryString = "";
			$maxCount = $criteria->getCountChildElements();

			for ($i = 0; $i < $maxCount ; $i++) 
			{
				$queryString .= " " . $this->_makeCriteria4sql($criteria->getChildElement($i));
			
				if (($i + 1) != $maxCount) 
				{
						$queryString .= " " . $criteria->getCondition($i);
				}
			}

			return "(" . $queryString . ")";
		}
		else 
		{
			$name = $criteria->getName();
			$value = $criteria->getValue();

			if ($name != null && isset($obj->_vars[$name])) 
			{
				$value = $this->_makeCriteriaElement4sql_datatype($criteria, $obj);
			}

			if ($name != null) 
			{
				return $name . " " . $criteria->getOperator() . " " . $value;
			}
			else 
			{
				return null;
			}

			return $string;
		}
	}
}

function _makeCriteriaElement4sql_datatype($criteria, &$obj)
{
	$name  = $criteria->getName();
	$value = $criteria->getValue();
	$dataType = $obj->_vars[$name]['data_type'];

	if ( in_array($dataType, $this->_STRING_TYPES) )
	{
		$value = $this->quoteString($value);
	}
	else
	{
		switch ($dataType) 
		{
			case XOBJ_DTYPE_BOOL:
				$value = $value ? "1" : "0";
				break;

			case XOBJ_DTYPE_INT:
				$value = intval($value);
				break;

			case XOBJ_DTYPE_FLOAT:
				$value = floatval($value);
				break;

			default:
				$value = $criteria->getValue();
		}
	}

	return $value;
}

//---------------------------------------------------------
// set parameter
//---------------------------------------------------------
function set_class_name($val)
{
	$this->_class_name = $val;
}

function set_criteria_class_name($val)
{
	$this->_criteria_class_name = $val;
}

function set_mode_criteria($val)
{
	$this->_MODE_CRITERIA = intval($val);
}

function set_debug_insert($val)
{
	$this->_DEBUG_INSERT = (bool)$val;
}

function set_debug_update($val)
{
	$this->_DEBUG_UPDATE = (bool)$val;
}

function set_debug_delete($val)
{
	$this->_DEBUG_DELETE = (bool)$val;
}

//---------------------------------------------------------
// get parameter
//---------------------------------------------------------
function get_table_name()
{
	return $this->_table;
}

// --- class end ---
}

?>