Generator.php 16.7 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
		return array_merge(parent::rules(), [
56 57 58 59 60 61 62 63 64 65 66
			[['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', 'skipOnEmpty' => false],
			[['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]],
			[['generateRelations', 'generateLabelsFromComments'], 'boolean'],
Alexander Makarov committed
67
		]);
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>.
96
				The table name may end with asterisk to match multiple table names, e.g. <code>tbl_*</code>
Qiang Xue committed
97 98 99 100
				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
			'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
103
				if "Table Name" ends with asterisk, in which case multiple ActiveRecord classes will be generated.',
Qiang Xue committed
104 105 106
			'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 process.',
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
	}

113 114 115 116 117
	/**
	 * @inheritdoc
	 */
	public function autoCompleteData()
	{
Qiang Xue committed
118
		$db = $this->getDbConnection();
Qiang Xue committed
119
		if ($db !== null) {
Qiang Xue committed
120 121 122 123 124 125 126 127
			return [
				'tableName' => function () use ($db) {
					return $db->getSchema()->getTableNames();
				},
			];
		} else {
			return [];
		}
128 129
	}

Qiang Xue committed
130 131 132
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
133 134
	public function requiredTemplates()
	{
Alexander Makarov committed
135
		return ['model.php'];
Qiang Xue committed
136 137
	}

Qiang Xue committed
138 139 140
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
141 142
	public function stickyAttributes()
	{
Alexander Makarov committed
143
		return ['ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments'];
Qiang Xue committed
144 145
	}

Qiang Xue committed
146
	/**
Qiang Xue committed
147
	 * @inheritdoc
Qiang Xue committed
148
	 */
Qiang Xue committed
149 150
	public function generate()
	{
Alexander Makarov committed
151
		$files = [];
Qiang Xue committed
152 153
		$relations = $this->generateRelations();
		$db = $this->getDbConnection();
Qiang Xue committed
154 155
		foreach ($this->getTableNames() as $tableName) {
			$className = $this->generateClassName($tableName);
Qiang Xue committed
156
			$tableSchema = $db->getTableSchema($tableName);
Alexander Makarov committed
157
			$params = [
Qiang Xue committed
158
				'tableName' => $tableName,
Qiang Xue committed
159
				'className' => $className,
Qiang Xue committed
160 161
				'tableSchema' => $tableSchema,
				'labels' => $this->generateLabels($tableSchema),
162
				'rules' => $this->generateRules($tableSchema),
Alexander Makarov committed
163 164
				'relations' => isset($relations[$className]) ? $relations[$className] : [],
			];
Qiang Xue committed
165
			$files[] = new CodeFile(
Qiang Xue committed
166
				Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $className . '.php',
Qiang Xue committed
167
				$this->render('model.php', $params)
Qiang Xue committed
168 169
			);
		}
Qiang Xue committed
170 171

		return $files;
Qiang Xue committed
172 173
	}

Qiang Xue committed
174 175 176 177 178
	/**
	 * 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
179 180
	public function generateLabels($table)
	{
Alexander Makarov committed
181
		$labels = [];
Qiang Xue committed
182
		foreach ($table->columns as $column) {
Qiang Xue committed
183
			if ($this->generateLabelsFromComments && !empty($column->comment)) {
Qiang Xue committed
184
				$labels[$column->name] = $column->comment;
Qiang Xue committed
185 186
			} elseif (!strcasecmp($column->name, 'id')) {
				$labels[$column->name] = 'ID';
Qiang Xue committed
187
			} else {
Qiang Xue committed
188
				$label = Inflector::camel2words($column->name);
Qiang Xue committed
189
				if (strcasecmp(substr($label, -3), ' id') === 0) {
Qiang Xue committed
190
					$label = substr($label, 0, -3) . ' ID';
Qiang Xue committed
191 192 193 194 195 196 197
				}
				$labels[$column->name] = $label;
			}
		}
		return $labels;
	}

198
	/**
Qiang Xue committed
199 200 201
	 * Generates validation rules for the specified table.
	 * @param \yii\db\TableSchema $table the table schema
	 * @return array the generated validation rules
202
	 */
Qiang Xue committed
203 204
	public function generateRules($table)
	{
Alexander Makarov committed
205 206
		$types = [];
		$lengths = [];
Qiang Xue committed
207 208 209 210
		foreach ($table->columns as $column) {
			if ($column->autoIncrement) {
				continue;
			}
211 212
			if (!$column->allowNull && $column->defaultValue === null) {
				$types['required'][] = $column->name;
Qiang Xue committed
213
			}
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
			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
240 241
			}
		}
242

Alexander Makarov committed
243
		$rules = [];
244
		foreach ($types as $type => $columns) {
KiTE committed
245
			$rules[] = "[['" . implode("', '", $columns) . "'], '$type']";
Qiang Xue committed
246
		}
247
		foreach ($lengths as $length => $columns) {
KiTE committed
248
			$rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]";
Qiang Xue committed
249 250 251 252 253
		}

		return $rules;
	}

Qiang Xue committed
254 255 256
	/**
	 * @return array the generated relation declarations
	 */
