Commit 28423486 by Qiang Xue

model generator WIP

parent 2d6ec6bb
......@@ -497,14 +497,15 @@ class Connection extends Component
* Processes a SQL statement by quoting table and column names that are enclosed within double brackets.
* Tokens enclosed within double curly brackets are treated as table names, while
* tokens enclosed within double square brackets are column names. They will be quoted accordingly.
* Also, the percentage character "%" in a table name will be replaced with [[tablePrefix]].
* Also, the percentage character "%" at the beginning or ending of a table name will be replaced
* with [[tablePrefix]].
* @param string $sql the SQL to be quoted
* @return string the quoted SQL
*/
public function quoteSql($sql)
{
$db = $this;
return preg_replace_callback('/(\\{\\{([%\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/',
return preg_replace_callback('/(\\{\\{(%?[\w\-\. ]+)\\}\\}|\\{\\{([\w\-\. ]+%?)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/',
function ($matches) use ($db) {
if (isset($matches[3])) {
return $db->quoteColumnName($matches[3]);
......
......@@ -302,16 +302,19 @@ abstract class Generator extends Model
*/
public function validateClass($attribute, $params)
{
$class = $this->$attribute;
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.");
if (class_exists($class)) {
if (isset($params['extends'])) {
if (ltrim($class, '\\') !== ltrim($params['extends'], '\\') && !is_subclass_of($class, $params['extends'])) {
$this->addError($attribute, "'$class' must extend from {$params['extends']} or its child class.");
}
}
} else {
$this->addError($attribute, "Class '{$this->$attribute}' does not exist or has syntax error.");
$this->addError($attribute, "Class '$class' does not exist or has syntax error.");
}
} catch (\Exception $e) {
$this->addError($attribute, "Class '{$this->$attribute}' does not exist or has syntax error.");
$this->addError($attribute, "Class '$class' does not exist or has syntax error.");
}
}
......
......@@ -24,7 +24,7 @@ class Generator extends \yii\gii\Generator
public $ns = 'app\models';
public $tableName;
public $modelClass;
public $baseClass = '\yii\db\ActiveRecord';
public $baseClass = 'yii\db\ActiveRecord';
public $generateRelations = true;
public $generateLabelsFromComments = false;
......@@ -46,7 +46,7 @@ class Generator extends \yii\gii\Generator
array('db, ns, tableName, baseClass', 'required'),
array('db, modelClass', 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'),
array('ns, baseClass', 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'),
array('tableName', 'match', 'pattern' => '/^(\w+\.)?\w+\*?$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'),
array('tableName', 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'),
array('db', 'validateDb'),
array('ns', 'validateNamespace'),
array('tableName', 'validateTableName'),
......@@ -123,7 +123,7 @@ class Generator extends \yii\gii\Generator
'labels' => $this->generateLabels($tableSchema),
);
$files[] = new CodeFile(
Yii::getAlias('@' . $this->ns) . '/' . $className . '.php',
Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $className . '.php',
$this->render('model.php', $params)
);
}
......@@ -142,6 +142,8 @@ class Generator extends \yii\gii\Generator
foreach ($table->columns as $column) {
if ($this->generateLabelsFromComments && !empty($column->comment)) {
$labels[$column->name] = $column->comment;
} elseif (!strcasecmp($column->name, 'id')) {
$labels[$column->name] = 'ID';
} else {
$label = Inflector::camel2words($column->name);
if (strcasecmp(substr($label, -3), ' id') === 0) {
......@@ -317,22 +319,30 @@ class Generator extends \yii\gii\Generator
protected function generateClassName($tableName)
{
if ($this->tableName === $tableName || ($pos = strrpos($this->tableName, '.')) !== false && substr($this->tableName, $pos + 1) === $tableName) {
return $this->modelClass;
if (($pos = strrpos($tableName, '.')) !== false) {
$tableName = substr($tableName, $pos + 1);
}
$tableName = $this->removePrefix($tableName, false);
if (($pos = strpos($tableName, '.')) !== false) // remove schema part (e.g. remove 'public2.' from 'public2.post')
{
$tableName = substr($tableName, $pos + 1);
$db = $this->getDbConnection();
$patterns = array();
if (strpos($this->tableName, '*') !== false) {
$pattern = $this->tableName;
if (($pos = strrpos($pattern, '.')) !== false) {
$pattern = substr($pattern, $pos + 1);
}
$patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
}
$className = '';
foreach (explode('_', $tableName) as $name) {
if ($name !== '') {
$className .= ucfirst($name);
if (!empty($db->tablePrefix)) {
$patterns[] = "/^{$db->tablePrefix}(.*?)|(.*?){$db->tablePrefix}$/";
}
$className = $tableName;
foreach ($patterns as $pattern) {
if (preg_match($pattern, $tableName, $matches)) {
$className = $matches[1];
}
}
return $className;
return Inflector::id2camel($className, '_');
}
/**
......@@ -375,14 +385,17 @@ class Generator extends \yii\gii\Generator
public function validateDb()
{
if (Yii::$app->hasComponent($this->db) === false || !(Yii::$app->getComponent($this->db) instanceof Connection)) {
$this->addError('db', 'Database Connection ID must refer to a valid application component.');
if (Yii::$app->hasComponent($this->db) === false) {
$this->addError('db', 'There is no application component named "db".');
} elseif (!Yii::$app->getComponent($this->db) instanceof Connection) {
$this->addError('db', 'The "db" application component must be a DB connection instance.');
}
}
public function validateNamespace()
{
$path = Yii::getAlias('@' . ltrim($this->ns, '\\'), false);
$this->ns = ltrim($this->ns, '\\');
$path = Yii::getAlias('@' . str_replace('\\', '/', $this->ns), false);
if ($path === false) {
$this->addError('ns', 'Namespace must be associated with an existing directory.');
}
......@@ -400,14 +413,18 @@ class Generator extends \yii\gii\Generator
public function validateTableName()
{
if (($pos = strpos($this->tableName, '*')) !== false && strpos($this->tableName, '*', $pos + 1) !== false) {
$this->addError('tableName', 'At most one asterisk is allowed.');
return;
}
$tables = $this->getTableNames();
if (empty($tables)) {
$this->addError('tableName', "Table '{$this->tableName}' does not exist.'");
$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.");
$this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword.");
break;
}
}
......@@ -418,13 +435,13 @@ class Generator extends \yii\gii\Generator
{
$db = $this->getDbConnection();
$tableNames = array();
if ($this->tableName[strlen($this->tableName) - 1] === '*') {
if (strpos($this->tableName, '*') !== false) {
if (($pos = strrpos($this->tableName, '.')) !== false) {
$schema = substr($this->tableName, 0, $pos);
$pattern = '/' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '/';
$pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/';
} else {
$schema = '';
$pattern = '/' . str_replace('*', '\w+', $this->tableName) . '/';
$pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
}
foreach ($db->schema->getTableNames($schema) as $table) {
......
......@@ -17,14 +17,10 @@
* - $relations: list of relations (name=>relation declaration)
*/
$pos = strrpos($className, '\\');
$ns = ltrim(substr($className, 0, $pos), '\\');
$className = substr($className, $pos + 1);
echo "<?php\n";
?>
namespace <?php echo $ns; ?>;
namespace <?php echo $generator->ns; ?>;
/**
* This is the model class for table "<?php echo $tableName; ?>".
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment