Como configurar CodeIgniter 2.1.3 con Doctrine 2


CodeIgniter es un entorno de desarrollo abierto que permite crear paginas webs dinámicas con PHP. Su principal objetivo es ayudar a que los desarrolladores, puedan realizar proyectos mucho más rápido que creando toda la estructura desde cero.

También hay que destacar que CodeIgniter es más rápido que muchos otros entornos.Incluso en una discusión sobre entornos de desarrollo con PHP.

Doctrine es un mapeador de Objetos-relacionales (ORM) escrito en PHP que proporciona una capa de persistencia para objetos PHP. Es una capa de abstracción que se sitúa justo encima de un SGBD. Esta bien escrito, tiene una documentacion extensiva y es activamente actualizado.

La combinacion de estos dos sistemas hace que construir aplicaciones web orientadas a bases de datos sea mas facil que nunca.

Configurando CodeIgniter

Se debe poner todos los archivos de CodeIgniter dentro de un directorio en tu servidor web y configuralo a tu gusto. Si necesitas una gui para hacer esto ultimo el mejor lugar para empezar es la Gui de Usuarios de CodeIgniter. Se debe Tener en cuenta que a la hora de trabajar con Doctrine este va a cargar la configuracion de la base de datos desde la configuracion de CodeIgniter situado en (application/config/database.php).

Configurando Doctrine

Como Doctrine es un sistema entero en si mismo, trabaja bien como un plugin para CodeIgniter 1. Desafortunadamente uno de los mayores cambios de CodeIgniter 2 es la eliminacion de los plugins. EllisLab recomienda utilizar los plugins como librerias asi que eso es exactamente lo que haremos.

Configurar Doctrine como una libreria de CodeIgniter es bastante simple:

  1. Poner el directorio de Doctrine dentro de applications/libraries (entonces se tendria un directorio en application/libraries/Doctrine).
  2. Crear un fichero llamado Doctrine.php dentro de application/libraries (entonces se tendria un fichero application/libraries/Doctrine.php).
  3. Copiar El siguiente codigo dentro del fichero Doctrine.php:

use Doctrine\Common\ClassLoader,
    Doctrine\ORM\Tools\Setup,
    Doctrine\ORM\EntityManager;

class Doctrine
{

    public $em;

    public function __construct()
    {
        require_once __DIR__ . '/Doctrine/ORM/Tools/Setup.php';
        Setup::registerAutoloadDirectory(__DIR__);

        // Carga la configuración de la base de datos desde CodeIgniter
        require APPPATH . 'config/database.php';

        $connection_options = array(
            'driver'        => 'pdo_mysql',
            'user'          => $db['default']['username'],
            'password'      => $db['default']['password'],
            'host'          => $db['default']['hostname'],
            'dbname'        => $db['default']['database'],
            'charset'       => $db['default']['char_set'],
            'driverOptions' => array(
                'charset'   => $db['default']['char_set'],
            ),
        );

        // Con esta configuración, tus archivos del modelo necesitan estar en application/models/Entity
        // Ejemplo: Al crear un nuevo Entity\User cargamos la clase desde application/models/Entity/User.php
        $models_namespace = 'Entity';
        $models_path = APPPATH . 'models';
        $proxies_dir = APPPATH . 'models/Proxies';
        $metadata_paths = array(APPPATH . 'models');

        // Establezca $ dev_mode = TRUE para deshabilitar el almacenamiento en caché mientras desarrollas
        $config = Setup::createAnnotationMetadataConfiguration($metadata_paths, $dev_mode = true, $proxies_dir);
        $this->em = EntityManager::create($connection_options, $config);

        $loader = new ClassLoader($models_namespace, $models_path);
        $loader->register();
    }

}

Hay algunas partes de este fichero que se deberan cambiar para que se ajuste a las necesidades de su aplicacion web:

Lineas 34-37:

$models_namespace = 'Entity';
$models_path = APPPATH . 'models';
$proxies_dir = APPPATH . 'models/Proxies';
$metadata_paths = array(APPPATH . 'models');

Esas lineas determinan donde necesitas poner los ficheros del modelo y como realizar la instanciacion de las clases. Con estas configuraciones, los modelos deben encontrarse en application/models/Entity y a la misma ves se encontraran en el Namespace Entity. Por ejemplo al instanciar un modelo (new Entity\MiModelo) estariamos cargando la clase MiModelo desde application/models/Entity/MiModelo.php

Linea 40:

$config = Setup::createAnnotationMetadataConfiguration($metadata_paths, $dev_mode = true, $proxies_dir);

Esta linea usa la clase Setup de Doctrine para automaticamente crear la configuracion de los metadatos. El Metadata Driver es lo que usa Doctrine para interpretar los modelos y para mapearlos hacia la base de datos. En este tutorial vamos a usar el Annotations Driver. Si se quisiera usar un Metadata Driver diferente se debe cambiar createAnnotationMetadataConfiguration a uno de los siguientes:

  • createXMLMetadataConfiguration – Usa el XML Mapping Driver
  • createYAMLMetadataConfiguration – Usa el YAML Mapping Driver

Cargando Doctrine dentro de CodeIgniter

Una ves realizados los pasos anteriores ya podemos cargar el Doctrine como si fuera una libreria de CodeIgniter:

$this->load->library('doctrine');

Una ves que la libreria de Doctrine esta cargada podemos acceder al Entity Manager de esta manera:

