PageRenderTime 28ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/yii/framework/cli/commands/shell/CrudCommand.php

http://github.com/eryx/php-framework-benchmark
PHP | 327 lines | 256 code | 36 blank | 35 comment | 37 complexity | 9bdc6ee7e4e5504ca07b51fcff9977d7 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, Apache-2.0, LGPL-2.1, LGPL-3.0, BSD-2-Clause
  1. <?php
  2. /**
  3. * CrudCommand class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. * @version $Id: CrudCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
  10. */
  11. /**
  12. * CrudCommand generates code implementing CRUD operations.
  13. *
  14. * @author Qiang Xue <qiang.xue@gmail.com>
  15. * @version $Id: CrudCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
  16. * @package system.cli.commands.shell
  17. * @since 1.0
  18. */
  19. class CrudCommand extends CConsoleCommand
  20. {
  21. /**
  22. * @var string the directory that contains templates for crud commands.
  23. * Defaults to null, meaning using 'framework/cli/views/shell/crud'.
  24. * If you set this path and some views are missing in the directory,
  25. * the default views will be used.
  26. */
  27. public $templatePath;
  28. /**
  29. * @var string the directory that contains functional test classes.
  30. * Defaults to null, meaning using 'protected/tests/functional'.
  31. * If this is false, it means functional test file should NOT be generated.
  32. */
  33. public $functionalTestPath;
  34. /**
  35. * @var array list of actions to be created. Each action must be associated with a template file with the same name.
  36. */
  37. public $actions=array('create','update','index','view','admin','_form','_view','_search');
  38. public function getHelp()
  39. {
  40. return <<<EOD
  41. USAGE
  42. crud <model-class> [controller-ID] ...
  43. DESCRIPTION
  44. This command generates a controller and views that accomplish
  45. CRUD operations for the specified data model.
  46. PARAMETERS
  47. * model-class: required, the name of the data model class. This can
  48. also be specified as a path alias (e.g. application.models.Post).
  49. If the model class belongs to a module, it should be specified
  50. as 'ModuleID.models.ClassName'.
  51. * controller-ID: optional, the controller ID (e.g. 'post').
  52. If this is not specified, the model class name will be used
  53. as the controller ID. In this case, if the model belongs to
  54. a module, the controller will also be created under the same
  55. module.
  56. If the controller should be located under a subdirectory,
  57. please specify the controller ID as 'path/to/ControllerID'
  58. (e.g. 'admin/user').
  59. If the controller belongs to a module (different from the module
  60. that the model belongs to), please specify the controller ID
  61. as 'ModuleID/ControllerID' or 'ModuleID/path/to/Controller'.
  62. EXAMPLES
  63. * Generates CRUD for the Post model:
  64. crud Post
  65. * Generates CRUD for the Post model which belongs to module 'admin':
  66. crud admin.models.Post
  67. * Generates CRUD for the Post model. The generated controller should
  68. belong to module 'admin', but not the model class:
  69. crud Post admin/post
  70. EOD;
  71. }
  72. /**
  73. * Execute the action.
  74. * @param array command line parameters specific for this command
  75. */
  76. public function run($args)
  77. {
  78. if(!isset($args[0]))
  79. {
  80. echo "Error: data model class is required.\n";
  81. echo $this->getHelp();
  82. return;
  83. }
  84. $module=Yii::app();
  85. $modelClass=$args[0];
  86. if(($pos=strpos($modelClass,'.'))===false)
  87. $modelClass='application.models.'.$modelClass;
  88. else
  89. {
  90. $id=substr($modelClass,0,$pos);
  91. if(($m=Yii::app()->getModule($id))!==null)
  92. $module=$m;
  93. }
  94. $modelClass=Yii::import($modelClass);
  95. if(isset($args[1]))
  96. {
  97. $controllerID=$args[1];
  98. if(($pos=strrpos($controllerID,'/'))===false)
  99. {
  100. $controllerClass=ucfirst($controllerID).'Controller';
  101. $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.$controllerClass.'.php';
  102. $controllerID[0]=strtolower($controllerID[0]);
  103. }
  104. else
  105. {
  106. $last=substr($controllerID,$pos+1);
  107. $last[0]=strtolower($last);
  108. $pos2=strpos($controllerID,'/');
  109. $first=substr($controllerID,0,$pos2);
  110. $middle=$pos===$pos2?'':substr($controllerID,$pos2+1,$pos-$pos2);
  111. $controllerClass=ucfirst($last).'Controller';
  112. $controllerFile=($middle===''?'':$middle.'/').$controllerClass.'.php';
  113. $controllerID=$middle===''?$last:$middle.'/'.$last;
  114. if(($m=Yii::app()->getModule($first))!==null)
  115. $module=$m;
  116. else
  117. {
  118. $controllerFile=$first.'/'.$controllerFile;
  119. $controllerID=$first.'/'.$controllerID;
  120. }
  121. $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.str_replace('/',DIRECTORY_SEPARATOR,$controllerFile);
  122. }
  123. }
  124. else
  125. {
  126. $controllerID=$modelClass;
  127. $controllerClass=ucfirst($controllerID).'Controller';
  128. $controllerFile=$module->controllerPath.DIRECTORY_SEPARATOR.$controllerClass.'.php';
  129. $controllerID[0]=strtolower($controllerID[0]);
  130. }
  131. $templatePath=$this->templatePath===null?YII_PATH.'/cli/views/shell/crud':$this->templatePath;
  132. $functionalTestPath=$this->functionalTestPath===null?Yii::getPathOfAlias('application.tests.functional'):$this->functionalTestPath;
  133. $viewPath=$module->viewPath.DIRECTORY_SEPARATOR.str_replace('.',DIRECTORY_SEPARATOR,$controllerID);
  134. $fixtureName=$this->pluralize($modelClass);
  135. $fixtureName[0]=strtolower($fixtureName);
  136. $list=array(
  137. basename($controllerFile)=>array(
  138. 'source'=>$templatePath.'/controller.php',
  139. 'target'=>$controllerFile,
  140. 'callback'=>array($this,'generateController'),
  141. 'params'=>array($controllerClass,$modelClass),
  142. ),
  143. );
  144. if($functionalTestPath!==false)
  145. {
  146. $list[$modelClass.'Test.php']=array(
  147. 'source'=>$templatePath.'/test.php',
  148. 'target'=>$functionalTestPath.DIRECTORY_SEPARATOR.$modelClass.'Test.php',
  149. 'callback'=>array($this,'generateTest'),
  150. 'params'=>array($controllerID,$fixtureName,$modelClass),
  151. );
  152. }
  153. foreach($this->actions as $action)
  154. {
  155. $list[$action.'.php']=array(
  156. 'source'=>$templatePath.'/'.$action.'.php',
  157. 'target'=>$viewPath.'/'.$action.'.php',
  158. 'callback'=>array($this,'generateView'),
  159. 'params'=>$modelClass,
  160. );
  161. }
  162. $this->copyFiles($list);
  163. if($module instanceof CWebModule)
  164. $moduleID=$module->id.'/';
  165. else
  166. $moduleID='';
  167. echo "\nCrud '{$controllerID}' has been successfully created. You may access it via:\n";
  168. echo "http://hostname/path/to/index.php?r={$moduleID}{$controllerID}\n";
  169. }
  170. public function generateController($source,$params)
  171. {
  172. list($controllerClass,$modelClass)=$params;
  173. $model=CActiveRecord::model($modelClass);
  174. $id=$model->tableSchema->primaryKey;
  175. if($id===null)
  176. throw new ShellException(Yii::t('yii','Error: Table "{table}" does not have a primary key.',array('{table}'=>$model->tableName())));
  177. else if(is_array($id))
  178. 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())));
  179. if(!is_file($source)) // fall back to default ones
  180. $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
  181. return $this->renderFile($source,array(
  182. 'ID'=>$id,
  183. 'controllerClass'=>$controllerClass,
  184. 'modelClass'=>$modelClass,
  185. ),true);
  186. }
  187. public function generateView($source,$modelClass)
  188. {
  189. $model=CActiveRecord::model($modelClass);
  190. $table=$model->getTableSchema();
  191. $columns=$table->columns;
  192. if(!is_file($source)) // fall back to default ones
  193. $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
  194. return $this->renderFile($source,array(
  195. 'ID'=>$table->primaryKey,
  196. 'modelClass'=>$modelClass,
  197. 'columns'=>$columns),true);
  198. }
  199. public function generateTest($source,$params)
  200. {
  201. list($controllerID,$fixtureName,$modelClass)=$params;
  202. if(!is_file($source)) // fall back to default ones
  203. $source=YII_PATH.'/cli/views/shell/crud/'.basename($source);
  204. return $this->renderFile($source, array(
  205. 'controllerID'=>$controllerID,
  206. 'fixtureName'=>$fixtureName,
  207. 'modelClass'=>$modelClass,
  208. ),true);
  209. }
  210. public function generateInputLabel($modelClass,$column)
  211. {
  212. return "CHtml::activeLabelEx(\$model,'{$column->name}')";
  213. }
  214. public function generateInputField($modelClass,$column)
  215. {
  216. if($column->type==='boolean')
  217. return "CHtml::activeCheckBox(\$model,'{$column->name}')";
  218. else if(stripos($column->dbType,'text')!==false)
  219. return "CHtml::activeTextArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
  220. else
  221. {
  222. if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
  223. $inputField='activePasswordField';
  224. else
  225. $inputField='activeTextField';
  226. if($column->type!=='string' || $column->size===null)
  227. return "CHtml::{$inputField}(\$model,'{$column->name}')";
  228. else
  229. {
  230. if(($size=$maxLength=$column->size)>60)
  231. $size=60;
  232. return "CHtml::{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
  233. }
  234. }
  235. }
  236. public function generateActiveLabel($modelClass,$column)
  237. {
  238. return "\$form->labelEx(\$model,'{$column->name}')";
  239. }
  240. public function generateActiveField($modelClass,$column)
  241. {
  242. if($column->type==='boolean')
  243. return "\$form->checkBox(\$model,'{$column->name}')";
  244. else if(stripos($column->dbType,'text')!==false)
  245. return "\$form->textArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50))";
  246. else
  247. {
  248. if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))
  249. $inputField='passwordField';
  250. else
  251. $inputField='textField';
  252. if($column->type!=='string' || $column->size===null)
  253. return "\$form->{$inputField}(\$model,'{$column->name}')";
  254. else
  255. {
  256. if(($size=$maxLength=$column->size)>60)
  257. $size=60;
  258. return "\$form->{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
  259. }
  260. }
  261. }
  262. public function guessNameColumn($columns)
  263. {
  264. foreach($columns as $column)
  265. {
  266. if(!strcasecmp($column->name,'name'))
  267. return $column->name;
  268. }
  269. foreach($columns as $column)
  270. {
  271. if(!strcasecmp($column->name,'title'))
  272. return $column->name;
  273. }
  274. foreach($columns as $column)
  275. {
  276. if($column->isPrimaryKey)
  277. return $column->name;
  278. }
  279. return 'id';
  280. }
  281. public function class2id($className)
  282. {
  283. return trim(strtolower(str_replace('_','-',preg_replace('/(?<![A-Z])[A-Z]/', '-\0', $className))),'-');
  284. }
  285. public function class2name($className,$pluralize=false)
  286. {
  287. if($pluralize)
  288. $className=$this->pluralize($className);
  289. return ucwords(trim(strtolower(str_replace(array('-','_'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $className)))));
  290. }
  291. }