0byt3m1n1-V2
Path:
/
home
/
magalijoj
/
www
/
blog
/
inc
/
clearbricks
/
dbschema
/
[
Home
]
File: class.dbstruct.php
<?php # ***** BEGIN LICENSE BLOCK ***** # This file is part of Clearbricks. # Copyright (c) 2006 Olivier Meunier and contributors. All rights # reserved. # # Clearbricks is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # Clearbricks is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Clearbricks; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # ***** END LICENSE BLOCK ***** class dbStruct { protected $con; protected $prefix; protected $tables = array(); protected $references = array(); public function __construct(&$con,$prefix='') { $this->con =& $con; $this->prefix = $prefix; } public function table($name) { $this->tables[$name] = new dbStructTable($name); return $this->tables[$name]; } public function __get($name) { if (!isset($this->tables[$name])) { return $this->table($name); } return $this->tables[$name]; } public function reverse() { $schema = dbSchema::init($this->con); # Get tables $tables = $schema->getTables(); foreach ($tables as $t_name) { if ($this->prefix && strpos($t_name,$this->prefix) !== 0) { continue; } $t = $this->table($t_name); # Get columns $cols = $schema->getColumns($t_name); foreach ($cols as $c_name => $col) { $type = $schema->dbt2udt($col['type'],$col['len'],$col['default']); $t->field($c_name,$type,$col['len'],$col['null'],$col['default']); } # Get keys $keys = $schema->getKeys($t_name); foreach ($keys as $k) { $args = $k['cols']; array_unshift($args,$k['name']); if ($k['primary']) { call_user_func_array(array($t,'primary'),$args); } elseif ($k['unique']) { call_user_func_array(array($t,'unique'),$args); } } # Get indexes $idx = $schema->getIndexes($t_name); foreach ($idx as $i) { $args = array($i['name'],$i['type']); $args = array_merge($args,$i['cols']); call_user_func_array(array($t,'index'),$args); } # Get foreign keys $ref = $schema->getReferences($t_name); foreach ($ref as $r) { $t->reference($r['name'],$r['c_cols'],$r['p_table'],$r['p_cols'],$r['update'],$r['delete']); } } } /** Synchronize this schema taken from database with $schema. @param s <b>dbStruct</b> Structure to synchronize with */ public function synchronize($s) { $this->tables = array(); $this->reverse(); if (!($s instanceof self)) { throw new Exception('Invalid database schema'); } $tables = $s->getTables(); $table_create = array(); $key_create = array(); $index_create = array(); $reference_create = array(); $field_create = array(); $field_update = array(); $key_update = array(); $index_update = array(); $reference_update = array(); $got_work = false; $schema = dbSchema::init($this->con); foreach ($tables as $tname => $t) { if (!$this->tableExists($tname)) { # Table does not exists, create table $table_create[$tname] = $t->getFields(); # Add keys, indexes and references $keys = $t->getKeys(); $indexes = $t->getIndexes(); $references = $t->getReferences(); foreach ($keys as $k => $v) { $key_create[$tname][$this->prefix.$k] = $v; } foreach ($indexes as $k => $v) { $index_create[$tname][$this->prefix.$k] = $v; } foreach ($references as $k => $v) { $v['p_table'] = $this->prefix.$v['p_table']; $reference_create[$tname][$this->prefix.$k] = $v; } $got_work = true; } else # Table exists { # Check new fields to create $fields = $t->getFields(); $db_fields = $this->tables[$tname]->getFields(); foreach ($fields as $fname => $f) { if (!$this->tables[$tname]->fieldExists($fname)) { # Field doest not exists, create it $field_create[$tname][$fname] = $f; $got_work = true; } elseif ($this->fieldsDiffer($db_fields[$fname],$f)) { # Field exists and differs from db version $field_update[$tname][$fname] = $f; $got_work = true; } } # Check keys to add or upgrade $keys = $t->getKeys(); $db_keys = $this->tables[$tname]->getKeys(); foreach ($keys as $kname => $k) { if ($k['type'] == 'primary' && $this->con->driver() == 'mysql') { $kname = 'PRIMARY'; } else { $kname = $this->prefix.$kname; } $db_kname = $this->tables[$tname]->keyExists($kname,$k['type'],$k['cols']); if (!$db_kname) { # Key does not exists, create it $key_create[$tname][$kname] = $k; $got_work = true; } elseif ($this->keysDiffer($db_kname,$db_keys[$db_kname]['cols'],$kname,$k['cols'])) { # Key exists and differs from db version $key_update[$tname][$db_kname] = array_merge(array('name'=>$kname),$k); $got_work = true; } } # Check index to add or upgrade $idx = $t->getIndexes(); $db_idx = $this->tables[$tname]->getIndexes(); foreach ($idx as $iname => $i) { $iname = $this->prefix.$iname; $db_iname = $this->tables[$tname]->indexExists($iname,$i['type'],$i['cols']); if (!$db_iname) { # Index does not exists, create it $index_create[$tname][$iname] = $i; $got_work = true; } elseif ($this->indexesDiffer($db_iname,$db_idx[$db_iname],$iname,$i)) { # Index exists and differs from db version $index_update[$tname][$db_iname] = array_merge(array('name'=>$iname),$i); $got_work = true; } } # Check references to add or upgrade $ref = $t->getReferences(); $db_ref = $this->tables[$tname]->getReferences(); foreach ($ref as $rname => $r) { $rname = $this->prefix.$rname; $r['p_table'] = $this->prefix.$r['p_table']; $db_rname = $this->tables[$tname]->referenceExists($rname,$r['c_cols'],$r['p_table'],$r['p_cols']); if (!$db_rname) { # Reference does not exists, create it $reference_create[$tname][$rname] = $r; $got_work = true; } elseif ($this->referencesDiffer($db_rname,$db_ref[$db_rname],$rname,$r)) { $reference_update[$tname][$db_rname] = array_merge(array('name'=>$rname),$r); $got_work = true; } } } } if (!$got_work) { return; } # Create tables foreach ($table_create as $table => $fields) { $schema->createTable($table,$fields); } # Create new fields foreach ($field_create as $tname => $fields) { foreach ($fields as $fname => $f) { $schema->createField($tname,$fname,$f['type'],$f['len'],$f['null'],$f['default']); } } # Update fields foreach ($field_update as $tname => $fields) { foreach ($fields as $fname => $f) { $schema->alterField($tname,$fname,$f['type'],$f['len'],$f['null'],$f['default']); } } # Create new keys foreach ($key_create as $tname => $keys) { foreach ($keys as $kname => $k) { if ($k['type'] == 'primary') { $schema->createPrimary($tname,$kname,$k['cols']); } elseif ($k['type'] == 'unique') { $schema->createUnique($tname,$kname,$k['cols']); } } } # Update keys foreach ($key_update as $tname => $keys) { foreach ($keys as $kname => $k) { if ($k['type'] == 'primary') { $schema->alterPrimary($tname,$kname,$k['name'],$k['cols']); } elseif ($k['type'] == 'unique') { $schema->alterUnique($tname,$kname,$k['name'],$k['cols']); } } } # Create indexes foreach ($index_create as $tname => $index) { foreach ($index as $iname => $i) { $schema->createIndex($tname,$iname,$i['type'],$i['cols']); } } # Update indexes foreach ($index_update as $tname => $index) { foreach ($index as $iname => $i) { $schema->alterIndex($tname,$iname,$i['name'],$i['type'],$i['cols']); } } # Create references foreach ($reference_create as $tname => $ref) { foreach ($ref as $rname => $r) { $schema->createReference($rname,$tname,$r['c_cols'],$r['p_table'],$r['p_cols'],$r['update'],$r['delete']); } } # Update references foreach ($reference_update as $tname => $ref) { foreach ($ref as $rname => $r) { //$schema->alterReference($name,$newname,$c_table,$name,$c_cols,$p_table,$p_cols,$update,$delete); $schema->alterReference($rname,$r['name'],$tname,$r['c_cols'],$r['p_table'],$r['p_cols'],$r['update'],$r['delete']); } } # Flush execution stack $schema->flushStack(); return count($table_create) + count($key_create) + count($index_create) + count($reference_create) + count($field_create) + count($field_update) + count($key_update) + count($index_update) + count($reference_update); } public function getTables() { $res = array(); foreach ($this->tables as $t => $v) { $res[$this->prefix.$t] = $v; } return $res; } public function tableExists($name) { return isset($this->tables[$name]); } private function fieldsDiffer($db_field,$schema_field) { $d_type = $db_field['type']; $d_len = (integer) $db_field['len']; $d_default = $db_field['default']; $d_null = $db_field['null']; $s_type = $schema_field['type']; $s_len = (integer) $schema_field['len']; $s_default = $schema_field['default']; $s_null = $schema_field['null']; return $d_type != $s_type || $d_len != $s_len || $d_default != $s_default || $d_null != $s_null; } private function keysDiffer($d_name,$d_cols,$s_name,$s_cols) { return $d_name != $s_name || $d_cols != $s_cols; } private function indexesDiffer($d_name,$d_i,$s_name,$s_i) { return $d_name != $s_name || $d_i['cols'] != $s_i['cols'] || $d_i['type'] != $s_i['type']; } private function referencesDiffer($d_name,$d_r,$s_name,$s_r) { return $d_name != $s_name || $d_r['c_cols'] != $s_r['c_cols'] || $d_r['p_table'] != $s_r['p_table'] || $d_r['p_cols'] != $s_r['p_cols'] || $d_r['update'] != $s_r['update'] || $d_r['delete'] != $s_r['delete']; } } class dbStructTable { protected $name; protected $has_primary = false; protected $fields = array(); protected $keys = array(); protected $indexes = array(); protected $references = array(); /** Universal data types supported by dbSchema SMALLINT : signed 2 bytes integer INTEGER : signed 4 bytes integer BIGINT : signed 8 bytes integer REAL : signed 4 bytes floating point number FLOAT : signed 8 bytes floating point number NUMERIC : exact numeric type DATE : Calendar date (day, month and year) TIME : Time of day TIMESTAMP : Date and time CHAR : A fixed n-length character string VARCHAR : A variable length character string TEXT : A variable length of text */ protected $allowed_types = array( 'smallint','integer','bigint','real','float','numeric', 'date','time','timestamp', 'char','varchar','text' ); public function __construct($name) { $this->name = $name; return $this; } public function getFields() { return $this->fields; } public function getKeys($primary=null) { return $this->keys; } public function getIndexes() { return $this->indexes; } public function getReferences() { return $this->references; } public function fieldExists($name) { return isset($this->fields[$name]); } public function keyExists($name,$type,$cols) { # Look for key with the same name if (isset($this->keys[$name])) { return $name; } # Look for key with the same columns list and type foreach ($this->keys as $n => $k) { if ($k['cols'] == $cols && $k['type'] == $type) { # Same columns and type, return new name return $n; } } return false; } public function indexExists($name,$type,$cols) { # Look for key with the same name if (isset($this->indexes[$name])) { return $name; } # Look for index with the same columns list and type foreach ($this->indexes as $n => $i) { if ($i['cols'] == $cols && $i['type'] == $type) { # Same columns and type, return new name return $n; } } return false; } public function referenceExists($name,$c_cols,$p_table,$p_cols) { if (isset($this->references[$name])) { return $name; } # Look for reference with same chil columns, parent table and columns foreach ($this->references as $n => $r) { if ($c_cols == $r['c_cols'] && $p_table == $r['p_table'] && $p_cols == $r['p_cols']) { # Only name differs, return new name return $n; } } return false; } public function field($name,$type,$len,$null=true,$default=false) { $type = strtolower($type); if (!in_array($type,$this->allowed_types)) { throw new Exception('Invalid data type '.$type.' in schema'); } $this->fields[$name] = array( 'type' => $type, 'len' => (integer) $len, 'default' => $default, 'null' => (boolean) $null ); return $this; } public function __call($name,$args) { array_unshift($args,$name); return call_user_func_array(array($this,'field'),$args); } public function primary($name,$col) { if ($this->has_primary) { throw new Exception(sprintf('Table %s already has a primary key',$this->name)); } $cols = func_get_args(); array_shift($cols); return $this->newKey('primary',$name,$cols); } public function unique($name,$col) { $cols = func_get_args(); array_shift($cols); return $this->newKey('unique',$name,$cols); } public function index($name,$type,$col) { $cols = func_get_args(); array_shift($cols); array_shift($cols); $this->checkCols($cols); $this->indexes[$name] = array( 'type' => strtolower($type), 'cols' => $cols ); return $this; } public function reference($name,$c_cols,$p_table,$p_cols,$update=false,$delete=false) { if (!is_array($p_cols)) { $p_cols = array($p_cols); } if (!is_array($c_cols)) { $c_cols = array($c_cols); } $this->checkCols($c_cols); $this->references[$name] = array( 'c_cols' => $c_cols, 'p_table' => $p_table, 'p_cols' => $p_cols, 'update' => $update, 'delete' => $delete ); } protected function newKey($type,$name,$cols) { $this->checkCols($cols); $this->keys[$name] = array( 'type' => $type, 'cols' => $cols ); if ($type == 'primary') { $this->has_primary = true; } return $this; } protected function checkCols($cols) { foreach ($cols as $v) { if (!isset($this->fields[$v])) { throw new Exception(sprintf('Field %s does not exists in table %s',$v,$this->name)); } } } } ?>
©
2018.