00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 App::import('Model', 'ConnectionManager');
00028
00029
00030
00031
00032
00033
00034 class CakeSchema extends Object {
00035
00036
00037
00038
00039
00040
00041 var $name = null;
00042
00043
00044
00045
00046
00047
00048 var $path = null;
00049
00050
00051
00052
00053
00054
00055 var $file = 'schema.php';
00056
00057
00058
00059
00060
00061
00062 var $connection = 'default';
00063
00064
00065
00066
00067
00068
00069 var $tables = array();
00070
00071
00072
00073
00074
00075 function __construct($options = array()) {
00076 parent::__construct();
00077
00078 if (empty($options['name'])) {
00079 $this->name = preg_replace('/schema$/i', '', get_class($this));
00080 }
00081
00082 if ($this->name === 'Cake') {
00083 $this->name = Inflector::camelize(Inflector::slug(Configure::read('App.dir')));
00084 }
00085
00086 if (empty($options['path'])) {
00087 $this->path = CONFIGS . 'sql';
00088 }
00089
00090 $options = array_merge(get_object_vars($this), $options);
00091 $this->_build($options);
00092 }
00093
00094
00095
00096
00097
00098
00099 function _build($data) {
00100 $file = null;
00101 foreach ($data as $key => $val) {
00102 if (!empty($val)) {
00103 if (!in_array($key, array('name', 'path', 'file', 'connection', 'tables', '_log'))) {
00104 $this->tables[$key] = $val;
00105 unset($this->{$key});
00106 } elseif ($key !== 'tables') {
00107 if ($key === 'name' && $val !== $this->name) {
00108 $file = Inflector::underscore($val) . '.php';
00109 }
00110 $this->{$key} = $val;
00111 }
00112 }
00113 }
00114
00115 if (file_exists($this->path . DS . $file) && is_file($this->path . DS . $file)) {
00116 $this->file = $file;
00117 }
00118 }
00119
00120
00121
00122
00123
00124
00125
00126 function before($event = array()) {
00127 return true;
00128 }
00129
00130
00131
00132
00133
00134
00135 function after($event = array()) {
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 function load($options = array()) {
00145 if (is_string($options)) {
00146 $options = array('path'=> $options);
00147 }
00148
00149 $this->_build($options);
00150 extract(get_object_vars($this));
00151
00152 $class = $name .'Schema';
00153 if (!class_exists($class)) {
00154 if (file_exists($path . DS . $file) && is_file($path . DS . $file)) {
00155 require_once($path . DS . $file);
00156 } elseif (file_exists($path . DS . 'schema.php') && is_file($path . DS . 'schema.php')) {
00157 require_once($path . DS . 'schema.php');
00158 }
00159 }
00160
00161 if (class_exists($class)) {
00162 $Schema =& new $class($options);
00163 return $Schema;
00164 }
00165
00166 return false;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 function read($options = array()) {
00176 extract(array_merge(
00177 array(
00178 'connection' => $this->connection,
00179 'name' => $this->name,
00180 'models' => true,
00181 ),
00182 $options
00183 ));
00184 $db =& ConnectionManager::getDataSource($connection);
00185
00186 App::import('Model', 'AppModel');
00187
00188 $tables = array();
00189 $currentTables = $db->listSources();
00190
00191 $prefix = null;
00192 if (isset($db->config['prefix'])) {
00193 $prefix = $db->config['prefix'];
00194 }
00195
00196 if (!is_array($models) && $models !== false) {
00197 $models = Configure::listObjects('model');
00198 }
00199
00200 if (is_array($models)) {
00201 foreach ($models as $model) {
00202 if (PHP5) {
00203 $Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection));
00204 } else {
00205 $Object =& ClassRegistry::init(array('class' => $model, 'ds' => $connection));
00206 }
00207
00208 if (is_object($Object)) {
00209 $Object->setDataSource($connection);
00210 $table = $db->fullTableName($Object, false);
00211
00212 if (in_array($table, $currentTables)) {
00213 $key = array_search($table, $currentTables);
00214 if (empty($tables[$Object->table])) {
00215 $tables[$Object->table] = $this->__columns($Object);
00216 $tables[$Object->table]['indexes'] = $db->index($Object);
00217 unset($currentTables[$key]);
00218 }
00219 if (!empty($Object->hasAndBelongsToMany)) {
00220 foreach($Object->hasAndBelongsToMany as $Assoc => $assocData) {
00221 if (isset($assocData['with'])) {
00222 $class = $assocData['with'];
00223 } elseif ($assocData['_with']) {
00224 $class = $assocData['_with'];
00225 }
00226 if (is_object($Object->$class)) {
00227 $table = $db->fullTableName($Object->$class, false);
00228 if (in_array($table, $currentTables)) {
00229 $key = array_search($table, $currentTables);
00230 $tables[$Object->$class->table] = $this->__columns($Object->$class);
00231 $tables[$Object->$class->table]['indexes'] = $db->index($Object->$class);
00232 unset($currentTables[$key]);
00233 }
00234 }
00235 }
00236 }
00237 }
00238 }
00239 }
00240 }
00241 if (!empty($currentTables)) {
00242 foreach($currentTables as $table) {
00243 if ($prefix) {
00244 $table = str_replace($prefix, '', $table);
00245 }
00246 $Object = new AppModel(array('name'=> Inflector::classify($table), 'table'=> $table, 'ds'=> $connection));
00247 if (in_array($table, array('aros', 'acos', 'aros_acos', Configure::read('Session.table'), 'i18n'))) {
00248 $tables[$Object->table] = $this->__columns($Object);
00249 $tables[$Object->table]['indexes'] = $db->index($Object);
00250 } elseif ($models === false) {
00251 $tables[$table] = $this->__columns($Object);
00252 $tables[$table]['indexes'] = $db->index($Object);
00253 } else {
00254 $tables['missing'][$table] = $this->__columns($Object);
00255 $tables['missing'][$table]['indexes'] = $db->index($Object);
00256 }
00257 }
00258 }
00259
00260 ksort($tables);
00261 return compact('name', 'tables');
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271 function write($object, $options = array()) {
00272 if (is_object($object)) {
00273 $object = get_object_vars($object);
00274 $this->_build($object);
00275 }
00276
00277 if (is_array($object)) {
00278 $options = $object;
00279 unset($object);
00280 }
00281
00282 extract(array_merge(
00283 get_object_vars($this), $options
00284 ));
00285
00286 $out = "class {$name}Schema extends CakeSchema {\n";
00287
00288 $out .= "\tvar \$name = '{$name}';\n\n";
00289
00290 if ($path !== $this->path) {
00291 $out .= "\tvar \$path = '{$path}';\n\n";
00292 }
00293
00294 if ($file !== $this->file) {
00295 $out .= "\tvar \$file = '{$file}';\n\n";
00296 }
00297
00298 if ($connection !== 'default') {
00299 $out .= "\tvar \$connection = '{$connection}';\n\n";
00300 }
00301
00302 $out .= "\tfunction before(\$event = array()) {\n\t\treturn true;\n\t}\n\n\tfunction after(\$event = array()) {\n\t}\n\n";
00303
00304 if (empty($tables)) {
00305 $this->read();
00306 }
00307
00308 foreach ($tables as $table => $fields) {
00309 if (!is_numeric($table) && $table !== 'missing') {
00310 $out .= "\tvar \${$table} = array(\n";
00311 if (is_array($fields)) {
00312 $cols = array();
00313 foreach ($fields as $field => $value) {
00314 if ($field != 'indexes') {
00315 if (is_string($value)) {
00316 $type = $value;
00317 $value = array('type'=> $type);
00318 }
00319 $col = "\t\t\t'{$field}' => array('type'=>'" . $value['type'] . "', ";
00320 unset($value['type']);
00321 $col .= join(', ', $this->__values($value));
00322 } else {
00323 $col = "\t\t\t'indexes' => array(";
00324 $props = array();
00325 foreach ((array)$value as $key => $index) {
00326 $props[] = "'{$key}' => array(".join(', ', $this->__values($index)).")";
00327 }
00328 $col .= join(', ', $props);
00329 }
00330 $col .= ")";
00331 $cols[] = $col;
00332 }
00333 $out .= join(",\n", $cols);
00334 }
00335 $out .= "\n\t\t);\n";
00336 }
00337 }
00338 $out .="}\n";
00339
00340
00341 $File =& new File($path . DS . $file, true);
00342 $header = '$Id';
00343 $content = "<?php \n/* SVN FILE: $header$ */\n/* ". $name ." schema generated on: " . date('Y-m-d H:m:s') . " : ". time() . "*/\n{$out}?>";
00344 $content = $File->prepare($content);
00345 if ($File->write($content)) {
00346 return $content;
00347 }
00348 return false;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358 function compare($old, $new = null) {
00359 if (empty($new)) {
00360 $new = $this;
00361 }
00362 if (is_array($new)) {
00363 if (isset($new['tables'])) {
00364 $new = $new['tables'];
00365 }
00366 } else {
00367 $new = $new->tables;
00368 }
00369
00370 if (is_array($old)) {
00371 if (isset($old['tables'])) {
00372 $old = $old['tables'];
00373 }
00374 } else {
00375 $old = $old->tables;
00376 }
00377 $tables = array();
00378 foreach ($new as $table => $fields) {
00379 if ($table == 'missing') {
00380 break;
00381 }
00382 if (!array_key_exists($table, $old)) {
00383 $tables[$table]['add'] = $fields;
00384 } else {
00385 $diff = array_diff_assoc($fields, $old[$table]);
00386 if (!empty($diff)) {
00387 $tables[$table]['add'] = $diff;
00388 }
00389 $diff = array_diff_assoc($old[$table], $fields);
00390 if (!empty($diff)) {
00391 $tables[$table]['drop'] = $diff;
00392 }
00393 }
00394 foreach ($fields as $field => $value) {
00395 if (isset($old[$table][$field])) {
00396 $diff = array_diff_assoc($value, $old[$table][$field]);
00397 if (!empty($diff)) {
00398 $tables[$table]['change'][$field] = array_merge($old[$table][$field], $diff);
00399 }
00400 }
00401
00402 if (isset($add[$table][$field])) {
00403 $wrapper = array_keys($fields);
00404 if ($column = array_search($field, $wrapper)) {
00405 if (isset($wrapper[$column - 1])) {
00406 $tables[$table]['add'][$field]['after'] = $wrapper[$column - 1];
00407 }
00408 }
00409 }
00410 }
00411 }
00412 return $tables;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421 function __values($values) {
00422 $vals = array();
00423 if (is_array($values)) {
00424 foreach ($values as $key => $val) {
00425 if (is_array($val)) {
00426 $vals[] = "'{$key}' => array('".join("', '", $val)."')";
00427 } else if (!is_numeric($key)) {
00428 $val = var_export($val, true);
00429 $vals[] = "'{$key}' => {$val}";
00430 }
00431 }
00432 }
00433 return $vals;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442 function __columns(&$Obj) {
00443 $db =& ConnectionManager::getDataSource($Obj->useDbConfig);
00444 $fields = $Obj->schema(true);
00445 $columns = $props = array();
00446 foreach ($fields as $name => $value) {
00447
00448 if ($Obj->primaryKey == $name) {
00449 $value['key'] = 'primary';
00450 }
00451 if (!isset($db->columns[$value['type']])) {
00452 trigger_error('Schema generation error: invalid column type ' . $value['type'] . ' does not exist in DBO', E_USER_NOTICE);
00453 continue;
00454 } else {
00455 $defaultCol = $db->columns[$value['type']];
00456 if (isset($defaultCol['limit']) && $defaultCol['limit'] == $value['length']) {
00457 unset($value['length']);
00458 } elseif (isset($defaultCol['length']) && $defaultCol['length'] == $value['length']) {
00459 unset($value['length']);
00460 }
00461 unset($value['limit']);
00462 }
00463
00464 if (isset($value['default']) && ($value['default'] === '' || $value['default'] === false)) {
00465 unset($value['default']);
00466 }
00467 if (empty($value['length'])) {
00468 unset($value['length']);
00469 }
00470 if (empty($value['key'])) {
00471 unset($value['key']);
00472 }
00473 $columns[$name] = $value;
00474 }
00475
00476 return $columns;
00477 }
00478 }
00479 ?>