Qiang Xue committed
257 258
	protected function generateRelations()
	{
Qiang Xue committed
259
		if (!$this->generateRelations) {
Alexander Makarov committed
260
			return [];
Qiang Xue committed
261 262
		}

Qiang Xue committed
263 264
		$db = $this->getDbConnection();

Qiang Xue committed
265 266
		if (($pos = strpos($this->tableName, '.')) !== false) {
			$schemaName = substr($this->tableName, 0, $pos);
Qiang Xue committed
267 268
		} else {
			$schemaName = '';
Qiang Xue committed
269 270
		}

Alexander Makarov committed
271
		$relations = [];
Qiang Xue committed
272
		foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
Qiang Xue committed
273
			$tableName = $table->name;
Qiang Xue committed
274 275 276 277 278 279 280 281 282 283
			$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
284
				$relations[$className][$relationName] = [
Gudz Taras committed
285 286
					"return \$this->hasOne($refClassName::className(), $link);",
					$refClassName,
Qiang Xue committed
287
					false,
Alexander Makarov committed
288
				];
Qiang Xue committed
289 290 291 292 293 294 295

				// 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
296 297
					}
				}
Qiang Xue committed
298 299
				$link = $this->generateRelationLink($refs);
				$relationName = $this->generateRelationName($relations, $refClassName, $refTable, $className, $hasMany);
Alexander Makarov committed
300
				$relations[$refClassName][$relationName] = [
301
					"return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($className::className(), $link);",
Gudz Taras committed
302
					$className,
Qiang Xue committed
303
					$hasMany,
Alexander Makarov committed
304
				];
Qiang Xue committed
305 306 307 308
			}

			if (($fks = $this->checkPivotTable($table)) === false) {
				continue;
Qiang Xue committed
309
			}
Qiang Xue committed
310 311 312 313 314
			$table0 = $fks[$table->primaryKey[0]][0];
			$table1 = $fks[$table->primaryKey[1]][0];
			$className0 = $this->generateClassName($table0);
			$className1 = $this->generateClassName($table1);

Alexander Makarov committed
315 316
			$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
317
			$relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true);
Alexander Makarov committed
318
			$relations[$className0][$relationName] = [
Gudz Taras committed
319 320
				"return \$this->hasMany($className1::className(), $link)->viaTable('{$table->name}', $viaLink);",
				$className0,
Qiang Xue committed
321
				true,
Alexander Makarov committed
322
			];
Qiang Xue committed
323

Alexander Makarov committed
324 325
			$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
326
			$relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true);
Alexander Makarov committed
327
			$relations[$className1][$relationName] = [
Gudz Taras committed
328 329
				"return \$this->hasMany($className0::className(), $link)->viaTable('{$table->name}', $viaLink);",
				$className1,
Qiang Xue committed
330
				true,
Alexander Makarov committed
331
			];
Qiang Xue committed
332 333 334 335
		}
		return $relations;
	}

336
	/**
Qiang Xue committed
337 338 339
	 * Generates the link parameter to be used in generating the relation declaration.
	 * @param array $refs reference constraint
	 * @return string the generated link parameter.
340
	 */
Qiang Xue committed
341
	protected function generateRelationLink($refs)
Qiang Xue committed
342
	{
Alexander Makarov committed
343
		$pairs = [];
Qiang Xue committed
344 345 346
		foreach ($refs as $a => $b) {
			$pairs[] = "'$a' => '$b'";
		}
Alexander Makarov committed
347
		return '[' . implode(', ', $pairs) . ']';
Qiang Xue committed
348 349 350
	}

	/**
Qiang Xue committed
351 352 353 354 355 356
	 * 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
357
	 */
Qiang Xue committed
358
	protected function checkPivotTable($table)
Qiang Xue committed
359
	{
Qiang Xue committed
360 361 362 363
		$pk = $table->primaryKey;
		if (count($pk) !== 2) {
			return false;
		}
Alexander Makarov committed
364
		$fks = [];
Qiang Xue committed
365 366 367
		foreach ($table->foreignKeys as $refs) {
			if (count($refs) === 2) {
				if (isset($refs[$pk[0]])) {
Alexander Makarov committed
368
					$fks[$pk[0]] = [$refs[0], $refs[$pk[0]]];
Qiang Xue committed
369
				} elseif (isset($refs[$pk[1]])) {
Alexander Makarov committed
370
					$fks[$pk[1]] = [$refs[0], $refs[$pk[1]]];
Qiang Xue committed
371 372 373 374 375
				}
			}
		}
		if (count($fks) === 2 && $fks[$pk[0]][0] !== $fks[$pk[1]][0]) {
			return $fks;
Qiang Xue committed
376
		} else {
Qiang Xue committed
377
			return false;
Qiang Xue committed
378
		}
Qiang Xue committed
379
	}
Qiang Xue committed
380

