summaryrefslogtreecommitdiff
path: root/framework/cli/commands/shell/CrudCommand.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/cli/commands/shell/CrudCommand.php')
-rw-r--r--framework/cli/commands/shell/CrudCommand.php327
1 files changed, 327 insertions, 0 deletions
diff --git a/framework/cli/commands/shell/CrudCommand.php b/framework/cli/commands/shell/CrudCommand.php
new file mode 100644
index 0000000..5932dea
--- /dev/null
+++ b/framework/cli/commands/shell/CrudCommand.php
@@ -0,0 +1,327 @@
+<?php
+/**
+ * CrudCommand class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ * @version $Id: CrudCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ */
+
+/**
+ * CrudCommand generates code implementing CRUD operations.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CrudCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package system.cli.commands.shell
+ * @since 1.0
+ */
+class CrudCommand extends CConsoleCommand
+{
+ /**
+ * @var string the directory that contains templates for crud commands.
+ * Defaults to null, meaning using 'framework/cli/views/shell/crud'.
+ * If you set this path and some views are missing in the directory,
+ * the default views will be used.
+ */
+ public $templatePath;
+ /**
+ * @var string the directory that contains functional test classes.
+ * Defaults to null, meaning using 'protected/tests/functional'.
+ * If this is false, it means functional test file should NOT be generated.
+ */
+ public $functionalTestPath;
+ /**
+ * @var array list of actions to be created. Each action must be associated with a template file with the same name.
+ */
+ public $actions=array('create','update','index','view','admin','_form','_view','_search');
+
+ public function getHelp()
+ {
+ return <<<EOD
+USAGE
+ crud <model-class> [controller-ID] ...
+
+DESCRIPTION
+ This command generates a controller and views that accomplish
+ CRUD operations for the specified data model.
+
+PARAMETERS
+ * model-class: required, the name of the data model class. This can
+ also be specified as a path alias (e.g. application.models.Post).
+ If the model class belongs to a module, it should be specified
+ as 'ModuleID.models.ClassName'.
+
+ * controller-ID: optional, the controller ID (e.g. 'post').
+ If this is not specified, the model class name will be used
+ as the controller ID. In this case, if the model belongs to
+ a module, the controller will also be created under the same
+ module.
+
+ If the controller should be located under a subdirectory,
+ please specify the controller ID as 'path/to/ControllerID'
+ (e.g. 'admin/user').
+
+ If the controller belongs to a module (different from the module
+ that the model belongs to), please specify the controller ID
+ as 'ModuleID/ControllerID' or 'ModuleID/path/to/Controller'.
+
+EXAMPLES
+ * Generates CRUD for the Post model:
+ crud Post
+
+ * Generates CRUD for the Post model which belongs to module 'admin':
+ crud admin.models.Post
+
+ * Generates CRUD for the Post model. The generated controller should
+ belong to module 'admin', but not the model class:
+ crud Post admin/post
+
+EOD;
+ }
+
+ /**
+ * Execute the action.
+ * @param array command line parameters specific for this command
+ */
+ public function run($args)
+ {
+ if(!isset($args[0]))
+ {
+ echo "Error: data model class is required.\n";
+ echo $this->getHelp();
+ return;
+ }
+ $module=Yii::app();
+ $modelClass=$args[0];
+ if(($pos=strpos($modelClass,'.'))===false)
+ $modelClass='application.models.'.$modelClass;
+ else
+ {
+ $id=substr($modelClass,0,$pos);
+ if(($m=Yii::app()->getModule($id))!==null)
+ $module=$m;
+ }
+ $modelClass=Yii::import($modelClass);
+
+ if(isset($args[1]))
+ {
+ $controllerID=$args[1];
+ if(($pos=strrpos($controllerID,'/'))===false)
+ {
+ $controllerClass=ucfirst($controllerID).'Controller';
+ $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.$controllerClass.'.php';
+ $controllerID[0]=strtolower($controllerID[0]);
+ }
+ else
+ {
+ $last=substr($controllerID,$pos+1);
+ $last[0]=strtolower($last);
+ $pos2=strpos($controllerID,'/');
+ $first=substr($controllerID,0,$pos2);
+ $middle=$pos===$pos2?'':substr($controllerID,$pos2+1,$pos-$pos2);
+
+ $controllerClass=ucfirst($last).'Controller';
+ $controllerFile=($middle===''?'':$middle.'/').$controllerClass.'.php';
+ $controllerID=$middle===''?$last:$middle.'/'.$last;
+ if(($m=Yii::app()->getModule($first))!==null)
+ $module=$m;
+ else
+ {
+ $controllerFile=$first.'/'.$controllerFile;
+ $controllerID=$first.'/'.$controllerID;
+ }
+
+ $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.str_replace('/',DIRECTORY_SEPARATOR,$controllerFile);
+ }
+ }
+ else
+ {
+ $controllerID=$modelClass;
+ $controllerClass=ucfirst($controllerID).'Controller';
+ $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.$controllerClass.'.php';
+ $controllerID[0]=strtolower($controllerID[0]);
+ }
+
+ $templatePath=$this->templatePath===null?YII_PATH.'/cli/views/shell/crud':$this->templatePath;
+ $functionalTestPath=$this->functionalTestPath===null?Yii::getPathOfAlias('application.tests.functional'):$this->functionalTestPath;
+
+ $viewPath=$module->viewPath.DIRECTORY_SEPARATOR.str_replace('.',DIRECTORY_SEPARATOR,$controllerID);
+ $fixtureName=$this->pluralize($modelClass);
+ $fixtureName[0]=strtolower($fixtureName);
+ $list=array(
+ basename($controllerFile)=>array(
+ 'source'=>$templatePath.'/controller.php',
+ 'target'=>$controllerFile,
+ 'callback'=>array($this,'generateController'),
+ 'params'=>array($controllerClass,$modelClass),
+ ),
+ );
+
+ if($functionalTestPath!==false)
+ {
+ $list[$modelClass.'Test.php']=array(
+ 'source'=>$templatePath.'/test.php',
+ 'target'=>$functionalTestPath.DIRECTORY_SEPARATOR.$modelClass.'Test.php',
+ 'callback'=>array($this,'generateTest'),
+ 'params'=>array($controllerID,$fixtureName,$modelClass),
+ );
+ }
+
+ foreach($this->actions as $action)
+ {
+ $list[$action.'.php']=array(
+ 'source'=>$templatePath.'/'.$action.'.php',
+ 'target'=>$viewPath.'/'.$action.'.php',
+ 'callback'=>array($this,'generateView'),
+ 'params'=>$modelClass,
+ );
+ }
+
+ $this->copyFiles($list);
+
+ if($module instanceof CWebModule)
+ $moduleID=$module->id.'/';
+ else
+ $moduleID='';
+
+ echo "\nCrud '{$controllerID}' has been successfully created. You may access it via:\n";
+ echo "http://hostname/path/to/index.php?r={$moduleID}{$controllerID}\n";
+ }
+
+ public function generateController($source,$params)
+ {
+ list($controllerClass,$modelClass)=$params;
+ $model=CActiveRecord::model($modelClass);
+ $id=$model->tableSchema->primaryKey;
+ if($id===null)
+ throw new ShellException(Yii::t('yii','Error: Table "{table}" does not have a primary key.',array('{table}'=>$model->tableName())));
+ else if(is_array($id))
+ throw new ShellException(Yii::t('yii','Error: Table "{table}" has a composite primary key which is not supported by crud command.',array('{table}'=>$model->tableName())));
+
+ if(!is_file($source)) // fall back to default ones
+ $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
+
+ return $this->renderFile($source,array(
+ 'ID'=>$id,
+ 'controllerClass'=>$controllerClass,
+ 'modelClass'=>$modelClass,
+ ),true);
+ }
+
+ public function generateView($source,$modelClass)
+ {
+ $model=CActiveRecord::model($modelClass);
+ $table=$model->getTableSchema();
+ $columns=$table->columns;
+ if(!is_file($source)) // fall back to default ones
+ $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
+ return $this->renderFile($source,array(
+ 'ID'=>$table->primaryKey,
+ 'modelClass'=>$modelClass,
+ 'columns'=>$columns),true);
+ }
+
+ public function generateTest($source,$params)
+ {
+ list($controllerID,$fixtureName,$modelClass)=$params;
+ if(!is_file($source)) // fall back to default ones
+ $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
+ return $this->renderFile($source, array(
+ 'controllerID'=>$controllerID,
+ 'fixtureName'=>$fixtureName,
+ 'modelClass'=>$modelClass,
+ ),true);
+ }
+
+ public function generateInputLabel($modelClass,$column)
+ {
+ return "CHtml::activeLabelEx(\$model,'{$column->name}')";
+ }
+
+ public function generateInputField($modelClass,$column)
+ {
+ if($column->type==='boolean')
+ return "CHtml::activeCheckBox(\$model,'{$column->name}')";
+ else if(stripos($column->dbType,'text')!==false)
+ return "CHtml::activeTextArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
+ else
+ {
+ if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
+ $inputField='activePasswordField';
+ else
+ $inputField='activeTextField';
+
+ if($column->type!=='string' || $column->size===null)
+ return "CHtml::{$inputField}(\$model,'{$column->name}')";
+ else
+ {
+ if(($size=$maxLength=$column->size)>60)
+ $size=60;
+ return "CHtml::{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
+ }
+ }
+ }
+
+ public function generateActiveLabel($modelClass,$column)
+ {
+ return "\$form->labelEx(\$model,'{$column->name}')";
+ }
+
+ public function generateActiveField($modelClass,$column)
+ {
+ if($column->type==='boolean')
+ return "\$form->checkBox(\$model,'{$column->name}')";
+ else if(stripos($column->dbType,'text')!==false)
+ return "\$form->textArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
+ else
+ {
+ if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
+ $inputField='passwordField';
+ else
+ $inputField='textField';
+
+ if($column->type!=='string' || $column->size===null)
+ return "\$form->{$inputField}(\$model,'{$column->name}')";
+ else
+ {
+ if(($size=$maxLength=$column->size)>60)
+ $size=60;
+ return "\$form->{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
+ }
+ }
+ }
+
+ public function guessNameColumn($columns)
+ {
+ foreach($columns as $column)
+ {
+ if(!strcasecmp($column->name,'name'))
+ return $column->name;
+ }
+ foreach($columns as $column)
+ {
+ if(!strcasecmp($column->name,'title'))
+ return $column->name;
+ }
+ foreach($columns as $column)
+ {
+ if($column->isPrimaryKey)
+ return $column->name;
+ }
+ return 'id';
+ }
+
+ public function class2id($className)
+ {
+ return trim(strtolower(str_replace('_','-',preg_replace('/(?<![A-Z])[A-Z]/', '-\0', $className))),'-');
+ }
+
+ public function class2name($className,$pluralize=false)
+ {
+ if($pluralize)
+ $className=$this->pluralize($className);
+ return ucwords(trim(strtolower(str_replace(array('-','_'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $className)))));
+ }
+}