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. 124
      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()

124
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'),
)); ));
} }
@ -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.'");
if ($this->tableName[strlen($this->tableName) - 1] === '*') {
if (($pos = strrpos($this->tableName, '.')) !== false) {
$schema = substr($this->tableName, 0, $pos);
} else { } else {
$schema = '';
}
$this->modelClass = '';
$tables = $this->getDbConnection()->schema->getTables($schema);
foreach ($tables as $table) { foreach ($tables as $table) {
if ($this->tablePrefix == '' || strpos($table->name, $this->tablePrefix) === 0) { $class = $this->generateClassName($table);
if (in_array(strtolower($table->name), self::$keywords)) { if ($this->isReservedKeyword($class)) {
$invalidTables[] = $table->name; $this->addError('tableName', "Table '$table' would generate a class which is a reserved PHP keyword.");
} break;
if (($invalidColumn = $this->checkColumns($table)) !== null) {
$invalidColumns[] = $invalidColumn;
} }
} }
} }
} else {
if (($table = $this->getTableSchema($this->tableName)) === null) {
$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) { protected function getTableNames()
$invalidColumns[] = $invalidColumn; {
} $db = $this->getDbConnection();
$tableNames = array();
if ($this->tableName[strlen($this->tableName) - 1] === '*') {
if (($pos = strrpos($this->tableName, '.')) !== false) {
$schema = substr($this->tableName, 0, $pos);
$pattern = '/' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '/';
} else {
$schema = '';
$pattern = '/' . str_replace('*', '\w+', $this->tableName) . '/';
} }
if ($invalidTables != array()) { foreach ($db->schema->getTableNames($schema) as $table) {
$this->addError('tableName', 'Model class cannot take a reserved PHP keyword! Table name: ' . implode(', ', $invalidTables) . "."); if (preg_match($pattern, $table)) {
} $tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
if ($invalidColumns != array()) {
$this->addError('tableName', 'Column names that does not follow PHP variable naming convention: ' . implode(', ', $invalidColumns) . ".");
} }
} }
} elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
public function validateBaseClass() $tableNames[] = $this->tableName;
{
$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