Inicio > Bases de datos, Doctrine > Configuración de Doctrine 2

Configuración de Doctrine 2

Vamos a ver como configurar Doctrine 2 paso a paso. Recordar que no es una guía exhausta de los pasos a seguir. Es una traducción brevemente resumida de la documentación oficial que podeis encontrar en www.doctrine-project.org.

Configurar Doctrine 2 es un procedimiento simple de dos pasos:

  1. Cargar las clases.
  2. Obtener una instancia del EntityManager.

Cargar las clases de Doctrine

Necesitamos configurar el cargador de clase (autoloader) para que se carguen las clases de Doctrine según las vayamos necesitando. El namespace Doctrine contiene un cargador de clase muy rápido que podemos utilizar para cargar las clases del ORM y otras clases que necesitemos.

Configurar el autoloader es diferente dependiendo de como hayamos instalado Doctrine 2. Si nos hemos bajado el paquete desde la web o instalado desde Pear basta con hacer lo siguiente:

<?php

require '/path/to/libraries/Doctrine/Common/ClassLoader.php';
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', '/path/to/libraries');
$classLoader->register(); // register on SPL autoload stack

Si no utilizamos Doctrine 2 junto con Symfony debemos de cargar también un namespace adicional para ser capaz de utilizar el CLI (línea de comandos) de Doctrine y el driver que mapea desde archivos YAML.

$classloader = new \Doctrine\Common\ClassLoader('Symfony', '/path/to/libraries/Doctrine');
$classloader->register();

Obtener una instancia del EntityManager

Una vez hayamos registrado los namespaces en el autoloader tenemos que obtener una instancia del EntityManager ya que es el principal punto de acceso a la funcionalidad del ORM.

Para obtener una instancia del EntityManager necesitamos crear una instancia de Doctrine\ORM\Configuration y establecer unas opciones de configuración de la base de datos.

<?php
use Doctrine\ORM\EntityManager,
    Doctrine\ORM\Configuration;

// ...

if ($applicationMode == "development") {
    $cache = new \Doctrine\Common\Cache\ArrayCache;
} else {
    $cache = new \Doctrine\Common\Cache\ApcCache;
}

$config = new Configuration;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');

if ($applicationMode == "development") {
    $config->setAutoGenerateProxyClasses(true);
} else {
    $config->setAutoGenerateProxyClasses(false);
}

$connectionOptions = array(
    'driver' => 'pdo_sqlite',
    'path' => 'database.sqlite'
);

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

No usar Doctrine sin una cache de consultas y metadatos ya que Doctrine está optimizado para trabajar con cachés: Doctrine cahealos metadatos con la información del mapeo y las conversiones entre DQL y SQL. El driver de caché recomendado es APC, http://www.php.net/apc.

NOTA: Esto es lo que dice la documentación de Doctrine 2 para conseguir obtener una instancia del EntityManager. Yo he sufrido un poco más, sobretodo porque no me aclaraba mucho con la novedad de los namespaces. Pero en cuanto le coges el truco te das cuenta de que los namespaces te ayudan mucho a estructurar el código y hacerlo mucho más claro.

Dejo por aquí el código que he adaptado para probar la configuración inicial de Doctrine 2. Lo único que pueda dar problemas a la hora de configurarlo es establecer bien las rutas a las clases dentro de tu sistema de archivos. Yo he optado por utilizar dirname(__FILE__) que te devuelve la ruta absoluta del directorio donde está contenido tu script de prueba. Si os fijáis lo he colocado en un nivel superior a la carpeta Doctrine que es la que contiene las carpetas Common, DBAL, ORM y Symfony. Además he añadido un vardump de la instancia que he recuperado para ver si la estaba creando bien o se había producido algún error. De todas formas activad los errores para poder ver que está sucediendo en todo momento. Además he configurado las opciones de conexión para utilizar una base de datos prueba desde MySQL.

<?php

require 'Doctrine/Common/ClassLoader.php';

//Registramos el namespace de las clases de Doctrine.
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', dirname(__FILE__));
$classLoader->register(); 

