XOOPS  2.6.0
Tables.php
Go to the documentation of this file.
1 <?php
2 /*
3  You may not change or alter any portion of this comment or credits
4  of supporting developers from this source code or any supporting source code
5  which is considered copyrighted (c) material of the original comment or credit authors.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  */
11 
12 namespace Xmf\Database;
13 
14 use Xmf\Language;
15 
36 class Tables
37 {
41  const POSITION_FIRST = 1;
42 
46  private $db;
47 
51  private $tables;
52 
56  private $queue;
57 
61  protected $lastError;
62 
66  protected $lastErrNo;
67 
72  public function __construct()
73  {
74  global $xoopsDB; // lock this to legacy support
75  //\Xmf\Debug::dump($xoopsDB,true);
76  Language::load('database', 'xmf');
77 
78  $this->db =& $xoopsDB;
79  $this->queueReset();
80  }
81 
89  public function name($table)
90  {
91  return $this->db->prefix($table);
92  }
93 
105  public function addColumn($table, $column, $attributes, $position = null)
106  {
107  $columnDef=array(
108  'name'=>$column,
109  'position'=>$position,
110  'attributes'=>$attributes
111  );
112 
113  // Find table def.
114  if (isset($this->tables[$table])) {
115  $tableDef = &$this->tables[$table];
116  // Is this on a table we are adding?
117  if (isset($tableDef['create']) && $tableDef['create']) {
118  switch ($position) {
120  array_unshift($tableDef['columns'], $columnDef);
121  break;
122  case '':
123  case null:
124  case false:
125  array_push($tableDef['columns'], $columnDef);
126  break;
127  default:
128  // should be a column name to add after
129  // loop thru and find that column
130  $i=0;
131  foreach ($tableDef['columns'] as $col) {
132  ++$i;
133  if (strcasecmp($col['name'], $position)==0) {
134  array_splice($tableDef['columns'], $i, 0, array($columnDef));
135  break;
136  }
137  }
138  }
139 
140  return true;
141  } else {
142  foreach ($tableDef['columns'] as $col) {
143  if (strcasecmp($col['name'], $column)==0) {
144  return true;
145  }
146  }
147  switch ($position) {
149  $pos='FIRST';
150  break;
151  case '':
152  case null:
153  case false:
154  $pos='';
155  break;
156  default:
157  $pos="AFTER `{$position}`";
158  }
159  $this->queue[]="ALTER TABLE `{$tableDef['name']}`"
160  . " ADD COLUMN {$column} {$columnDef['attributes']} {$pos} ";
161 
162  }
163  } else { // no table established
164  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
165  $this->lastErrNo = -1;
166 
167  return false;
168  }
169 
170  return true; // exists or is added to queue
171  }
172 
182  public function addPrimaryKey($table, $column)
183  {
184  if (isset($this->tables[$table])) {
185  $this->queue[]
186  = "ALTER TABLE `{$table}` ADD PRIMARY KEY({$column})";
187  } else { // no table established
188  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
189  $this->lastErrNo = -1;
190 
191  return false;
192  }
193 
194  return true;
195  }
196 
205  public function addTable($table)
206  {
207  if (isset($this->tables[$table])) {
208  return true;
209  }
210  $tableDef=$this->getTable($table);
211  if (is_array($tableDef)) {
212  $this->tables[$table] = $tableDef;
213 
214  return true;
215  } else {
216  if ($tableDef===true) {
217  $tableDef=array();
218  $tableDef = array(
219  'name' => $this->db->prefix($table)
220  , 'options' => 'ENGINE=MyISAM');
221  $tableDef['create'] = true;
222  $this->tables[$table] = $tableDef;
223 
224  $this->queue[]=array('createtable'=>$table);
225 
226  return true;
227  } else {
228  return false;
229  }
230  }
231  }
232 
240  public function useTable($table)
241  {
242  if (isset($this->tables[$table])) {
243  return true;
244  }
245  $tableDef=$this->getTable($table);
246  if (is_array($tableDef)) {
247  $this->tables[$table] = $tableDef;
248  return true;
249  }
250  return false;
251  }
252 
253 
266  public function alterColumn($table, $column, $attributes, $newName = '', $position = null)
267  {
268  if (empty($newName)) {
269  $newName=$column;
270  }
271  // Find table def.
272  if (isset($this->tables[$table])) {
273  $tableDef = &$this->tables[$table];
274  // Is this on a table we are adding?
275  if (isset($tableDef['create']) && $tableDef['create']
276  && empty($position)
277  ) {
278  // loop thru and find the column
279  foreach ($tableDef['columns'] as &$col) {
280  if (strcasecmp($col['name'], $column)==0) {
281  $col['name']=$newName;
282  $col['attributes']=$attributes;
283  break;
284  }
285  }
286 
287  return true;
288  } else {
289  switch ($position) {
291  $pos='FIRST';
292  break;
293  case '':
294  case null:
295  case false:
296  $pos='';
297  break;
298  default:
299  $pos="AFTER `{$position}`";
300  }
301  $this->queue[]="ALTER TABLE `{$tableDef['name']}` " .
302  "CHANGE COLUMN `{$column}` `{$newName}` {$attributes} {$pos} ";
303  }
304  } else { // no table established
305  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
306  $this->lastErrNo = -1;
307 
308  return false;
309  }
310 
311  return true;
312  }
313 
324  public function copyTable($table, $newTable, $withData = false)
325  {
326  if (isset($this->tables[$newTable])) {
327  return true;
328  }
329  $tableDef=$this->getTable($table);
330  $copy=$this->name($newTable);
331  $original=$this->name($table);
332 
333  if (is_array($tableDef)) {
334  $tableDef['name']=$copy;
335  if ($withData) {
336  $this->queue[] = "CREATE TABLE `{$copy}` LIKE `{$original}` ;";
337  $this->queue[]
338  = "INSERT INTO `{$copy}` SELECT * FROM `{$original}` ;";
339  } else {
340  $tableDef['create'] = true;
341  $this->queue[]=array('createtable'=>$newTable);
342  }
343  $this->tables[$newTable]=$tableDef;
344 
345  return true;
346  } else {
347  return false;
348  }
349 
350  }
351 
363  public function createIndex($name, $table, $column, $unique = false)
364  {
365  if (isset($this->tables[$table])) {
366  //ALTER TABLE `table` ADD INDEX `product_id` (`product_id`)
367  $add = ($unique?'ADD UNIQUE INDEX':'ADD INDEX');
368  $this->queue[]
369  = "ALTER TABLE `{$table}` {$add} {$name} ({$column})";
370  } else { // no table established
371  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
372  $this->lastErrNo = -1;
373 
374  return false;
375  }
376 
377  return true;
378  }
379 
388  public function dropColumn($table, $column)
389  {
390  // Find table def.
391  if (isset($this->tables[$table])) {
392  $tableDef = &$this->tables[$table];
393  $this->queue[]
394  = "ALTER TABLE `{$tableDef['name']}` DROP COLUMN `{$column}`";
395  } else { // no table established
396  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
397  $this->lastErrNo = -1;
398 
399  return false;
400  }
401 
402  return true;
403  }
404 
413  public function dropIndex($name, $table)
414  {
415  if (isset($this->tables[$table])) {
416  $tableDef = &$this->tables[$table];
417  $this->queue[]="ALTER TABLE `{$tableDef['name']}` DROP INDEX `{$name}`";
418  } else { // no table established
419  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
420  $this->lastErrNo = -1;
421 
422  return false;
423  }
424 
425  return true;
426  }
427 
436  public function dropIndexes($table)
437  {
438  // Find table def.
439  if (isset($this->tables[$table])) {
440  $tableDef = &$this->tables[$table];
441  // Is this on a table we are adding?
442  if (isset($tableDef['create']) && $tableDef['create']) {
443  // strip everything but the PRIMARY from definition
444  foreach ($tableDef['keys'] as $keyname => $key) {
445  if ($keyname!='PRIMARY') {
446  unset($tableDef['keys'][$keyname]);
447  }
448  }
449  } else {
450  // build drops to strip everything but the PRIMARY
451  foreach ($tableDef['keys'] as $keyname => $key) {
452  if ($keyname!='PRIMARY') {
453  $this->queue[] = "ALTER TABLE `{$tableDef['name']}`"
454  . " DROP INDEX {$keyname}";
455  }
456  }
457  }
458  } else { // no table established
459  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
460  $this->lastErrNo = -1;
461 
462  return false;
463  }
464 
465  return true;
466  }
467 
475  public function dropPrimaryKey($table)
476  {
477  if (isset($this->tables[$table])) {
478  $tableDef = &$this->tables[$table];
479  $this->queue[]="ALTER TABLE `{$tableDef['name']}` DROP PRIMARY KEY ";
480  } else { // no table established
481  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
482  $this->lastErrNo = -1;
483 
484  return false;
485  }
486 
487  return true;
488  }
489 
497  public function dropTable($table)
498  {
499  if (isset($this->tables[$table])) {
500  $tableDef = &$this->tables[$table];
501  $this->queue[]="DROP TABLE `{$tableDef['name']}` ";
502  unset($this->tables[$table]);
503  }
504  // no table is not an error since we are dropping it anyway
505  return true;
506  }
507 
508 
517  public function renameTable($table, $newName)
518  {
519  if (isset($this->tables[$table])) {
520  $tableDef = &$this->tables[$table];
521  $newTable = $this->name($newName);
522  $this->queue[]
523  = "ALTER TABLE `{$tableDef['name']}` RENAME TO `{$newTable}`";
524  $tableDef['name'] = $newTable;
525  } else { // no table established
526  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
527  $this->lastErrNo = -1;
528 
529  return false;
530  }
531 
532  return true;
533  }
534 
544  public function setTableOptions($table, $options)
545  {
546  // ENGINE=MEMORY DEFAULT CHARSET=utf8;
547  if (isset($this->tables[$table])) {
548  $tableDef = &$this->tables[$table];
549  $this->queue[]="ALTER TABLE `{$tableDef['name']}` {$options} ";
550  $tableDef['options'] = $options;
551  } else { // no table established
552  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
553  $this->lastErrNo = -1;
554 
555  return false;
556  }
557 
558  return true;
559  }
560 
561 
567  public function queueReset()
568  {
569  $this->tables = array();
570  $this->queue = array();
571  }
572 
580  public function queueExecute($force = false)
581  {
582  $this->expandQueue();
583  foreach ($this->queue as &$ddl) {
584  if (is_array($ddl)) {
585  if (isset($ddl['createtable'])) {
586  $ddl=$this->renderTableCreate($ddl['createtable']);
587  }
588  }
589  $result = $this->execSql($ddl, $force);
590  if (!$result) {
591  $this->lastError = $this->db->error();
592  $this->lastErrNo = $this->db->errno();
593 
594  return false;
595  }
596  }
597 
598  return true;
599  }
600 
601 
610  public function delete($table, $criteria)
611  {
612  if (isset($this->tables[$table])) {
613  $tableDef = &$this->tables[$table];
614  $where = '';
615  if (is_scalar($criteria)) {
616  $where = 'WHERE '.$criteria;
617  } elseif (is_object($criteria)) {
618  $where = $criteria->renderWhere();
619  }
620  $this->queue[]="DELETE FROM `{$tableDef['name']}` {$where}";
621  } else { // no table established
622  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
623  $this->lastErrNo = -1;
624 
625  return false;
626  }
627 
628  return true;
629  }
630 
638  public function insert($table, $columns)
639  {
640  if (isset($this->tables[$table])) {
641  $tableDef = &$this->tables[$table];
642  $colsql = '';
643  $valsql = '';
644  foreach ($tableDef['columns'] as $col) {
645  $comma=empty($colsql)?'':', ';
646  if (isset($columns[$col['name']])) {
647  $colsql .= $comma.$col['name'];
648  $valsql .= $comma.$this->db->quote($columns[$col['name']]);
649  }
650  }
651  $sql = "INSERT INTO `{$tableDef['name']}` ({$colsql}) VALUES({$valsql})";
652  $this->queue[]=$sql;
653 
654  return true;
655  } else { // no table established
656  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
657  $this->lastErrNo = -1;
658 
659  return null;
660  }
661  }
662 
672  public function update($table, $columns, $criteria)
673  {
674  if (isset($this->tables[$table])) {
675  $tableDef = &$this->tables[$table];
676  $where = '';
677  if (is_scalar($criteria)) {
678  $where = 'WHERE '.$criteria;
679  } elseif (is_object($criteria)) {
680  $where = $criteria->renderWhere();
681  }
682  $colsql = '';
683  foreach ($tableDef['columns'] as $col) {
684  $comma=empty($colsql)?'':', ';
685  if (isset($columns[$col['name']])) {
686  $colsql .= $comma . $col['name'] . ' = '
687  . $this->db->quote($columns[$col['name']]);
688  }
689  }
690  $sql = "UPDATE `{$tableDef['name']}` SET {$colsql} {$where}";
691  $this->queue[]=$sql;
692 
693  return true;
694  } else { // no table established
695  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
696  $this->lastErrNo = -1;
697 
698  return null;
699  }
700  }
701 
709  public function truncate($table)
710  {
711  if (isset($this->tables[$table])) {
712  $tableDef = &$this->tables[$table];
713  $this->queue[]="TRUNCATE TABLE `{$tableDef['name']}`";
714  } else { // no table established
715  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
716  $this->lastErrNo = -1;
717 
718  return false;
719  }
720 
721  return true;
722  }
723 
724 
725 
734  public function renderTableCreate($table, $prefixed = false)
735  {
736  if (isset($this->tables[$table])) {
737  $tableDef = &$this->tables[$table];
738  $tablename=($prefixed?$tableDef['name']:$table);
739  $sql = "CREATE TABLE `{$tablename}` (\n";
740  foreach ($tableDef['columns'] as $col) {
741  $sql .= " {$col['name']} {$col['attributes']},\n";
742  }
743  $keysql='';
744  foreach ($tableDef['keys'] as $keyname => $key) {
745  $comma = empty($keysql)?' ':', ';
746  if ($keyname=='PRIMARY') {
747  $keysql .= " {$comma}PRIMARY KEY ({$key['columns']})\n";
748  } else {
749  $unique=$key['unique']?'UNIQUE ':'';
750  $keysql .= " {$comma}{$unique}KEY {$keyname} "
751  . " ({$key['columns']})\n";
752  }
753  }
754  $sql .= $keysql;
755  $sql .= ") {$tableDef['options']};\n";
756 
757  return $sql;
758  } else { // no table established
759  $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
760  $this->lastErrNo = -1;
761 
762  return null;
763  }
764 
765  }
766 
778  private function & execSql($sql, $force = false)
779  {
780  if ($force) {
781  $result = $this->db->queryF($sql);
782  } else {
783  $result = $this->db->query($sql);
784  }
785 
786  if (!$result) {
787  $this->lastError = $this->db->error();
788  $this->lastErrNo = $this->db->errno();
789  }
790 
791  return $result;
792 
793  }
794 
803  private function fetch(&$result)
804  {
805  return $this->db->fetchArray($result);
806  }
807 
816  private function getTable($table)
817  {
818 
819  $tableDef = array();
820 
821  $sql = 'SELECT TABLE_NAME, ENGINE, CHARACTER_SET_NAME ';
822  $sql .= ' FROM `INFORMATION_SCHEMA`.`TABLES` t, ';
823  $sql .= ' `INFORMATION_SCHEMA`.`COLLATIONS` c ';
824  $sql .= ' WHERE t.TABLE_SCHEMA = \'' . \XoopsBaseConfig::get('db-name') . '\' ';
825  $sql .= ' AND t.TABLE_NAME = \'' . $this->name($table) . '\' ';
826  $sql .= ' AND t.TABLE_COLLATION = c.COLLATION_NAME ';
827 
828  $result = $this->execSql($sql);
829  if (!$result) {
830  return false;
831  }
832  $tableSchema = $this->fetch($result);
833  if (empty($tableSchema)) {
834  return true;
835  }
836  $tableDef['name'] = $tableSchema['TABLE_NAME'];
837  $tableDef['options'] = 'ENGINE=' . $tableSchema['ENGINE'] . ' '
838  . 'DEFAULT CHARSET=' . $tableSchema['CHARACTER_SET_NAME'];
839 
840  $sql = 'SELECT * ';
841  $sql .= ' FROM `INFORMATION_SCHEMA`.`COLUMNS` ';
842  $sql .= ' WHERE TABLE_SCHEMA = \'' . \XoopsBaseConfig::get('db-name') . '\' ';
843  $sql .= ' AND TABLE_NAME = \'' . $this->name($table) . '\' ';
844  $sql .= ' ORDER BY `ORDINAL_POSITION` ';
845 
846  $result = $this->execSql($sql);
847 
848  while ($column=$this->fetch($result)) {
849  $attributes = ' ' . $column['COLUMN_TYPE'] . ' '
850  . (($column['IS_NULLABLE'] == 'NO') ? ' NOT NULL ' : '' )
851  . (($column['COLUMN_DEFAULT'] === null) ? '' :
852  " DEFAULT '". $column['COLUMN_DEFAULT'] . "' ")
853  . $column['EXTRA'];
854 
855  $columnDef=array(
856  'name'=>$column['COLUMN_NAME'],
857  'position'=>$column['ORDINAL_POSITION'],
858  'attributes'=>$attributes
859  );
860 
861  $tableDef['columns'][] = $columnDef;
862  };
863 
864  $sql = 'SELECT `INDEX_NAME`, `SEQ_IN_INDEX`, `NON_UNIQUE`, ';
865  $sql .= ' `COLUMN_NAME`, `SUB_PART` ';
866  $sql .= ' FROM `INFORMATION_SCHEMA`.`STATISTICS` ';
867  $sql .= ' WHERE TABLE_SCHEMA = \'' . \XoopsBaseConfig::get('db-name') . '\' ';
868  $sql .= ' AND TABLE_NAME = \'' . $this->name($table) . '\' ';
869  $sql .= ' ORDER BY `INDEX_NAME`, `SEQ_IN_INDEX` ';
870 
871  $result = $this->execSql($sql);
872 
873  $lastkey = '';
874  $keycols='';
875  $keyunique = false;
876  while ($key=$this->fetch($result)) {
877  if ($lastkey != $key['INDEX_NAME']) {
878  if (!empty($lastkey)) {
879  $tableDef['keys'][$lastkey]['columns'] = $keycols;
880  $tableDef['keys'][$lastkey]['unique'] = $keyunique;
881  }
882  $lastkey = $key['INDEX_NAME'];
883  $keycols = $key['COLUMN_NAME'];
884  if (!empty($key['SUB_PART'])) {
885  $keycols .= ' (' . $key['SUB_PART'] . ')';
886  }
887  $keyunique = !$key['NON_UNIQUE'];
888  } else {
889  $keycols .= ', ' . $key['COLUMN_NAME'];
890  if (!empty($key['SUB_PART'])) {
891  $keycols .= ' ('.$key['SUB_PART'].')';
892  }
893  }
894  //$tableDef['keys'][$key['INDEX_NAME']][$key['SEQ_IN_INDEX']] = $key;
895  };
896  if (!empty($lastkey)) {
897  $tableDef['keys'][$lastkey]['columns'] = $keycols;
898  $tableDef['keys'][$lastkey]['unique'] = $keyunique;
899  }
900 
901  return $tableDef;
902 
903  }
904 
913  private function expandQueue()
914  {
915  foreach ($this->queue as &$ddl) {
916  if (is_array($ddl)) {
917  if (isset($ddl['createtable'])) {
918  $ddl=$this->renderTableCreate($ddl['createtable'], true);
919  }
920  }
921  }
922  }
923 
929  public function getLastError()
930  {
931  return $this->lastError;
932  }
933 
939  public function getLastErrNo()
940  {
941  return $this->lastErrNo;
942  }
943 
949  public function dumpTables()
950  {
951  return $this->tables;
952  }
953 
959  public function dumpQueue()
960  {
961  $this->expandQueue();
962 
963  return $this->queue;
964  }
965 }
dropTable($table)
Definition: Tables.php:497
$i
Definition: dialog.php:68
update($table, $columns, $criteria)
Definition: Tables.php:672
dropIndexes($table)
Definition: Tables.php:436
const POSITION_FIRST
Definition: Tables.php:41
$options['editor']
$result
Definition: pda.php:33
addPrimaryKey($table, $column)
Definition: Tables.php:182
setTableOptions($table, $options)
Definition: Tables.php:544
addTable($table)
Definition: Tables.php:205
renameTable($table, $newName)
Definition: Tables.php:517
copyTable($table, $newTable, $withData=false)
Definition: Tables.php:324
addColumn($table, $column, $attributes, $position=null)
Definition: Tables.php:105
dropPrimaryKey($table)
Definition: Tables.php:475
dropIndex($name, $table)
Definition: Tables.php:413
truncate($table)
Definition: Tables.php:709
const _DB_XMF_TABLE_IS_NOT_DEFINED
Definition: database.php:32
static get($name)
insert($table, $columns)
Definition: Tables.php:638
global $xoopsDB
Definition: common.php:36
useTable($table)
Definition: Tables.php:240
alterColumn($table, $column, $attributes, $newName= '', $position=null)
Definition: Tables.php:266
$sql
Definition: pda.php:32
renderTableCreate($table, $prefixed=false)
Definition: Tables.php:734
fetch(&$result)
Definition: Tables.php:803
& execSql($sql, $force=false)
Definition: Tables.php:778
static load($name, $domain= '', $language=null)
Definition: Language.php:54
$criteria
queueExecute($force=false)
Definition: Tables.php:580
dropColumn($table, $column)
Definition: Tables.php:388
getTable($table)
Definition: Tables.php:816
createIndex($name, $table, $column, $unique=false)
Definition: Tables.php:363