2008-05-30 11:40:08 +00:00
< ? php
/**
* Schema database management for CakePHP .
*
2009-11-06 06:46:59 +00:00
* CakePHP ( tm ) : Rapid Development Framework ( http :// cakephp . org )
2013-02-08 11:59:49 +00:00
* Copyright ( c ) Cake Software Foundation , Inc . ( http :// cakefoundation . org )
2008-05-30 11:40:08 +00:00
*
* Licensed under The MIT License
2013-02-08 12:22:51 +00:00
* For full copyright and license information , please see the LICENSE . txt
2008-05-30 11:40:08 +00:00
* Redistributions of files must retain the above copyright notice .
*
2013-02-08 11:59:49 +00:00
* @ copyright Copyright ( c ) Cake Software Foundation , Inc . ( http :// cakefoundation . org )
2009-11-06 06:00:11 +00:00
* @ link http :// cakephp . org CakePHP ( tm ) Project
2011-07-26 06:16:14 +00:00
* @ package Cake . Model
2008-10-30 17:30:26 +00:00
* @ since CakePHP ( tm ) v 1.2 . 0.5550
2013-05-30 22:11:14 +00:00
* @ license http :// www . opensource . org / licenses / mit - license . php MIT License
2008-05-30 11:40:08 +00:00
*/
2011-12-08 15:35:02 +00:00
2010-12-08 01:12:50 +00:00
App :: uses ( 'Model' , 'Model' );
App :: uses ( 'AppModel' , 'Model' );
App :: uses ( 'ConnectionManager' , 'Model' );
2012-03-23 06:48:57 +00:00
App :: uses ( 'File' , 'Utility' );
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Base Class for Schema management .
2008-05-30 11:40:08 +00:00
*
2011-07-26 06:16:14 +00:00
* @ package Cake . Model
2008-05-30 11:40:08 +00:00
*/
2016-04-08 12:33:26 +00:00
class CakeSchema extends CakeObject {
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Name of the schema .
2008-05-30 11:40:08 +00:00
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $name = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Path to write location .
2008-05-30 11:40:08 +00:00
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $path = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* File to write .
2008-05-30 11:40:08 +00:00
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $file = 'schema.php' ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Connection used for read .
2008-05-30 11:40:08 +00:00
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $connection = 'default' ;
2009-07-24 19:18:37 +00:00
2009-08-28 05:06:21 +00:00
/**
2014-08-12 17:28:34 +00:00
* Plugin name .
2009-08-28 05:06:21 +00:00
*
* @ var string
2009-11-14 12:19:25 +00:00
*/
2010-04-04 07:14:00 +00:00
public $plugin = null ;
2009-08-28 05:06:21 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Set of tables .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 07:14:00 +00:00
public $tables = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Constructor
*
2014-08-12 17:28:34 +00:00
* @ param array $options Optional load object properties .
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function __construct ( $options = array ()) {
2008-05-30 11:40:08 +00:00
parent :: __construct ();
if ( empty ( $options [ 'name' ])) {
$this -> name = preg_replace ( '/schema$/i' , '' , get_class ( $this ));
}
2009-08-28 05:06:21 +00:00
if ( ! empty ( $options [ 'plugin' ])) {
$this -> plugin = $options [ 'plugin' ];
}
2008-05-30 11:40:08 +00:00
2008-08-04 19:46:44 +00:00
if ( strtolower ( $this -> name ) === 'cake' ) {
2014-08-11 14:12:16 +00:00
$this -> name = 'App' ;
2008-05-30 11:40:08 +00:00
}
if ( empty ( $options [ 'path' ])) {
2011-05-16 19:52:25 +00:00
$this -> path = APP . 'Config' . DS . 'Schema' ;
2008-05-30 11:40:08 +00:00
}
$options = array_merge ( get_object_vars ( $this ), $options );
2010-04-09 10:41:28 +00:00
$this -> build ( $options );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Builds schema object properties .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $data Loaded object properties .
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-09 10:41:28 +00:00
public function build ( $data ) {
2008-05-30 11:40:08 +00:00
$file = null ;
foreach ( $data as $key => $val ) {
if ( ! empty ( $val )) {
2009-08-28 05:06:21 +00:00
if ( ! in_array ( $key , array ( 'plugin' , 'name' , 'path' , 'file' , 'connection' , 'tables' , '_log' ))) {
2010-08-02 03:22:46 +00:00
if ( $key [ 0 ] === '_' ) {
continue ;
}
2008-05-30 11:40:08 +00:00
$this -> tables [ $key ] = $val ;
unset ( $this -> { $key });
} elseif ( $key !== 'tables' ) {
2008-08-04 19:46:44 +00:00
if ( $key === 'name' && $val !== $this -> name && ! isset ( $data [ 'file' ])) {
2008-05-30 11:40:08 +00:00
$file = Inflector :: underscore ( $val ) . '.php' ;
}
$this -> { $key } = $val ;
}
}
}
if ( file_exists ( $this -> path . DS . $file ) && is_file ( $this -> path . DS . $file )) {
$this -> file = $file ;
2009-10-04 17:32:33 +00:00
} elseif ( ! empty ( $this -> plugin )) {
2011-05-15 04:10:09 +00:00
$this -> path = CakePlugin :: path ( $this -> plugin ) . 'Config' . DS . 'Schema' ;
2008-05-30 11:40:08 +00:00
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Before callback to be implemented in subclasses .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $event Schema object properties .
* @ return bool Should process continue .
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function before ( $event = array ()) {
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* After callback to be implemented in subclasses .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $event Schema object properties .
2011-07-30 22:38:57 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function after ( $event = array ()) {
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Reads database and creates schema tables .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $options Schema object properties .
* @ return array Set of name and tables .
2008-05-30 11:40:08 +00:00
*/
2010-12-02 04:49:43 +00:00
public function load ( $options = array ()) {
2008-05-30 11:40:08 +00:00
if ( is_string ( $options )) {
2008-08-26 18:39:18 +00:00
$options = array ( 'path' => $options );
2008-05-30 11:40:08 +00:00
}
2010-04-09 10:41:28 +00:00
$this -> build ( $options );
2008-05-30 11:40:08 +00:00
extract ( get_object_vars ( $this ));
2012-03-04 19:18:04 +00:00
$class = $name . 'Schema' ;
2009-08-01 21:50:03 +00:00
2014-08-11 15:40:57 +00:00
if ( ! class_exists ( $class ) && ! $this -> _requireFile ( $path , $file )) {
$class = Inflector :: camelize ( Inflector :: slug ( Configure :: read ( 'App.dir' ))) . 'Schema' ;
if ( ! class_exists ( $class )) {
$this -> _requireFile ( $path , $file );
2008-05-30 11:40:08 +00:00
}
}
if ( class_exists ( $class )) {
2010-06-07 04:35:40 +00:00
$Schema = new $class ( $options );
2008-05-30 11:40:08 +00:00
return $Schema ;
}
2010-12-02 04:49:43 +00:00
return false ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Reads database and creates schema tables .
2008-05-30 11:40:08 +00:00
*
2009-02-04 05:00:59 +00:00
* Options
2009-07-24 19:18:37 +00:00
*
2009-02-04 05:00:59 +00:00
* - 'connection' - the db connection to use
* - 'name' - name of the schema
* - 'models' - a list of models to use , or false to ignore models
2009-08-15 00:06:27 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $options Schema object properties .
* @ return array Array indexed by name and tables .
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function read ( $options = array ()) {
2008-05-30 11:40:08 +00:00
extract ( array_merge (
array (
'connection' => $this -> connection ,
'name' => $this -> name ,
'models' => true ,
),
$options
));
2010-06-07 04:35:40 +00:00
$db = ConnectionManager :: getDataSource ( $connection );
2008-05-30 11:40:08 +00:00
2009-08-28 05:06:21 +00:00
if ( isset ( $this -> plugin )) {
2011-05-25 19:14:23 +00:00
App :: uses ( $this -> plugin . 'AppModel' , $this -> plugin . '.Model' );
2009-08-28 05:06:21 +00:00
}
2008-05-30 11:40:08 +00:00
$tables = array ();
2012-03-04 19:18:04 +00:00
$currentTables = ( array ) $db -> listSources ();
2008-05-30 11:40:08 +00:00
$prefix = null ;
if ( isset ( $db -> config [ 'prefix' ])) {
$prefix = $db -> config [ 'prefix' ];
}
if ( ! is_array ( $models ) && $models !== false ) {
2009-08-28 05:06:21 +00:00
if ( isset ( $this -> plugin )) {
2011-01-09 04:15:07 +00:00
$models = App :: objects ( $this -> plugin . '.Model' , null , false );
2009-08-28 05:06:21 +00:00
} else {
2011-01-09 04:15:07 +00:00
$models = App :: objects ( 'Model' );
2009-08-28 05:06:21 +00:00
}
2008-05-30 11:40:08 +00:00
}
2011-07-15 21:49:33 +00:00
2008-05-30 11:40:08 +00:00
if ( is_array ( $models )) {
foreach ( $models as $model ) {
2010-10-01 03:22:57 +00:00
$importModel = $model ;
2011-01-09 04:15:07 +00:00
$plugin = null ;
2013-02-12 02:38:08 +00:00
if ( $model === 'AppModel' ) {
2011-07-15 19:48:38 +00:00
continue ;
}
2011-07-15 21:49:33 +00:00
2009-08-28 05:06:21 +00:00
if ( isset ( $this -> plugin )) {
2014-04-29 12:19:33 +00:00
if ( $model === $this -> plugin . 'AppModel' ) {
2011-02-22 03:58:00 +00:00
continue ;
}
2011-01-09 04:15:07 +00:00
$importModel = $model ;
$plugin = $this -> plugin . '.' ;
2009-08-28 05:06:21 +00:00
}
2011-07-15 21:49:33 +00:00
2011-01-09 04:15:07 +00:00
App :: uses ( $importModel , $plugin . 'Model' );
2010-12-09 03:45:18 +00:00
if ( ! class_exists ( $importModel )) {
2010-10-01 03:22:57 +00:00
continue ;
}
2011-02-22 03:58:00 +00:00
2010-10-01 03:22:57 +00:00
$vars = get_class_vars ( $model );
if ( empty ( $vars [ 'useDbConfig' ]) || $vars [ 'useDbConfig' ] != $connection ) {
continue ;
}
2011-12-08 01:58:01 +00:00
try {
$Object = ClassRegistry :: init ( array ( 'class' => $model , 'ds' => $connection ));
} catch ( CakeException $e ) {
continue ;
}
2012-08-08 12:44:38 +00:00
if ( ! is_object ( $Object ) || $Object -> useTable === false ) {
2012-08-08 11:42:40 +00:00
continue ;
}
2012-08-11 01:48:22 +00:00
$db = $Object -> getDataSource ();
2012-08-08 12:44:38 +00:00
$fulltable = $table = $db -> fullTableName ( $Object , false , false );
if ( $prefix && strpos ( $table , $prefix ) !== 0 ) {
2012-08-08 11:42:40 +00:00
continue ;
}
if ( ! in_array ( $fulltable , $currentTables )) {
continue ;
}
$table = $this -> _noPrefixTable ( $prefix , $table );
$key = array_search ( $fulltable , $currentTables );
if ( empty ( $tables [ $table ])) {
$tables [ $table ] = $this -> _columns ( $Object );
$tables [ $table ][ 'indexes' ] = $db -> index ( $Object );
$tables [ $table ][ 'tableParameters' ] = $db -> readTableParameters ( $fulltable );
unset ( $currentTables [ $key ]);
}
if ( empty ( $Object -> hasAndBelongsToMany )) {
continue ;
}
2012-12-20 12:47:03 +00:00
foreach ( $Object -> hasAndBelongsToMany as $assocData ) {
2012-08-08 11:42:40 +00:00
if ( isset ( $assocData [ 'with' ])) {
$class = $assocData [ 'with' ];
}
if ( ! is_object ( $Object -> $class )) {
2010-10-21 03:17:04 +00:00
continue ;
}
2012-08-08 11:42:40 +00:00
$withTable = $db -> fullTableName ( $Object -> $class , false , false );
if ( $prefix && strpos ( $withTable , $prefix ) !== 0 ) {
continue ;
}
if ( in_array ( $withTable , $currentTables )) {
$key = array_search ( $withTable , $currentTables );
$noPrefixWith = $this -> _noPrefixTable ( $prefix , $withTable );
$tables [ $noPrefixWith ] = $this -> _columns ( $Object -> $class );
$tables [ $noPrefixWith ][ 'indexes' ] = $db -> index ( $Object -> $class );
$tables [ $noPrefixWith ][ 'tableParameters' ] = $db -> readTableParameters ( $withTable );
unset ( $currentTables [ $key ]);
2008-05-30 11:40:08 +00:00
}
}
}
}
2011-07-15 21:49:33 +00:00
2008-05-30 11:40:08 +00:00
if ( ! empty ( $currentTables )) {
2008-10-23 00:10:44 +00:00
foreach ( $currentTables as $table ) {
2008-05-30 11:40:08 +00:00
if ( $prefix ) {
2008-09-17 01:47:19 +00:00
if ( strpos ( $table , $prefix ) !== 0 ) {
continue ;
}
2011-05-31 16:38:09 +00:00
$table = $this -> _noPrefixTable ( $prefix , $table );
2008-05-30 11:40:08 +00:00
}
2008-10-01 15:27:29 +00:00
$Object = new AppModel ( array (
'name' => Inflector :: classify ( $table ), 'table' => $table , 'ds' => $connection
));
$systemTables = array (
'aros' , 'acos' , 'aros_acos' , Configure :: read ( 'Session.table' ), 'i18n'
);
2011-10-24 16:34:49 +00:00
2011-11-05 10:57:08 +00:00
$fulltable = $db -> fullTableName ( $Object , false , false );
2011-10-24 16:34:49 +00:00
2008-10-01 15:27:29 +00:00
if ( in_array ( $table , $systemTables )) {
2011-08-20 05:39:30 +00:00
$tables [ $Object -> table ] = $this -> _columns ( $Object );
2008-05-30 11:40:08 +00:00
$tables [ $Object -> table ][ 'indexes' ] = $db -> index ( $Object );
2011-10-24 16:34:49 +00:00
$tables [ $Object -> table ][ 'tableParameters' ] = $db -> readTableParameters ( $fulltable );
2008-05-30 11:40:08 +00:00
} elseif ( $models === false ) {
2011-08-20 05:39:30 +00:00
$tables [ $table ] = $this -> _columns ( $Object );
2008-05-30 11:40:08 +00:00
$tables [ $table ][ 'indexes' ] = $db -> index ( $Object );
2011-10-24 16:34:49 +00:00
$tables [ $table ][ 'tableParameters' ] = $db -> readTableParameters ( $fulltable );
2008-05-30 11:40:08 +00:00
} else {
2011-08-20 05:39:30 +00:00
$tables [ 'missing' ][ $table ] = $this -> _columns ( $Object );
2008-05-30 11:40:08 +00:00
$tables [ 'missing' ][ $table ][ 'indexes' ] = $db -> index ( $Object );
2011-10-24 16:34:49 +00:00
$tables [ 'missing' ][ $table ][ 'tableParameters' ] = $db -> readTableParameters ( $fulltable );
2008-05-30 11:40:08 +00:00
}
}
}
ksort ( $tables );
return compact ( 'name' , 'tables' );
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Writes schema file from object or options .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array | object $object Schema object or options array .
* @ param array $options Schema object properties to override object .
* @ return mixed False or string written to file .
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function write ( $object , $options = array ()) {
2008-05-30 11:40:08 +00:00
if ( is_object ( $object )) {
$object = get_object_vars ( $object );
2010-04-09 10:41:28 +00:00
$this -> build ( $object );
2008-05-30 11:40:08 +00:00
}
if ( is_array ( $object )) {
$options = $object ;
unset ( $object );
}
extract ( array_merge (
get_object_vars ( $this ), $options
));
2011-11-20 19:40:23 +00:00
$out = " class { $name } Schema extends CakeSchema { \n \n " ;
2008-05-30 11:40:08 +00:00
if ( $path !== $this -> path ) {
2011-11-20 19:40:23 +00:00
$out .= " \t public \$ path = ' { $path } '; \n \n " ;
2008-05-30 11:40:08 +00:00
}
if ( $file !== $this -> file ) {
2011-11-20 19:40:23 +00:00
$out .= " \t public \$ file = ' { $file } '; \n \n " ;
2008-05-30 11:40:08 +00:00
}
if ( $connection !== 'default' ) {
2011-11-20 19:40:23 +00:00
$out .= " \t public \$ connection = ' { $connection } '; \n \n " ;
2008-05-30 11:40:08 +00:00
}
2011-11-20 19:40:23 +00:00
$out .= " \t public function before( \$ event = array()) { \n \t \t return true; \n \t } \n \n \t public function after( \$ event = array()) { \n \t } \n \n " ;
2008-05-30 11:40:08 +00:00
if ( empty ( $tables )) {
$this -> read ();
}
foreach ( $tables as $table => $fields ) {
if ( ! is_numeric ( $table ) && $table !== 'missing' ) {
2009-10-03 16:41:14 +00:00
$out .= $this -> generateTable ( $table , $fields );
2008-05-30 11:40:08 +00:00
}
}
2009-10-03 20:08:54 +00:00
$out .= " } \n " ;
2008-05-30 11:40:08 +00:00
2012-02-26 15:25:39 +00:00
$file = new File ( $path . DS . $file , true );
2012-02-26 17:04:28 +00:00
$content = " <?php \n { $out } " ;
2012-02-26 15:25:39 +00:00
if ( $file -> write ( $content )) {
2008-05-30 11:40:08 +00:00
return $content ;
}
return false ;
}
2009-07-24 19:18:37 +00:00
2009-10-03 16:41:14 +00:00
/**
2014-10-16 17:10:52 +00:00
* Generate the schema code for a table .
*
* Takes a table name and $fields array and returns a completed ,
* escaped variable declaration to be used in schema classes .
2009-10-03 16:41:14 +00:00
*
* @ param string $table Table name you want returned .
* @ param array $fields Array of field information to generate the table with .
2014-08-12 17:28:34 +00:00
* @ return string Variable declaration for a schema class .
2016-10-02 16:23:05 +00:00
* @ throws Exception
2009-11-14 12:19:25 +00:00
*/
2011-05-28 20:38:46 +00:00
public function generateTable ( $table , $fields ) {
2016-10-02 16:23:05 +00:00
// Valid var name regex (http://www.php.net/manual/en/language.variables.basics.php)
if ( ! preg_match ( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/' , $table )) {
throw new Exception ( " Invalid table name ' { $table } ' " );
}
2011-11-20 19:40:23 +00:00
$out = " \t public \$ { $table } = array( \n " ;
2009-10-03 16:41:14 +00:00
if ( is_array ( $fields )) {
$cols = array ();
foreach ( $fields as $field => $value ) {
2013-02-12 02:38:08 +00:00
if ( $field !== 'indexes' && $field !== 'tableParameters' ) {
2009-10-03 16:41:14 +00:00
if ( is_string ( $value )) {
$type = $value ;
2011-12-01 07:21:31 +00:00
$value = array ( 'type' => $type );
2009-10-03 16:41:14 +00:00
}
$col = " \t \t ' { $field } ' => array('type' => ' " . $value [ 'type' ] . " ', " ;
unset ( $value [ 'type' ]);
2012-10-26 22:46:12 +00:00
$col .= implode ( ', ' , $this -> _values ( $value ));
2013-02-12 02:38:08 +00:00
} elseif ( $field === 'indexes' ) {
2012-05-09 14:29:06 +00:00
$col = " \t \t 'indexes' => array( \n \t \t \t " ;
2009-10-03 16:41:14 +00:00
$props = array ();
foreach (( array ) $value as $key => $index ) {
2012-10-26 22:46:12 +00:00
$props [] = " ' { $key } ' => array( " . implode ( ', ' , $this -> _values ( $index )) . " ) " ;
2009-10-03 16:41:14 +00:00
}
2012-09-15 10:06:02 +00:00
$col .= implode ( " , \n \t \t \t " , $props ) . " \n \t \t " ;
2013-02-12 02:38:08 +00:00
} elseif ( $field === 'tableParameters' ) {
2009-10-03 16:44:49 +00:00
$col = " \t \t 'tableParameters' => array( " ;
2014-10-16 17:10:52 +00:00
$props = $this -> _values ( $value );
2012-09-15 10:06:02 +00:00
$col .= implode ( ', ' , $props );
2009-10-03 16:41:14 +00:00
}
$col .= " ) " ;
$cols [] = $col ;
}
2012-09-15 10:06:02 +00:00
$out .= implode ( " , \n " , $cols );
2009-10-03 16:41:14 +00:00
}
2012-10-26 06:25:41 +00:00
$out .= " \n \t ); \n \n " ;
2009-10-03 16:41:14 +00:00
return $out ;
}
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Compares two sets of schemas .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array | object $old Schema object or array .
* @ param array | object $new Schema object or array .
* @ return array Tables ( that are added , dropped , or changed . )
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function compare ( $old , $new = null ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $new )) {
2010-06-07 04:35:40 +00:00
$new = $this ;
2008-05-30 11:40:08 +00:00
}
if ( is_array ( $new )) {
if ( isset ( $new [ 'tables' ])) {
$new = $new [ 'tables' ];
}
} else {
$new = $new -> tables ;
}
if ( is_array ( $old )) {
if ( isset ( $old [ 'tables' ])) {
$old = $old [ 'tables' ];
}
} else {
$old = $old -> tables ;
}
$tables = array ();
foreach ( $new as $table => $fields ) {
2013-02-12 02:38:08 +00:00
if ( $table === 'missing' ) {
2010-05-29 15:06:36 +00:00
continue ;
2008-05-30 11:40:08 +00:00
}
if ( ! array_key_exists ( $table , $old )) {
2013-04-03 15:37:09 +00:00
$tables [ $table ][ 'create' ] = $fields ;
2008-05-30 11:40:08 +00:00
} else {
2010-10-28 03:03:31 +00:00
$diff = $this -> _arrayDiffAssoc ( $fields , $old [ $table ]);
2008-05-30 11:40:08 +00:00
if ( ! empty ( $diff )) {
$tables [ $table ][ 'add' ] = $diff ;
}
2010-10-28 03:03:31 +00:00
$diff = $this -> _arrayDiffAssoc ( $old [ $table ], $fields );
2008-05-30 11:40:08 +00:00
if ( ! empty ( $diff )) {
2008-11-07 11:33:13 +00:00
$tables [ $table ][ 'drop' ] = $diff ;
2008-05-30 11:40:08 +00:00
}
}
2010-03-15 03:31:52 +00:00
2008-05-30 11:40:08 +00:00
foreach ( $fields as $field => $value ) {
2011-06-21 15:43:33 +00:00
if ( ! empty ( $old [ $table ][ $field ])) {
2010-10-28 03:03:31 +00:00
$diff = $this -> _arrayDiffAssoc ( $value , $old [ $table ][ $field ]);
2016-07-26 20:57:14 +00:00
if ( empty ( $diff )) {
$diff = $this -> _arrayDiffAssoc ( $old [ $table ][ $field ], $value );
}
2009-10-03 20:08:54 +00:00
if ( ! empty ( $diff ) && $field !== 'indexes' && $field !== 'tableParameters' ) {
2012-03-12 10:30:52 +00:00
$tables [ $table ][ 'change' ][ $field ] = $value ;
2008-05-30 11:40:08 +00:00
}
}
2011-09-16 13:28:28 +00:00
if ( isset ( $tables [ $table ][ 'add' ][ $field ]) && $field !== 'indexes' && $field !== 'tableParameters' ) {
2008-05-30 11:40:08 +00:00
$wrapper = array_keys ( $fields );
if ( $column = array_search ( $field , $wrapper )) {
if ( isset ( $wrapper [ $column - 1 ])) {
$tables [ $table ][ 'add' ][ $field ][ 'after' ] = $wrapper [ $column - 1 ];
}
}
}
}
2008-12-09 04:54:58 +00:00
if ( isset ( $old [ $table ][ 'indexes' ]) && isset ( $new [ $table ][ 'indexes' ])) {
$diff = $this -> _compareIndexes ( $new [ $table ][ 'indexes' ], $old [ $table ][ 'indexes' ]);
if ( $diff ) {
2010-01-16 23:26:06 +00:00
if ( ! isset ( $tables [ $table ])) {
$tables [ $table ] = array ();
}
if ( isset ( $diff [ 'drop' ])) {
2010-01-07 22:49:57 +00:00
$tables [ $table ][ 'drop' ][ 'indexes' ] = $diff [ 'drop' ];
}
2010-01-16 23:26:06 +00:00
if ( $diff && isset ( $diff [ 'add' ])) {
2010-01-07 22:49:57 +00:00
$tables [ $table ][ 'add' ][ 'indexes' ] = $diff [ 'add' ];
}
2008-12-09 04:54:58 +00:00
}
}
2009-10-03 20:08:54 +00:00
if ( isset ( $old [ $table ][ 'tableParameters' ]) && isset ( $new [ $table ][ 'tableParameters' ])) {
2009-10-03 20:48:10 +00:00
$diff = $this -> _compareTableParameters ( $new [ $table ][ 'tableParameters' ], $old [ $table ][ 'tableParameters' ]);
if ( $diff ) {
2009-10-05 00:53:49 +00:00
$tables [ $table ][ 'change' ][ 'tableParameters' ] = $diff ;
2009-10-03 20:48:10 +00:00
}
2009-10-03 20:08:54 +00:00
}
2008-05-30 11:40:08 +00:00
}
return $tables ;
}
2009-07-24 19:18:37 +00:00
2010-10-28 03:03:31 +00:00
/**
2014-08-12 17:28:34 +00:00
* Extended array_diff_assoc noticing change from / to NULL values .
2010-10-28 03:03:31 +00:00
*
* It behaves almost the same way as array_diff_assoc except for NULL values : if
* one of the values is not NULL - change is detected . It is useful in situation
* where one value is strval ( '' ) ant other is strval ( null ) - in string comparing
* methods this results as EQUAL , while it is not .
*
2014-08-12 17:28:34 +00:00
* @ param array $array1 Base array .
* @ param array $array2 Corresponding array checked for equality .
2010-10-28 03:03:31 +00:00
* @ return array Difference as array with array ( keys => values ) from input array
* where match was not found .
*/
2011-05-30 20:26:42 +00:00
protected function _arrayDiffAssoc ( $array1 , $array2 ) {
2010-10-28 03:03:31 +00:00
$difference = array ();
foreach ( $array1 as $key => $value ) {
if ( ! array_key_exists ( $key , $array2 )) {
$difference [ $key ] = $value ;
continue ;
}
$correspondingValue = $array2 [ $key ];
2013-10-16 13:52:29 +00:00
if (( $value === null ) !== ( $correspondingValue === null )) {
2010-10-28 03:03:31 +00:00
$difference [ $key ] = $value ;
continue ;
}
if ( is_bool ( $value ) !== is_bool ( $correspondingValue )) {
$difference [ $key ] = $value ;
continue ;
}
2011-11-13 01:43:55 +00:00
if ( is_array ( $value ) && is_array ( $correspondingValue )) {
continue ;
}
if ( $value === $correspondingValue ) {
2010-10-28 03:03:31 +00:00
continue ;
}
$difference [ $key ] = $value ;
}
return $difference ;
}
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Formats Schema columns from Model Object .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $values Options keys ( type , null , default , key , length , extra ) .
* @ return array Formatted values .
2008-05-30 11:40:08 +00:00
*/
2011-08-20 05:39:30 +00:00
protected function _values ( $values ) {
2008-05-30 11:40:08 +00:00
$vals = array ();
if ( is_array ( $values )) {
foreach ( $values as $key => $val ) {
if ( is_array ( $val )) {
2012-12-15 17:24:29 +00:00
$vals [] = " ' { $key } ' => array( " . implode ( " , " , $this -> _values ( $val )) . " ) " ;
2012-12-03 03:58:57 +00:00
} else {
2008-05-30 11:40:08 +00:00
$val = var_export ( $val , true );
2012-05-01 21:39:35 +00:00
if ( $val === 'NULL' ) {
$val = 'null' ;
}
2012-12-03 03:58:57 +00:00
if ( ! is_numeric ( $key )) {
$vals [] = " ' { $key } ' => { $val } " ;
} else {
$vals [] = " { $val } " ;
}
2008-05-30 11:40:08 +00:00
}
}
}
return $vals ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2014-08-12 17:28:34 +00:00
* Formats Schema columns from Model Object .
2008-05-30 11:40:08 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array & $Obj model object .
* @ return array Formatted columns .
2008-05-30 11:40:08 +00:00
*/
2011-08-20 05:39:30 +00:00
protected function _columns ( & $Obj ) {
2011-02-24 06:01:03 +00:00
$db = $Obj -> getDataSource ();
2008-05-30 11:40:08 +00:00
$fields = $Obj -> schema ( true );
2011-02-05 20:24:46 +00:00
2017-03-04 05:51:20 +00:00
$hasPrimaryAlready = false ;
foreach ( $fields as $value ) {
if ( isset ( $value [ 'key' ]) && $value [ 'key' ] === 'primary' ) {
$hasPrimaryAlready = true ;
}
}
2012-12-20 12:47:03 +00:00
$columns = array ();
2008-05-30 11:40:08 +00:00
foreach ( $fields as $name => $value ) {
2017-03-04 05:51:20 +00:00
if ( $Obj -> primaryKey === $name && ! $hasPrimaryAlready && ! isset ( $value [ 'key' ])) {
2008-05-30 11:40:08 +00:00
$value [ 'key' ] = 'primary' ;
}
if ( ! isset ( $db -> columns [ $value [ 'type' ]])) {
2011-10-19 08:17:10 +00:00
trigger_error ( __d ( 'cake_dev' , 'Schema generation error: invalid column type %s for %s.%s does not exist in DBO' , $value [ 'type' ], $Obj -> name , $name ), E_USER_NOTICE );
2008-05-30 11:40:08 +00:00
continue ;
} else {
$defaultCol = $db -> columns [ $value [ 'type' ]];
if ( isset ( $defaultCol [ 'limit' ]) && $defaultCol [ 'limit' ] == $value [ 'length' ]) {
unset ( $value [ 'length' ]);
} elseif ( isset ( $defaultCol [ 'length' ]) && $defaultCol [ 'length' ] == $value [ 'length' ]) {
unset ( $value [ 'length' ]);
}
unset ( $value [ 'limit' ]);
}
2013-03-01 14:51:15 +00:00
if ( isset ( $value [ 'default' ]) && ( $value [ 'default' ] === '' || ( $value [ 'default' ] === false && $value [ 'type' ] !== 'boolean' ))) {
2008-05-30 11:40:08 +00:00
unset ( $value [ 'default' ]);
}
if ( empty ( $value [ 'length' ])) {
unset ( $value [ 'length' ]);
}
if ( empty ( $value [ 'key' ])) {
unset ( $value [ 'key' ]);
}
$columns [ $name ] = $value ;
}
return $columns ;
}
2009-07-24 19:18:37 +00:00
2009-10-03 20:48:10 +00:00
/**
2014-08-12 17:28:34 +00:00
* Compare two schema files table Parameters .
2009-10-03 20:48:10 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $new New indexes .
* @ param array $old Old indexes .
2009-10-03 20:48:10 +00:00
* @ return mixed False on failure , or an array of parameters to add & drop .
2009-11-14 12:19:25 +00:00
*/
2011-05-28 20:38:46 +00:00
protected function _compareTableParameters ( $new , $old ) {
2009-10-05 00:53:49 +00:00
if ( ! is_array ( $new ) || ! is_array ( $old )) {
return false ;
}
2010-10-28 03:03:31 +00:00
$change = $this -> _arrayDiffAssoc ( $new , $old );
2009-10-05 00:53:49 +00:00
return $change ;
2009-10-03 20:48:10 +00:00
}
2008-12-09 04:54:58 +00:00
/**
2014-08-12 17:28:34 +00:00
* Compare two schema indexes .
2008-12-09 04:54:58 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param array $new New indexes .
* @ param array $old Old indexes .
* @ return mixed False on failure or array of indexes to add and drop .
2008-12-09 04:54:58 +00:00
*/
2011-05-28 20:38:46 +00:00
protected function _compareIndexes ( $new , $old ) {
2008-12-09 04:54:58 +00:00
if ( ! is_array ( $new ) || ! is_array ( $old )) {
return false ;
}
$add = $drop = array ();
2010-10-28 03:03:31 +00:00
$diff = $this -> _arrayDiffAssoc ( $new , $old );
2008-12-09 04:54:58 +00:00
if ( ! empty ( $diff )) {
$add = $diff ;
}
2010-10-28 03:03:31 +00:00
$diff = $this -> _arrayDiffAssoc ( $old , $new );
2008-12-09 04:54:58 +00:00
if ( ! empty ( $diff )) {
$drop = $diff ;
}
foreach ( $new as $name => $value ) {
if ( isset ( $old [ $name ])) {
$newUnique = isset ( $value [ 'unique' ]) ? $value [ 'unique' ] : 0 ;
$oldUnique = isset ( $old [ $name ][ 'unique' ]) ? $old [ $name ][ 'unique' ] : 0 ;
$newColumn = $value [ 'column' ];
$oldColumn = $old [ $name ][ 'column' ];
$diff = false ;
if ( $newUnique != $oldUnique ) {
$diff = true ;
} elseif ( is_array ( $newColumn ) && is_array ( $oldColumn )) {
$diff = ( $newColumn !== $oldColumn );
} elseif ( is_string ( $newColumn ) && is_string ( $oldColumn )) {
$diff = ( $newColumn != $oldColumn );
} else {
$diff = true ;
}
if ( $diff ) {
$drop [ $name ] = null ;
$add [ $name ] = $value ;
}
}
}
2009-10-05 01:48:20 +00:00
return array_filter ( compact ( 'add' , 'drop' ));
2008-12-09 04:54:58 +00:00
}
2011-06-01 03:29:27 +00:00
/**
2014-08-12 17:28:34 +00:00
* Trim the table prefix from the full table name , and return the prefix - less
* table .
2011-06-01 03:29:27 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param string $prefix Table prefix .
* @ param string $table Full table name .
* @ return string Prefix - less table name .
2011-06-01 03:29:27 +00:00
*/
2011-08-20 05:39:30 +00:00
protected function _noPrefixTable ( $prefix , $table ) {
2011-05-31 16:38:09 +00:00
return preg_replace ( '/^' . preg_quote ( $prefix ) . '/' , '' , $table );
}
2012-03-04 19:18:04 +00:00
2014-08-11 15:40:57 +00:00
/**
2014-08-12 17:28:34 +00:00
* Attempts to require the schema file specified .
2014-08-11 15:40:57 +00:00
*
2014-08-12 17:28:34 +00:00
* @ param string $path Filesystem path to the file .
* @ param string $file Filesystem basename of the file .
* @ return bool True when a file was successfully included , false on failure .
2014-08-11 15:40:57 +00:00
*/
protected function _requireFile ( $path , $file ) {
if ( file_exists ( $path . DS . $file ) && is_file ( $path . DS . $file )) {
require_once $path . DS . $file ;
return true ;
} elseif ( file_exists ( $path . DS . 'schema.php' ) && is_file ( $path . DS . 'schema.php' )) {
require_once $path . DS . 'schema.php' ;
return true ;
}
return false ;
}
2008-05-30 11:40:08 +00:00
}