Ingeniería en inversa en PHP con Doctrine (Reverse Engineering DB)

Bueno ahora voy a colocar como obtener las entidades y el mapeo desde una base de datos ya existente, sin embargo esto no es un proceso seguro ya que depende completamente de la base de datos, si tienes una base de datos compleja puede que el resultado no sea el esperado, yo recomiendo hacer el mapeo manualmente, pero si tu modelo de base es bueno y esta correctamente desarrollado puedes intentar la ingeniería en inversa.

Hay que tomar las consideraciones que vienen en la documentación:

Reverse Engineering is not always working perfectly depending on special cases.

Reverse Engineering is a one-time process that can get you started with a project. Converting an existing database schema into mapping files only detects about 70-80% of the necessary mapping information. Additionally the detection from an existing database cannot detect inverse associations, inheritance types, entities with foreign keys as primary keys and many of the semantical operations on associations such as cascade.

Requisitos:

Procedimiento

Vamos generar las entidades de dos formas:

1. Desde consola con el comando doctrine

Cuando se instala doctrine incluye un pequeño interprete de comandos , primero vamos a generar una base de datos:

CREATE SCHEMA doctrine;
USE doctrine;

CREATE TABLE `doctrine`.`User` (
  id INTEGER  NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50)  NOT NULL,
  password VARCHAR(50)  NOT NULL
)
ENGINE = InnoDB;

Creas una carpeta para el ejemplo en “/var/www/doctrine2“, luego generas dentro un archivo llamado cli-config.php y una carpeta llamada “Entities” y colocas lo siguiente:

<?php

use Doctrine\ORM\Tools\Setup;

require_once “Doctrine/ORM/Tools/Setup.php”;

// (1) Class Auto Loader
Setup::registerAutoloadPEAR();

// (2) Configuración
$config = new \Doctrine\ORM\Configuration();

// (3) Caché
$cache = new \Doctrine\Common\Cache\ArrayCache();
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);

// (4) Driver
$driverImpl = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(array(__DIR__.”/Entities”));
//$driverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver(“./config/yml/”);
//$driverImpl = new Doctrine\ORM\Mapping\Driver\XmlDriver(“./config/xml/”);

$config->setMetadataDriverImpl($driverImpl);

// (5) Proxies
$config->setProxyDir(__DIR__ . ‘./Proxies’);
$config->setProxyNamespace(‘Proxies’);

// (6) Conexión
$connectionOptions = array(
‘dbname’    => ‘doctrine’,
‘user’      => ‘root’,
‘password’  => ‘root’,
‘host’      => ‘localhost’,
‘driver’    => ‘pdo_mysql’,
);

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

// (8) HelperSet
$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)
));

?>

Antes de generar los archivos hay que destacar algunas cosas importantes:

  • Debes seleccionar el driver que doctrine va a utilizar para crear las Classes, Classes con anotaciones o los archivos de configuración (xml, yml), en el punto cuatro puedes elegir el driver, (ahorita yo lo voy a hacer con anotaciones pero si quieres algún otro solo tienes que descomentarlo)

Ahora abres una terminal donde tienes el archivo y puedes ejecutar cualquiera de los siquientes comandos, segun corresponda:

  • Generar mapeo con xml
    doctrine orm:convert-mapping --from-database xml config/xml/
  • Generar mapeo con yml
    doctrine orm:convert-mapping --from-database yml config/yml/
  • Generar Classes
    doctrine orm:generate-entities Entities/
  • Generar Classes con anotaciones
    doctrine orm:generate-entities --generate-annotations=true --regenerate-entities=true Entities/

Nota:Para generar las clases es necesario que hayas generado primero los archivos de mapeo ya sea xml o yml, porque si no te va a lanzar una Exception.

Al final debes de ver algo como esto:

2. Desde el código fuente

Personalmente me agrada más este método porque no necesito de la consola, además puede ser configurado con lineas de código. Creas un nuevo archivo por ejemplo cli-config2.php y colocas lo siguiente:

<?php
/**
* Created by JetBrains PhpStorm.
* User: alberto
* Date: 17/11/11
* Time: 06:07 PM
* To change this template use File | Settings | File Templates.
*/
use Doctrine\ORM\Tools\Setup;
require_once “Doctrine/ORM/Tools/Setup.php”;// (1) Load Classes
Setup::registerAutoloadPEAR();// (2) Configuración
$config = new \Doctrine\ORM\Configuration();// (3) Caché, in production use APC
$cache = new \Doctrine\Common\Cache\ArrayCache();
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);// (4) Driver select Driver [annotationsClasses,classes,xml, yml]
$driverType=”annotationsClasses”;
$driverImpl = getDriver($driverType);

$config->setMetadataDriverImpl($driverImpl);

// (5) Proxies
$config->setProxyDir(__DIR__.’/Proxies’);
$config->setProxyNamespace(‘Proxies’);

// (6) Conexión
$connectionOptions = array(
‘dbname’    => ‘doctrine’,
‘user’      => ‘root’,
‘password’  => ‘root’,
‘host’      => ‘localhost’,
‘driver’    => ‘pdo_mysql’,
);

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

// (8) HelperSet
$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)
));

// Load Metadata
$em->getConfiguration()->setMetadataDriverImpl(
new Doctrine\ORM\Mapping\Driver\DatabaseDriver( $em->getConnection()->getSchemaManager())
);

$cmf = new Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);
$metadata = $cmf->getAllMetadata();

$cme = new Doctrine\ORM\Tools\Export\ClassMetadataExporter();

//Create mapping metadata
if($driverType==”xml” || $driverType==”yml”){
$exporter = $cme->getExporter($driverType, __DIR__.”/config/”.$driverType);
$exporter->setMetadata($metadata);
$exporter->export();
echo “make config files: “.$driverType;
}

// Create Objects
makeEntities($cme,$metadata,$driverType);

function makeEntities($cme,$metadata,$driverType){

echo “make entities…”;
// Generate Entities

$exporter = $cme->getExporter(‘annotation’, ‘config/ann’);
$generator = new Doctrine\ORM\Tools\EntityGenerator();
$generator->setUpdateEntityIfExists(true);    // only update if class already exists
$generator->setGenerateStubMethods(true);
if($driverType==”annotationsClasses”){
$generator->setGenerateAnnotations(true);
}
else{
$generator->setGenerateAnnotations(false);
}
$result = $generator->generate($metadata, __DIR__.”/Entities”);

echo “done…”;

}

function getDriver($variable){

$driverImpl= null;

if($variable==”annotationsClasses” || $variable==”classes”)
{
$driverImpl = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(array(__DIR__.”/Entities”));
}
else if($variable==”xml”){
$driverImpl = new Doctrine\ORM\Mapping\Driver\XmlDriver(__DIR__.”/config/xml/”);
}
else if($variable==”yml”){
$driverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__.”/config/yml/”);
}
else{
echo “Select one Driver…”;
exit;
}
return $driverImpl;
}

El archivo en escencia es el mismo que el anterior, solo tiene unas cuantas lineas extra de código y encapsule algunas en funciones. El truco está en el punto cuatro, solo debes seleccionar lo que deseas generar (annonatedClasses, classes, xml, yml). Si seleccionas los archivos de configuración creará tambien sus clases.

Para ejecutar el acrhivo puedes ejecutarlo desde tu navegador (en mi caso yo lo he probado desde el Intellij).

Anexo los archivos de código fuente.



Referencias:

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s