Generator.php 16.3 KB
Newer Older
Qiang Xue committed
1 2 3 4 5 6 7 8 9
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\gii\generators\model;

Qiang Xue committed
10
use Yii;
Qiang Xue committed
11
use yii\db\ActiveRecord;
Qiang Xue committed
12
use yii\db\Connection;
13
use yii\db\Schema;
Qiang Xue committed
14
use yii\gii\CodeFile;
Qiang Xue committed
15
use yii\helpers\Inflector;
Qiang Xue committed
16

Qiang Xue committed
17
/**
Qiang Xue committed
18
 * This generator will generate one or multiple ActiveRecord classes for the specified database table.
Qiang Xue committed
19 20 21 22 23 24
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Generator extends \yii\gii\Generator
{
Qiang Xue committed
25
	public $db = 'db';
Qiang Xue committed
26
	public $ns = 'app\models';
Qiang Xue committed
27 28
	public $tableName;
	public $modelClass;
Qiang Xue committed
29
	public $baseClass = 'yii\db\ActiveRecord';
Qiang Xue committed
30
	public $generateRelations = true;
Qiang Xue committed
31
	public $generateLabelsFromComments = false;
Qiang Xue committed
32 33


Qiang Xue committed
34 35 36
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
37 38 39 40 41
	public function getName()
	{
		return 'Model Generator';
	}

Qiang Xue committed
42 43 44
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
45 46
	public function getDescription()
	{
Qiang Xue committed
47
		return 'This generator generates an ActiveRecord class for the specified database table.';
Qiang Xue committed
48
	}
49

Qiang Xue committed
50 51 52
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
53 54
	public function rules()
	{
Alexander Makarov committed
55 56 57 58 59 60 61 62 63 64 65 66 67
		return array_merge(parent::rules(), [
			['db, ns, tableName, modelClass, baseClass', 'filter', 'filter' => 'trim'],
			['db, ns, tableName, baseClass', 'required'],
			['db, modelClass', 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'],
			['ns, baseClass', 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'],
			['tableName', 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'],
			['db', 'validateDb'],
			['ns', 'validateNamespace'],
			['tableName', 'validateTableName'],
			['modelClass', 'validateModelClass'],
			['baseClass', 'validateClass', 'params' => ['extends' => ActiveRecord::className()]],
			['generateRelations, generateLabelsFromComments', 'boolean'],
		]);
Qiang Xue committed
68 69
	}

Qiang Xue committed
70 71 72
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
73 74
	public function attributeLabels()
	{
Alexander Makarov committed
75
		return [
Qiang Xue committed
76 77
			'ns' => 'Namespace',
			'db' => 'Database Connection ID',
Qiang Xue committed
78 79 80
			'tableName' => 'Table Name',
			'modelClass' => 'Model Class',
			'baseClass' => 'Base Class',
Qiang Xue committed
81
			'generateRelations' => 'Generate Relations',
Qiang Xue committed
82
			'generateLabelsFromComments' => 'Generate Labels from DB Comments',
Alexander Makarov committed
83
		];
Qiang Xue committed
84 85
	}

Qiang Xue committed
86 87 88
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
89 90
	public function hints()
	{
Alexander Makarov committed
91
		return [
Qiang Xue committed
92 93 94 95
			'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>tbl_post</code>.
				The table name may consist of the DB schema part if needed, e.g. <code>public.tbl_post</code>.
Qiang Xue committed
96 97 98 99 100
				The table name may contain an 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.',
Qiang Xue committed
101 102 103 104 105 106
			'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" contains an asterisk at the end, in which case multiple ActiveRecord classes will be generated.',
			'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,
Qiang Xue committed
107
				you may want to uncheck this option to accelerate the code generation proc	ess.',
Qiang Xue committed
108 109
			'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels
				by using the comments of the corresponding DB columns.',
Alexander Makarov committed
110
		];
Qiang Xue committed
111 112
	}

Qiang Xue committed
113 114 115
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
116 117
	public function requiredTemplates()
	{
Alexander Makarov committed
118
		return ['model.php'];
Qiang Xue committed
119 120
	}

Qiang Xue committed
121 122 123
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
124 125
	public function stickyAttributes()
	{
Alexander Makarov committed
126
		return ['ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments'];
Qiang Xue committed
127 128
	}

Qiang Xue committed
129
	/**
Qiang Xue committed
130
	 * @inheritdoc
Qiang Xue committed
131
	 */
Qiang Xue committed
132 133
	public function generate()
	{
Alexander Makarov committed
134
		$files = [];
Qiang Xue committed
135 136
		$relations = $this->generateRelations();
		$db = $this->getDbConnection();
Qiang Xue committed
137 138
		foreach ($this->getTableNames() as $tableName) {
			$className = $this->generateClassName($tableName);
Qiang Xue committed
139
			$tableSchema = $db->getTableSchema($tableName);
Alexander Makarov committed
140
			$params = [
Qiang Xue committed
141
				'tableName' => $tableName,
Qiang Xue committed
142
				'className' => $className,
Qiang Xue committed
143 144
				'tableSchema' => $tableSchema,
				'labels' => $this->generateLabels($tableSchema),
145
				'rules' => $this->generateRules($tableSchema),
Alexander Makarov committed
146 147
				'relations' => isset($relations[$className]) ? $relations[$className] : [],
			];
Qiang Xue committed
148
			$files[] = new CodeFile(
Qiang Xue committed
149
				Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $className . '.php',
Qiang Xue committed
150
				$this->render('model.php', $params)
Qiang Xue committed
151 152
			);
		}
Qiang Xue committed
153 154

		return $files;
Qiang Xue committed
155 156
	}

Qiang Xue committed
157 158 159 160 161
	/**
	 * Generates the attribute labels for the specified table.
	 * @param \yii\db\TableSchema $table the table schema
	 * @return array the generated attribute labels (name => label)
	 */
Qiang Xue committed
162 163
	public function generateLabels($table)
	{
Alexander Makarov committed
164
		$labels = [];
Qiang Xue committed
165
		foreach ($table->columns as $column) {
Qiang Xue committed
166
			if ($this->generateLabelsFromComments && !empty($column->comment)) {
Qiang Xue committed
167
				$labels[$column->name] = $column->comment;
Qiang Xue committed
168 169
			} elseif (!strcasecmp($column->name, 'id')) {
				$labels[$column->name] = 'ID';
Qiang Xue committed
170
			} else {
Qiang Xue committed
171
				$label = Inflector::camel2words($column->name);
Qiang Xue committed
172
				if (strcasecmp(substr($label, -3), ' id') === 0) {
Qiang Xue committed
173
					$label = substr($label, 0, -3) . ' ID';
Qiang Xue committed
174 175 176 177 178 179 180
				}
				$labels[$column->name] = $label;
			}
		}
		return $labels;
	}

181
	/**
Qiang Xue committed
182 183 184
	 * Generates validation rules for the specified table.
	 * @param \yii\db\TableSchema $table the table schema
	 * @return array the generated validation rules
185
	 */
Qiang Xue committed
186 187
	public function generateRules($table)
	{
Alexander Makarov committed
188 189
		$types = [];
		$lengths = [];
Qiang Xue committed
190 191 192 193
		foreach ($table->columns as $column) {
			if ($column->autoIncrement) {
				continue;
			}
194 195
			if (!$column->allowNull && $column->defaultValue === null) {
				$types['required'][] = $column->name;
Qiang Xue committed
196
			}
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
			switch ($column->type) {
				case Schema::TYPE_SMALLINT:
				case Schema::TYPE_INTEGER:
				case Schema::TYPE_BIGINT:
					$types['integer'][] = $column->name;
					break;
				case Schema::TYPE_BOOLEAN:
					$types['boolean'][] = $column->name;
					break;
				case Schema::TYPE_FLOAT:
				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:
					$types['safe'][] = $column->name;
					break;
				default: // strings
					if ($column->size > 0) {
						$lengths[$column->size][] = $column->name;
					} else {
						$types['string'][] = $column->name;
					}
Qiang Xue committed
223 224
			}
		}
225

Alexander Makarov committed
226
		$rules = [];
227
		foreach ($types as $type => $columns) {
Alexander Makarov committed
228
			$rules[] = "['" . implode(', ', $columns) . "', '$type']";
Qiang Xue committed
229
		}
230
		foreach ($lengths as $length => $columns) {
Alexander Makarov committed
231
			$rules[] = "['" . implode(', ', $columns) . "', 'string', 'max' => $length]";
Qiang Xue committed
232 233 234 235 236
		}

		return $rules;
	}

