Файл: framework/cli/commands/shell/ModelCommand.php
Строк: 498
<?php
/**
* ModelCommand class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008-2013 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* ModelCommand generates a model class.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package system.cli.commands.shell
* @since 1.0
*/
class ModelCommand extends CConsoleCommand
{
/**
* @var string the directory that contains templates for the model command.
* Defaults to null, meaning using 'framework/cli/views/shell/model'.
* If you set this path and some views are missing in the directory,
* the default views will be used.
*/
public $templatePath;
/**
* @var string the directory that contains test fixtures.
* Defaults to null, meaning using 'protected/tests/fixtures'.
* If this is false, it means fixture file should NOT be generated.
*/
public $fixturePath;
/**
* @var string the directory that contains unit test classes.
* Defaults to null, meaning using 'protected/tests/unit'.
* If this is false, it means unit test file should NOT be generated.
*/
public $unitTestPath;
private $_schema;
private $_relations; // where we keep table relations
private $_tables;
private $_classes;
public function getHelp()
{
return <<<EOD
USAGE
model <class-name> [table-name]
DESCRIPTION
This command generates a model class with the specified class name.
PARAMETERS
* class-name: required, model class name. By default, the generated
model class file will be placed under the directory aliased as
'application.models'. To override this default, specify the class
name in terms of a path alias, e.g., 'application.somewhere.ClassName'.
If the model class belongs to a module, it should be specified
as 'ModuleID.models.ClassName'.
If the class name ends with '*', then a model class will be generated
for EVERY table in the database.
If the class name contains a regular expression deliminated by slashes,
then a model class will be generated for those tables whose name
matches the regular expression. If the regular expression contains
sub-patterns, the first sub-pattern will be used to generate the model
class name.
* table-name: optional, the associated database table name. If not given,
it is assumed to be the model class name.
Note, when the class name ends with '*', this parameter will be
ignored.
EXAMPLES
* Generates the Post model:
model Post
* Generates the Post model which is associated with table 'posts':
model Post posts
* Generates the Post model which should belong to module 'admin':
model admin.models.Post
* Generates a model class for every table in the current database:
model *
* Same as above, but the model class files should be generated
under 'protected/models2':
model application.models2.*
* Generates a model class for every table whose name is prefixed
with 'tbl_' in the current database. The model class will not
contain the table prefix.
model /^tbl_(.*)$/
* Same as above, but the model class files should be generated
under 'protected/models2':
model application.models2./^tbl_(.*)$/
EOD;
}
/**
* Checks if the given table is a "many to many" helper table.
* Their PK has 2 fields, and both of those fields are also FK to other separate tables.
* @param CDbTableSchema $table table to inspect
* @return boolean true if table matches description of helper table.
*/
protected function isRelationTable($table)
{
$pk=$table->primaryKey;
return (count($pk) === 2 // we want 2 columns
&& isset($table->foreignKeys[$pk[0]]) // pk column 1 is also a foreign key
&& isset($table->foreignKeys[$pk[1]]) // pk column 2 is also a foreign key
&& $table->foreignKeys[$pk[0]][0] !== $table->foreignKeys[$pk[1]][0]); // and the foreign keys point different tables
}
/**
* Generate code to put in ActiveRecord class's relations() function.
* @return array indexed by table names, each entry contains array of php code to go in appropriate ActiveRecord class.
* Empty array is returned if database couldn't be connected.
*/
protected function generateRelations()
{
$this->_relations=array();
$this->_classes=array();
foreach($this->_schema->getTables() as $table)
{
$tableName=$table->name;
if ($this->isRelationTable($table))
{
$pks=$table->primaryKey;
$fks=$table->foreignKeys;
$table0=$fks[$pks[1]][0];
$table1=$fks[$pks[0]][0];
$className0=$this->getClassName($table0);
$className1=$this->getClassName($table1);
$unprefixedTableName=$this->removePrefix($tableName,true);
$relationName=$this->generateRelationName($table0, $table1, true);
$this->_relations[$className0][$relationName]="array(self::MANY_MANY, '$className1', '$unprefixedTableName($pks[0], $pks[1])')";
$relationName=$this->generateRelationName($table1, $table0, true);
$this->_relations[$className1][$relationName]="array(self::MANY_MANY, '$className0', '$unprefixedTableName($pks[0], $pks[1])')";
}
else
{
$this->_classes[$tableName]=$className=$this->getClassName($tableName);
foreach ($table->foreignKeys as $fkName => $fkEntry)
{
// Put table and key name in variables for easier reading
$refTable=$fkEntry[0]; // Table name that current fk references to
$refKey=$fkEntry[1]; // Key in that table being referenced
$refClassName=$this->getClassName($refTable);
// Add relation for this table
$relationName=$this->generateRelationName($tableName, $fkName, false);
$this->_relations[$className][$relationName]="array(self::BELONGS_TO, '$refClassName', '$fkName')";
// Add relation for the referenced table
$relationType=$table->primaryKey === $fkName ? 'HAS_ONE' : 'HAS_MANY';
$relationName=$this->generateRelationName($refTable, $this->removePrefix($tableName), $relationType==='HAS_MANY');
$this->_relations[$refClassName][$relationName]="array(self::$relationType, '$className', '$fkName')";
}
}
}
}
protected function getClassName($tableName)
{
return isset($this->_tables[$tableName]) ? $this->_tables[$tableName] : $this->generateClassName($tableName);
}
/**
* Generates model class name based on a table name
* @param string $tableName the table name
* @return string the generated model class name
*/
protected function generateClassName($tableName)
{
return str_replace(' ','',
ucwords(
trim(
strtolower(
str_replace(array('-','_'),' ',
preg_replace('/(?<![A-Z])[A-Z]/', '