Gii 是一个蛮不错的学习Module
console 生成model的解析:
- gii的config配置
* return [ * 'bootstrap' => ['gii'], * 'modules' => [ * 'gii' => ['class' => 'yii\gii\Module'], * ], * ]
也就说,在初始化的时候需要执行Module的bootstrap方法:
public function bootstrap($app) { if ($app instanceof \yii\web\Application) { $app->getUrlManager()->addRules([ $this->id => $this->id . '/default/index', $this->id . '/<id:\w+>' => $this->id . '/default/view', $this->id . '/<controller:[\w\-]+>/<action:[\w\-]+>' => $this->id . '/<controller>/<action>', ], false); } elseif ($app instanceof \yii\console\Application) { $app->controllerMap[$this->id] = [ 'class' => 'yii\gii\console\GenerateController', 'generators' => array_merge($this->coreGenerators(), $this->generators), 'module' => $this, ]; } }
如果是console的话,就设置app的controllerMap。也就是console的Gii/访问路径:
yii\gii\console\GenerateController。
传递参数:generators:
protected function coreGenerators() { return [ 'model' => ['class' => 'yii\gii\generators\model\Generator'], 'crud' => ['class' => 'yii\gii\generators\crud\Generator'], 'controller' => ['class' => 'yii\gii\generators\controller\Generator'], 'form' => ['class' => 'yii\gii\generators\form\Generator'], 'module' => ['class' => 'yii\gii\generators\module\Generator'], 'extension' => ['class' => 'yii\gii\generators\extension\Generator'], ]; }
还有一部分就是config配置中对gii的 generators 参数的配置,也就是可以自定义gii了。
生成model的命令为:
./yii gii/model --tableName=city --modelClass=City
也就是找到 yii\gii\console\GenerateController。 去找actionModel()方法,但是这个方法不存在,那么,在actions中查找
public function actions() { $actions = []; foreach ($this->generators as $name => $generator) { $actions[$name] = [ 'class' => 'yii\gii\console\GenerateAction', 'generator' => $generator, ]; } return $actions; }
从上面可以看出来,就是通过GenerateAction这个class,根据穿入的generator的不同实例化不同的参数。这个generator参数就是上面的配置
'model' => ['class' => 'yii\gii\generators\model\Generator'],
下面我们查看这个文件
yii\gii\console\GenerateAction
的run方法:
public function run() { echo "Running '{$this->generator->getName()}'...\n\n"; if ($this->generator->validate()) { $this->generateCode(); } else { $this->displayValidationErrors(); } }
也就是代码:
$this->generateCode();
protected function generateCode() { $files = $this->generator->generate(); $n = count($files); if ($n === 0) { echo "No code to be generated.\n"; return; } echo "The following files will be generated:\n"; $skipAll = $this->controller->interactive ? null : !$this->controller->overwrite; $answers = []; foreach ($files as $file) { $path = $file->getRelativePath(); if (is_file($file->path)) { if (file_get_contents($file->path) === $file->content) { echo ' ' . $this->controller->ansiFormat('[unchanged]', Console::FG_GREY); echo $this->controller->ansiFormat(" $path\n", Console::FG_CYAN); $answers[$file->id] = false; } else { echo ' ' . $this->controller->ansiFormat('[changed]', Console::FG_RED); echo $this->controller->ansiFormat(" $path\n", Console::FG_CYAN); if ($skipAll !== null) { $answers[$file->id] = !$skipAll; } else { $answer = $this->controller->select("Do you want to overwrite this file?", [ 'y' => 'Overwrite this file.', 'n' => 'Skip this file.', 'ya' => 'Overwrite this and the rest of the changed files.', 'na' => 'Skip this and the rest of the changed files.', ]); $answers[$file->id] = $answer === 'y' || $answer === 'ya'; if ($answer === 'ya') { $skipAll = false; } elseif ($answer === 'na') { $skipAll = true; } } } } else { echo ' ' . $this->controller->ansiFormat('[new]', Console::FG_GREEN); echo $this->controller->ansiFormat(" $path\n", Console::FG_CYAN); $answers[$file->id] = true; } } if (!array_sum($answers)) { $this->controller->stdout("\nNo files were chosen to be generated.\n", Console::FG_CYAN); return; } if (!$this->controller->confirm("\nReady to generate the selected files?", true)) { $this->controller->stdout("\nNo file was generated.\n", Console::FG_CYAN); return; } if ($this->generator->save($files, (array) $answers, $results)) { $this->controller->stdout("\nFiles were generated successfully!\n", Console::FG_GREEN); } else { $this->controller->stdout("\nSome errors occurred while generating the files.", Console::FG_RED); } echo preg_replace('%<span class="error">(.*?)</span>%', '\1', $results) . "\n"; }
$files = $this->generator->generate();
generator就是上面的:
'model' => ['class' => 'yii\gii\generators\model\Generator'],
也就是这个文件的generate()方法返回的内容,就是文件内容:
public function generate() { $files = []; $relations = $this->generateRelations(); $db = $this->getDbConnection(); foreach ($this->getTableNames() as $tableName) { // model : $modelClassName = $this->generateClassName($tableName); $queryClassName = ($this->generateQuery) ? $this->generateQueryClassName($modelClassName) : false; $tableSchema = $db->getTableSchema($tableName); $params = [ 'tableName' => $tableName, 'className' => $modelClassName, 'queryClassName' => $queryClassName, 'tableSchema' => $tableSchema, 'labels' => $this->generateLabels($tableSchema), 'rules' => $this->generateRules($tableSchema), 'relations' => isset($relations[$tableName]) ? $relations[$tableName] : [], ]; $files[] = new CodeFile( Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $modelClassName . '.php', $this->render('model.php', $params) ); // query : if ($queryClassName) { $params = [ 'className' => $queryClassName, 'modelClassName' => $modelClassName, ]; $files[] = new CodeFile( Yii::getAlias('@' . str_replace('\\', '/', $this->queryNs)) . '/' . $queryClassName . '.php', $this->render('query.php', $params) ); } } return $files; }
生成文件的部分:
$this->render('model.php', $params)
public function render($template, $params = []) { $view = new View(); $params['generator'] = $this; return $view->renderFile($this->getTemplatePath() . '/' . $template, $params, $this); }
在这里可以看到,还是用的view的renderFile来生成的:
public function renderFile($viewFile, $params = [], $context = null) { $viewFile = Yii::getAlias($viewFile); if ($this->theme !== null) { $viewFile = $this->theme->applyTo($viewFile); } if (is_file($viewFile)) { $viewFile = FileHelper::localize($viewFile); } else { throw new InvalidParamException("The view file does not exist: $viewFile"); } $oldContext = $this->context; if ($context !== null) { $this->context = $context; } $output = ''; $this->_viewFiles[] = $viewFile; if ($this->beforeRender($viewFile, $params)) { Yii::trace("Rendering view file: $viewFile", __METHOD__); $ext = pathinfo($viewFile, PATHINFO_EXTENSION); if (isset($this->renderers[$ext])) { if (is_array($this->renderers[$ext]) || is_string($this->renderers[$ext])) { $this->renderers[$ext] = Yii::createObject($this->renderers[$ext]); } /* @var $renderer ViewRenderer */ $renderer = $this->renderers[$ext]; $output = $renderer->render($this, $viewFile, $params); } else { $output = $this->renderPhpFile($viewFile, $params); } $this->afterRender($viewFile, $params, $output); } array_pop($this->_viewFiles); $this->context = $oldContext; return $output; }
最终生成内容。
下面查看对应的model.php文件:
yii2-gii/generators/model/default/model.php
<?php /** * This is the template for generating the model class of a specified table. */ /* @var $this yii\web\View */ /* @var $generator yii\gii\generators\model\Generator */ /* @var $tableName string full table name */ /* @var $className string class name */ /* @var $queryClassName string query class name */ /* @var $tableSchema yii\db\TableSchema */ /* @var $labels string[] list of attribute labels (name => label) */ /* @var $rules string[] list of validation rules */ /* @var $relations array list of relations (name => relation declaration) */ echo "<?php\n"; ?> namespace <?= $generator->ns ?>; use Yii; /** * This is the model class for table "<?= $generator->generateTableName($tableName) ?>". * <?php foreach ($tableSchema->columns as $column): ?> * @property <?= "{$column->phpType} \${$column->name}\n" ?> <?php endforeach; ?> <?php if (!empty($relations)): ?> * <?php foreach ($relations as $name => $relation): ?> * @property <?= $relation[1] . ($relation[2] ? '[]' : '') . ' $' . lcfirst($name) . "\n" ?> <?php endforeach; ?> <?php endif; ?> */ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') . "\n" ?> { /** * @inheritdoc */ public static function tableName() { return '<?= $generator->generateTableName($tableName) ?>'; } <?php if ($generator->db !== 'db'): ?> /** * @return \yii\db\Connection the database connection used by this AR class. */ public static function getDb() { return Yii::$app->get('<?= $generator->db ?>'); } <?php endif; ?> /** * @inheritdoc */ public function rules() { return [<?= "\n " . implode(",\n ", $rules) . "\n " ?>]; } /** * @inheritdoc */ public function attributeLabels() { return [ <?php foreach ($labels as $name => $label): ?> <?= "'$name' => " . $generator->generateString($label) . ",\n" ?> <?php endforeach; ?> ]; } <?php foreach ($relations as $name => $relation): ?> /** * @return \yii\db\ActiveQuery */ public function get<?= $name ?>() { <?= $relation[0] . "\n" ?> } <?php endforeach; ?> <?php if ($queryClassName): ?> <?php $queryClassFullName = ($generator->ns === $generator->queryNs) ? $queryClassName : '\\' . $generator->queryNs . '\\' . $queryClassName; echo "\n"; ?> /** * @inheritdoc * @return <?= $queryClassFullName ?> the active query used by this AR class. */ public static function find() { return new <?= $queryClassFullName ?>(get_called_class()); } <?php endif; ?> }
也就是一个模板文件生成而来。
OK,到这里就完成了流程的查看了。
好咬