//Registramos el namespace de las clases de Symfony.
$classloader = new \Doctrine\Common\ClassLoader('Symfony', dirname(__FILE__).DIRECTORY_SEPARATOR.'Doctrine');
$classloader->register();

use Doctrine\ORM\EntityManager,
    Doctrine\ORM\Configuration,
    Symfony\Component\Yaml\Yaml;

echo \Symfony\Component\Yaml\Yaml::dump(array('prueba' => 'prueba'));

$applicationMode = "development";

if ($applicationMode == "development") {
    $cache = new \Doctrine\Common\Cache\ArrayCache;
} else {
    $cache = new \Doctrine\Common\Cache\ApcCache;
}

$config = new Configuration;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver(dirname(__FILE__).DIRECTORY_SEPARATOR.'Entities');
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setProxyDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'Entities');
$config->setProxyNamespace('MyProject\Proxies');

if ($applicationMode == "development") {
    $config->setAutoGenerateProxyClasses(true);
} else {
    $config->setAutoGenerateProxyClasses(false);
}

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

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

var_dump($em);

Opciones de configuración

Este apartado describe todas las opciones de configuración que podemos establecer en la instancia \Doctrine\ORM\Configuration. Las voy a tratar muy por encima ya que podéis encontrar más información donde ya sabéis.

Proxy Directory (REQUERIDO):
<?php
$config->setProxyDir($dir);
$config->getProxyDir();

Establece/obtiene el directorio donde Doctrine generará las clases proxy.

Proxy Namespace (REQUERIDO):
<?php
$config->setProxyNamespace($namespace);
$config->getProxyNamespace();

Establece/obtiene el namespace utilizado para generar las clases proxy.

Metadata Driver (REQUERIDO):
<?php
$config->setMetadataDriverImpl($driver);
$config->getMetadataDriverImpl();

Establece/obtiene la implementación del driver utilizado para mapear los metadatos.

Hay cuatro implementaciones disponibles:

  • Doctrine\ORM\Mapping\Driver\AnnotationDriver: Mapea la información a partir de anotaciones en el código fuente.
  • Doctrine\ORM\Mapping\Driver\XmlDriver: Mapea la información a partir de un fichero XML.
  • Doctrine\ORM\Mapping\Driver\YamlDriver: Mapea la información a partir de un fichero YAML.
  • Doctrine\ORM\Mapping\Driver\DriverChain

El driver que mapea a través de anotaciones puede ser configurado con un método fábrica desde Doctrine\ORM\Configuration:

<?php
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
$config->setMetadataDriverImpl($driverImpl);

El path a tu directorio con las entidades es necesario. Se acepta un único directorio como un string o un array de directorios.

Metadata Cache (RECOMENDADO):
<?php
$config->setMetadataCacheImpl($cache);
$config->getMetadataCacheImpl();

Establece/obtiene la implementación de la caché a utilizar para cachear los metadatos con la información del mapeo.

Se utiliza para evitar tener que mapear la información con cada petición. La implementación de la caché debe implementar la interface Doctrine\Common\Cache\Cache.

Se recomienda utilizar una de las siguientes cachés dependiendo del entorno.

En producción:

  • Doctrine\Common\Cache\ApcCache
  • Doctrine\Common\Cache\MemcacheCache
  • Doctrine\Common\Cache\XcacheCache

En desarrollo:

  • Doctrine\Common\Cache\ArrayCache
Query Cache (RECOMENDADO):
<?php
$config->setQueryCacheImpl($cache);
$config->getQueryCacheImpl();

Igual a la anterior pero utilizada para cachear las consultas DQL, es decir la traducción de las consultas DQL a las consultas SQL finales.

SQL Logger (OPCIONAL):
<?php
$config->setSQLLogger($logger);
$config->getSQLLogger();

Establece/obtiene el logger utilizado para mantener un log de todas las consultas SQL que son ejecutadas por Doctrine. La clase logger debe de implementar la interfaz Doctrine\DBAL\Logging\SQLLogger.

Autogenerar Proxy Classes (OPCIONAL):
<?php
$config->setAutoGenerateProxyClasses($bool);
$config->getAutoGenerateProxyClasses();

