Class yii\gii\generators\model\Generator
Inheritance | yii\gii\generators\model\Generator » yii\gii\Generator » yii\base\Model |
---|---|
Available since extension's version | 2.0 |
Source Code | https://github.com/yiisoft/yii2-gii/blob/master/src/generators/model/Generator.php |
This generator will generate one or multiple ActiveRecord classes for the specified database table.
Public Properties
Public Methods
Method | Description | Defined By |
---|---|---|
actionGenerateClassName() | Action to generate class name. | yii\gii\generators\model\Generator |
attributeLabels() | yii\gii\generators\model\Generator | |
autoCompleteData() | Returns the list of auto complete values. | yii\gii\generators\model\Generator |
defaultTemplate() | Returns the root path to the default code template files. | yii\gii\Generator |
formView() | Returns the view file for the input form of the generator. | yii\gii\Generator |
generate() | Generates the code based on the current user input and the specified code template files. | yii\gii\generators\model\Generator |
generateLabels() | Generates the attribute labels for the specified table. | yii\gii\generators\model\Generator |
generateRelationsClassHints() | Generates the relation class hints for the relation methods | yii\gii\generators\model\Generator |
generateRules() | Generates validation rules for the specified table. | yii\gii\generators\model\Generator |
generateString() | Generates a string depending on the $enableI18N property |
yii\gii\Generator |
generateTableName() | Generates the table name by considering table prefix. | yii\gii\generators\model\Generator |
getDescription() | Returns the detailed description of the generator. | yii\gii\generators\model\Generator |
getName() | Returns the name of the code generator. | yii\gii\generators\model\Generator |
getStickyDataFile() | Returns the file path that stores the sticky attribute values. | yii\gii\Generator |
getTablePrefix() | Returns the tablePrefix property of the DB connection as specified |
yii\gii\generators\model\Generator |
getTemplatePath() | yii\gii\Generator | |
hints() | Returns the list of hint messages. | yii\gii\generators\model\Generator |
init() | yii\gii\generators\model\Generator | |
isReservedKeyword() | yii\gii\Generator | |
render() | Generates code using the specified code template and parameters. | yii\gii\Generator |
requiredTemplates() | Returns a list of code template files that are required. | yii\gii\generators\model\Generator |
rules() | yii\gii\generators\model\Generator | |
save() | Saves the generated code into files. | yii\gii\Generator |
stickyAttributes() | Returns the list of sticky attributes. | yii\gii\generators\model\Generator |
successMessage() | Returns the message to be displayed when the newly generated code is saved successfully. | yii\gii\Generator |
validateClass() | An inline validator that checks if the attribute value refers to an existing class name. | yii\gii\Generator |
validateDb() | Validates the $db attribute. | yii\gii\generators\model\Generator |
validateMessageCategory() | Checks if message category is not empty when I18N is enabled. | yii\gii\Generator |
validateModelClass() | Validates the $modelClass attribute. | yii\gii\generators\model\Generator |
validateNamespace() | Validates the namespace. | yii\gii\generators\model\Generator |
validateNewClass() | An inline validator that checks if the attribute value refers to a valid namespaced class name. | yii\gii\Generator |
validateTableName() | Validates the $tableName attribute. | yii\gii\generators\model\Generator |
validateTemplate() | Validates the template selection. | yii\gii\Generator |
Protected Methods
Constants
Constant | Value | Description | Defined By |
---|---|---|---|
JUNCTION_RELATION_VIA_MODEL | 'model' | yii\gii\generators\model\Generator | |
JUNCTION_RELATION_VIA_TABLE | 'table' | yii\gii\generators\model\Generator | |
RELATIONS_ALL | 'all' | yii\gii\generators\model\Generator | |
RELATIONS_ALL_INVERSE | 'all-inverse' | yii\gii\generators\model\Generator | |
RELATIONS_NONE | 'none' | yii\gii\generators\model\Generator |
Property Details
Method Details
Action to generate class name.
public string actionGenerateClassName ( ) |
public function actionGenerateClassName()
{
return $this->generateClassName($this->tableName);
}
Adds inverse relations
protected array addInverseRelations ( $relations ) | ||
$relations | array |
Relation declarations |
return | array |
Relation declarations extended with inverse relation names |
---|
protected function addInverseRelations($relations)
{
$db = $this->getDbConnection();
$relationNames = [];
$schemaNames = $this->getSchemaNames();
foreach ($schemaNames as $schemaName) {
foreach ($db->schema->getTableSchemas($schemaName) as $table) {
$className = $this->generateClassName($table->fullName);
foreach ($table->foreignKeys as $refs) {
$refTable = $refs[0];
$refTableSchema = $db->getTableSchema($refTable);
if ($refTableSchema === null) {
// Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
continue;
}
unset($refs[0]);
$fks = array_keys($refs);
$leftRelationName = $this->generateRelationName($relationNames, $table, $fks[0], false);
$relationNames[$table->fullName][$leftRelationName] = true;
$hasMany = $this->isHasManyRelation($table, $fks);
$rightRelationName = $this->generateRelationName(
$relationNames,
$refTableSchema,
$className,
$hasMany
);
$relationNames[$refTableSchema->fullName][$rightRelationName] = true;
$relations[$table->fullName][$leftRelationName][0] =
rtrim($relations[$table->fullName][$leftRelationName][0], ';')
. "->inverseOf('".lcfirst($rightRelationName)."');";
$relations[$refTableSchema->fullName][$rightRelationName][0] =
rtrim($relations[$refTableSchema->fullName][$rightRelationName][0], ';')
. "->inverseOf('".lcfirst($leftRelationName)."');";
}
}
}
return $relations;
}
public void attributeLabels ( ) |
public function attributeLabels()
{
return array_merge(parent::attributeLabels(), [
'ns' => 'Namespace',
'db' => 'Database Connection ID',
'tableName' => 'Table Name',
'standardizeCapitals' => 'Standardize Capitals',
'singularize' => 'Singularize',
'modelClass' => 'Model Class Name',
'baseClass' => 'Base Class',
'generateRelations' => 'Generate Relations',
'generateJunctionRelationMode' => 'Generate Junction Relations As',
'generateRelationsFromCurrentSchema' => 'Generate Relations from Current Schema',
'useClassConstant' => 'Use `::class`',
'generateLabelsFromComments' => 'Generate Labels from DB Comments',
'generateQuery' => 'Generate ActiveQuery',
'queryNs' => 'ActiveQuery Namespace',
'queryClass' => 'ActiveQuery Class',
'queryBaseClass' => 'ActiveQuery Base Class',
'useSchemaName' => 'Use Schema Name',
]);
}
Returns the list of auto complete values.
The array keys are the attribute names, and the array values are the corresponding auto complete values. Auto complete values can also be callable typed in order one want to make postponed data generation.
public array[] autoCompleteData ( ) | ||
return | array[] |
The list of auto complete values |
---|
public function autoCompleteData()
{
$db = $this->getDbConnection();
if ($db !== null) {
return [
'tableName' => function () use ($db) {
return $db->getSchema()->getTableNames();
},
];
}
return [];
}
Checks if the given table is a junction table, that is it has at least one pair of unique foreign keys.
protected array|boolean checkJunctionTable ( $table ) | ||
$table | ||
return | array|boolean |
All unique foreign key pairs if the table is a junction table, or false if the table is not a junction table. |
---|
protected function checkJunctionTable($table)
{
if (count($table->foreignKeys) < 2) {
return false;
}
$uniqueKeys = [$table->primaryKey];
try {
$uniqueKeys = array_merge($uniqueKeys, $this->getDbConnection()->getSchema()->findUniqueIndexes($table));
} catch (NotSupportedException $e) {
// ignore
}
$result = [];
// find all foreign key pairs that have all columns in an unique constraint
$foreignKeyNames = array_keys($table->foreignKeys);
$foreignKeys = array_values($table->foreignKeys);
$foreignKeysCount = count($foreignKeys);
for ($i = 0; $i < $foreignKeysCount; $i++) {
$firstColumns = $foreignKeys[$i];
unset($firstColumns[0]);
for ($j = $i + 1; $j < $foreignKeysCount; $j++) {
$secondColumns = $foreignKeys[$j];
unset($secondColumns[0]);
$fks = array_merge(array_keys($firstColumns), array_keys($secondColumns));
foreach ($uniqueKeys as $uniqueKey) {
if (count(array_diff(array_merge($uniqueKey, $fks), array_intersect($uniqueKey, $fks))) === 0) {
// save the foreign key pair
$result[] = [
[
$foreignKeys[$i],
$table->fullName . '.' . $foreignKeyNames[$i]
],
[
$foreignKeys[$j],
$table->fullName . '.' . $foreignKeyNames[$j]
]
];
break;
}
}
}
}
return empty($result) ? false : $result;
}
Defined in: yii\gii\Generator::defaultTemplate()
Returns the root path to the default code template files.
The default implementation will return the "templates" subdirectory of the directory containing the generator class file.
public string defaultTemplate ( ) | ||
return | string |
The root path to the default code template files. |
---|
public function defaultTemplate()
{
$class = new ReflectionClass($this);
return dirname($class->getFileName()) . '/default';
}
Defined in: yii\gii\Generator::formView()
Returns the view file for the input form of the generator.
The default implementation will return the "form.php" file under the directory that contains the generator class file.
public string formView ( ) | ||
return | string |
The view file for the input form of the generator. |
---|
public function formView()
{
$class = new ReflectionClass($this);
return dirname($class->getFileName()) . '/form.php';
}
Generates the code based on the current user input and the specified code template files.
Please refer to yii\gii\generators\controller\Generator::generate() as an example on how to implement this method.
public yii\gii\CodeFile[] generate ( ) | ||
return | yii\gii\CodeFile[] |
A list of code files to be created. |
---|
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;
$tableRelations = isset($relations[$tableName]) ? $relations[$tableName] : [];
$tableSchema = $db->getTableSchema($tableName);
$params = [
'tableName' => $tableName,
'className' => $modelClassName,
'queryClassName' => $queryClassName,
'tableSchema' => $tableSchema,
'properties' => $this->generateProperties($tableSchema),
'labels' => $this->generateLabels($tableSchema),
'rules' => $this->generateRules($tableSchema),
'relations' => $tableRelations,
'relationsClassHints' => $this->generateRelationsClassHints($tableRelations, $this->generateQuery),
];
$files[] = new CodeFile(
Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $modelClassName . '.php',
$this->render('model.php', $params)
);
// query:
if ($queryClassName) {
$params['className'] = $queryClassName;
$params['modelClassName'] = $modelClassName;
$files[] = new CodeFile(
Yii::getAlias('@' . str_replace('\\', '/', $this->queryNs)) . '/' . $queryClassName . '.php',
$this->render('query.php', $params)
);
}
}
return $files;
}
Generates a class name from the specified table name.
protected string generateClassName ( $tableName, $useSchemaName = null ) | ||
$tableName | string |
The table name (which may contain schema prefix) |
$useSchemaName | boolean |
Should schema name be included in the class name, if present |
return | string |
The generated class name |
---|
protected function generateClassName($tableName, $useSchemaName = null)
{
if (!empty($this->classNames[$tableName])) {
return $this->classNames[$tableName];
}
$schemaName = '';
$fullTableName = $tableName;
if (($pos = strrpos($tableName, '.')) !== false) {
if (($useSchemaName === null && $this->useSchemaName) || $useSchemaName) {
$schemaName = substr($tableName, 0, $pos) . '_';
}
$tableName = substr($tableName, $pos + 1);
}
$db = $this->getDbConnection();
$patterns = [];
$patterns[] = "/^{$db->tablePrefix}(.*?)$/";
$patterns[] = "/^(.*?){$db->tablePrefix}$/";
if (strpos($this->tableName, '*') !== false) {
$pattern = $this->tableName;
if (($pos = strrpos($pattern, '.')) !== false) {
$pattern = substr($pattern, $pos + 1);
}
$patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
}
$className = $tableName;
foreach ($patterns as $pattern) {
if (preg_match($pattern, $tableName, $matches)) {
$className = $matches[1];
break;
}
}
if ($this->standardizeCapitals) {
$schemaName = ctype_upper(preg_replace('/[_-]/', '', $schemaName)) ? strtolower($schemaName) : $schemaName;
$className = ctype_upper(preg_replace('/[_-]/', '', $className)) ? strtolower($className) : $className;
$this->classNames[$fullTableName] = Inflector::camelize(Inflector::camel2words($schemaName.$className));
} else {
$this->classNames[$fullTableName] = Inflector::id2camel($schemaName.$className, '_');
}
if ($this->singularize) {
$this->classNames[$fullTableName] = Inflector::singularize($this->classNames[$fullTableName]);
}
return $this->classNames[$fullTableName];
}
Returns the class name resolution
protected string generateClassNameResolution ( $class ) | ||
$class | string |
protected function generateClassNameResolution($class)
{
return $class . '::class' . ($this->useClassConstant ? '' : 'Name()');
}
Generates the attribute labels for the specified table.
public array generateLabels ( $table ) | ||
$table | \yii\db\TableSchema |
The table schema |
return | array |
The generated attribute labels (name => label) |
---|
public function generateLabels($table)
{
$labels = [];
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 (!empty($label) && substr_compare($label, ' id', -3, 3, true) === 0) {
$label = substr($label, 0, -3) . ' ID';
}
$labels[$column->name] = $label;
}
}
return $labels;
}
Generates the properties for the specified table.
protected array generateProperties ( $table ) | ||
$table | \yii\db\TableSchema |
The table schema |
return | array |
The generated properties (property => type) |
---|
protected function generateProperties($table)
{
$properties = [];
foreach ($table->columns as $column) {
switch ($column->type) {
case Schema::TYPE_SMALLINT:
case Schema::TYPE_INTEGER:
case Schema::TYPE_BIGINT:
case Schema::TYPE_TINYINT:
$type = 'int';
break;
case Schema::TYPE_BOOLEAN:
$type = 'bool';
break;
case Schema::TYPE_FLOAT:
case Schema::TYPE_DOUBLE:
case Schema::TYPE_DECIMAL:
case Schema::TYPE_MONEY:
$type = 'float';
break;
case Schema::TYPE_DATE:
case Schema::TYPE_TIME:
case Schema::TYPE_DATETIME:
case Schema::TYPE_TIMESTAMP:
case Schema::TYPE_JSON:
$type = 'string';
break;
default:
$type = $column->phpType;
}
if ($column->allowNull){
$type .= '|null';
}
$properties[$column->name] = [
'type' => $type,
'name' => $column->name,
'comment' => $column->comment,
];
}
return $properties;
}
Generates a query class name from the specified model class name.
protected string generateQueryClassName ( $modelClassName ) | ||
$modelClassName | string |
Model class name |
return | string |
Generated class name |
---|
protected function generateQueryClassName($modelClassName)
{
$queryClassName = $this->queryClass;
if (empty($queryClassName) || strpos($this->tableName, '*') !== false) {
$queryClassName = $modelClassName . 'Query';
}
return $queryClassName;
}
Generates the link parameter to be used in generating the relation declaration.
protected string generateRelationLink ( $refs ) | ||
$refs | array |
Reference constraint |
return | string |
The generated link parameter. |
---|
protected function generateRelationLink($refs)
{
$pairs = [];
foreach ($refs as $a => $b) {
$pairs[] = "'$a' => '$b'";
}
return '[' . implode(', ', $pairs) . ']';
}
Generate a relation name for the specified table and a base name.
protected string generateRelationName ( $relations, $table, $key, $multiple ) | ||
$relations | array |
The relations being generated currently. |
$table | \yii\db\TableSchema |
The table schema |
$key | string |
A base name that the relation name may be generated from |
$multiple | boolean |
Whether this is a has-many relation |
return | string |
The relation name |
---|
protected function generateRelationName($relations, $table, $key, $multiple)
{
static $baseModel;
/* @var $baseModel \yii\db\ActiveRecord */
if ($baseModel === null) {
$baseClass = $this->baseClass;
$baseClassReflector = new \ReflectionClass($baseClass);
if ($baseClassReflector->isAbstract()) {
$baseClassWrapper =
'namespace ' . __NAMESPACE__ . ';'.
'class GiiBaseClassWrapper extends \\' . $baseClass . ' {' .
'public static function tableName(){' .
'return "' . addslashes($table->fullName) . '";' .
'}' .
'};' .
'return new GiiBaseClassWrapper();';
$baseModel = eval($baseClassWrapper);
} else {
$baseModel = new $baseClass();
}
$baseModel->setAttributes([]);
}
if (!empty($key) && strcasecmp($key, 'id')) {
if (substr_compare($key, 'id', -2, 2, true) === 0) {
$key = rtrim(substr($key, 0, -2), '_');
} elseif (substr_compare($key, 'id_', 0, 3, true) === 0) {
$key = ltrim(substr($key, 3, strlen($key)), '_');
}
}
if ($multiple) {
$key = Inflector::pluralize($key);
}
$name = $rawName = Inflector::id2camel($key, '_');
$i = 0;
while ($baseModel->hasProperty(lcfirst($name))) {
$name = $rawName . ($i++);
}
while (isset($table->columns[lcfirst($name)])) {
$name = $rawName . ($i++);
}
while (isset($relations[$table->fullName][$name])) {
$name = $rawName . ($i++);
}
return $name;
}
protected array generateRelations ( ) | ||
return | array |
The generated relation declarations |
---|
protected function generateRelations()
{
if ($this->generateRelations === self::RELATIONS_NONE) {
return [];
}
$db = $this->getDbConnection();
$relations = [];
$schemaNames = $this->getSchemaNames();
foreach ($schemaNames as $schemaName) {
foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
$className = $this->generateClassName($table->fullName);
$classNameResolution = $this->generateClassNameResolution($className);
foreach ($table->foreignKeys as $foreignKey => $refs) {
$refTable = $refs[0];
$refTableSchema = $db->getTableSchema($refTable);
if ($refTableSchema === null) {
// Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
continue;
}
unset($refs[0]);
$fks = array_keys($refs);
$refClassName = $this->generateClassName($refTable);
$refClassNameResolution = $this->generateClassNameResolution($refClassName);
// Add relation for this table
$link = $this->generateRelationLink(array_flip($refs));
$relationName = $this->generateRelationName($relations, $table, $fks[0], false);
$relations[$table->fullName][$relationName] = [
"return \$this->hasOne($refClassNameResolution, $link);",
$refClassName,
false,
$table->fullName . '.' . $foreignKey
];
// Add relation for the referenced table
$hasMany = $this->isHasManyRelation($table, $fks);
$link = $this->generateRelationLink($refs);
$relationName = $this->generateRelationName($relations, $refTableSchema, $className, $hasMany);
$relations[$refTableSchema->fullName][$relationName] = [
"return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($classNameResolution, $link);",
$className,
$hasMany,
$table->fullName . '.' . $foreignKey
];
}
}
foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
if (($junctionFks = $this->checkJunctionTable($table)) === false) {
continue;
}
$relations = $this->generateManyManyRelations($table, $junctionFks, $relations);
}
}
if ($this->generateRelations === self::RELATIONS_ALL_INVERSE) {
$relations = $this->addInverseRelations($relations);
}
foreach ($relations as &$relation) {
ksort($relation);
}
return $relations;
}
Generates the relation class hints for the relation methods
public array generateRelationsClassHints ( $relations, $generateQuery ) | ||
$relations | array |
The relation array for single table |
$generateQuery | boolean |
Generates ActiveQuery class (for ActiveQuery namespace available) |
public function generateRelationsClassHints($relations, $generateQuery){
$result = [];
foreach ($relations as $name => $relation){
// The queryNs options available if generateQuery is active
if ($generateQuery) {
$queryClassRealName = '\\' . $this->queryNs . '\\' . $relation[1];
if (class_exists($queryClassRealName, true) && is_subclass_of($queryClassRealName, '\yii\db\BaseActiveRecord')) {
/** @var \yii\db\ActiveQuery $activeQuery */
$activeQuery = $queryClassRealName::find();
$activeQueryClass = $activeQuery::className();
if (strpos($activeQueryClass, $this->ns) === 0){
$activeQueryClass = StringHelper::basename($activeQueryClass);
}
$result[$name] = '\yii\db\ActiveQuery|' . $activeQueryClass;
} else {
$result[$name] = '\yii\db\ActiveQuery|' . (($this->ns === $this->queryNs) ? $relation[1]: '\\' . $this->queryNs . '\\' . $relation[1]) . 'Query';
}
} else {
$result[$name] = '\yii\db\ActiveQuery';
}
}
return $result;
}
Generates validation rules for the specified table.
public array generateRules ( $table ) | ||
$table | \yii\db\TableSchema |
The table schema |
return | array |
The generated validation rules |
---|
public function generateRules($table)
{
$types = [];
$lengths = [];
foreach ($table->columns as $column) {
if ($column->autoIncrement) {
continue;
}
if (!$column->allowNull && $column->defaultValue === null) {
$types['required'][] = $column->name;
}
switch ($column->type) {
case Schema::TYPE_SMALLINT:
case Schema::TYPE_INTEGER:
case Schema::TYPE_BIGINT:
case Schema::TYPE_TINYINT:
$types['integer'][] = $column->name;
break;
case Schema::TYPE_BOOLEAN:
$types['boolean'][] = $column->name;
break;
case Schema::TYPE_FLOAT:
case Schema::TYPE_DOUBLE:
case Schema::TYPE_DECIMAL:
case Schema::TYPE_MONEY:
$types['number'][] = $column->name;
break;
case Schema::TYPE_DATE:
case Schema::TYPE_TIME:
case Schema::TYPE_DATETIME:
case Schema::TYPE_TIMESTAMP:
case Schema::TYPE_JSON:
$types['safe'][] = $column->name;
break;
default: // strings
if ($column->size > 0) {
$lengths[$column->size][] = $column->name;
} else {
$types['string'][] = $column->name;
}
}
}
$rules = [];
$driverName = $this->getDbDriverName();
foreach ($types as $type => $columns) {
if ($driverName === 'pgsql' && $type === 'integer') {
$rules[] = "[['" . implode("', '", $columns) . "'], 'default', 'value' => null]";
}
$rules[] = "[['" . implode("', '", $columns) . "'], '$type']";
}
foreach ($lengths as $length => $columns) {
$rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]";
}
$db = $this->getDbConnection();
// Unique indexes rules
try {
$uniqueIndexes = array_merge($db->getSchema()->findUniqueIndexes($table), [$table->primaryKey]);
$uniqueIndexes = array_unique($uniqueIndexes, SORT_REGULAR);
foreach ($uniqueIndexes as $uniqueColumns) {
// Avoid validating auto incremental columns
if (!$this->isColumnAutoIncremental($table, $uniqueColumns)) {
$attributesCount = count($uniqueColumns);
if ($attributesCount === 1) {
$rules[] = "[['" . $uniqueColumns[0] . "'], 'unique']";
} elseif ($attributesCount > 1) {
$columnsList = implode("', '", $uniqueColumns);
$rules[] = "[['$columnsList'], 'unique', 'targetAttribute' => ['$columnsList']]";
}
}
}
} catch (NotSupportedException $e) {
// doesn't support unique indexes information...do nothing
}
// Exist rules for foreign keys
foreach ($table->foreignKeys as $refs) {
$refTable = $refs[0];
$refTableSchema = $db->getTableSchema($refTable);
if ($refTableSchema === null) {
// Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
continue;
}
$refClassName = $this->generateClassName($refTable);
$refClassNameResolution = $this->generateClassNameResolution($refClassName);
unset($refs[0]);
$attributes = implode("', '", array_keys($refs));
$targetAttributes = [];
foreach ($refs as $key => $value) {
$targetAttributes[] = "'$key' => '$value'";
}
$targetAttributes = implode(', ', $targetAttributes);
$rules[] = "[['$attributes'], 'exist', 'skipOnError' => true, 'targetClass' => $refClassNameResolution, 'targetAttribute' => [$targetAttributes]]";
}
return $rules;
}
Defined in: yii\gii\Generator::generateString()
Generates a string depending on the $enableI18N
property
public string generateString ( $string = '', $placeholders = [] ) | ||
$string | string |
The text be generated |
$placeholders | array |
The placeholders to use by |
public function generateString($string = '', $placeholders = [])
{
$string = addslashes($string);
if ($this->enableI18N) {
// If there are placeholders, use them
if (!empty($placeholders)) {
$ph = ', ' . VarDumper::export($placeholders);
} else {
$ph = '';
}
$str = "Yii::t('" . $this->messageCategory . "', '" . $string . "'" . $ph . ")";
} else {
// No I18N, replace placeholders by real words, if any
if (!empty($placeholders)) {
$phKeys = array_map(function($word) {
return '{' . $word . '}';
}, array_keys($placeholders));
$phValues = array_values($placeholders);
$str = "'" . str_replace($phKeys, $phValues, $string) . "'";
} else {
// No placeholders, just the given string
$str = "'" . $string . "'";
}
}
return $str;
}
Generates the table name by considering table prefix.
If $useTablePrefix is false, the table name will be returned without change.
public string generateTableName ( $tableName ) | ||
$tableName | string |
The table name (which may contain schema prefix) |
return | string |
The generated table name |
---|
public function generateTableName($tableName)
{
if (!$this->useTablePrefix) {
return $tableName;
}
$db = $this->getDbConnection();
if (preg_match("/^{$db->tablePrefix}(.*?)$/", $tableName, $matches)) {
$tableName = '{{%' . $matches[1] . '}}';
} elseif (preg_match("/^(.*?){$db->tablePrefix}$/", $tableName, $matches)) {
$tableName = '{{' . $matches[1] . '%}}';
}
return $tableName;
}
Returns the database connection as specified by $db.
protected \yii\db\Connection|null getDbConnection ( ) | ||
return | \yii\db\Connection|null |
Database connection instance |
---|
protected function getDbConnection()
{
return Yii::$app->get($this->db, false);
}
Returns the driver name of $db connection.
protected string|null getDbDriverName ( ) | ||
return | string|null |
Driver name of db connection. |
---|
protected function getDbDriverName()
{
$db = $this->getDbConnection();
return $db instanceof Connection ? $db->driverName : null;
}
Returns the detailed description of the generator.
public string getDescription ( ) |
public function getDescription()
{
return 'This generator generates an ActiveRecord class for the specified database table.';
}
Returns the name of the code generator.
public string getName ( ) |
public function getName()
{
return 'Model Generator';
}
protected string[] getSchemaNames ( ) | ||
return | string[] |
All db schema names or an array with a single empty string |
---|---|---|
throws | \yii\base\NotSupportedException |
protected function getSchemaNames()
{
$db = $this->getDbConnection();
if ($this->generateRelationsFromCurrentSchema) {
if ($db->schema->defaultSchema !== null) {
return [$db->schema->defaultSchema];
}
return [''];
}
$schema = $db->getSchema();
if ($schema->hasMethod('getSchemaNames')) { // keep BC to Yii versions < 2.0.4
try {
$schemaNames = $schema->getSchemaNames();
} catch (NotSupportedException $e) {
// schema names are not supported by schema
}
}
if (!isset($schemaNames)) {
if (($pos = strpos($this->tableName, '.')) !== false) {
$schemaNames = [substr($this->tableName, 0, $pos)];
} else {
$schemaNames = [''];
}
}
return $schemaNames;
}
Defined in: yii\gii\Generator::getStickyDataFile()
Returns the file path that stores the sticky attribute values.
public string getStickyDataFile ( ) |
public function getStickyDataFile()
{
return Yii::$app->getRuntimePath() . '/gii-' . Yii::getVersion() . '/' . str_replace('\\', '-', get_class($this)) . '.json';
}
protected array getTableNames ( ) | ||
return | array |
The table names that match the pattern specified by $tableName. |
---|
protected function getTableNames()
{
if ($this->tableNames !== null) {
return $this->tableNames;
}
$db = $this->getDbConnection();
if ($db === null) {
return [];
}
$tableNames = [];
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)) . '$/';
} else {
$schema = '';
$pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
}
foreach ($db->schema->getTableNames($schema) as $table) {
if (preg_match($pattern, $table)) {
$tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
}
}
} elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
$tableNames[] = $this->tableName;
$this->classNames[$this->tableName] = $this->modelClass;
}
return $this->tableNames = $tableNames;
}
Returns the tablePrefix
property of the DB connection as specified
See also getDbConnection().
public string getTablePrefix ( ) |
public function getTablePrefix()
{
$db = $this->getDbConnection();
return $db === null ? '' : $db->tablePrefix;
}
Defined in: yii\gii\Generator::getTemplatePath()
public string getTemplatePath ( ) | ||
return | string |
The root path of the template files that are currently being used. |
---|---|---|
throws | \yii\base\InvalidConfigException |
if $template is invalid |
public function getTemplatePath()
{
if (isset($this->templates[$this->template])) {
return $this->templates[$this->template];
}
throw new InvalidConfigException("Unknown template: {$this->template}");
}
Returns the list of hint messages.
The array keys are the attribute names, and the array values are the corresponding hint messages. Hint messages will be displayed to end users when they are filling the form for the generator.
public array hints ( ) | ||
return | array |
The list of hint messages |
---|
public function hints()
{
return array_merge(parent::hints(), [
'ns' => 'This is the namespace of the ActiveRecord class to be generated, e.g., <code>app\models</code>',
'db' => 'This is the ID of the DB application component.',
'tableName' => 'This is the name of the DB table that the new ActiveRecord class is associated with, e.g. <code>post</code>.
The table name may consist of the DB schema part if needed, e.g. <code>public.post</code>.
The table name may end with asterisk to match multiple table names, e.g. <code>tbl_*</code>
will match tables who name starts with <code>tbl_</code>. In this case, multiple ActiveRecord classes
will be generated, one for each matching table name; and the class names will be generated from
the matching characters. For example, table <code>tbl_post</code> will generate <code>Post</code>
class.',
'modelClass' => 'This is the name of the ActiveRecord class to be generated. The class name should not contain
the namespace part as it is specified in "Namespace". You do not need to specify the class name
if "Table Name" ends with asterisk, in which case multiple ActiveRecord classes will be generated.',
'standardizeCapitals' => 'This indicates whether the generated class names should have standardized capitals. For example,
table names like <code>SOME_TABLE</code> or <code>Other_Table</code> will have class names <code>SomeTable</code>
and <code>OtherTable</code>, respectively. If not checked, the same tables will have class names <code>SOMETABLE</code>
and <code>OtherTable</code> instead.',
'singularize' => 'This indicates whether the generated class names should be singularized. For example,
table names like <code>some_tables</code> will have class names <code>SomeTable</code>.',
'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
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.',
'generateJunctionRelationMode' => 'This indicates whether junction relations are generated with `viaTable()` or `via()` (Via Model) relations.
Make sure you also generate the junction models when using the "Via Model" option.
',
'generateRelationsFromCurrentSchema' => 'This indicates whether the generator should generate relations from current schema or from all available schemas.',
'useClassConstant' => 'Use the `::class` constant instead of the `::className()` method.',
'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels
by using the comments of the corresponding DB columns.',
'useTablePrefix' => 'This indicates whether the table name returned by the generated ActiveRecord class
should consider the <code>tablePrefix</code> setting of the DB connection. For example, if the
table name is <code>tbl_post</code> and <code>tablePrefix=tbl_</code>, the ActiveRecord class
will return the table name as <code>{{%post}}</code>.',
'useSchemaName' => 'This indicates whether to include the schema name in the ActiveRecord class
when it\'s auto generated. Only non default schema would be used.',
'generateQuery' => 'This indicates whether to generate ActiveQuery for the ActiveRecord class.',
'queryNs' => 'This is the namespace of the ActiveQuery class to be generated, e.g., <code>app\models</code>',
'queryClass' => 'This is the name of the ActiveQuery class to be generated. The class name should not contain
the namespace part as it is specified in "ActiveQuery Namespace". You do not need to specify the class name
if "Table Name" ends with asterisk, in which case multiple ActiveQuery classes will be generated.',
'queryBaseClass' => 'This is the base class of the new ActiveQuery class. It should be a fully qualified namespaced class name.',
]);
}
public void init ( ) |
public function init()
{
parent::init();
if ($this->useClassConstant === null) {
$this->useClassConstant = PHP_VERSION_ID >= 50500;
}
}
Checks if any of the specified columns is auto incremental.
protected boolean isColumnAutoIncremental ( $table, $columns ) | ||
$table | \yii\db\TableSchema |
The table schema |
$columns | string[] |
Columns to check for autoIncrement property |
return | boolean |
Whether any of the specified columns is auto incremental. |
---|
protected function isColumnAutoIncremental($table, $columns)
{
foreach ($columns as $column) {
if (isset($table->columns[$column]) && $table->columns[$column]->autoIncrement) {
return true;
}
}
return false;
}
Determines if relation is of has many type
protected boolean isHasManyRelation ( $table, $fks ) | ||
$table | \yii\db\TableSchema | |
$fks | array |
protected function isHasManyRelation($table, $fks)
{
$uniqueKeys = [$table->primaryKey];
try {
$uniqueKeys = array_merge($uniqueKeys, $this->getDbConnection()->getSchema()->findUniqueIndexes($table));
} catch (NotSupportedException $e) {
// ignore
}
foreach ($uniqueKeys as $uniqueKey) {
if (array_diff(array_merge($uniqueKey, $fks), array_intersect($uniqueKey, $fks)) === []) {
return false;
}
}
return true;
}
Defined in: yii\gii\Generator::isReservedKeyword()
public boolean isReservedKeyword ( $value ) | ||
$value | string |
The attribute to be validated |
return | boolean |
Whether the value is a reserved PHP keyword. |
---|
public function isReservedKeyword($value)
{
static $keywords = [
'__class__',
'__dir__',
'__file__',
'__function__',
'__line__',
'__method__',
'__namespace__',
'__trait__',
'abstract',
'and',
'array',
'as',
'break',
'case',
'catch',
'callable',
'cfunction',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exception',
'exit',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'fn',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'isset',
'list',
'namespace',
'new',
'old_function',
'or',
'parent',
'php_user_filter',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'switch',
'this',
'throw',
'trait',
'try',
'unset',
'use',
'var',
'while',
'xor',
'yield'
];
return in_array(strtolower($value), $keywords, true);
}
Defined in: yii\gii\Generator::render()
Generates code using the specified code template and parameters.
Note that the code template will be used as a PHP file.
public string render ( $template, $params = [] ) | ||
$template | string |
The code template file. This must be specified as a file path relative to $templatePath. |
$params | array |
List of parameters to be passed to the template file. |
return | string |
The generated code |
---|
public function render($template, $params = [])
{
$view = new View();
$params['generator'] = $this;
return $view->renderFile($this->getTemplatePath() . '/' . $template, $params, $this);
}
Returns a list of code template files that are required.
Derived classes usually should override this method if they require the existence of certain template files.
public array requiredTemplates ( ) | ||
return | array |
List of code template files that are required. They should be file paths relative to $templatePath. |
---|
public function requiredTemplates()
{
$templates = ['model.php'];
if ($this->queryClass !== null) {
$templates[] = 'query.php';
}
return $templates;
}
Child classes should override this method like the following so that the parent rules are included:
return array_merge(parent::rules(), [
...rules for the child class...
]);
public void rules ( ) |
public function rules()
{
return array_merge(parent::rules(), [
[['db', 'tableName', 'modelClass', 'baseClass', 'queryClass', 'queryBaseClass'], 'trim'],
[
['ns', 'queryNs'],
'filter',
'filter' => static function ($value) {
return $value === null ? null : trim($value, ' \\');
}
],
[['db', 'ns', 'tableName', 'baseClass', 'queryNs', 'queryBaseClass'], 'required'],
[['db', 'modelClass', 'queryClass'], 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'],
[['ns', 'baseClass', 'queryNs', 'queryBaseClass'], 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'],
[['tableName'], 'match', 'pattern' => '/^([\w ]+\.)?([\w\* ]+)$/', 'message' => 'Only word characters, and optionally spaces, an asterisk and/or a dot are allowed.'],
[['db'], 'validateDb'],
[['ns', 'queryNs'], 'validateNamespace'],
[['tableName'], 'validateTableName'],
[['modelClass'], 'validateModelClass', 'skipOnEmpty' => false],
[['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]],
[['queryBaseClass'], 'validateClass', 'params' => ['extends' => ActiveQuery::className()]],
[['generateRelations'], 'in', 'range' => [self::RELATIONS_NONE, self::RELATIONS_ALL, self::RELATIONS_ALL_INVERSE]],
[['generateJunctionRelationMode'], 'in', 'range' => [self::JUNCTION_RELATION_VIA_TABLE, self::JUNCTION_RELATION_VIA_MODEL]],
[
['generateLabelsFromComments', 'useTablePrefix', 'useSchemaName', 'generateQuery', 'generateRelationsFromCurrentSchema', 'useClassConstant', 'enableI18N', 'standardizeCapitals', 'singularize'],
'boolean'
],
[['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false],
]);
}
Defined in: yii\gii\Generator::save()
Saves the generated code into files.
public boolean save ( $files, $answers, &$results ) | ||
$files | yii\gii\CodeFile[] |
The code files to be saved |
$answers | array | |
$results | string |
This parameter receives a value from this method indicating the log messages generated while saving the code files. |
return | boolean |
Whether files are successfully saved without any error. |
---|
public function save($files, $answers, &$results)
{
$lines = ['Generating code using template "' . $this->getTemplatePath() . '"...'];
$hasError = false;
foreach ($files as $file) {
$relativePath = $file->getRelativePath();
if (isset($answers[$file->id]) && !empty($answers[$file->id]) && $file->operation !== CodeFile::OP_SKIP) {
$error = $file->save();
if (is_string($error)) {
$hasError = true;
$lines[] = "generating $relativePath\n<span class=\"error\">$error</span>";
} else {
$lines[] = $file->operation === CodeFile::OP_CREATE ? " generated $relativePath" : " overwrote $relativePath";
}
} else {
$lines[] = " skipped $relativePath";
}
}
$lines[] = "done!\n";
$results = implode("\n", $lines);
return !$hasError;
}
Returns the list of sticky attributes.
A sticky attribute will remember its value and will initialize the attribute with this value when the generator is restarted.
public array stickyAttributes ( ) | ||
return | array |
List of sticky attributes |
---|
public function stickyAttributes()
{
return array_merge(
parent::stickyAttributes(),
[
'ns',
'db',
'baseClass',
'generateRelations',
'generateJunctionRelationMode',
'generateLabelsFromComments',
'queryNs',
'queryBaseClass',
'useTablePrefix',
'generateQuery',
'useClassConstant',
]
);
}
Defined in: yii\gii\Generator::successMessage()
Returns the message to be displayed when the newly generated code is saved successfully.
Child classes may override this method to customize the message.
public string successMessage ( ) | ||
return | string |
The message to be displayed when the newly generated code is saved successfully. |
---|
public function successMessage()
{
return 'The code has been generated successfully.';
}
Defined in: yii\gii\Generator::validateClass()
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.
public void validateClass ( $attribute, $params ) | ||
$attribute | string |
The attribute being validated |
$params | array |
The validation options |
public function validateClass($attribute, $params)
{
$class = $this->$attribute;
try {
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 '$class' does not exist or has syntax error.");
}
} catch (\Exception $e) {
$this->addError($attribute, "Class '$class' does not exist or has syntax error.");
}
}
Validates the $db attribute.
public void validateDb ( ) |
public function validateDb()
{
if (!Yii::$app->has($this->db)) {
$this->addError('db', 'There is no application component named "db".');
} elseif (!Yii::$app->get($this->db) instanceof Connection) {
$this->addError('db', 'The "db" application component must be a DB connection instance.');
}
}
Defined in: yii\gii\Generator::validateMessageCategory()
Checks if message category is not empty when I18N is enabled.
public void validateMessageCategory ( ) |
public function validateMessageCategory()
{
if ($this->enableI18N) {
if (empty($this->messageCategory)) {
$this->addError('messageCategory', 'Message Category cannot be blank.');
} elseif (!preg_match('~^[\w./-]+$~', $this->messageCategory)) {
$this->addError('messageCategory', 'Message Category is not valid. It should contain only alphanumeric characters, ".", "-", "/", and "_".');
}
}
}
Validates the $modelClass attribute.
public void validateModelClass ( ) |
public function validateModelClass()
{
if ($this->isReservedKeyword($this->modelClass)) {
$this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
}
if ((empty($this->tableName) || substr_compare($this->tableName, '*', -1, 1)) && $this->modelClass == '') {
$this->addError('modelClass', 'Model Class cannot be blank if table name does not end with asterisk.');
}
}
Validates the namespace.
public void validateNamespace ( $attribute ) | ||
$attribute | string |
Namespace variable. |
public function validateNamespace($attribute)
{
$value = $this->$attribute;
$value = ltrim($value, '\\');
$path = Yii::getAlias('@' . str_replace('\\', '/', $value), false);
if ($path === false) {
$this->addError($attribute, 'Namespace must be associated with an existing directory.');
}
}
Defined in: yii\gii\Generator::validateNewClass()
An inline validator that checks if the attribute value refers to a valid namespaced class name.
The validator will check if the directory containing the new class file exist or not.
public void validateNewClass ( $attribute, $params ) | ||
$attribute | string |
The attribute being validated |
$params | array |
The validation options |
public function validateNewClass($attribute, $params)
{
$class = ltrim($this->$attribute, '\\');
if (($pos = strrpos($class, '\\')) === false) {
$this->addError($attribute, "The class name must contain fully qualified namespace name.");
} else {
$ns = substr($class, 0, $pos);
$path = Yii::getAlias('@' . str_replace('\\', '/', $ns), false);
if ($path === false) {
$this->addError($attribute, "The class namespace is invalid: $ns");
} elseif (!is_dir($path)) {
$this->addError($attribute, "Please make sure the directory containing this class exists: $path");
}
}
}
Validates the $tableName attribute.
public void validateTableName ( ) |
public function validateTableName()
{
if (strpos($this->tableName, '*') !== false && substr_compare($this->tableName, '*', -1, 1)) {
$this->addError('tableName', 'Asterisk is only allowed as the last character.');
return;
}
$tables = $this->getTableNames();
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' will generate a class which is a reserved PHP keyword.");
break;
}
}
}
}
Defined in: yii\gii\Generator::validateTemplate()
Validates the template selection.
This method validates whether the user selects an existing template and the template contains all required template files as specified in requiredTemplates().
public void validateTemplate ( ) |
public function validateTemplate()
{
$templates = $this->templates;
if (!isset($templates[$this->template])) {
$this->addError('template', 'Invalid template selection.');
} else {
$templatePath = $this->templates[$this->template];
foreach ($this->requiredTemplates() as $template) {
if (!is_file(Yii::getAlias($templatePath . '/' . $template))) {
$this->addError('template', "Unable to find the required code template file '$template'.");
}
}
}
}