. */ 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(strtolower($tableName)); $metadata->name = $className; $metadata->table['name'] = $tableName; $columns = $this->_sm->listTableColumns($tableName); if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { $foreignKeys = $this->_sm->listTableForeignKeys($tableName); } else { $foreignKeys = array(); } $allForeignKeyColumns = array(); foreach ($foreignKeys AS $foreignKey) { $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns()); } $indexes = $this->_sm->listTableIndexes($tableName); $ids = array(); $fieldMappings = array(); foreach ($columns as $column) { if (in_array($column->getName(), $allForeignKeyColumns)) { continue; } $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['nullable'] = $column->getNotNull() ? false : true; 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) { $cols = $foreignKey->getColumns(); $localColumn = current($cols); $fkCols = $foreignKey->getForeignColumns(); $associationMapping = array(); $associationMapping['fieldName'] = Inflector::camelize(str_replace('_id', '', strtolower($localColumn))); $associationMapping['targetEntity'] = Inflector::classify($foreignKey->getForeignTableName()); for ($i = 0; $i < count($cols); $i++) { $associationMapping['joinColumns'][] = array( 'name' => $cols[$i], 'referencedColumnName' => $fkCols[$i], ); } $metadata->mapManyToOne($associationMapping); } } /** * {@inheritdoc} */ public function isTransient($className) { return true; } /** * Return all the class names supported by this driver. * * IMPORTANT: This method must return an array of table names because we need * to know the table name after we inflect it to create the entity class name. * * @return array */ public function getAllClassNames() { $classes = array(); foreach ($this->_sm->listTableNames() as $tableName) { $classes[] = $tableName; } return $classes; } }