Establece/obtiene si las clases proxy deben de ser generadas automaticamente por Doctrine en tiempo de ejecución. Si lo establecemos a FALSE deberán ser generadas manualmente a través de la línea de comandos de Doctrine utilizando la tarea generate-proxies. El valor recomendado para entornos de producción es FALSE.

La variable $connectionOptions pasada como primer argumento al EntityManager::create() es el mismo array que se le pasa a una instancia de Doctrine\DBAL\Connection. Podéis consultar todas las opciones en la documentación del proyecto DBAL: http://www.doctrine-project.org/docs/dbal/2.0/en/reference/configuration.html.

Anuncios
  1. Andrés
    26 abril, 2011 en 18:13

    Hola Francisco, muy interesante tu artículo sobre Doctrine 2. Tengo una duda, mi servidor no soporta el uso de Cache, es decir no puedo instalar ni APC, ni Memcache ni XCache, ¿hay una pérdida muy significativa de rendimiento con Doctrine, si no se utiliza caché de por medio? ¿Se puede utilizar el ArrayCache para ambientes de producción?

    Muchas gracias y felicitaciones por el blog! contiene articulos muy buenos y prácticos.

    • 26 abril, 2011 en 18:19

      Buenas Andrés.

      El impacto en el rendimiento es bastante grande al tener que procesar en cada petición HTTP todas las entidades, todas las consultas DQL y demás.

      No he utilizado aún Doctrine2 en un entorno de producción estable pero como última alternativa puedes utilizar el driver ArrayCache. Es algo más lento pero tienes la ventaja de no tener que instalar nada ni configurar el php.ini.

      Además si sola la utilizas para lo básico que es guardar los metadatos de las entidades y las consultas DQL te sirve perfectamente porque tampoco es una gran cantidad de datos. Si lo quieres para cachear los resultados de las consultas pues ya es menos efectivo que los demás drivers, pero mejor eso que nada.

  2. chelmist
    27 abril, 2011 en 12:32

    Buenas Francisco gracias por tu blog.

    Tengo una duda en este tuto. Yo tengo symfony instalado sin configurar aun.

    Quisiera saber en que directorio dentro de la carpeta symfony, debemos de poner el archivo que contiene este código :

    register(); // register on SPL autoload stack

    Un cordial Saludo,

    • 27 abril, 2011 en 13:18

      Lo bueno de Symfony2 es que no tienes que configurar el namespace de Doctrine porque ya viene configurado por defecto. Lo que tendrás que configurar son las opciones de la base de datos a través del archivo de configuración config.yml situado dentro del directorio app/config.

  3. Rafael Ribeiro
    29 abril, 2011 en 5:35

    ¿Cómo puedo solucionar esto? No entiendo el problema.
    Doctrine\ORM\Mapping\MappingException: Class entidades\Users is not a valid entity or mapped super class.

    map/
    Doctrine/
    entidades/
    Users.php
    proxes/
    index.php

    id;
    }

    public function setId($id) {
    $this->id = $id;
    }

    public function getName() {
    return $this->name;
    }

    public function setName($name) {
    $this->name = $name;
    }

    }
    ?>

    setEntityNamespaces(array(“entidades”));
    $configuration->setMetadataCacheImpl(new Doctrine\Common\Cache\ArrayCache());
    $configuration->setMetadataDriverImpl($configuration->newDefaultAnnotationDriver(array(“entidades”)));
    $configuration->setProxyDir(“entidades”);
    $configuration->setProxyNamespace(‘proxes’);

    $database = array(
    ‘driver’ => ‘pdo_mysql’,
    ‘host’ => ‘localhost’,
    ‘user’ => ‘root’,
    ‘password’ => ”,
    ‘dbname’ => ‘test’
    );

    $em = \Doctrine\ORM\EntityManager::create($database, $configuration);
    $find = $em->getRepository(“entidades\Users”)->find(1);

    ?>

    • juan
      4 agosto, 2012 en 9:39

      tengo e mismo problema como se arregla esto ¿?

      • GerMonti
        3 marzo, 2015 en 18:02

        Yo tuve el mismo problema y habia cambiado los vendors. El problema estaba en las notaciones de la entity
        /**
        @ORM\Table(name=”nombre_tabla”)
        @ORM\Entity(repositoryClass=”lugar_repository”)
        */

        y se solucionó colocando esto

        /**
        * @ORM\Table(name=”nombre_tabla”)
        * @ORM\Entity(repositoryClass=”lugar_repository”)
        */

        es decir me faltaban los asteriscos delante del arroba

  4. Alberto Veliz
    25 julio, 2011 en 15:12

    Buenas hermano una pregunta yo puedo generar los modelos manualmente de que manera por que de verdad que no entiendo como hacerlo ya que en la versión anterior de doctrine se generaban con una función de el mismo pero acá no se como hacerlo tienes una ida estoy empezando a conocer bien el doctrine 2

    • 26 julio, 2011 en 14:27

      Buenas Alberto Veliz. Perdón por el retraso en contestar, hace dos meses que no he podido estar atento al blog.

      En Doctrine 2 y Symfony2 hay varias formas de generar los modelos. Puedes generarlos mediante archivos de configuración en XML, YML o PHP, o mediante anotaciones en el código fuente de la entidad de tu modelo. Incluso si tienes una base de datos bien definida con sus relaciones puedes generarlos mediante ingeniería inversa.

      Si estás utilizando Symfony2 echarás en falta el AdminGenerator que venía con la primera versión. Oficialmente aún no existe uno para la versión dos pero Fabien Potencier ya ha desvelado una gran sorpresa y ya puedes probarlo, un bundle que te genera las entidades y los controladores necesarios para manejar el CRUD de la entidad. Puedes encontrar un vídeo en el que te explica como utilizarlo en la misma portada del sitio oficial de Symfony2: http://symfony.com/

  5. Denis
    19 agosto, 2011 en 15:08

    Saludos Parasitovi!..como siempre, sigo prendido por tu blog para ir aprendiendo..creo tener el mismo problema que Rafael Ribeiro, que la generación de las clases no es correcta. He leido todo lo que publicaste y los links oficiales pero no puedo econtrar la configuración correcta para que me mapee las clases. Pongo un link de un documento que arme para no ponerte un código tan largo en el comentario. Si puedes verlo y decirme algo te voy a agradecer. Saludos
    https://docs.google.com/document/d/1_orj2Xm_XVKEE6jcPoBEn9vOffD6LxjydbWYvsrb_jY/edit?hl=en_US

    • 24 agosto, 2011 en 8:58

      Buenas Denis.

      El error que te está dando es que no está reconociendo la entidad como válida, cosa que ya habrás supuesto. Si estás utilizando Doctrine2 junto a Symfony2 no tienes que poner todo el código para registrar el namespace de Doctrine, ni configurar y crear el EntityManager. Puedes utilizarlo por defecto en los controladores de tu aplicación a través del contenedor de inyección de dependencias. En las entidades que te definas, solo tiene que haber una clase PHP muy básica, en la que definas tus propiedades. En tu caso estás haciendo ingeniería inversa, de una base de datos a tus entidades con anotaciones, pero para que todo funcione en la base de datos deben de estar definidas todas las relaciones entre las diferentes tablas, para que Doctrine2 luego sepa cuales tiene que cruzar.

      No puedo ayudarte más con los datos que me das. Si puedes enséñame la entidad Usuarios que te genera Doctrine para ver mejor la causa. Te remito también a la lista de Symfony en castellano por si allí pueden ayudarte mejor que yo:

      http://groups.google.com/group/symfony-es

      Saludos.

  6. German
    9 diciembre, 2012 en 20:06

    hola! yo necesito saber como puedo hacer una clase BaseDao (que tiene como atributo el EntityManager) y de ahi hereden las demas clases como PersonaDao y UsuarioDao donde creo sus metodos de alta, baja y modificacion (ABM). Saludos…

  1. 18 noviembre, 2011 en 1:15
  2. 14 septiembre, 2015 en 14:09

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 )

Google+ photo

Estás comentando usando tu cuenta de Google+. 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 )

Conectando a %s

A %d blogueros les gusta esto: