DDC-2476 Better approach for reverse engineer. Some refactoring done to driver.
This commit is contained in:
parent
0d834d0bd4
commit
3d86c82a7f
@ -19,12 +19,15 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
@ -84,249 +87,15 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager.
|
||||
* Set the namespace for the generated entities.
|
||||
*
|
||||
* @param array $entityTables
|
||||
* @param array $manyToManyTables
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTables($entityTables, $manyToManyTables)
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
foreach ($entityTables as $table) {
|
||||
$className = $this->getClassNameForTable($table->getName());
|
||||
$this->classToTableNames[$className] = $table->getName();
|
||||
$this->tables[$table->getName()] = $table;
|
||||
}
|
||||
foreach ($manyToManyTables as $table) {
|
||||
$this->manyToManyTables[$table->getName()] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\Mapping\MappingException
|
||||
*/
|
||||
private function reverseEngineerMappingFromDatabase()
|
||||
{
|
||||
if ($this->tables !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
foreach ($tables as $tableName => $table) {
|
||||
/* @var $table \Doctrine\DBAL\Schema\Table */
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $table->getForeignKeys();
|
||||
} else {
|
||||
$foreignKeys = array();
|
||||
}
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
if ( ! $table->hasPrimaryKey()) {
|
||||
throw new MappingException(
|
||||
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
|
||||
"support reverse engineering from tables that don't have a primary key."
|
||||
);
|
||||
}
|
||||
|
||||
$pkColumns = $table->getPrimaryKey()->getColumns();
|
||||
sort($pkColumns);
|
||||
sort($allForeignKeyColumns);
|
||||
|
||||
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
|
||||
$this->manyToManyTables[$tableName] = $table;
|
||||
} else {
|
||||
// lower-casing is necessary because of Oracle Uppercase Tablenames,
|
||||
// assumption is lower-case + underscore separated.
|
||||
$className = $this->getClassNameForTable($tableName);
|
||||
$this->tables[$tableName] = $table;
|
||||
$this->classToTableNames[$className] = $tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if (!isset($this->classToTableNames[$className])) {
|
||||
throw new \InvalidArgumentException("Unknown class " . $className);
|
||||
}
|
||||
|
||||
$tableName = $this->classToTableNames[$className];
|
||||
|
||||
$metadata->name = $className;
|
||||
$metadata->table['name'] = $tableName;
|
||||
|
||||
$columns = $this->tables[$tableName]->getColumns();
|
||||
$indexes = $this->tables[$tableName]->getIndexes();
|
||||
try {
|
||||
$primaryKeyColumns = $this->tables[$tableName]->getPrimaryKey()->getColumns();
|
||||
} catch(SchemaException $e) {
|
||||
$primaryKeyColumns = array();
|
||||
}
|
||||
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
|
||||
} else {
|
||||
$foreignKeys = array();
|
||||
}
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
$fieldMappings = array();
|
||||
foreach ($columns as $column) {
|
||||
$fieldMapping = array();
|
||||
|
||||
if (in_array($column->getName(), $allForeignKeyColumns)) {
|
||||
continue;
|
||||
} else if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
|
||||
$fieldMapping['id'] = true;
|
||||
}
|
||||
|
||||
$fieldMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $column->getName(), false);
|
||||
$fieldMapping['columnName'] = $column->getName();
|
||||
$fieldMapping['type'] = strtolower((string) $column->getType());
|
||||
|
||||
if ($column->getType() instanceof \Doctrine\DBAL\Types\StringType) {
|
||||
$fieldMapping['length'] = $column->getLength();
|
||||
$fieldMapping['fixed'] = $column->getFixed();
|
||||
} else if ($column->getType() instanceof \Doctrine\DBAL\Types\IntegerType) {
|
||||
$fieldMapping['unsigned'] = $column->getUnsigned();
|
||||
}
|
||||
$fieldMapping['nullable'] = $column->getNotNull() ? false : true;
|
||||
|
||||
if (isset($fieldMapping['id'])) {
|
||||
$ids[] = $fieldMapping;
|
||||
} else {
|
||||
$fieldMappings[] = $fieldMapping;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ids) {
|
||||
// We need to check for the columns here, because we might have associations as id as well.
|
||||
if (count($primaryKeyColumns) == 1) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$metadata->mapField($id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fieldMappings as $fieldMapping) {
|
||||
$metadata->mapField($fieldMapping);
|
||||
}
|
||||
|
||||
foreach ($this->manyToManyTables as $manyTable) {
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
// foreign key maps to the table of the current entity, many to many association probably exists
|
||||
if (strtolower($tableName) == strtolower($foreignKey->getForeignTableName())) {
|
||||
$myFk = $foreignKey;
|
||||
$otherFk = null;
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
if ($foreignKey != $myFk) {
|
||||
$otherFk = $foreignKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$otherFk) {
|
||||
// the definition of this many to many table does not contain
|
||||
// enough foreign key information to continue reverse engineering.
|
||||
continue;
|
||||
}
|
||||
|
||||
$localColumn = current($myFk->getColumns());
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName());
|
||||
if (current($manyTable->getColumns())->getName() == $localColumn) {
|
||||
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
$associationMapping['joinTable'] = array(
|
||||
'name' => strtolower($manyTable->getName()),
|
||||
'joinColumns' => array(),
|
||||
'inverseJoinColumns' => array(),
|
||||
);
|
||||
|
||||
$fkCols = $myFk->getForeignColumns();
|
||||
$cols = $myFk->getColumns();
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
$fkCols = $otherFk->getForeignColumns();
|
||||
$cols = $otherFk->getColumns();
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['inverseJoinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
}
|
||||
$metadata->mapManyToMany($associationMapping);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$foreignTable = $foreignKey->getForeignTableName();
|
||||
$cols = $foreignKey->getColumns();
|
||||
$fkCols = $foreignKey->getForeignColumns();
|
||||
|
||||
$localColumn = current($cols);
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $localColumn, true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($foreignTable);
|
||||
|
||||
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
|
||||
$associationMapping['fieldName'] = $associationMapping['fieldName'] . "2";
|
||||
}
|
||||
|
||||
if ($primaryKeyColumns && in_array($localColumn, $primaryKeyColumns)) {
|
||||
$associationMapping['id'] = true;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
//Here we need to check if $cols are the same as $primaryKeyColumns
|
||||
if (!array_diff($cols,$primaryKeyColumns)) {
|
||||
$metadata->mapOneToOne($associationMapping);
|
||||
} else {
|
||||
$metadata->mapManyToOne($associationMapping);
|
||||
}
|
||||
}
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,6 +143,376 @@ class DatabaseDriver implements MappingDriver
|
||||
$this->fieldNamesForColumns[$tableName][$columnName] = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager.
|
||||
*
|
||||
* @param array $entityTables
|
||||
* @param array $manyToManyTables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTables($entityTables, $manyToManyTables)
|
||||
{
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
|
||||
foreach ($entityTables as $table) {
|
||||
$className = $this->getClassNameForTable($table->getName());
|
||||
|
||||
$this->classToTableNames[$className] = $table->getName();
|
||||
$this->tables[$table->getName()] = $table;
|
||||
}
|
||||
|
||||
foreach ($manyToManyTables as $table) {
|
||||
$this->manyToManyTables[$table->getName()] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if ( ! isset($this->classToTableNames[$className])) {
|
||||
throw new \InvalidArgumentException("Unknown class " . $className);
|
||||
}
|
||||
|
||||
$tableName = $this->classToTableNames[$className];
|
||||
|
||||
$metadata->name = $className;
|
||||
$metadata->table['name'] = $tableName;
|
||||
|
||||
$this->buildIndexes($metadata);
|
||||
$this->buildFieldMappings($metadata);
|
||||
$this->buildToOneAssociationMappings($metadata);
|
||||
|
||||
foreach ($this->manyToManyTables as $manyTable) {
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
// foreign key maps to the table of the current entity, many to many association probably exists
|
||||
if ( ! (strtolower($tableName) === strtolower($foreignKey->getForeignTableName()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$myFk = $foreignKey;
|
||||
$otherFk = null;
|
||||
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
if ($foreignKey != $myFk) {
|
||||
$otherFk = $foreignKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $otherFk) {
|
||||
// the definition of this many to many table does not contain
|
||||
// enough foreign key information to continue reverse engineering.
|
||||
continue;
|
||||
}
|
||||
|
||||
$localColumn = current($myFk->getColumns());
|
||||
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName());
|
||||
|
||||
if (current($manyTable->getColumns())->getName() == $localColumn) {
|
||||
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
$associationMapping['joinTable'] = array(
|
||||
'name' => strtolower($manyTable->getName()),
|
||||
'joinColumns' => array(),
|
||||
'inverseJoinColumns' => array(),
|
||||
);
|
||||
|
||||
$fkCols = $myFk->getForeignColumns();
|
||||
$cols = $myFk->getColumns();
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
$fkCols = $otherFk->getForeignColumns();
|
||||
$cols = $otherFk->getColumns();
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['inverseJoinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($associationMapping);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\Mapping\MappingException
|
||||
*/
|
||||
private function reverseEngineerMappingFromDatabase()
|
||||
{
|
||||
if ($this->tables !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
|
||||
foreach ($tables as $tableName => $table) {
|
||||
$foreignKeys = ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
|
||||
? $table->getForeignKeys()
|
||||
: array();
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
if ( ! $table->hasPrimaryKey()) {
|
||||
throw new MappingException(
|
||||
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
|
||||
"support reverse engineering from tables that don't have a primary key."
|
||||
);
|
||||
}
|
||||
|
||||
$pkColumns = $table->getPrimaryKey()->getColumns();
|
||||
|
||||
sort($pkColumns);
|
||||
sort($allForeignKeyColumns);
|
||||
|
||||
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
|
||||
$this->manyToManyTables[$tableName] = $table;
|
||||
} else {
|
||||
// lower-casing is necessary because of Oracle Uppercase Tablenames,
|
||||
// assumption is lower-case + underscore separated.
|
||||
$className = $this->getClassNameForTable($tableName);
|
||||
|
||||
$this->tables[$tableName] = $table;
|
||||
$this->classToTableNames[$className] = $tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build indexes from a class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildIndexes(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$indexes = $this->tables[$tableName]->getIndexes();
|
||||
|
||||
foreach($indexes as $index){
|
||||
if ($index->isPrimary()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$indexName = $index->getName();
|
||||
$indexColumns = $index->getColumns();
|
||||
$constraintType = $index->isUnique()
|
||||
? 'uniqueConstraints'
|
||||
: 'indexes';
|
||||
|
||||
$metadata->table[$constraintType][$indexName]['columns'] = $indexColumns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build field mapping from class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildFieldMappings(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$columns = $this->tables[$tableName]->getColumns();
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
$allForeignKeys = array();
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
$fieldMappings = array();
|
||||
|
||||
foreach ($columns as $column) {
|
||||
if (in_array($column->getName(), $allForeignKeys)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldMapping = $this->buildFieldMapping($tableName, $column);
|
||||
|
||||
if ($primaryKeys && in_array($column->getName(), $primaryKeys)) {
|
||||
$fieldMapping['id'] = true;
|
||||
$ids[] = $fieldMapping;
|
||||
}
|
||||
|
||||
$fieldMappings[] = $fieldMapping;
|
||||
}
|
||||
|
||||
// We need to check for the columns here, because we might have associations as id as well.
|
||||
if ($ids && count($primaryKeys) == 1) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
foreach ($fieldMappings as $fieldMapping) {
|
||||
$metadata->mapField($fieldMapping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build field mapping from a schema column definition
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param \Doctrine\DBAL\Schema\Column $column
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function buildFieldMapping($tableName, Column $column)
|
||||
{
|
||||
$fieldMapping = array(
|
||||
'fieldName' => $this->getFieldNameForColumn($tableName, $column->getName(), false),
|
||||
'columnName' => $column->getName(),
|
||||
'type' => strtolower((string) $column->getType()),
|
||||
'nullable' => ( ! $column->getNotNull()),
|
||||
);
|
||||
|
||||
// Type specific elements
|
||||
switch ($fieldMapping['type']) {
|
||||
case Type::TARRAY:
|
||||
case Type::BLOB:
|
||||
case Type::GUID:
|
||||
case Type::JSON_ARRAY:
|
||||
case Type::OBJECT:
|
||||
case Type::SIMPLE_ARRAY:
|
||||
case Type::STRING:
|
||||
case Type::TEXT:
|
||||
$fieldMapping['length'] = $column->getLength();
|
||||
$fieldMapping['fixed'] = $column->getFixed();
|
||||
break;
|
||||
|
||||
case Type::DECIMAL:
|
||||
case Type::FLOAT:
|
||||
$fieldMapping['precision'] = $column->getPrecision();
|
||||
$fieldMapping['scale'] = $column->getScale();
|
||||
break;
|
||||
|
||||
case Type::INTEGER:
|
||||
case Type::BIGINT:
|
||||
case Type::SMALLINT:
|
||||
$fieldMapping['unsigned'] = $column->getUnsigned();
|
||||
break;
|
||||
}
|
||||
|
||||
// Comment
|
||||
if (($comment = $column->getComment()) !== null) {
|
||||
$fieldMapping['comment'] = $comment;
|
||||
}
|
||||
|
||||
// Default
|
||||
if (($default = $column->getDefault()) !== null) {
|
||||
$fieldMapping['default'] = $default;
|
||||
}
|
||||
|
||||
return $fieldMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build to one (one to one, many to one) association mapping from class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildToOneAssociationMappings(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$foreignTableName = $foreignKey->getForeignTableName();
|
||||
$fkColumns = $foreignKey->getColumns();
|
||||
$fkForeignColumns = $foreignKey->getForeignColumns();
|
||||
$localColumn = current($fkColumns);
|
||||
$associationMapping = array(
|
||||
'fieldName' => $this->getFieldNameForColumn($tableName, $localColumn, true),
|
||||
'targetEntity' => $this->getClassNameForTable($foreignTableName),
|
||||
);
|
||||
|
||||
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
|
||||
$associationMapping['fieldName'] .= '2'; // "foo" => "foo2"
|
||||
}
|
||||
|
||||
if ($primaryKeys && in_array($localColumn, $primaryKeys)) {
|
||||
$associationMapping['id'] = true;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($fkColumns); $i++) {
|
||||
$associationMapping['joinColumns'][] = array(
|
||||
'name' => $fkColumns[$i],
|
||||
'referencedColumnName' => $fkForeignColumns[$i],
|
||||
);
|
||||
}
|
||||
|
||||
// Here we need to check if $fkColumns are the same as $primaryKeys
|
||||
if ( ! array_diff($fkColumns, $primaryKeys)) {
|
||||
$metadata->mapOneToOne($associationMapping);
|
||||
} else {
|
||||
$metadata->mapManyToOne($associationMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive schema table definition foreign keys.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Schema\Table $table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTableForeignKeys(Table $table)
|
||||
{
|
||||
return ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
|
||||
? $table->getForeignKeys()
|
||||
: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive schema table definition primary keys.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Schema\Table $table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTablePrimaryKeys(Table $table)
|
||||
{
|
||||
try {
|
||||
return $table->getPrimaryKey()->getColumns();
|
||||
} catch(SchemaException $e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version.
|
||||
*
|
||||
@ -413,16 +552,4 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
return Inflector::camelize($columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace for the generated entities.
|
||||
*
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
}
|
||||
|
@ -145,4 +145,57 @@ class DatabaseDriverTest extends DatabaseDriverTestCase
|
||||
|
||||
$this->assertEquals(0, count($metadatas['DbdriverBaz']->associationMappings), "no association mappings should be detected.");
|
||||
}
|
||||
|
||||
public function testLoadMetadataFromDatabaseDetail()
|
||||
{
|
||||
if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Platform does not support foreign keys.');
|
||||
}
|
||||
|
||||
$table = new \Doctrine\DBAL\Schema\Table("dbdriver_foo");
|
||||
$table->addColumn('id', 'integer',array('unsigned'=>true));
|
||||
$table->setPrimaryKey(array('id'));
|
||||
$table->addColumn('column_unsigned','integer',array('unsigned'=>true));
|
||||
$table->addColumn('column_comment','string',array('comment'=>'test_comment'));
|
||||
$table->addColumn('column_default','string',array('default'=>'test_default'));
|
||||
$table->addColumn('column_decimal','decimal',array('precision'=>4,'scale'=>3));
|
||||
|
||||
$table->addColumn('column_index1','string');
|
||||
$table->addColumn('column_index2','string');
|
||||
$table->addIndex(array('column_index1','column_index2'),'index1');
|
||||
|
||||
$table->addColumn('column_unique_index1','string');
|
||||
$table->addColumn('column_unique_index2','string');
|
||||
$table->addUniqueIndex(array('column_unique_index1','column_unique_index2'),'unique_index1');
|
||||
$this->_sm->dropAndCreateTable($table);
|
||||
|
||||
$metadatas = $this->extractClassMetadata(array("DbdriverFoo"));
|
||||
|
||||
$this->assertArrayHasKey('DbdriverFoo', $metadatas);
|
||||
$metadata = $metadatas['DbdriverFoo'];
|
||||
|
||||
$this->assertArrayHasKey('id', $metadata->fieldMappings);
|
||||
$this->assertEquals('id', $metadata->fieldMappings['id']['fieldName']);
|
||||
$this->assertEquals('id', strtolower($metadata->fieldMappings['id']['columnName']));
|
||||
$this->assertEquals('integer', (string)$metadata->fieldMappings['id']['type']);
|
||||
|
||||
$this->assertArrayHasKey('columnUnsigned', $metadata->fieldMappings);
|
||||
$this->assertTrue($metadata->fieldMappings['columnUnsigned']['unsigned']);
|
||||
|
||||
$this->assertArrayHasKey('columnComment', $metadata->fieldMappings);
|
||||
$this->assertEquals('test_comment', $metadata->fieldMappings['columnComment']['comment']);
|
||||
|
||||
$this->assertArrayHasKey('columnDefault', $metadata->fieldMappings);
|
||||
$this->assertEquals('test_default', $metadata->fieldMappings['columnDefault']['default']);
|
||||
|
||||
$this->assertArrayHasKey('columnDecimal', $metadata->fieldMappings);
|
||||
$this->assertEquals(4, $metadata->fieldMappings['columnDecimal']['precision']);
|
||||
$this->assertEquals(3, $metadata->fieldMappings['columnDecimal']['scale']);
|
||||
|
||||
$this->assertTrue(!empty($metadata->table['indexes']['index1']['columns']));
|
||||
$this->assertEquals(array('column_index1','column_index2'),$metadata->table['indexes']['index1']['columns']);
|
||||
|
||||
$this->assertTrue(!empty($metadata->table['uniqueConstraints']['unique_index1']['columns']));
|
||||
$this->assertEquals(array('column_unique_index1','column_unique_index2'),$metadata->table['uniqueConstraints']['unique_index1']['columns']);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user