2007-08-21 21:46:59 +00:00
< ? php
/* SVN FILE: $Id$ */
/**
* Command - line database management utility to automate programmer chores .
*
* Schema is CakePHP ' s database management utility . This helps you maintain versions of
* of your database .
*
* PHP versions 4 and 5
*
* CakePHP ( tm ) : Rapid Development Framework < http :// www . cakephp . org />
* Copyright 2005 - 2007 , Cake Software Foundation , Inc .
* 1785 E . Sahara Avenue , Suite 490 - 204
* Las Vegas , Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
*
* @ filesource
* @ copyright Copyright 2005 - 2007 , Cake Software Foundation , Inc .
* @ link http :// www . cakefoundation . org / projects / info / cakephp CakePHP ( tm ) Project
* @ package cake
* @ subpackage cake . cake . console . libs
* @ since CakePHP ( tm ) v 1.2 . 0.5550
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
*/
uses ( 'file' , 'model' . DS . 'schema' );
/**
* Schema is a command - line database management utility for automating programmer chores .
*
* @ package cake
* @ subpackage cake . cake . console . libs
*/
class SchemaShell extends Shell {
2007-10-27 20:00:29 +00:00
/**
* is this a dry run ?
*
* @ var boolean
* @ access private
*/
var $__dry = null ;
2007-08-21 21:46:59 +00:00
/**
* Override initialize
*
* @ access public
*/
function initialize () {
$this -> out ( 'Cake Schema Shell' );
$this -> hr ();
}
/**
* Override startup
*
* @ access public
*/
function startup () {
2007-11-24 23:12:57 +00:00
$name = null ;
if ( ! empty ( $this -> params [ 'name' ])) {
$name = $this -> params [ 'name' ];
}
$path = null ;
if ( ! empty ( $this -> params [ 'path' ])) {
$path = $this -> params [ 'path' ];
}
$file = null ;
if ( ! empty ( $this -> params [ 'file' ])) {
$file = $this -> params [ 'file' ];
}
$this -> Schema =& new CakeSchema ( compact ( 'name' , 'path' , 'file' ));
2007-08-21 23:22:15 +00:00
}
/**
* Override main
*
* @ access public
*/
function main () {
$this -> help ();
2007-08-21 21:46:59 +00:00
}
/**
* Read and output contents od schema object
* path to read as second arg
*
* @ access public
*/
function view () {
2007-08-21 23:22:15 +00:00
$File = new File ( $this -> Schema -> path . DS . 'schema.php' );
2007-08-21 21:46:59 +00:00
if ( $File -> exists ()) {
$this -> out ( $File -> read ());
exit ();
} else {
$this -> err ( __ ( 'Schema could not be found' , true ));
exit ();
}
}
/**
* Read database and Write schema object
* accepts a connection as first arg or path to save as second arg
*
* @ access public
*/
function generate () {
$this -> out ( 'Generating Schema...' );
2007-10-27 20:00:29 +00:00
$options = array ();
if ( isset ( $this -> params [ 'f' ])) {
$options = array ( 'models' => false );
}
$snapshot = false ;
if ( isset ( $this -> args [ 0 ]) && $this -> args [ 0 ] === 'snapshot' ) {
$snapshot = true ;
}
if ( ! $snapshot && file_exists ( $this -> Schema -> path . DS . 'schema.php' )) {
$snapshot = true ;
$result = $this -> in ( " Schema file exists. \n [O]verwrite \n [S]napshot \n [Q]uit \n Would you like to do? " , array ( 'o' , 's' , 'q' ), 's' );
if ( $result === 'q' ) {
exit ();
}
if ( $result === 'o' ) {
$snapshot = false ;
}
}
2007-11-08 19:06:06 +00:00
$content = $this -> Schema -> read ( $options );
2007-10-27 20:00:29 +00:00
$content [ 'file' ] = 'schema.php' ;
2007-11-08 19:06:06 +00:00
2007-10-27 20:00:29 +00:00
if ( $snapshot === true ) {
$Folder =& new Folder ( $this -> Schema -> path );
$result = $Folder -> read ();
$count = 1 ;
if ( ! empty ( $result [ 1 ])) {
foreach ( $result [ 1 ] as $file ) {
if ( preg_match ( '/schema/' , $file )) {
$count ++ ;
}
}
}
$content [ 'file' ] = 'schema_' . $count . '.php' ;
}
2007-08-21 21:46:59 +00:00
if ( $this -> Schema -> write ( $content )) {
2007-10-27 20:00:29 +00:00
$this -> out ( sprintf ( __ ( 'Schema file: %s generated' , true ), $content [ 'file' ]));
2007-08-21 21:46:59 +00:00
exit ();
} else {
2007-10-27 20:00:29 +00:00
$this -> err ( __ ( 'Schema file: %s generated' , true ));
2007-08-21 21:46:59 +00:00
exit ();
}
}
/**
* Dump Schema object to sql file
* if first arg == write , file will be written to sql file
* or it will output sql
*
* @ access public
*/
function dump () {
$write = false ;
$Schema = $this -> Schema -> load ();
2007-11-24 23:12:57 +00:00
if ( ! $Schema ) {
$this -> err ( __ ( 'Schema could not be loaded' , true ));
exit ();
}
2007-08-23 00:57:00 +00:00
if ( ! empty ( $this -> args [ 0 ])) {
if ( $this -> args [ 0 ] == 'true' ) {
$write = Inflector :: underscore ( $this -> Schema -> name );
} else {
$write = $this -> args [ 0 ];
}
}
2007-08-21 21:46:59 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> Schema -> connection );
2007-08-23 00:57:00 +00:00
$contents = " # " . $Schema -> name . " sql generated on: " . date ( 'Y-m-d H:m:s' ) . " : " . time () . " \n \n " ;
$contents .= $db -> dropSchema ( $Schema ) . " \n \n " . $db -> createSchema ( $Schema );
if ( $write ) {
if ( strpos ( $write , '.sql' ) === false ) {
$write .= '.sql' ;
}
$File = new File ( $this -> Schema -> path . DS . $write , true );
2007-08-21 21:46:59 +00:00
if ( $File -> write ( $contents )) {
2007-09-18 04:16:04 +00:00
$this -> out ( sprintf ( __ ( 'SQL dump file created in %s' , true ), $File -> pwd ()));
2007-08-21 21:46:59 +00:00
exit ();
} else {
$this -> err ( __ ( 'SQL dump could not be created' , true ));
exit ();
}
}
$this -> out ( $contents );
return $contents ;
}
/**
2007-10-27 20:00:29 +00:00
* Run database commands : create , update
2007-08-21 21:46:59 +00:00
*
* @ access public
*/
2007-10-27 20:00:29 +00:00
function run () {
if ( ! isset ( $this -> args [ 0 ])) {
$this -> err ( 'command not found' );
exit ();
}
$command = $this -> args [ 0 ];
$this -> Dispatch -> shiftArgs ();
if ( isset ( $this -> params [ 'dry' ])) {
$this -> __dry = true ;
$this -> out ( __ ( 'Performing a dry run.' , true ));
}
$options = array ( 'file' => $this -> Schema -> file );
if ( isset ( $this -> params [ 's' ])) {
$options = array ( 'file' => 'schema_' . $this -> params [ 's' ] . '.php' );
}
$Schema = $this -> Schema -> load ( $options );
if ( ! $Schema ) {
$this -> err ( sprintf ( __ ( '%s could not be loaded' , true ), $options [ 'file' ]));
exit ();
}
$table = null ;
if ( isset ( $this -> args [ 1 ])) {
$table = $this -> args [ 1 ];
}
switch ( $command ) {
case 'create' :
$this -> __create ( $Schema , $table );
break ;
case 'update' :
$this -> __update ( $Schema , $table );
break ;
default :
$this -> err ( 'command not found' );
exit ();
}
}
/**
* Create database from Schema object
* Should be called via the run method
*
* @ access private
*/
function __create ( $Schema , $table = null ) {
$options = array ();
2007-08-21 23:22:15 +00:00
$table = null ;
$event = array_keys ( $Schema -> tables );
2007-10-27 20:00:29 +00:00
if ( $table ) {
2007-08-21 23:22:15 +00:00
$event = array ( $table );
}
2007-08-23 00:57:00 +00:00
$errors = array ();
2007-10-27 20:00:29 +00:00
Configure :: write ( 'debug' , 2 );
2007-08-21 21:46:59 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> Schema -> connection );
2007-10-27 20:00:29 +00:00
$db -> fullDebug = true ;
2007-08-21 23:22:15 +00:00
$drop = $db -> dropSchema ( $Schema , $table );
2007-10-27 20:00:29 +00:00
2007-08-21 21:46:59 +00:00
$this -> out ( $drop );
if ( 'y' == $this -> in ( 'Are you sure you want to drop tables and create your database?' , array ( 'y' , 'n' ), 'n' )) {
2007-08-23 00:57:00 +00:00
$create = $db -> createSchema ( $Schema , $table );
2007-08-21 21:46:59 +00:00
$this -> out ( 'Updating Database...' );
2007-08-23 00:57:00 +00:00
$contents = array_map ( 'trim' , explode ( " ; " , $drop . $create ));
foreach ( $contents as $sql ) {
2007-10-27 20:00:29 +00:00
if ( $this -> __dry === true ) {
$this -> out ( $sql );
} else {
if ( ! empty ( $sql )) {
if ( ! $this -> Schema -> before ( array ( 'created' => $event ))) {
return false ;
}
if ( ! $db -> _execute ( $sql )) {
$errors [] = $db -> lastError ();
}
$this -> Schema -> after ( array ( 'created' => $event , 'errors' => $errors ));
2007-08-23 00:57:00 +00:00
}
}
2007-08-21 21:46:59 +00:00
}
2007-10-27 20:00:29 +00:00
if ( ! empty ( $errors )) {
$this -> err ( $errors );
} elseif ( $this -> __dry !== true ) {
$this -> out ( __ ( 'Database updated' , true ));
exit ();
}
2007-08-21 21:46:59 +00:00
}
2007-10-27 20:00:29 +00:00
$this -> out ( __ ( 'End' , true ));
2007-08-23 00:57:00 +00:00
exit ();
2007-08-21 21:46:59 +00:00
}
/**
* Update database with Schema object
2007-10-27 20:00:29 +00:00
* Should be called via the run method
2007-08-21 21:46:59 +00:00
*
2007-10-27 20:00:29 +00:00
* @ access private
2007-08-21 21:46:59 +00:00
*/
2007-10-27 20:00:29 +00:00
function __update ( $Schema , $table = null ) {
2007-08-21 21:46:59 +00:00
$this -> out ( 'Comparing Database to Schema...' );
$Old = $this -> Schema -> read ();
$compare = $this -> Schema -> compare ( $Old , $Schema );
2007-10-27 20:00:29 +00:00
if ( isset ( $compare [ $table ])) {
2007-08-21 23:22:15 +00:00
$compare = array ( $table => $compare [ $table ]);
}
2007-10-27 20:00:29 +00:00
Configure :: write ( 'debug' , 2 );
2007-08-21 21:46:59 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> Schema -> connection );
$db -> fullDebug = true ;
2007-08-21 22:46:05 +00:00
2007-08-21 23:22:15 +00:00
$contents = $db -> alterSchema ( $compare , $table );
2007-08-21 21:46:59 +00:00
if ( empty ( $contents )) {
2007-10-27 20:00:29 +00:00
$this -> out ( __ ( 'Schema is up to date.' , true ));
2007-08-21 21:46:59 +00:00
exit ();
2007-10-27 20:00:29 +00:00
} elseif ( $this -> __dry === true || 'y' == $this -> in ( 'Would you like to see the changes?' , array ( 'y' , 'n' ), 'y' )) {
2007-08-21 21:46:59 +00:00
$this -> out ( $contents );
}
2007-10-27 20:00:29 +00:00
if ( $this -> __dry !== true ) {
if ( 'y' == $this -> in ( 'Are you sure you want to update your database?' , array ( 'y' , 'n' ), 'n' )) {
$this -> out ( 'Updating Database...' );
if ( ! $this -> Schema -> before ( $compare )) {
return false ;
}
if ( $db -> _execute ( $contents )) {
$this -> Schema -> after ( $compare );
$this -> out ( __ ( 'Database updated' , true ));
} else {
$this -> err ( __ ( 'Database could not be updated' , true ));
$this -> err ( $db -> lastError ());
}
2007-08-21 21:46:59 +00:00
exit ();
}
}
2007-10-27 20:00:29 +00:00
$this -> out ( __ ( 'End' , true ));
exit ();
2007-08-21 21:46:59 +00:00
}
/**
* Displays help contents
*
2007-10-22 05:52:20 +00:00
* @ access public
2007-08-21 21:46:59 +00:00
*/
function help () {
2007-10-27 20:00:29 +00:00
$this -> out ( " The Schema Shell generates a schema object from \n \t \t the database and updates the database from the schema. " );
2007-08-21 21:46:59 +00:00
$this -> hr ();
$this -> out ( " Usage: cake schema <command> <arg1> <arg2>... " );
$this -> hr ();
2007-08-21 23:22:15 +00:00
$this -> out ( 'Params:' );
2007-10-27 20:00:29 +00:00
$this -> out ( " \n \t -connection <config> \n \t \t set db config <config>. uses 'default' if none is specified " );
$this -> out ( " \n \t -path <dir> \n \t \t path <dir> to read and write schema.php. \n \t \t default path: " . $this -> Schema -> path );
$this -> out ( " \n \t -file <name> \n \t \t file <name> to read and write. \n \t \t default file: " . $this -> Schema -> file );
$this -> out ( " \n \t -s <number> \n \t \t snapshot <number> to use for run. " );
$this -> out ( " \n \t -dry \n \t \t Perform a dry run on 'run' commands. \n \t \t Queries will be output to window instead of executed. " );
$this -> out ( " \n \t -f \n \t \t force 'generate' to create a new schema. " );
2007-08-21 21:46:59 +00:00
$this -> out ( 'Commands:' );
$this -> out ( " \n \t schema help \n \t \t shows this help message. " );
2007-08-21 23:22:15 +00:00
$this -> out ( " \n \t schema view \n \t \t read and output contents of schema file " );
2007-10-27 20:00:29 +00:00
$this -> out ( " \n \t schema generate \n \t \t reads from 'connection' writes to 'path' \n \t \t To force genaration of all tables into the schema, use the -f param. " );
$this -> out ( " \n \t schema dump <filename> \n \t \t dump database sql based on schema file to filename in schema path. \n \t \t if filename is true, default will use the app directory name. " );
$this -> out ( " \n \t schema run create <table> \n \t \t drop tables and create database based on schema file \n \t \t optional <table> arg for creating only one table \n \t \t pass the -s param with a number to use a snapshot \n \t \t To see the changes, perform a dry run with the -dry param " );
$this -> out ( " \n \t schema run update <table> \n \t \t alter tables based on schema file \n \t \t optional <table> arg for altering only one table. \n \t \t To use a snapshot, pass the -s param with the snapshot number \n \t \t To see the changes, perform a dry run with the -dry param " );
2007-08-21 21:46:59 +00:00
$this -> out ( " " );
exit ();
}
}
?>