. */ namespace Doctrine\ORM\Mapping\Driver; use Doctrine\Common\Cache\ArrayCache, Doctrine\Common\Annotations\AnnotationReader, Doctrine\DBAL\Schema\AbstractSchemaManager, Doctrine\ORM\Mapping\ClassMetadataInfo, Doctrine\ORM\Mapping\MappingException, Doctrine\Common\Util\Inflector; /** * The DatabaseDriver reverse engineers the mapping metadata from a database * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Guilherme Blanco * @author Jonathan Wage */ class DatabaseDriver implements Driver { /** The SchemaManager. */ private $_sm; /** * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading * docblock annotations. * * @param AnnotationReader $reader The AnnotationReader to use. */ public function __construct(AbstractSchemaManager $schemaManager) { $this->_sm = $schemaManager; } /** * {@inheritdoc} */ public function loadMetadataForClass($className, ClassMetadataInfo $metadata) { $tableName = $className; $className = Inflector::classify($tableName); $metadata->name = $className; $metadata->primaryTable['name'] = $tableName; $columns = $this->_sm->listTableColumns($tableName); if($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { $foreignKeys = $this->_sm->listTableForeignKeys($tableName); } else { $foreignKeys = array(); } $indexes = $this->_sm->listTableIndexes($tableName); $ids = array(); $fieldMappings = array(); foreach ($columns as $column) { // Skip columns that are foreign keys foreach ($foreignKeys as $foreignKey) { if (in_array(strtolower($column->getName()), array_map('strtolower', $foreignKey->getColumns()))) { continue(2); } } $fieldMapping = array(); if (isset($indexes['primary']) && in_array($column->getName(), $indexes['primary']->getColumns())) { $fieldMapping['id'] = true; } $fieldMapping['fieldName'] = Inflector::camelize(strtolower($column->getName())); $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['notnull'] = $column->getNotNull(); if (isset($fieldMapping['id'])) { $ids[] = $fieldMapping; } else { $fieldMappings[] = $fieldMapping; } } if ($ids) { if (count($ids) == 1) { $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); } foreach ($ids as $id) { $metadata->mapField($id); } } foreach ($fieldMappings as $fieldMapping) { $metadata->mapField($fieldMapping); } foreach ($foreignKeys as $foreignKey) { if (count($foreignKey->getColumns()) != 1) { throw new MappingException( "Cannot generate mapping for table '".$tableName."' with foreign keys with multiple local columns." ); } $cols = $foreignKey->getColumns(); $localColumn = current($cols); $fkCols = $foreignKey->getForeignColumns(); if (count($fkCols) != 1) { throw new MappingException( "Cannot generate mapping for table '".$tableName."' with foreign keys with multiple foreign columns." ); } $foreignColumn = current($fkCols); $associationMapping = array(); $associationMapping['fieldName'] = Inflector::camelize(str_ireplace('_id', '', $localColumn)); $associationMapping['columnName'] = $localColumn; $associationMapping['targetEntity'] = Inflector::classify($foreignKey->getForeignTableName()); $associationMapping['joinColumns'][] = array( 'name' => $localColumn, 'referencedColumnName' => $foreignColumn ); $metadata->mapManyToOne($associationMapping); } } /** * {@inheritdoc} */ public function isTransient($className) { return true; } /** * {@inheritDoc} */ public function getAllClassNames() { $classes = array(); foreach ($this->_sm->listTables() as $table) { $classes[] = $table->getName(); // TODO: Why is this not correct? Inflector::classify($table->getName()); } return $classes; } }