.
if (!defined('EG')) die('Direct access not allowed!');
class Model_Tree extends Model_Base {
public function __construct() {
parent::__construct();
}
// //method to create the first part of where clause
// //$index: the index of $this->_tablesArray
// public function createTreeWhere($index) {
// if (!empty($this->on))
// {
// return $this->on;
// }
// else
// {
// $whereArray = array();
// for ($i = $index; $i < (count($this->_tablesArray)-1); $i++)
// {
// $whereArray[] = $this->_tablesArray[$i].'.'.$this->_idFieldsArray[$i+1].'='.$this->_tablesArray[$i+1].'.'.$this->_idFieldsArray[$i+1];
// }
// $whereString = !empty($whereArray) ? implode(' and ',$whereArray) : null;
// return $whereString;
// }
// }
// //create the list of tables of the select query
// //$index: the index of $this->_tablesArray
// public function createTablesList($index) {
// if (isset($this->from))
// {
// return $this->from;
// }
// else
// {
// $tablesString = null;
// for ($i = $index; $i < (count($this->_tablesArray)-1); $i++)
// {
// $tablesString .= $this->_tablesArray[$i] . ',';
// }
// $tablesString .= $this->_tablesArray[count($this->_tablesArray)-1];
// return $tablesString;
// }
// }
//
// //method to create the list of fields of the select query
// public function createFieldsList($index) {
// $fieldsString = null;
// for ($i = $index; $i < (count($this->_tablesArray)-1); $i++)
// {
// $fieldsString .= $this->_tablesArray[$i] . '.*,';
// }
// $fieldsString .= $this->_tablesArray[count($this->_tablesArray)-1].'.*';
// return $fieldsString;
// }
//method to create the where clause and the list of tables and fields of the select query
//$tableName: the table name ($this->_tablesArray)
//$choice:all->all the tables in $this->_arrayTables, other value->only the table of $this->_arrayTables ad index $index
//return: $elements = array('tables'=>$tables,'where'=>$where,'fields'=>$fields)
public function treeQueryElements($tableName,$choice = 'all')
{
// $index = array_search($tableName,$this->_tablesArray);
// $subArray = ($choice === 'all') ? array_slice($this->_tablesArray,$index) : array($tableName); //this array is necessary to verify that the where clause makes sense
// $tables = ($choice === 'all') ? $this->createTablesList($index) : $tableName;
// $where = ($choice === 'all') ? $this->createTreeWhere($index) : null;
// $fields = ($choice === 'all') ? $this->createFieldsList($index) : $tableName.'.*';
//
// $wherePlus = $this->createWhereClause();
//
// if (empty($this->on))
// {
// $on = array();
//
// if (isset($where) and isset($wherePlus))
// {
// $where .= ' AND ' . $wherePlus;
// }
// else if (!isset($where) and isset($wherePlus))
// {
// $where .= $wherePlus;
// }
// }
// else
// {
// $on = $where;
// $where = $wherePlus;
// }
$where = $this->createWhereClause();
if (isset($where))
{
if (isset($this->sWhere))
{
$where .= " AND " . $this->sWhere;
}
}
else
{
$where = $this->sWhere;
}
$tables = isset($this->from) ? $this->from : $tableName;
$fields = $tableName.".*";
$on = $this->on;
return array('tables' => $tables,'where' => $where,'fields'=>$fields,'on'=>$on);
}
//method to obtain the values of the whole tree
//$choice:all->all the tables in $this->_arrayTables, other value->only the table of $this->_arrayTables ad index $index
public function getAll($choice = 'all') {
return $this->getFields('',$choice);
}
//method to get the values of the selected fields
//it walks the tree by means of a join query
//$fields: the fields that have to be excracted from the tableName
public function getFields($fields = '',$choice = 'all')
{
$elements = $this->treeQueryElements($this->_tablesArray[0],$choice);
$queryFields = (strcmp($fields,'') === 0) ? $elements['fields'] : $fields;
$row = $this->db->select($elements['tables'],$queryFields,$elements['where'],$this->groupBy,$this->orderBy,$this->limit,$elements['on'],$this->using,$this->join);
//convert from MySQL values
if ($this->convert)
{
if (count($row) > 0)
{
$types = array();
$tablesList = array_keys($row[0]);
foreach ($tablesList as $table)
{
$types[$table] = $this->db->getTypes($table, "*", false, true);
}
for ($i=0;$i< count ($row); $i++)
{
foreach ($tablesList as $table)
{
$row[$i][$table] = $this->convertFromMysqlT($types[$table], $row[$i][$table]);
}
}
}
}
return $row;
}
public function send()
{
$table = $this->getFields($this->select);
if ($this->toList)
{
$key = $this->listArray[0];
$value = isset($this->listArray[1]) ? $this->listArray[1] : null;
$this->toList = false;
return $this->getList($table, $key, $value);
}
else
{
return $table;
}
}
//call the getAll method with $tableName = $this->_tablesArray[0]
//the fields that have to be extracted from the table
public function getTable($fields = null) {
return isset($fields) ? $this->getFields($fields) : $this->getAll();
}
//select the values of a specified record
//$id: the id (primary key) of the record
//$fields: the comma separated list of fields that have to be extracted
public function selectId($id,$fields = null) {
$this->save()->clear()->setWhereQueryClause(array($this->_idFieldsArray[0] => (int)$id));
$this->using = null;
if (isset($fields))
{
$values = $this->getFields($fields,'other');
}
else
{
$values = $this->getAll('other');
}
$this->restore();
return (count($values) > 0) ? $values[0][$this->_tablesArray[0]] : array();
}
//get the number of records ()
//the number of records of the table $tableName is returned
public function rowNumber() {
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->get_num_rows($elements['tables'],$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
public function getMax($field)
{
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->getMax($elements['tables'],$field,$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
public function getMin($field)
{
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->getMin($elements['tables'],$field,$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
public function getSum($field)
{
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->getSum($elements['tables'],$field,$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
public function getAvg($field)
{
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->getAvg($elements['tables'],$field,$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
//check if the table has the field $field equal to $value
public function has($field,$value)
{
$elements = $this->treeQueryElements($this->_tablesArray[0]);
return $this->db->recordExists($elements['tables'],$field,$value,$elements['where'],$this->groupBy,$elements['on'],$this->using,$this->join);
}
//check referential integrity during delete
public function checkOnDeleteIntegrity($id = null, $whereClause = null)
{
$this->save();
$result = true;
if (count($this->foreignKeys) > 0)
{
foreach ($this->foreignKeys as $f)
{
if (preg_match('/^(.*?)\s(parent of)\s(.*?)\((.*?)\)(\s(on delete)\s(cascade|restrict)\s\((.*?)\))?$/i',$f,$matches))
{
$parentKey = $matches[1];
$childModel = $matches[3];
$childField = $matches[4];
if (isset($whereClause))
{
$this->clear()->sWhere($whereClause);
}
else
{
$this->clear()->where(array($this->_idFields=>(int)$id));
}
$keys = sanitizeDbDeep($this->toList($parentKey)->send());
$this->restore();
if (count($keys) > 0)
{
$child = new $childModel();
$childrenIds = $child->clear()->where(array($childField=>"in('".implode("','",$keys)."')"))->toList($child->getPrimaryKey())->send();
if (count($childrenIds) > 0)
{
if (isset($matches[7]) and strcmp($matches[7],"cascade") === 0)
{
foreach ($childrenIds as $childId)
{
$child->del((int)$childId);
}
if (strcmp($matches[8],"") !== 0)
{
$this->notice .= "
".$matches[8]."
";
}
}
else
{
$this->notice .= isset($matches[8]) ? "".$matches[8]."
" : $this->_resultString->getString('associate');
$result = false;
}
}
}
}
}
}
return $result;
}
//check referential integrity during insert or update
public function checkOnUpdateIntegrity($queryType)
{
$result = true;
if (count($this->foreignKeys) > 0)
{
foreach ($this->foreignKeys as $f)
{
if (preg_match('/^(.*?)\s(child of)\s(.*?)\((.*?)\)(\s(on update)\s(restrict)\s\((.*?)\))?$/i',$f,$matches))
{
$childKey = $matches[1];
$ParentModel = $matches[3];
$ParentField = $matches[4];
$notice = isset($matches[8]) ? "".$matches[8]."
" : "";
if (array_key_exists($childKey,$this->values))
{
$parent = new $ParentModel();
$res = $parent->clear()->where(array($ParentField=>sanitizeDb($this->values[$childKey])))->send();
if (count($res) === 0)
{
$this->notice .= $notice;
$this->result = false;
$result = false;
}
}
else if ($queryType === "insert")
{
$this->notice .= $notice;
$this->result = false;
$result = false;
}
}
}
}
return $result;
}
//get the first extracted full record
public function record()
{
$res = $this->getFields($this->select);
if (count($res) > 0)
{
return $res[0][$this->_tables];
}
return array();
}
//get a single field from the first extracted record
public function field($fieldName)
{
$res = $this->save()->select($fieldName)->send();
$this->restore();
if (count($res) > 0 and isset($res[0][$this->_tables][$fieldName]))
{
return $res[0][$this->_tables][$fieldName];
}
return "";
}
//get the types of the fields in $this->values
public function getTypes($full = false)
{
return $types = $this->db->getTypes($this->_tables,implode(",",array_keys($this->values)),$full);
}
//automatically set the values conditions
public function setValuesConditionsFromDbFields($queryType)
{
$fields = array_keys($this->values);
$fieldsAsString = implode(",",$fields);
$types = $this->getTypes(true);
$fieldKeys = $this->db->getKeys($this->_tables,$fieldsAsString,true,false);
if (count($this->values) > 0)
{
if (!$types)
{
$this->notice .= $this->_resultString->getString('not-existing-fields');
$this->result = false;
return false;
}
else
{
$this->saveConditions("values");
$this->saveConditions("database");
if (Params::$setValuesConditionsFromDbTableStruct)
{
foreach ($types as $index => $t)
{
if (preg_match('/^('.implode("|",$this->db->getCharTypes()).')\(([0-9]*?)\)$/i',$t,$matches))
{
$this->addValuesCondition($queryType,'checkLength|'.$matches[2],$fields[$index]);
}
else if (preg_match('/^('.implode("|",$this->db->getIntegerTypes()).')/i',$t,$matches))
{
$this->addValuesCondition($queryType,'checkInteger',$fields[$index]);
}
else if (preg_match('/^('.implode("|",$this->db->getFloatTypes()).')$/i',$t,$matches))
{
$this->addValuesCondition($queryType,'checkNumeric',$fields[$index]);
}
else if (preg_match('/^('.implode("|",$this->db->getDateTypes()).')$/i',$t,$matches))
{
$this->addValuesCondition($queryType,'checkIsoDate',$fields[$index]);
}
else if (preg_match('/^('.implode("|",$this->db->getEnumTypes()).')\((.*?)\)$/i',$t,$matches))
{
$temp = array();
$strings = explode(",",$matches[2]);
for ($i=0;$iaddValuesCondition($queryType,'checkIsStrings|'.implode(",",$temp),$fields[$index]);
}
else if (preg_match('/^('.implode("|",$this->db->getDecimalTypes()).')\((.*?)\)$/i',$t,$matches))
{
$this->addValuesCondition($queryType,'checkDecimal|'.$matches[2],$fields[$index]);
}
}
//set unique conditions
foreach ($fieldKeys as $index => $fk)
{
if (preg_match('/^('.implode("|",$this->db->getUniqueIndexStrings()).')$/i',$fk,$matches))
{
if ($queryType === "insert")
{
$this->addDatabaseCondition($queryType,'checkUnique',$fields[$index]);
}
else
{
$this->addDatabaseCondition($queryType,'checkUniqueCompl',$fields[$index]);
}
}
}
}
foreach (Params::$valuesConditionsFromFormatsOfFieldsNames as $regExpr => $function)
{
foreach ($fields as $f)
{
if (preg_match($regExpr,$f,$matches))
{
$this->addValuesCondition($queryType,$function,$f);
}
}
}
}
}
// print_r($fields);
// print_r($types);
return true;
}
//convert values of the $this->values to MySQL formats
public function convertValuesToDb()
{
if (Params::$automaticConversionToDbFormat)
{
if (isset($this->_conversionToDbObject))
{
$types = $this->getTypes();
if ($types)
{
$fields = array_keys($this->values);
foreach ($types as $index => $t)
{
if (method_exists($this->_conversionToDbObject,strtolower($t)))
{
$this->values[$fields[$index]] = call_user_func(array($this->_conversionToDbObject, strtolower($t)), $this->values[$fields[$index]]);
}
}
}
}
}
}
public function insert()
{
$this->db->setAutocommit(true);
$this->notice = null;
$this->queryResult = false;
$this->convertValuesToDb();
if ($this->checkOnUpdateIntegrity("insert"))
{
//set the values conditions from the table description
if ($this->setValuesConditionsFromDbFields("insert"))
{
if ($this->applyDatabaseConditions("insert",null))
{
$this->restoreConditions("database");
if ($this->applyValidateConditions("insert",'values'))
{
$this->restoreConditions("values");
return parent::insert();
}
$this->restoreConditions("values");
}
$this->restoreConditions("database");
}
}
return false;
}
public function update($id = null, $whereClause = null)
{
$this->db->setAutocommit(true);
$this->notice = null;
$this->queryResult = false;
$this->convertValuesToDb();
if ($this->checkOnUpdateIntegrity("update"))
{
//set the values conditions from the table description
if ($this->setValuesConditionsFromDbFields("update"))
{
if (!isset($id) or $this->applyDatabaseConditions("update",(int)$id))
{
$this->restoreConditions("database");
//check the values conditions
if ($this->applyValidateConditions("update",'values'))
{
$this->restoreConditions("values");
return parent::update($id, $whereClause);
}
$this->restoreConditions("values");
}
$this->restoreConditions("database");
}
}
return false;
}
//method to call the delete query (overriding of the del method of Model.php)
//check the referential integrity
public function del($id = null, $whereClause = null)
{
$this->notice = null;
$this->queryResult = false;
if ($this->checkOnDeleteIntegrity($id, $whereClause))
{
return parent::del($id, $whereClause);
}
else
{
return false;
}
// if (isset($whereClause))
// {
// return parent::del(null,$whereClause);
// }
// else
// {
// if ($this->_onDelete === 'check' and isset($this->_reference))
// {
// if (isset($this->_reference[0]) and isset($this->_reference[1]))
// {
// if ($this->db->recordExists($this->_reference[0],$this->_reference[1],(int)$id))
// {
// $this->notice = $this->_resultString->getString('associate');
// $this->identifierValue = null;
// $this->result = false;
// }
// else
// {
// return parent::del((int)$id);
// }
// }
// else
// {
// throw new Exception('you have forgotten to set \'$this->_reference\' or you have forgotten to set $this->_onDelete = \'nocheck\'');
// }
// }
// else
// {
// return parent::del((int)$id);
// }
// }
// return false;
}
//method to obtain one columns from the tables $this->_tablesArray as an associative array
//$valueField: the column that have to be extracted (array_values of the resulting associative array), $keyField: the column that have to play the role of array_keys
public function getFieldArray($valueField,$keyField = null, $groupBy = null, $orderBy = null, $limit = null) {
$keyField = isset($keyField) ? $keyField : $valueField;
$valueFieldArray = explode(':',$valueField);
$keyFieldArray = explode(':',$keyField);
$keyFieldTable = $keyFieldArray[0];
$valueFieldTable = $valueFieldArray[0];
$keyFieldName = $keyFieldArray[1];
$valueFieldName = $valueFieldArray[1];
$fields = implode('.',$keyFieldArray) . ',' . implode('.',$valueFieldArray);
$temp = $this->where; //save the $this->where array
$this->where = array();
if (strcmp($keyFieldTable,$valueFieldTable) !== 0) {
throw new Exception("the tables '$valueFieldTable' and '$keyFieldTable' do not match in ".__METHOD__);
}
if (!in_array($keyFieldTable,$this->_tablesArray)) {
throw new Exception("the table '$keyFieldTable' is not allowed in ".__METHOD__);
}
$elements = $this->treeQueryElements($keyFieldTable,'');
$table = $this->db->select($elements['tables'],$fields,$elements['where'],$groupBy,$orderBy,$limit,$elements['on'],$this->using);
$this->where = $temp;
$returnArray = array();
foreach ($table as $record) {
$returnArray[$record[$keyFieldTable][$keyFieldName]] = $record[$valueFieldTable][$valueFieldName];
}
return $returnArray;
}
}