Qiang Xue committed
237 238 239
	/**
	 * @return array the generated relation declarations
	 */
Qiang Xue committed
240 241
	protected function generateRelations()
	{
Qiang Xue committed
242
		if (!$this->generateRelations) {
Alexander Makarov committed
243
			return [];
Qiang Xue committed
244 245
		}

Qiang Xue committed
246 247
		$db = $this->getDbConnection();

Qiang Xue committed
248 249
		if (($pos = strpos($this->tableName, '.')) !== false) {
			$schemaName = substr($this->tableName, 0, $pos);
Qiang Xue committed
250 251
		} else {
			$schemaName = '';
Qiang Xue committed
252 253
		}

Alexander Makarov committed
254
		$relations = [];
Qiang Xue committed
255
		foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
Qiang Xue committed
256
			$tableName = $table->name;
Qiang Xue committed
257 258 259 260 261 262 263 264 265 266
			$className = $this->generateClassName($tableName);
			foreach ($table->foreignKeys as $refs) {
				$refTable = $refs[0];
				unset($refs[0]);
				$fks = array_keys($refs);
				$refClassName = $this->generateClassName($refTable);

				// Add relation for this table
				$link = $this->generateRelationLink(array_flip($refs));
				$relationName = $this->generateRelationName($relations, $className, $table, $fks[0], false);
Alexander Makarov committed
267
				$relations[$className][$relationName] = [
Qiang Xue committed
268 269 270
					"return \$this->hasOne('$refClassName', $link);",
					$refClassName,
					false,
Alexander Makarov committed
271
				];
Qiang Xue committed
272 273 274 275 276 277 278

				// Add relation for the referenced table
				$hasMany = false;
				foreach ($fks as $key) {
					if (!in_array($key, $table->primaryKey, true)) {
						$hasMany = true;
						break;
Qiang Xue committed
279 280
					}
				}
Qiang Xue committed
281 282
				$link = $this->generateRelationLink($refs);
				$relationName = $this->generateRelationName($relations, $refClassName, $refTable, $className, $hasMany);
Alexander Makarov committed
283
				$relations[$refClassName][$relationName] = [
Qiang Xue committed
284 285 286
					"return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "('$className', $link);",
					$className,
					$hasMany,
Alexander Makarov committed
287
				];
Qiang Xue committed
288 289 290 291
			}

			if (($fks = $this->checkPivotTable($table)) === false) {
				continue;
Qiang Xue committed
292
			}
Qiang Xue committed
293 294 295 296 297
			$table0 = $fks[$table->primaryKey[0]][0];
			$table1 = $fks[$table->primaryKey[1]][0];
			$className0 = $this->generateClassName($table0);
			$className1 = $this->generateClassName($table1);

Alexander Makarov committed
298 299
			$link = $this->generateRelationLink([$fks[$table->primaryKey[1]][1] => $table->primaryKey[1]]);
			$viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]);
Qiang Xue committed
300
			$relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true);
Alexander Makarov committed
301
			$relations[$className0][$relationName] = [
Qiang Xue committed
302 303 304
				"return \$this->hasMany('$className1', $link)->viaTable('{$table->name}', $viaLink);",
				$className0,
				true,
Alexander Makarov committed
305
			];
Qiang Xue committed
306

Alexander Makarov committed
307 308
			$link = $this->generateRelationLink([$fks[$table->primaryKey[0]][1] => $table->primaryKey[0]]);
			$viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]);
Qiang Xue committed
309
			$relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true);
Alexander Makarov committed
310
			$relations[$className1][$relationName] = [
Qiang Xue committed
311 312 313
				"return \$this->hasMany('$className0', $link)->viaTable('{$table->name}', $viaLink);",
				$className1,
				true,
Alexander Makarov committed
314
			];
Qiang Xue committed
315 316 317 318
		}
		return $relations;
	}

319
	/**
Qiang Xue committed
320 321 322
	 * Generates the link parameter to be used in generating the relation declaration.
	 * @param array $refs reference constraint
	 * @return string the generated link parameter.
323
	 */
Qiang Xue committed
324
	protected function generateRelationLink($refs)
