PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/migrations/libs/model/cake_migration.php

https://github.com/ankursingh/cake_shell
PHP | 400 lines | 198 code | 38 blank | 164 comment | 24 complexity | 6658ed6718c2080eb496b344346bd370 MD5 | raw file
  1. <?php
  2. /**
  3. * CakePHP Migrations
  4. *
  5. * Copyright 2009 - 2010, Cake Development Corporation
  6. * 1785 E. Sahara Avenue, Suite 490-423
  7. * Las Vegas, Nevada 89104
  8. *
  9. * Licensed under The MIT License
  10. * Redistributions of files must retain the above copyright notice.
  11. *
  12. * @copyright 2009 - 2010, Cake Development Corporation
  13. * @link http://codaset.com/cakedc/migrations/
  14. * @package plugns.migrations
  15. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  16. */
  17. App::import('Model', 'CakeSchema', false);
  18. /**
  19. * Base Class for Migration management
  20. *
  21. * @package migrations
  22. * @subpackage migrations.libs.model
  23. */
  24. class CakeMigration extends Object {
  25. /**
  26. * Migration description
  27. *
  28. * @var string
  29. * @access public
  30. */
  31. var $description = '';
  32. /**
  33. * Migration information
  34. *
  35. * This variable will be set while the migration is runned and contains:
  36. * - `name` - File name without extension
  37. * - `class` - Class name
  38. * - `version` - What version represent on mapping
  39. * - `type` - Can be 'app' or a plugin name
  40. * - `migrated` - Datetime of when it was applied, or null
  41. *
  42. * @var array
  43. * @access public
  44. */
  45. var $info = null;
  46. /**
  47. * Actions to be performed
  48. *
  49. * @var array $migration
  50. * @access public
  51. */
  52. var $migration = array(
  53. 'up' => array(),
  54. 'down' => array()
  55. );
  56. /**
  57. * Running direction
  58. *
  59. * @var string $direction
  60. * @access public
  61. */
  62. var $direction = null;
  63. /**
  64. * Connection used
  65. *
  66. * @var string
  67. * @access public
  68. */
  69. var $connection = 'default';
  70. /**
  71. * DataSource used
  72. *
  73. * @var DataSource
  74. * @access public
  75. */
  76. var $db = null;
  77. /**
  78. * CakeSchema instace
  79. *
  80. * @var CakeSchema
  81. * @access public
  82. */
  83. var $Schema = null;
  84. /**
  85. * Callback class that will be called before/after every action
  86. *
  87. * @var object
  88. * @access public
  89. */
  90. var $callback = null;
  91. /**
  92. * Before migration callback
  93. *
  94. * @param string $direction, up or down direction of migration process
  95. * @return boolean Should process continue
  96. * @access public
  97. */
  98. function before($direction) {
  99. return true;
  100. }
  101. /**
  102. * After migration callback
  103. *
  104. * @param string $direction, up or down direction of migration process
  105. * @return boolean Should process continue
  106. * @access public
  107. */
  108. function after($direction) {
  109. return true;
  110. }
  111. /**
  112. * Constructor
  113. *
  114. * @param array $options optional load object properties
  115. */
  116. function __construct($options = array()) {
  117. parent::__construct();
  118. if (!empty($options['up'])) {
  119. $this->migration['up'] = $options['up'];
  120. }
  121. if (!empty($options['down'])) {
  122. $this->migration['down'] = $options['down'];
  123. }
  124. $allowed = array('connection', 'callback');
  125. foreach ($allowed as $variable) {
  126. if (!empty($options[$variable])) {
  127. $this->{$variable} = $options[$variable];
  128. }
  129. }
  130. }
  131. /**
  132. * Run migration
  133. *
  134. * @param string $direction, up or down direction of migration process
  135. * @return boolean Status of the process
  136. * @access public
  137. */
  138. function run($direction) {
  139. if (!in_array($direction, array('up', 'down'))) {
  140. trigger_error(sprintf(__d('migrations', 'Migration direction (%s) is not one of valid directions.', true), $direction), E_USER_NOTICE);
  141. return false;
  142. }
  143. $this->direction = $direction;
  144. $this->db =& ConnectionManager::getDataSource($this->connection);
  145. $this->db->cacheSources = false;
  146. $this->Schema = new CakeSchema(array('connection' => $this->connection));
  147. if (!$this->__invokeCallbacks('beforeMigration', $direction)) {
  148. return false;
  149. }
  150. foreach ($this->migration[$direction] as $type => $info) {
  151. switch ($type) {
  152. case 'create_table':
  153. $methodName = '_createTable';
  154. break;
  155. case 'drop_table':
  156. $methodName = '_dropTable';
  157. break;
  158. case 'rename_table':
  159. $methodName = '_renameTable';
  160. break;
  161. case 'create_field':
  162. $type = 'add';
  163. $methodName = '_alterTable';
  164. break;
  165. case 'drop_field':
  166. $type = 'drop';
  167. $methodName = '_alterTable';
  168. break;
  169. case 'alter_field':
  170. $type = 'change';
  171. $methodName = '_alterTable';
  172. break;
  173. case 'rename_field':
  174. $type = 'rename';
  175. $methodName = '_alterTable';
  176. break;
  177. default:
  178. trigger_error(sprintf(__d('migrations', 'Migration action type (%s) is not one of valid actions type.', true), $type), E_USER_NOTICE);
  179. continue 2;
  180. }
  181. $this->{$methodName}($type, $info);
  182. }
  183. $this->__clearCache();
  184. return $this->__invokeCallbacks('afterMigration', $direction);
  185. }
  186. /**
  187. * Create Table method
  188. *
  189. * @param string $type Type of operation to be done, in this case 'create_table'
  190. * @param array $tables List of tables to be created
  191. * @return boolean Return true in case of success, otherwise false
  192. * @access protected
  193. */
  194. function _createTable($type, $tables) {
  195. foreach ($tables as $table => $fields) {
  196. $this->Schema->tables = array($table => $fields);
  197. $this->__invokeCallbacks('beforeAction', 'create_table', array('table' => $table));
  198. $this->db->execute($this->db->createSchema($this->Schema));
  199. $this->__invokeCallbacks('afterAction', 'create_table', array('table' => $table));
  200. }
  201. return true;
  202. }
  203. /**
  204. * Drop Table method
  205. *
  206. * @param string $type Type of operation to be done, in this case 'drop_table'
  207. * @param array $tables List of tables to be dropped
  208. * @return boolean Return true in case of success, otherwise false
  209. * @access protected
  210. */
  211. function _dropTable($type, $tables) {
  212. foreach ($tables as $table) {
  213. $this->Schema->tables = array($table => array());
  214. $this->__invokeCallbacks('beforeAction', 'drop_table', array('table' => $table));
  215. $this->db->execute($this->db->dropSchema($this->Schema));
  216. $this->__invokeCallbacks('afterAction', 'drop_table', array('table' => $table));
  217. }
  218. return true;
  219. }
  220. /**
  221. * Rename Table method
  222. *
  223. * @param string $type Type of operation to be done, this case 'rename_table'
  224. * @param array $tables List of tables to be renamed
  225. * @return boolean Return true in case of success, otherwise false
  226. * @access protected
  227. */
  228. function _renameTable($type, $tables) {
  229. foreach ($tables as $oldName => $newName) {
  230. $sql = 'RENAME TABLE ' . $this->db->fullTableName($oldName) . ' TO ' . $this->db->fullTableName($newName) . ';';
  231. $this->__invokeCallbacks('beforeAction', 'rename_table', array('old_name' => $oldName, 'new_name' => $newName));
  232. $this->db->execute($sql);
  233. $this->__invokeCallbacks('afterAction', 'rename_table', array('old_name' => $oldName, 'new_name' => $newName));
  234. }
  235. return true;
  236. }
  237. /**
  238. * Alter Table method
  239. *
  240. * @param string $type Type of operation to be done
  241. * @param array $tables List of tables and fields
  242. * @return boolean Return true in case of success, otherwise false
  243. * @access protected
  244. */
  245. function _alterTable($type, $tables) {
  246. foreach ($tables as $table => $fields) {
  247. $indexes = array();
  248. if (isset($fields['indexes'])) {
  249. $indexes = $fields['indexes'];
  250. unset($fields['indexes']);
  251. }
  252. foreach ($fields as $field => $col) {
  253. switch ($type) {
  254. case 'add':
  255. $sql = $this->db->alterSchema(array(
  256. $table => array('add' => array($field => $col))
  257. ));
  258. break;
  259. case 'drop':
  260. $field = $col;
  261. $sql = $this->db->alterSchema(array(
  262. $table => array('drop' => array($field => array()))
  263. ));
  264. break;
  265. case 'change':
  266. $model = new Model(array('table' => $table, 'ds' => $this->connection));
  267. $tableFields = $this->db->describe($model);
  268. $sql = $this->db->alterSchema(array(
  269. $table => array('change' => array($field => array_merge($tableFields[$field], $col)))
  270. ));
  271. break;
  272. case 'rename':
  273. $model = new Model(array('table' => $table, 'ds' => $this->connection));
  274. $tableFields = $this->db->describe($model);
  275. $sql = $this->db->alterSchema(array(
  276. $table => array('change' => array($field => array_merge($tableFields[$field], array('name' => $col))))
  277. ));
  278. break;
  279. }
  280. if ($type == 'rename') {
  281. $data = array('table' => $table, 'old_name' => $field, 'new_name' => $col);
  282. } else {
  283. $data = array('table' => $table, 'field' => $field);
  284. }
  285. $this->__invokeCallbacks('beforeAction', $type . '_field', $data);
  286. $this->db->execute($sql);
  287. $this->__invokeCallbacks('afterAction', $type . '_field', $data);
  288. }
  289. foreach ($indexes as $key => $index) {
  290. if (is_numeric($key)) {
  291. $key = $index;
  292. $index = array();
  293. }
  294. $sql = $this->db->alterSchema(array(
  295. $table => array($type => array('indexes' => array($key => $index)))
  296. ));
  297. $this->__invokeCallbacks('beforeAction', $type . '_index', array('table' => $table, 'index' => $key));
  298. $this->db->execute($sql);
  299. $this->__invokeCallbacks('afterAction', $type . '_index', array('table' => $table, 'index' => $key));
  300. }
  301. }
  302. return true;
  303. }
  304. /**
  305. * This method will invoke the before/afterAction callbacks, it is good when
  306. * you need track every action.
  307. *
  308. * @param string $callback Callback name, beforeMigration, beforeAction, afterAction
  309. * or afterMigration.
  310. * @param string $type Type of action. i.e: create_table, drop_table, etc.
  311. * Or also can be the direction, for before and after Migration callbacks
  312. * @param array $data Data to send to the callback
  313. * @return void
  314. * @access private
  315. */
  316. function __invokeCallbacks($callback, $type, $data = array()) {
  317. if ($this->callback !== null && method_exists($this->callback, $callback)) {
  318. if ($callback == 'beforeMigration' || $callback == 'afterMigration') {
  319. $this->callback->{$callback}($this, $type);
  320. } else {
  321. $this->callback->{$callback}($this, $type, $data);
  322. }
  323. }
  324. if ($callback == 'beforeMigration' || $callback == 'afterMigration') {
  325. $callback = str_replace('Migration', '', $callback);
  326. return $this->{$callback}($type);
  327. }
  328. }
  329. /**
  330. * Clear all caches present related to models
  331. *
  332. * Before the 'after' callback method be called is needed to clear all caches.
  333. * Without it any model operations will use cached data instead of real/modified
  334. * data.
  335. *
  336. * @return void
  337. * @access private
  338. */
  339. function __clearCache() {
  340. Cache::clear(false, '_cake_model_');
  341. ClassRegistry::flush();
  342. }
  343. /**
  344. * Generate a instance of model for given options
  345. *
  346. * @param string $name Model name to be initialized
  347. * @param string $table Table name to be initialized
  348. * @return Model
  349. * @access public
  350. */
  351. function generateModel($name, $table = null, $options = array()) {
  352. if (empty($table)) {
  353. $table = Inflector::tableize($name);
  354. }
  355. $defaults = array(
  356. 'name' => $name, 'table' => $table, 'ds' => $this->connection
  357. );
  358. $options = array_merge($defaults, $options);
  359. return new AppModel($options);
  360. }
  361. }
  362. ?>