6

Is it possible to generate Doctrine 2 entities, with the relevant docblock annotations, from an existing database schema?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
waigani
  • 3,570
  • 5
  • 46
  • 71
  • Consider not doing this. You'll create better entities if you create them from scratch specifically for your application. Map them with annotations later. – rojoca Nov 02 '10 at 18:24

4 Answers4

8

I had to made these changes for the above code to work..

<?php 
use Doctrine\ORM\Tools\EntityGenerator;
ini_set("display_errors", "On");
$libPath = __DIR__; // Set this to where you have doctrine2 installed
// autoloaders
require_once $libPath . '/Doctrine/Common/ClassLoader.php';

$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', $libPath);
$classLoader->register();

$classLoader = new \Doctrine\Common\ClassLoader('Entities', __DIR__);
$classLoader->register();

$classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__);
$classLoader->register();

// config
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(__DIR__ . '/Entities'));
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');


$connectionParams = array(
    'path' => 'test.sqlite3',
    'driver' => 'pdo_sqlite',
);

$em = \Doctrine\ORM\EntityManager::create($connectionParams, $config);

// custom datatypes (not mapped for reverse engineering)
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('set', 'string');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

// fetch metadata
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
    $em->getConnection()->getSchemaManager()
);
$em->getConfiguration()->setMetadataDriverImpl($driver);
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory($em);
$cmf->setEntityManager($em); 
$classes = $driver->getAllClassNames();
$metadata = $cmf->getAllMetadata(); 
$generator = new EntityGenerator();
$generator->setUpdateEntityIfExists(true);
$generator->setGenerateStubMethods(true);
$generator->setGenerateAnnotations(true);
$generator->generate($metadata, __DIR__ . '/Entities');
print 'Done!';
?>

and mysql connection configuration like :

$connectionParams = array(
    'driver' => 'pdo_mysql',
    'host' => 'localhost',
    'port' => '3306',
    'user' => 'root',
    'password' => 'root',
    'dbname' => 'database',
    'charset' => 'utf8',
);
tawfekov
  • 5,084
  • 3
  • 28
  • 51
dminer
  • 1,121
  • 11
  • 9
  • Thanks! This actually worked. (No like the program included with doctrine). - Although I only used your code from under `$connectionParams` because I'm not confident about your enviroment setup. For example the function `register();` is clearly undefined. Big +1 anyway! – vbence Jul 08 '11 at 10:50
  • This works fine for me... A Big +1 for you. For others who have same problem please use this answer, all others will not work... – Tareq Jan 28 '12 at 07:16
  • @dminer: Your script run succeffully and saved lot of time of mine as i am new bie to Doctrine. This script created entity from database with setter and getter method excluding CRUD operations. What to do next if i want to add all basic CRUD operation in that entity. Please note that my project is not a symphony project but a simple core project. – Neeraj Jan 03 '13 at 09:45
2

Yes it possible though RDBMS data types are not fully supported, so you might have to play with your code a bit before using it in your project. It's not straight forward as Doctrine 1.x used to be but still rather easy. Here some sample code I used myself (create folders properly before using it)

use Doctrine\ORM\Tools\EntityGenerator;

ini_set("display_errors", "On");

$libPath = __DIR__ . '/../lib/doctrine2';

// autoloaders
require_once $libPath . '/Doctrine/Common/ClassLoader.php';

$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', $libPath);
$classLoader->register();

$classLoader = new \Doctrine\Common\ClassLoader('Entities', __DIR__);
$classLoader->register();

$classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__);
$classLoader->register();

// config
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(__DIR__ . '/Entities'));
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');


$connectionParams = array(
    'dbname' => 'xx',
    'user' => 'root',
    'password' => '',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
);

$em = \Doctrine\ORM\EntityManager::create($connectionParams, $config);

// custom datatypes (not mapped for reverse engineering)
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('set', 'string');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

// fetch metadata
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
    $em->getConnection()->getSchemaManager()
);
$classes = $driver->getAllClassNames();
foreach ($classes as $class) {
    //any unsupported table/schema could be handled here to exclude some classes
    if (true) {
        $metadata[] = $cmf->getMetadataFor($class);
    }
}

$em->getConfiguration()->setMetadataDriverImpl($driver);
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory($em);

$generator = new EntityGenerator();
$generator->setUpdateEntityIfExists(true);
$generator->setGenerateStubMethods(true);
$generator->setGenerateAnnotations(true);
$generator->generate($metadata, __DIR__ . '/Entities');

print 'Done!';
Daniel S. W.
  • 51
  • 1
  • 6
  • It fails on line $metadata[] = $cmf->getMetadataFor($class); Why does it try to get the parent of a class that does not yet exist?I mean, these are the names of the Entities which is going to reverse engineer. – Timmo Dec 03 '10 at 14:44
0

I have implemented new command to achieve that https://github.com/umpirsky/doctrine2/blob/master/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesDbCommand.php

Just add it like this:

$cli->addCommands(array(
// DBAL Commands
new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),

// ORM Commands
new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesDbCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),

)); $cli->run();

umpirsky
  • 9,902
  • 13
  • 71
  • 96
0

As of https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php , generating entities is already supported by Doctrine's default CLI

Ocramius
  • 25,171
  • 7
  • 103
  • 107