Qiang Xue committed
325
	{
Alexander Makarov committed
326
		$pairs = [];
Qiang Xue committed
327 328 329
		foreach ($refs as $a => $b) {
			$pairs[] = "'$a' => '$b'";
		}
Alexander Makarov committed
330
		return '[' . implode(', ', $pairs) . ']';
Qiang Xue committed
331 332 333
	}

	/**
Qiang Xue committed
334 335 336 337 338 339
	 * Checks if the given table is a pivot table.
	 * For simplicity, this method only deals with the case where the pivot contains two PK columns,
	 * each referencing a column in a different table.
	 * @param \yii\db\TableSchema the table being checked
	 * @return array|boolean the relevant foreign key constraint information if the table is a pivot table,
	 * or false if the table is not a pivot table.
Qiang Xue committed
340
	 */
Qiang Xue committed
341
	protected function checkPivotTable($table)
Qiang Xue committed
342
	{
Qiang Xue committed
343 344 345 346
		$pk = $table->primaryKey;
		if (count($pk) !== 2) {
			return false;
		}
Alexander Makarov committed
347
		$fks = [];
Qiang Xue committed
348 349 350
		foreach ($table->foreignKeys as $refs) {
			if (count($refs) === 2) {
				if (isset($refs[$pk[0]])) {
Alexander Makarov committed
351
					$fks[$pk[0]] = [$refs[0], $refs[$pk[0]]];
Qiang Xue committed
352
				} elseif (isset($refs[$pk[1]])) {
Alexander Makarov committed
353
					$fks[$pk[1]] = [$refs[0], $refs[$pk[1]]];
Qiang Xue committed
354 355 356 357 358
				}
			}
		}
		if (count($fks) === 2 && $fks[$pk[0]][0] !== $fks[$pk[1]][0]) {
			return $fks;
Qiang Xue committed
359
		} else {
Qiang Xue committed
360
			return false;
Qiang Xue committed
361
		}
Qiang Xue committed
362
	}
Qiang Xue committed
363

Qiang Xue committed
364 365 366 367 368 369 370 371 372 373 374 375 376
	/**
	 * Generate a relation name for the specified table and a base name.
	 * @param array $relations the relations being generated currently.
	 * @param string $className the class name that will contain the relation declarations
	 * @param \yii\db\TableSchema $table the table schema
	 * @param string $key a base name that the relation name may be generated from
	 * @param boolean $multiple whether this is a has-many relation
	 * @return string the relation name
	 */
	protected function generateRelationName($relations, $className, $table, $key, $multiple)
	{
		if (strcasecmp(substr($key, -2), 'id') === 0 && strcasecmp($key, 'id')) {
			$key = rtrim(substr($key, 0, -2), '_');
Qiang Xue committed
377
		}
Qiang Xue committed
378 379
		if ($multiple) {
			$key = Inflector::pluralize($key);
Qiang Xue committed
380
		}
Qiang Xue committed
381
		$name = $rawName = Inflector::id2camel($key, '_');
Qiang Xue committed
382 383 384 385
		$i = 0;
		while (isset($table->columns[$name])) {
			$name = $rawName . ($i++);
		}
Qiang Xue committed
386 387 388
		while (isset($relations[$className][$name])) {
			$name = $rawName . ($i++);
		}
Qiang Xue committed
389 390 391 392

		return $name;
	}

Qiang Xue committed
393 394 395
	/**
	 * Validates the [[db]] attribute.
	 */
Qiang Xue committed
396
	public function validateDb()
397
	{
Qiang Xue committed
398 399 400 401
		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.');
Qiang Xue committed
402 403 404
		}
	}

Qiang Xue committed
405 406 407
	/**
	 * Validates the [[ns]] attribute.
	 */
Qiang Xue committed
408 409
	public function validateNamespace()
	{
Qiang Xue committed
410 411
		$this->ns = ltrim($this->ns, '\\');
		$path = Yii::getAlias('@' . str_replace('\\', '/', $this->ns), false);
Qiang Xue committed
412 413 414
		if ($path === false) {
			$this->addError('ns', 'Namespace must be associated with an existing directory.');
		}
Qiang Xue committed
415 416
	}

Qiang Xue committed
417 418 419
	/**
	 * Validates the [[modelClass]] attribute.
	 */
Qiang Xue committed
420 421 422
	public function validateModelClass()
	{
		if ($this->isReservedKeyword($this->modelClass)) {
Qiang Xue committed
423
			$this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
Qiang Xue committed
424 425 426 427 428 429
		}
		if (strpos($this->tableName, '*') === false && $this->modelClass == '') {
			$this->addError('modelClass', 'Model Class cannot be blank.');
		}
	}

