Generate Doctrine2 Mappings From Existing Database

Object-Relational Mapping (ORM) is a programming technique for converting data between incompatible type systems in object-oriented programming languages. This creates, in effect, a “virtual object database” that can be used from within the programming language. Doctrine is an ORM tool for PHP 5.2.3+ that sits on top of a database abstraction layer. It allows easy access to all types of databases, such as MySQL, through the use of PHP objects. Doctrine2 is the new generation of Doctrine.

Recently I needed to use Doctrine2  and I wanted to make annotated entities for mapping from existing database, because I already had the database schema. (I do not recommend this, though, since some suggest that it is better to make the entities first, or to use XML or YAML mappings.) Supposedly we can make mappings using the CLI, but we still need to make a script, so I prefer an all-script method to accomplish it. I googled for it and found a script by Daniel S. W., but it still had some errors. I edited a bit, and so here it is:

use Doctrine\ORM\Tools\EntityGenerator;

ini_set("display_errors", "On");

// this is not necessary if you use Doctrine2 with PEAR
//$libPath = __DIR__ . '/../lib/doctrine2';

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

//$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', $libPath);	// custom path
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');	// with PEAR
$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' => 'xxx',
  '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()
);

$em->getConfiguration()->setMetadataDriverImpl($driver);
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);	// we must set the EntityManager

$classes = $driver->getAllClassNames();
$metadata = array();
foreach ($classes as $class) {
  //any unsupported table/schema could be handled here to exclude some classes
  if (true) {
    $metadata[] = $cmf->getMetadataFor($class);
  }
}

$generator = new EntityGenerator();
$generator->setAnnotationPrefix('');   // edit: quick fix for No Metadata Classes to process
$generator->setUpdateEntityIfExists(true);	// only update if class already exists
//$generator->setRegenerateEntityIfExists(true);	// this will overwrite the existing classes
$generator->setGenerateStubMethods(true);
$generator->setGenerateAnnotations(true);
$generator->generate($metadata, __DIR__ . '/Entities');

print 'Done!';

EDIT: I added a line to fix the “No Metadata Classes to process”

Command Line Interface

Like I said before, we can also use CLI to generate Doctrine2 mappings. To do this, however, we still need to make a configuration file named cli-config.php in the working folder. I took this code from Doctrine2 cookbook example (we actually don’t need some of the lines, I copy-pasted this from the file I have):

require_once 'Doctrine/Common/ClassLoader.php'; // with PEAR

// Setup Autoloader (1)
// Define application environment
define('APPLICATION_ENV', "development");
/*
defined('APPLICATION_ENV')
  || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
*/
// Autoloader (1)
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');
$classLoader->register();

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

// configuration (2)
$config = new \Doctrine\ORM\Configuration();

// Proxies (3)
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');

$config->setAutoGenerateProxyClasses((APPLICATION_ENV == "development"));

// Driver (4)
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__.DIRECTORY_SEPARATOR."Entities"));
$config->setMetadataDriverImpl($driverImpl);

// Caching Configuration (5)
if (APPLICATION_ENV == "development") {
  $cache = new \Doctrine\Common\Cache\ArrayCache();
} else {
  $cache = new \Doctrine\Common\Cache\ApcCache();
}

$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);

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

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

$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
  'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
  'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));

Now we can use the Doctrine2 CLI command. There’s a command to generate entities, orm:generate-entities, but it requires metadata classes. So we use another command to create mappings, orm:convert-mapping. I’m using XAMPP in Windows, so these steps are for Windows:

  1. Put cli-config.php to the folder where you will run the CLI command.
  2. If you don’t want to set the PATH variable, just copy all files (doctrine.bat, doctrine, doctrine.php) from Doctrine2’s bin folder to your working folder.
  3. You might want to create a folder to put the mapping files. I use a folder named mapping.
  4. Now enter command prompt. Go to your working folder.
  5. Now we’re ready to use the CLI command. Add php at the beginning of every command line:
    php doctrine orm:convert-mapping --from-database annotation .\mapping
    As you can see, I use the parameter --from-database to create mapping from the database to annotated PHP files, which will be put in the mapping folder. You can also change the parameter annotation to xml or yml to create mapping in XML and YAML, respectively.

The mapping files we get from this automated process are still half done, so we need to edit them to suit our needs. The output files from CLI command orm:convert-mapping don’t have setter and getter methods, while the ones from the first PHP script have. Either way we still have to add UNIQUE keys manually.

8 thoughts on “Generate Doctrine2 Mappings From Existing Database

  1. I have the yml files but I’m not sure what to do with those if I want to create all the entities.

    • I’ve only ever used annotated php, no yaml and xml so far. If you meant generating the .php files, you can do it in the console:

      1. Make sure in the cli-config.php file, in the block “driver (4)” it’s using yaml instead of annotation. In the example in the article, change the line:

      $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__.DIRECTORY_SEPARATOR.”Entities”));

      to

      $driverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__.DIRECTORY_SEPARATOR.”yml-mapping”);

      2. Use this console command to convert the yml files to annotated php:

      $ doctrine orm:convert-mapping annotation .\outputdir

  2. Ping-balik: Generate Doctrine2 Mappings From Existing Database « Jalan dan Pikiranku | TechRetriever

Tinggalkan Balasan ke Fiodorovich Batalkan balasan