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,到这里就完成了流程的查看了。