Qiang Xue committed
381 382 383 384 385 386 387 388 389 390 391 392 393
	/**
	 * 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
394
		}
Qiang Xue committed
395 396
		if ($multiple) {
			$key = Inflector::pluralize($key);
Qiang Xue committed
397
		}
Qiang Xue committed
398
		$name = $rawName = Inflector::id2camel($key, '_');
Qiang Xue committed
399 400 401 402
		$i = 0;
		while (isset($table->columns[$name])) {
			$name = $rawName . ($i++);
		}
Qiang Xue committed
403 404 405
		while (isset($relations[$className][$name])) {
			$name = $rawName . ($i++);
		}
Qiang Xue committed
406 407 408 409

		return $name;
	}

Qiang Xue committed
410 411 412
	/**
	 * Validates the [[db]] attribute.
	 */
Qiang Xue committed
413
	public function validateDb()
414
	{
Qiang Xue committed
415 416 417 418
		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
419 420 421
		}
	}

Qiang Xue committed
422 423 424
	/**
	 * Validates the [[ns]] attribute.
	 */
Qiang Xue committed
425 426
	public function validateNamespace()
	{
Qiang Xue committed
427 428
		$this->ns = ltrim($this->ns, '\\');
		$path = Yii::getAlias('@' . str_replace('\\', '/', $this->ns), false);
Qiang Xue committed
429 430 431
		if ($path === false) {
			$this->addError('ns', 'Namespace must be associated with an existing directory.');
		}
Qiang Xue committed
432 433
	}

Qiang Xue committed
434 435 436
	/**
	 * Validates the [[modelClass]] attribute.
	 */
Qiang Xue committed
437 438 439
	public function validateModelClass()
	{
		if ($this->isReservedKeyword($this->modelClass)) {
Qiang Xue committed
440
			$this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
Qiang Xue committed
441
		}
442 443
		if (substr($this->tableName, -1) !== '*' && $this->modelClass == '') {
			$this->addError('modelClass', 'Model Class cannot be blank if table name does not end with asterisk.');
Qiang Xue committed
444 445 446
		}
	}

Qiang Xue committed
447 448 449
	/**
	 * Validates the [[tableName]] attribute.
	 */
Qiang Xue committed
450 451
	public function validateTableName()
	{
452 453
		if (($pos = strpos($this->tableName, '*')) !== false && substr($this->tableName, -1) !== '*') {
			$this->addError('tableName', 'Asterisk is only allowed as the last character.');
Qiang Xue committed
454 455
			return;
		}
Qiang Xue committed
456 457
		$tables = $this->getTableNames();
		if (empty($tables)) {
Qiang Xue committed
458
			$this->addError('tableName', "Table '{$this->tableName}' does not exist.");
Qiang Xue committed
459 460 461 462
		} else {
			foreach ($tables as $table) {
				$class = $this->generateClassName($table);
				if ($this->isReservedKeyword($class)) {
Qiang Xue committed
463
					$this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword.");
Qiang Xue committed
464 465 466 467 468
					break;
				}
			}
		}
	}
Qiang Xue committed
469

470 471 472
	private $_tableNames;
	private $_classNames;

Qiang Xue committed
473 474 475
	/**
	 * @return array the table names that match the pattern specified by [[tableName]].
	 */
Qiang Xue committed
476 477
	protected function getTableNames()
	{
478 479 480
		if ($this->_tableNames !== null) {
			return $this->_tableNames;
		}
Qiang Xue committed
481
		$db = $this->getDbConnection();
482
		if ($db === null) {
Alexander Makarov committed
483
			return [];
484
		}
Alexander Makarov committed
485
		$tableNames = [];
Qiang Xue committed
486
		if (strpos($this->tableName, '*') !== false) {
Qiang Xue committed
487 488
			if (($pos = strrpos($this->tableName, '.')) !== false) {
				$schema = substr($this->tableName, 0, $pos);
Qiang Xue committed
489
				$pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/';
Qiang Xue committed
490 491
			} else {
				$schema = '';
Qiang Xue committed
492
				$pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
Qiang Xue committed
493 494
			}

Qiang Xue committed
495 496 497
			foreach ($db->schema->getTableNames($schema) as $table) {
				if (preg_match($pattern, $table)) {
					$tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
Qiang Xue committed
498 499
				}
			}
Qiang Xue committed
500 501
		} elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
			$tableNames[] = $this->tableName;
502 503 504 505 506
			$this->_classNames[$this->tableName] = $this->modelClass;
		}
		return $this->_tableNames = $tableNames;
	}

Qiang Xue committed
507 508 509 510 511
	/**
	 * 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
	 */
512 513 514 515 516 517 518 519 520 521 522
	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
523
		$patterns = [];
524 525 526 527 528 529 530 531
		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)) {
532 533
			$patterns[] = "/^{$db->tablePrefix}(.*?)$/";
			$patterns[] = "/^(.*?){$db->tablePrefix}$/";
534 535 536 537 538 539 540 541
		} else {
			$patterns[] = "/^tbl_(.*?)$/";
		}

		$className = $tableName;
		foreach ($patterns as $pattern) {
			if (preg_match($pattern, $tableName, $matches)) {
				$className = $matches[1];
542
				break;
543
			}
Qiang Xue committed
544
		}
545
		return $this->_classNames[$tableName] = Inflector::id2camel($className, '_');
546
	}
Qiang Xue committed
547 548 549 550 551 552 553 554

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