Browse Source

refactored generators.

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
95bc36c2e6
  1. 22
      framework/yii/gii/Generator.php
  2. 21
      framework/yii/gii/generators/form/Generator.php
  3. 128
      framework/yii/gii/generators/model/Generator.php
  4. 2
      framework/yii/gii/generators/model/form.php
  5. 6
      framework/yii/gii/generators/model/templates/model.php

22
framework/yii/gii/Generator.php

@ -294,6 +294,28 @@ abstract class Generator extends Model
} }
/** /**
* An inline validator that checks if the attribute value refers to an existing class name.
* If the `extends` option is specified, it will also check if the class is a child class
* of the class represented by the `extends` option.
* @param string $attribute the attribute being validated
* @param array $params the validation options
*/
public function validateClass($attribute, $params)
{
try {
if (class_exists($this->$attribute)) {
if (isset($params['extends']) && !is_subclass_of($this->$attribute, $params['extends'])) {
$this->addError($attribute, "'{$this->$attribute}' must extend from {$params['extends']} or its child class.");
}
} else {
$this->addError($attribute, "Class '{$this->$attribute}' does not exist or has syntax error.");
}
} catch (\Exception $e) {
$this->addError($attribute, "Class '{$this->$attribute}' does not exist or has syntax error.");
}
}
/**
* @param string $value the attribute to be validated * @param string $value the attribute to be validated
* @return boolean whether the value is a reserved PHP keyword. * @return boolean whether the value is a reserved PHP keyword.
*/ */

21
framework/yii/gii/generators/form/Generator.php

@ -63,7 +63,7 @@ class Generator extends \yii\gii\Generator
array('modelClass, viewName, scenarioName, viewPath', 'filter', 'filter' => 'trim'), array('modelClass, viewName, scenarioName, viewPath', 'filter', 'filter' => 'trim'),
array('modelClass, viewName, viewPath', 'required'), array('modelClass, viewName, viewPath', 'required'),
array('modelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'), array('modelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'),
array('modelClass', 'validateModel'), array('modelClass', 'validateClass', 'extends' => Model::className()),
array('viewName', 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'), array('viewName', 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'),
array('viewPath', 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'), array('viewPath', 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'),
array('viewPath', 'validateViewPath'), array('viewPath', 'validateViewPath'),
@ -130,25 +130,6 @@ EOD;
} }
/** /**
* Validates the model class to make sure it exists and is valid.
*/
public function validateModel()
{
try {
if (class_exists($this->modelClass)) {
if (!is_subclass_of($this->modelClass, Model::className())) {
$this->addError('modelClass', "'{$this->modelClass}' must extend from Model or its child class.");
}
} else {
$this->addError('modelClass', "Class '{$this->modelClass}' does not exist or has syntax error.");
}
} catch (\Exception $e) {
$this->addError('modelClass', "Class '{$this->modelClass}' does not exist or has syntax error.");
return;
}
}
/**
* Validates [[viewPath]] to make sure it is a valid path or path alias and exists. * Validates [[viewPath]] to make sure it is a valid path or path alias and exists.
*/ */
public function validateViewPath() public function validateViewPath()

128
framework/yii/gii/generators/model/Generator.php