Qiang Xue committed
430 431 432
	/**
	 * Validates the [[tableName]] attribute.
	 */
Qiang Xue committed
433 434
	public function validateTableName()
	{
Qiang Xue committed
435 436 437 438
		if (($pos = strpos($this->tableName, '*')) !== false && strpos($this->tableName, '*', $pos + 1) !== false) {
			$this->addError('tableName', 'At most one asterisk is allowed.');
			return;
		}
Qiang Xue committed
439 440
		$tables = $this->getTableNames();
		if (empty($tables)) {
Qiang Xue committed
441
			$this->addError('tableName', "Table '{$this->tableName}' does not exist.");
Qiang Xue committed
442 443 444 445
		} else {
			foreach ($tables as $table) {
				$class = $this->generateClassName($table);
				if ($this->isReservedKeyword($class)) {
Qiang Xue committed
446
					$this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword.");
Qiang Xue committed
447 448 449 450 451
					break;
				}
			}
		}
	}
Qiang Xue committed
452

453 454 455
	private $_tableNames;
	private $_classNames;

Qiang Xue committed
456 457 458
	/**
	 * @return array the table names that match the pattern specified by [[tableName]].
	 */
Qiang Xue committed
459 460
	protected function getTableNames()
	{
461 462 463
		if ($this->_tableNames !== null) {
			return $this->_tableNames;
		}
Qiang Xue committed
464
		$db = $this->getDbConnection();
465
		if ($db === null) {
Alexander Makarov committed
466
			return [];
467
		}
Alexander Makarov committed
468
		$tableNames = [];
Qiang Xue committed
469
		if (strpos($this->tableName, '*') !== false) {
Qiang Xue committed
470 471
			if (($pos = strrpos($this->tableName, '.')) !== false) {
				$schema = substr($this->tableName, 0, $pos);
Qiang Xue committed
472
				$pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/';
Qiang Xue committed
473 474
			} else {
				$schema = '';
Qiang Xue committed
475
				$pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
Qiang Xue committed
476 477
			}

Qiang Xue committed
478 479 480
			foreach ($db->schema->getTableNames($schema) as $table) {
				if (preg_match($pattern, $table)) {
					$tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
Qiang Xue committed
481 482
				}
			}
Qiang Xue committed
483 484
		} elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
			$tableNames[] = $this->tableName;
485 486 487 488 489
			$this->_classNames[$this->tableName] = $this->modelClass;
		}
		return $this->_tableNames = $tableNames;
	}

Qiang Xue committed
490 491 492 493 494
	/**
	 * Generates a class name from the specified table name.
	 * @param string $tableName the table name (which may contain schema prefix)
	 * @return string the generated class name
	 */
495 496 497 498 499 500 501 502 503 504 505
	protected function generateClassName($tableName)
	{
		if (isset($this->_classNames[$tableName])) {
			return $this->_classNames[$tableName];
		}

		if (($pos = strrpos($tableName, '.')) !== false) {
			$tableName = substr($tableName, $pos + 1);
		}

		$db = $this->getDbConnection();
Alexander Makarov committed
506
		$patterns = [];
507 508 509 510 511 512 513 514
		if (strpos($this->tableName, '*') !== false) {
			$pattern = $this->tableName;
			if (($pos = strrpos($pattern, '.')) !== false) {
				$pattern = substr($pattern, $pos + 1);
			}
			$patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
		}
		if (!empty($db->tablePrefix)) {
515 516
			$patterns[] = "/^{$db->tablePrefix}(.*?)$/";
			$patterns[] = "/^(.*?){$db->tablePrefix}$/";
517 518 519 520 521 522 523 524
		} else {
			$patterns[] = "/^tbl_(.*?)$/";
		}

		$className = $tableName;
		foreach ($patterns as $pattern) {
			if (preg_match($pattern, $tableName, $matches)) {
				$className = $matches[1];
525
				break;
526
			}
Qiang Xue committed
527
		}
528
		return $this->_classNames[$tableName] = Inflector::id2camel($className, '_');
529
	}
Qiang Xue committed
530 531 532 533 534 535 536 537

	/**
	 * @return Connection the DB connection as specified by [[db]].
	 */
	protected function getDbConnection()
	{
		return Yii::$app->{$this->db};
	}
Qiang Xue committed
538
}