$em = $this->doctrine->em;

Definiendo los Modelos

Construir los modelos usando el Annotation Driver es facil. Se pueden construir las clases
como si fueran clases PHP normales, y define los metadatos de Doctrine en Docblock
annotations.

namespace Entity;

/**
 * @Entity
 * @Table(name="user")
 */
class User
{
     // ...
}

La anotacion @Entity marca esta clase para persistencia objeto-relacional . Si el nombre de
la tabla no se especifica (usando la anotacion @Table), Doctrine creara una tabla con el
mismo nombre de la clase.

Las anotacion que se usaran con mas frecuencia probablemente seran:

  • @Column – Marca una propiedad para persistencia objeto-relacional.
  • @OneToOne, @ManyToOne, y ManyToMany – Define la relacion entre dos entidades
  • @JoinTable – Usado cuando se esta definiendo una relacion @manyToMany para especificar
    uniones entre las tablas de la base de datos.

Para una lista completa de las anotaciones disponibles ysus usos vea la referencia de las
anotaciones

Ahora se muestran dos ejemplos mostrando una basica relacion One-To-Many:

namespace Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * @Entity
 * @Table(name="user")
 */
class User
{

    /**
     * @Id
     * @Column(type="integer", nullable=false)
     * @GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Column(type="string", length=32, unique=true, nullable=false)
     */
    protected $username;

    /**
     * @Column(type="string", length=64, nullable=false)
     */
    protected $password;

    /**
     * @Column(type="string", length=255, unique=true, nullable=false)
     */
    protected $email;

    /**
     *
     * @ManyToOne(targetEntity="Group")
     * @JoinColumn(name="group_id", referencedColumnName="id")
     */
    protected $group;

}

/**
 * @Entity
 * @Table(name="group")
 */
class Group
{

    /**
     * @Id
     * @Column(type="integer", nullable=false)
     * @GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Column(type="string", length=32, unique=true, nullable=false)
     */
    protected $name;

    /**
     * @OneToMany(targetEntity="User", mappedBy="group")
     */
    protected $users;

}

Es importante que notes que cualquier propiedad mapeada en tus entidades necesita ser
private o protected, de otra manera la funcionalidad lazy-loading podria no trabajar como se
esperaria. Esto Significa que seria necesario usar metodos getter y setter al estilo java:

public function setUsername($username)
{
    $this->username = $username;
}

public function getUsername()
{
    return $this->username;
}

Se puede ahorrar mucho tiempo generando automaticamente esos metodos usando el comando
orm:generate-entities.

Configurando la consola de Doctrine

Este paso es opcional, sin embargo la consola de Doctrine tiene algunos comandos muy utiles
por lo que es altamente recomendable configurarlo.

Todo lo que necesitas hacer es crear un archivo llamado doctrine,php dentro de la carpeta
application (application/doctrine.php) y copiar el siguiente codigo dentro:

define('APPPATH', dirname(__FILE__) . '/');
define('BASEPATH', APPPATH . '/../system/');
define('ENVIRONMENT', 'development');

chdir(APPPATH);

require __DIR__ . '/libraries/Doctrine.php';

foreach ($GLOBALS as $helperSetCandidate) {
    if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) {
        $helperSet = $helperSetCandidate;
        break;
    }
}

$doctrine = new Doctrine;
$em = $doctrine->em;

$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)
));

\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);

Usando la consola de Doctrine

Si se ejecuta la consola de Doctrine sin argumentos, se presentaran una lista de todos lo
scomandos disponibles, por ahora solo estamos interesados en el comando orm:schema-tool.

  • orm:schema-tool:create – Crea las tablas en la base de datos basadas en los modelos de Doctrine
  • orm:schema-tool:drop – Elimina las tablas que tengan correlacion con modelos de Doctrine. Cualquier tabla que no haya sido mapeada a un modelo doctrine sera dejada sola en la BD
  • orm:schema-tool:update – Determinará si el esquema de la base de datos esta desactualizada y nos dara la opcion de actualizar la misma. Puedes ejecutar este comando con la bandera --dump-sql para ver los cambios o usando --force para ejecutar los cambios.

Usando Doctrine

Una ves que los modelos estan establecidos y la base de datos construida, se podra acceder a los modelos usando el Entity Manager de Doctrine

class MY_Controller extends Controller
{

    // Doctrine EntityManager
    public $em;

    function __construct()
    {
        parent::__construct();

        // No es necesario si se carga la libreria en en el archivo application/config/autoload.php
        $this->load->library('doctrine');

        $this->em = $this->doctrine->em;
    }

}

Una ves ejecutado el codigo $this->doctrine->em se puede acceder al Entity Manager usando $this->em:

$usuario = new Entity\User;
$usuario->setUsername('Nombre');
$usuario->setPassword('ClaveSecreta');
$usuario->setEmail('nombre@ejemplo.com');

$this->em->persist($usuario);
$this->em->flush();

Concluyendo…

En este artículo hemos visto como configurar CodeIgniter para que use Doctrine 2 como ORM, la combinación de estas herramientas nos permite crear aplicaciones web utilizando un Framework PHP súper ligero sin la necesidad de tener que preocuparnos de la capa de acceso a datos gracias al uso de Doctrine2. Recuerda siempre dejarnos tus comentarios en Disqus, Twitter o Facebook y así poder retroalimentar nuestros conocimientos. Hasta la próxima.