@ -8,6 +8,7 @@
namespace yii\gii\generators\model; namespace yii\gii\generators\model;
use Yii; use Yii;
use yii\db\ActiveRecord;
use yii\db\Connection; use yii\db\Connection;
use yii\gii\CodeFile; use yii\gii\CodeFile;
use yii\helpers\Inflector; use yii\helpers\Inflector;
@ -50,7 +51,7 @@ class Generator extends \yii\gii\Generator
array('ns', 'validateNamespace'), array('ns', 'validateNamespace'),
array('tableName', 'validateTableName'), array('tableName', 'validateTableName'),
array('modelClass', 'validateModelClass'), array('modelClass', 'validateModelClass'),
array('baseClass', 'validateBaseClass'), array('baseClass', 'validateClass', 'params' => array('extends' => ActiveRecord::className())),
array('generateRelations, generateLabelsFromComments', 'boolean'), array('generateRelations, generateLabelsFromComments', 'boolean'),
)); ));
} }
@ -83,7 +84,7 @@ class Generator extends \yii\gii\Generator
'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.', 'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.',
'generateRelations' => 'This indicates whether the generator should generate relations based on 'generateRelations' => 'This indicates whether the generator should generate relations based on
foreign key constraints it detects in the database. Note that if your database contains too many tables, foreign key constraints it detects in the database. Note that if your database contains too many tables,
you may want to uncheck this option to accelerate the code generation process.', you may want to uncheck this option to accelerate the code generation proc ess.',
'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels 'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels
by using the comments of the corresponding DB columns.', by using the comments of the corresponding DB columns.',
); );
@ -101,6 +102,9 @@ class Generator extends \yii\gii\Generator
return array('ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments'); return array('ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments');
} }
/**
* @return Connection
*/
public function getDbConnection() public function getDbConnection()
{ {
return Yii::$app->{$this->db}; return Yii::$app->{$this->db};
@ -108,33 +112,18 @@ class Generator extends \yii\gii\Generator
public function generate() public function generate()
{ {
$db = $this->getDbConnection();
if (($pos = strrpos($this->tableName, '.')) !== false) {
$schema = substr($this->tableName, 0, $pos);
$tableName = substr($this->tableName, $pos + 1);
} else {
$schema = '';
$tableName = $this->tableName;
}
if (strpos($tableName, '*') !== false) {
$tables = $db->getSchema()->getTableNames($schema);
} else {
$tables = array($db->getTableSchema($this->tableName, true));
}
$files = array(); $files = array();
foreach ($this->getTableNames() as $tableName) {
foreach ($tables as $table) { $className = $this->generateClassName($tableName);
$className = $this->generateClassName($table->name); $tableSchema = $this->getTableSchema($tableName);
$params = array( $params = array(
'tableName' => $schema === '' ? $tableName : $schema . '.' . $tableName, 'tableName' => $tableName,
'className' => $className, 'className' => $className,
'columns' => $table->columns, 'tableSchema' => $tableSchema,
'labels' => $this->generateLabels($table), 'labels' => $this->generateLabels($tableSchema),
); );
$files[] = new CodeFile( $files[] = new CodeFile(
Yii::getAlias($this->modelPath) . '/' . $className . '.php', Yii::getAlias('@' . $this->ns) . '/' . $className . '.php',
$this->render('model.php', $params) $this->render('model.php', $params)
); );
} }
@ -142,25 +131,9 @@ class Generator extends \yii\gii\Generator
return $files; return $files;
} }
/*
* Check that all database field names conform to PHP variable naming rules
* For example mysql allows field name like "2011aa", but PHP does not allow variable like "$model->2011aa"
* @param CDbTableSchema $table the table schema object
* @return string the invalid table column name. Null if no error.
*/
public function checkColumns($table)
{
foreach ($table->columns as $column) {
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $column->name)) {
return $table->name . '.' . $column->name;
}
}
}
public function getTableSchema($tableName) public function getTableSchema($tableName)
{ {
$db = $this->getDbConnection(); return $this->getDbConnection()->getTableSchema($tableName, true);
return $db->getSchema()->getTable($tableName, true);
} }
public function generateLabels($table) public function generateLabels($table)
@ -403,18 +376,22 @@ class Generator extends \yii\gii\Generator
public function validateDb() public function validateDb()
{ {
if (Yii::$app->hasComponent($this->db) === false || !(Yii::$app->getComponent($this->db) instanceof Connection)) { if (Yii::$app->hasComponent($this->db) === false || !(Yii::$app->getComponent($this->db) instanceof Connection)) {
$this->addError('db', 'A valid database connection is required to run this generator.'); $this->addError('db', 'Database Connection ID must refer to a valid application component.');
} }
} }
public function validateNamespace() public function validateNamespace()
{ {
$path = Yii::getAlias('@' . ltrim($this->ns, '\\'), false);
if ($path === false) {
$this->addError('ns', 'Namespace must be associated with an existing directory.');
}
} }
public function validateModelClass() public function validateModelClass()
{ {
if ($this->isReservedKeyword($this->modelClass)) { if ($this->isReservedKeyword($this->modelClass)) {
$this->addError('modelClass', 'The name is a reserved PHP keyword.'); $this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
} }
if (strpos($this->tableName, '*') === false && $this->modelClass == '') { if (strpos($this->tableName, '*') === false && $this->modelClass == '') {
$this->addError('modelClass', 'Model Class cannot be blank.'); $this->addError('modelClass', 'Model Class cannot be blank.');
@ -423,56 +400,41 @@ class Generator extends \yii\gii\Generator
public function validateTableName() public function validateTableName()
{ {
$invalidTables = array(); $tables = $this->getTableNames();
$invalidColumns = array(); if (empty($tables)) {
$this->addError('tableName', "Table '{$this->tableName}' does not exist.'");
} else {
foreach ($tables as $table) {
$class = $this->generateClassName($table);
if ($this->isReservedKeyword($class)) {
$this->addError('tableName', "Table '$table' would generate a class which is a reserved PHP keyword.");
break;
}
}
}
}
protected function getTableNames()
{
$db = $this->getDbConnection();
$tableNames = array();
if ($this->tableName[strlen($this->tableName) - 1] === '*') { if ($this->tableName[strlen($this->tableName) - 1] === '*') {
if (($pos = strrpos($this->tableName, '.')) !== false) { if (($pos = strrpos($this->tableName, '.')) !== false) {
$schema = substr($this->tableName, 0, $pos); $schema = substr($this->tableName, 0, $pos);
$pattern = '/' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '/';
} else { } else {
$schema = ''; $schema = '';
$pattern = '/' . str_replace('*', '\w+', $this->tableName) . '/';
} }
$this->modelClass = ''; foreach ($db->schema->getTableNames($schema) as $table) {
$tables = $this->getDbConnection()->schema->getTables($schema); if (preg_match($pattern, $table)) {
foreach ($tables as $table) { $tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
if ($this->tablePrefix == '' || strpos($table->name, $this->tablePrefix) === 0) {
if (in_array(strtolower($table->name), self::$keywords)) {
$invalidTables[] = $table->name;
}
if (($invalidColumn = $this->checkColumns($table)) !== null) {
$invalidColumns[] = $invalidColumn;
}
} }
} }
} else { } elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
if (($table = $this->getTableSchema($this->tableName)) === null) { $tableNames[] = $this->tableName;
$this->addError('tableName', "Table '{$this->tableName}' does not exist.");
}
if ($this->modelClass === '') {
$this->addError('modelClass', 'Model Class cannot be blank.');
}
if (!$this->hasErrors($attribute) && ($invalidColumn = $this->checkColumns($table)) !== null) {
$invalidColumns[] = $invalidColumn;
}
}
if ($invalidTables != array()) {
$this->addError('tableName', 'Model class cannot take a reserved PHP keyword! Table name: ' . implode(', ', $invalidTables) . ".");
}
if ($invalidColumns != array()) {
$this->addError('tableName', 'Column names that does not follow PHP variable naming convention: ' . implode(', ', $invalidColumns) . ".");
}
}
public function validateBaseClass()
{
$class = @Yii::import($this->baseClass, true);
if (!is_string($class) || !$this->classExists($class)) {
$this->addError('baseClass', "Class '{$this->baseClass}' does not exist or has syntax error.");
} elseif ($class !== 'CActiveRecord' && !is_subclass_of($class, 'CActiveRecord')) {
$this->addError('baseClass', "'{$this->model}' must extend from CActiveRecord.");
} }
return $tableNames;
} }
} }

2
framework/yii/gii/generators/model/form.php

@ -5,7 +5,7 @@
* @var yii\gii\generators\form\Generator $generator * @var yii\gii\generators\form\Generator $generator
*/ */
echo $form->field($generator, 'tableName'); echo $form->field($generator, 'tableNamess');
echo $form->field($generator, 'modelClass'); echo $form->field($generator, 'modelClass');
echo $form->field($generator, 'ns'); echo $form->field($generator, 'ns');
echo $form->field($generator, 'baseClass'); echo $form->field($generator, 'baseClass');

6
framework/yii/gii/generators/model/templates/model.php

@ -6,12 +6,12 @@
* @var yii\gii\generators\model\Generator $generator * @var yii\gii\generators\model\Generator $generator
* @var string $tableName * @var string $tableName
* @var string $className * @var string $className
* @var yii\db\ColumnSchema[] $columns * @var yii\db\TableSchema $tableSchema
* @var string[] $labels * @var string[] $labels
* *
* - $tableName: the table name for this class (prefix is already removed if necessary) * - $tableName: the table name for this class (prefix is already removed if necessary)
* - $modelClass: the model class name * - $modelClass: the model class name
* - $columns: list of table columns (name=>CDbColumnSchema) * - $tableSchema: list of table columns (name=>CDbColumnSchema)
* - $labels: list of attribute labels (name=>label) * - $labels: list of attribute labels (name=>label)
* - $rules: list of validation rules * - $rules: list of validation rules
* - $relations: list of relations (name=>relation declaration) * - $relations: list of relations (name=>relation declaration)
@ -31,7 +31,7 @@ namespace <?php echo $ns; ?>;
* *
* Attributes: * Attributes:
* *
<?php foreach ($columns as $column): ?> <?php foreach ($tableSchema->columns as $column): ?>
* @property <?php echo "{$column->phpType} \${$column->name}\n"; ?> * @property <?php echo "{$column->phpType} \${$column->name}\n"; ?>
<?php endforeach; ?> <?php endforeach; ?>
*/ */

Loading…
Cancel
Save