CDbMigration.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. <?php
  2. /**
  3. * CDbMigration class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CDbMigration is the base class for representing a database migration.
  12. *
  13. * CDbMigration is designed to be used together with the "yiic migrate" command.
  14. *
  15. * Each child class of CDbMigration represents an individual database migration which
  16. * is identified by the child class name.
  17. *
  18. * Within each migration, the {@link up} method contains the logic for "upgrading"
  19. * the database used in an application; while the {@link down} method contains "downgrading"
  20. * logic. The "yiic migrate" command manages all available migrations in an application.
  21. *
  22. * By overriding {@link safeUp} or {@link safeDown} methods instead of {@link up} and {@link down}
  23. * the migration logic will be wrapped with a DB transaction.
  24. *
  25. * CDbMigration provides a set of convenient methods for manipulating database data and schema.
  26. * For example, the {@link insert} method can be used to easily insert a row of data into
  27. * a database table; the {@link createTable} method can be used to create a database table.
  28. * Compared with the same methods in {@link CDbCommand}, these methods will display extra
  29. * information showing the method parameters and execution time, which may be useful when
  30. * applying migrations.
  31. *
  32. * @property CDbConnection $dbConnection The currently active database connection.
  33. *
  34. * @author Qiang Xue <qiang.xue@gmail.com>
  35. * @package system.db
  36. * @since 1.1.6
  37. */
  38. abstract class CDbMigration extends CComponent
  39. {
  40. private $_db;
  41. /**
  42. * This method contains the logic to be executed when applying this migration.
  43. * Child classes may implement this method to provide actual migration logic.
  44. * @return boolean Returning false means, the migration will not be applied.
  45. */
  46. public function up()
  47. {
  48. $transaction=$this->getDbConnection()->beginTransaction();
  49. try
  50. {
  51. if($this->safeUp()===false)
  52. {
  53. $transaction->rollback();
  54. return false;
  55. }
  56. $transaction->commit();
  57. }
  58. catch(Exception $e)
  59. {
  60. echo "Exception: ".$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
  61. echo $e->getTraceAsString()."\n";
  62. $transaction->rollback();
  63. return false;
  64. }
  65. }
  66. /**
  67. * This method contains the logic to be executed when removing this migration.
  68. * Child classes may override this method if the corresponding migrations can be removed.
  69. * @return boolean Returning false means, the migration will not be applied.
  70. */
  71. public function down()
  72. {
  73. $transaction=$this->getDbConnection()->beginTransaction();
  74. try
  75. {
  76. if($this->safeDown()===false)
  77. {
  78. $transaction->rollback();
  79. return false;
  80. }
  81. $transaction->commit();
  82. }
  83. catch(Exception $e)
  84. {
  85. echo "Exception: ".$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
  86. echo $e->getTraceAsString()."\n";
  87. $transaction->rollback();
  88. return false;
  89. }
  90. }
  91. /**
  92. * This method contains the logic to be executed when applying this migration.
  93. * This method differs from {@link up} in that the DB logic implemented here will
  94. * be enclosed within a DB transaction.
  95. * Child classes may implement this method instead of {@link up} if the DB logic
  96. * needs to be within a transaction.
  97. * @return boolean Returning false means, the migration will not be applied and
  98. * the transaction will be rolled back.
  99. * @since 1.1.7
  100. */
  101. public function safeUp()
  102. {
  103. }
  104. /**
  105. * This method contains the logic to be executed when removing this migration.
  106. * This method differs from {@link down} in that the DB logic implemented here will
  107. * be enclosed within a DB transaction.
  108. * Child classes may implement this method instead of {@link up} if the DB logic
  109. * needs to be within a transaction.
  110. * @return boolean Returning false means, the migration will not be applied and
  111. * the transaction will be rolled back.
  112. * @since 1.1.7
  113. */
  114. public function safeDown()
  115. {
  116. }
  117. /**
  118. * Returns the currently active database connection.
  119. * By default, the 'db' application component will be returned and activated.
  120. * You can call {@link setDbConnection} to switch to a different database connection.
  121. * Methods such as {@link insert}, {@link createTable} will use this database connection
  122. * to perform DB queries.
  123. * @throws CException if "db" application component is not configured
  124. * @return CDbConnection the currently active database connection
  125. */
  126. public function getDbConnection()
  127. {
  128. if($this->_db===null)
  129. {
  130. $this->_db=Yii::app()->getComponent('db');
  131. if(!$this->_db instanceof CDbConnection)
  132. throw new CException(Yii::t('yii', 'The "db" application component must be configured to be a CDbConnection object.'));
  133. }
  134. return $this->_db;
  135. }
  136. /**
  137. * Sets the currently active database connection.
  138. * The database connection will be used by the methods such as {@link insert}, {@link createTable}.
  139. * @param CDbConnection $db the database connection component
  140. */
  141. public function setDbConnection($db)
  142. {
  143. $this->_db=$db;
  144. }
  145. /**
  146. * Executes a SQL statement.
  147. * This method executes the specified SQL statement using {@link dbConnection}.
  148. * @param string $sql the SQL statement to be executed
  149. * @param array $params input parameters (name=>value) for the SQL execution. See {@link CDbCommand::execute} for more details.
  150. * @since 1.1.7
  151. */
  152. public function execute($sql, $params=array())
  153. {
  154. echo " > execute SQL: $sql ...";
  155. $time=microtime(true);
  156. $this->getDbConnection()->createCommand($sql)->execute($params);
  157. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  158. }
  159. /**
  160. * Creates and executes an INSERT SQL statement.
  161. * The method will properly escape the column names, and bind the values to be inserted.
  162. * @param string $table the table that new rows will be inserted into.
  163. * @param array $columns the column data (name=>value) to be inserted into the table.
  164. */
  165. public function insert($table, $columns)
  166. {
  167. echo " > insert into $table ...";
  168. $time=microtime(true);
  169. $this->getDbConnection()->createCommand()->insert($table, $columns);
  170. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  171. }
  172. /**
  173. * Creates and executes an UPDATE SQL statement.
  174. * The method will properly escape the column names and bind the values to be updated.
  175. * @param string $table the table to be updated.
  176. * @param array $columns the column data (name=>value) to be updated.
  177. * @param mixed $conditions the conditions that will be put in the WHERE part. Please
  178. * refer to {@link CDbCommand::where} on how to specify conditions.
  179. * @param array $params the parameters to be bound to the query.
  180. */
  181. public function update($table, $columns, $conditions='', $params=array())
  182. {
  183. echo " > update $table ...";
  184. $time=microtime(true);
  185. $this->getDbConnection()->createCommand()->update($table, $columns, $conditions, $params);
  186. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  187. }
  188. /**
  189. * Creates and executes a DELETE SQL statement.
  190. * @param string $table the table where the data will be deleted from.
  191. * @param mixed $conditions the conditions that will be put in the WHERE part. Please
  192. * refer to {@link CDbCommand::where} on how to specify conditions.
  193. * @param array $params the parameters to be bound to the query.
  194. */
  195. public function delete($table, $conditions='', $params=array())
  196. {
  197. echo " > delete from $table ...";
  198. $time=microtime(true);
  199. $this->getDbConnection()->createCommand()->delete($table, $conditions, $params);
  200. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  201. }
  202. /**
  203. * Builds and executes a SQL statement for creating a new DB table.
  204. *
  205. * The columns in the new table should be specified as name-definition pairs (e.g. 'name'=>'string'),
  206. * where name stands for a column name which will be properly quoted by the method, and definition
  207. * stands for the column type which can contain an abstract DB type.
  208. * The {@link getColumnType} method will be invoked to convert any abstract type into a physical one.
  209. *
  210. * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly
  211. * inserted into the generated SQL.
  212. *
  213. * @param string $table the name of the table to be created. The name will be properly quoted by the method.
  214. * @param array $columns the columns (name=>definition) in the new table.
  215. * @param string $options additional SQL fragment that will be appended to the generated SQL.
  216. */
  217. public function createTable($table, $columns, $options=null)
  218. {
  219. echo " > create table $table ...";
  220. $time=microtime(true);
  221. $this->getDbConnection()->createCommand()->createTable($table, $columns, $options);
  222. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  223. }
  224. /**
  225. * Builds and executes a SQL statement for renaming a DB table.
  226. * @param string $table the table to be renamed. The name will be properly quoted by the method.
  227. * @param string $newName the new table name. The name will be properly quoted by the method.
  228. */
  229. public function renameTable($table, $newName)
  230. {
  231. echo " > rename table $table to $newName ...";
  232. $time=microtime(true);
  233. $this->getDbConnection()->createCommand()->renameTable($table, $newName);
  234. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  235. }
  236. /**
  237. * Builds and executes a SQL statement for dropping a DB table.
  238. * @param string $table the table to be dropped. The name will be properly quoted by the method.
  239. */
  240. public function dropTable($table)
  241. {
  242. echo " > drop table $table ...";
  243. $time=microtime(true);
  244. $this->getDbConnection()->createCommand()->dropTable($table);
  245. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  246. }
  247. /**
  248. * Builds and executes a SQL statement for truncating a DB table.
  249. * @param string $table the table to be truncated. The name will be properly quoted by the method.
  250. */
  251. public function truncateTable($table)
  252. {
  253. echo " > truncate table $table ...";
  254. $time=microtime(true);
  255. $this->getDbConnection()->createCommand()->truncateTable($table);
  256. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  257. }
  258. /**
  259. * Builds and executes a SQL statement for adding a new DB column.
  260. * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method.
  261. * @param string $column the name of the new column. The name will be properly quoted by the method.
  262. * @param string $type the column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any)
  263. * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL.
  264. * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'.
  265. */
  266. public function addColumn($table, $column, $type)
  267. {
  268. echo " > add column $column $type to table $table ...";
  269. $time=microtime(true);
  270. $this->getDbConnection()->createCommand()->addColumn($table, $column, $type);
  271. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  272. }
  273. /**
  274. * Builds and executes a SQL statement for dropping a DB column.
  275. * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method.
  276. * @param string $column the name of the column to be dropped. The name will be properly quoted by the method.
  277. */
  278. public function dropColumn($table, $column)
  279. {
  280. echo " > drop column $column from table $table ...";
  281. $time=microtime(true);
  282. $this->getDbConnection()->createCommand()->dropColumn($table, $column);
  283. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  284. }
  285. /**
  286. * Builds and executes a SQL statement for renaming a column.
  287. * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method.
  288. * @param string $name the old name of the column. The name will be properly quoted by the method.
  289. * @param string $newName the new name of the column. The name will be properly quoted by the method.
  290. */
  291. public function renameColumn($table, $name, $newName)
  292. {
  293. echo " > rename column $name in table $table to $newName ...";
  294. $time=microtime(true);
  295. $this->getDbConnection()->createCommand()->renameColumn($table, $name, $newName);
  296. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  297. }
  298. /**
  299. * Builds and executes a SQL statement for changing the definition of a column.
  300. * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.
  301. * @param string $column the name of the column to be changed. The name will be properly quoted by the method.
  302. * @param string $type the new column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any)
  303. * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL.
  304. * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'.
  305. */
  306. public function alterColumn($table, $column, $type)
  307. {
  308. echo " > alter column $column in table $table to $type ...";
  309. $time=microtime(true);
  310. $this->getDbConnection()->createCommand()->alterColumn($table, $column, $type);
  311. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  312. }
  313. /**
  314. * Builds a SQL statement for adding a foreign key constraint to an existing table.
  315. * The method will properly quote the table and column names.
  316. * @param string $name the name of the foreign key constraint.
  317. * @param string $table the table that the foreign key constraint will be added to.
  318. * @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas.
  319. * @param string $refTable the table that the foreign key references to.
  320. * @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas.
  321. * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
  322. * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
  323. */
  324. public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
  325. {
  326. echo " > add foreign key $name: $table ($columns) references $refTable ($refColumns) ...";
  327. $time=microtime(true);
  328. $this->getDbConnection()->createCommand()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
  329. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  330. }
  331. /**
  332. * Builds a SQL statement for dropping a foreign key constraint.
  333. * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method.
  334. * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method.
  335. */
  336. public function dropForeignKey($name, $table)
  337. {
  338. echo " > drop foreign key $name from table $table ...";
  339. $time=microtime(true);
  340. $this->getDbConnection()->createCommand()->dropForeignKey($name, $table);
  341. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  342. }
  343. /**
  344. * Builds and executes a SQL statement for creating a new index.
  345. * @param string $name the name of the index. The name will be properly quoted by the method.
  346. * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method.
  347. * @param string $column the column(s) that should be included in the index. If there are multiple columns, please separate them
  348. * by commas. The column names will be properly quoted by the method.
  349. * @param boolean $unique whether to add UNIQUE constraint on the created index.
  350. */
  351. public function createIndex($name, $table, $column, $unique=false)
  352. {
  353. echo " > create".($unique ? ' unique':'')." index $name on $table ($column) ...";
  354. $time=microtime(true);
  355. $this->getDbConnection()->createCommand()->createIndex($name, $table, $column, $unique);
  356. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  357. }
  358. /**
  359. * Builds and executes a SQL statement for dropping an index.
  360. * @param string $name the name of the index to be dropped. The name will be properly quoted by the method.
  361. * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method.
  362. */
  363. public function dropIndex($name, $table)
  364. {
  365. echo " > drop index $name ...";
  366. $time=microtime(true);
  367. $this->getDbConnection()->createCommand()->dropIndex($name, $table);
  368. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  369. }
  370. /**
  371. * Refreshed schema cache for a table
  372. * @param string $table name of the table to refresh
  373. * @since 1.1.9
  374. */
  375. public function refreshTableSchema($table)
  376. {
  377. echo " > refresh table $table schema cache ...";
  378. $time=microtime(true);
  379. $this->getDbConnection()->getSchema()->getTable($table,true);
  380. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  381. }
  382. /**
  383. * Builds and executes a SQL statement for creating a primary key, supports composite primary keys.
  384. * @param string $name name of the primary key constraint to add
  385. * @param string $table name of the table to add primary key to
  386. * @param string $columns name of the column to utilise as primary key. If there are multiple columns, separate them with commas.
  387. * @since 1.1.13
  388. */
  389. public function addPrimaryKey($name,$table,$columns)
  390. {
  391. echo " > alter table $table add constraint $name primary key ($columns) ...";
  392. $time=microtime(true);
  393. $this->getDbConnection()->createCommand()->addPrimaryKey($name,$table,$columns);
  394. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  395. }
  396. /**
  397. * Builds and executes a SQL statement for removing a primary key, supports composite primary keys.
  398. * @param string $name name of the constraint to remove
  399. * @param string $table name of the table to remove primary key from
  400. * @since 1.1.13
  401. */
  402. public function dropPrimaryKey($name,$table)
  403. {
  404. echo " > alter table $table drop primary key $name ...";
  405. $time=microtime(true);
  406. $this->getDbConnection()->createCommand()->dropPrimaryKey($name,$table);
  407. echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
  408. }
  409. }