<?php
class table_structure{
var $_structure = array(); // поля и индексы таблицы
var $_properties = array();


function __construct($path = false)
{
if ($path) $this -> loadFromIniFile($path);
}

public function clear()
{
$this -> _structure = array();
$this -> _properties = array();
}

// загрузка структуры из INI файла
function loadFromIniFile($path)
{
$this -> clear();
$ini = ini::read($path, 1);
foreach ($ini as $key=>$value) {
	if ($key=='~TABLE~PROPERTIES~')$this -> _properties = $value;
	else $this -> _structure[$key] = $value;
}
}



// получение структуры таблицы из подключенной базы
function loadFromBase($table)
{
$this -> clear();


$table = mysql_real_escape_string($table);

// получение полей таблицы
$q = mysql_query("SHOW FULL COLUMNS FROM `$table`");
while ($result = mysql_fetch_assoc($q)) {

$structure = array();   
$structure['type'] = $result['Type'];
if ($result['Default']=='' && $result['Null']=='YES')$structure['default_and_null'] = 'DEFAULT NULL';
elseif($result['Default']!='' && $result['Null']=='YES')$structure['default_and_null'] = "NULL DEFAULT '".my_esc($result['Default'])."'";
elseif($result['Default']!='' && $result['Null']=='NO')$structure['default_and_null'] = "NOT NULL DEFAULT '".my_esc($result['Default'])."'"; 
else $structure['default_and_null'] = 'NOT NULL';


$structure['ai'] = $result['Extra']=='auto_increment'?'AUTO_INCREMENT':'';
$structure['comment'] = $result['Comment']?"COMMENT '".my_esc($result['Comment'])."'":'';
 
$this -> _structure['`'.$result['Field'].'`'] = $structure;
}

// получение ключей таблицы
$q = mysql_query("SHOW KEYS FROM `$table`");
while ($result = mysql_fetch_assoc($q)) {
$structure = array();
if ($result['Key_name']=='PRIMARY')$structure['type'] = 'PRIMARY KEY';
elseif ($result['Index_type']=='FULLTEXT')$structure['type'] = 'FULLTEXT KEY `'.my_esc($result['Key_name']).'`';
elseif (!$result['Non_unique'])$structure['type'] = 'UNIQUE KEY `'.my_esc($result['Key_name']).'`';
else $structure['type'] = 'KEY `'.my_esc($result['Key_name']).'`';

if (isset($this -> _structure[$structure['type']]['fields']))
$this -> _structure[$structure['type']]['fields'] .= ", `".my_esc($result['Column_name'])."`";
else
$this -> _structure[$structure['type']]['fields'] = "`".my_esc($result['Column_name'])."`";
}

// получение свойств таблицы
$q = mysql_query("SHOW TABLE STATUS LIKE '$table'");
$properties = mysql_fetch_assoc($q);

$this -> _properties['name']=$properties['Name'];
$this -> _properties['engine']='ENGINE='.$properties['Engine'];

$this -> _properties['auto_increment']='AUTO_INCREMENT='.$properties['Auto_increment'];
$this -> _properties['comment']="COMMENT='".my_esc($properties['Comment'])."'";


}

// сохранение структуры в INI файл
function saveToIniFile($path)
{
return ini::save($path,array_merge($this -> _structure, array('~TABLE~PROPERTIES~' => $this -> _properties)),true);
}

// получение SQL запроса на создание таблицы
function getSQLQueryCreate()
{
$sql = "CREATE TABLE `".my_esc($this -> _properties['name'])."` (\r\n";

$structure = array();
foreach ($this -> _structure as $name => $struct) {
$struct_tmp = array();
$struct_tmp[] = $name ;


if (isset($struct['fields']))
{
$struct_tmp[] = '('.$struct['fields'].')';
}
else
{
if ($struct['type'])$struct_tmp[] = $struct['type'];
if ($struct['default_and_null'])$struct_tmp[] = $struct['default_and_null'];
if ($struct['ai'])$struct_tmp[] = $struct['ai'];
if ($struct['comment'])$struct_tmp[] = $struct['comment'];

}

$structure[] = implode(' ',$struct_tmp);
}

$sql .= implode(",\r\n",$structure);

$sql .= "\r\n) ";

$prop_tmp = array();


if ($this -> _properties['engine'])$prop_tmp[] = $this -> _properties['engine'];

$prop_tmp[] = 'DEFAULT CHARSET=utf8';

//$prop_tmp[] = $this -> _properties['auto_increment'];
if ($this -> _properties['comment'])$prop_tmp[] = $this -> _properties['comment'];


$sql .= implode(' ',$prop_tmp);
return $sql;
}




// получение SQL запроса на изменение таблицы
function getSQLQueryChange($tStruct_obj)
{
$to_add = array(); // добавляем поля (индексы)
$to_delete = array(); // удаляем поля (индексы)
$to_edit = array(); // изменяем поля (индексы)

foreach ($tStruct_obj -> _structure as $key => $value) {
	if (!isset($this -> _structure[$key] ))
	{ // если в старой таблице такого поля не существует, то добавляе в создаваемые
  $to_add[$key] = $value;
  continue;
  }
}

foreach ($this -> _structure as $key => $value) {
	if (!isset($tStruct_obj -> _structure[$key] ))
	{ // если в новой таблице такого поля не существует, то добавляе в удаляемые
  $to_delete[$key] = $value;
  continue;
  }
	$new_value = $tStruct_obj -> _structure[$key];
 foreach ($value as $key2=>$value2) {
 	if ($new_value[$key2] != $value2)
 	{
 	// если хоть один из параметров расходится, то допавляем в изменяемые
   $to_edit[$key] = $new_value;
   continue(2);
   }
 }
	
}

// если нет изменений
if (!$to_add && !$to_delete && !$to_edit)return false;

$sql = "ALTER TABLE `".my_esc($this -> _properties['name'])."` \r\n";

$structure = array();



// обработка удаляемых полей (индексов)
ksort($to_delete);
foreach ($to_delete as $name => $struct) {

if (isset($struct['fields']))
{
if (strpos($name, 'PRIMARY')===0)
$structure[] = 'DROP PRIMARY KEY';
elseif (preg_match('#`(.+?)`#', $name,$m))
$structure[] = 'DROP INDEX '.$m[1];
continue;
}



$struct_tmp = array();
$struct_tmp[] = 'DROP';
$struct_tmp[] = $name;
$structure[] = implode(' ',$struct_tmp);
}


// обработка изменяемых полей (индексов)
foreach ($to_edit as $name => $struct) {
$struct_tmp = array();
$struct_tmp[] = 'CHANGE';
$struct_tmp[] = $name ;
$struct_tmp[] = $name ;

// индексы мы менять не можем, но зато мы можем удалить и создать заново
if (isset($struct['fields']))
{
if (strpos($name, 'PRIMARY')===0)
$structure[] = 'DROP PRIMARY KEY';
elseif (preg_match('#`(.+?)`#', $name,$m))
$structure[] = 'DROP INDEX '.$m[1];

$structure[] = 'ADD '.$name.' ('.$struct['fields'].')';
continue;
}


if ($struct['type'])$struct_tmp[] = $struct['type'];
if ($struct['default_and_null'])$struct_tmp[] = $struct['default_and_null'];
if ($struct['ai'])$struct_tmp[] = $struct['ai'];
if ($struct['comment'])$struct_tmp[] = $struct['comment'];

$structure[] = implode(' ',$struct_tmp);
}




// обработка добавляемых полей (индексов)
foreach ($to_add as $name => $struct) {
$struct_tmp = array();
$struct_tmp[] = 'ADD';
$struct_tmp[] = $name ;

if (isset($struct['fields']))
{
$struct_tmp[] = '('.$struct['fields'].')';
}
else
{
if ($struct['type'])$struct_tmp[] = $struct['type'];
if ($struct['default_and_null'])$struct_tmp[] = $struct['default_and_null'];
if ($struct['ai'])$struct_tmp[] = $struct['ai'];
if ($struct['comment'])$struct_tmp[] = $struct['comment'];

}

$structure[] = implode(' ',$struct_tmp);
}



$sql .= implode(",\r\n",$structure);


return $sql;
}


}
?>
