Sustitución del mapeo original de FOSUserBundle en symfony2

Para un nuevo proyecto en PHP que estamos empezando, hemos decidido utilizar la plataforma symfony2. En el pasado he tenido la suerte de trabajar, disfrutar y aprender con symfony 1.x, gracias a su coherente organización, buen uso del PHP y unos robustos cimientos fundados en una extensa documentación y una vasta comunidad de activos desarrolladores. En agosto del 2011, SensioLabs, la empresa liderada por Fabien Potencier, liberó la versión 2.0 y este septiembre pasado la 2.1 (la versión actual es la 2.1.2). Ya sólo respecto a la 2.0, la 2.1 incluye una serie de cambios importantes, como puede ser la gestión de la instalación y actualización de los bundles mediante composer. Ahora bien, el cambio de verdad, como es de suponer, se hizo al pasar de la serie 1.x a symfony2. Cierto es que siguen manteniendo la arquitectura MVC en su núcleo, pero la estructura de la aplicación cambia sustancialmente, así como la manera de auto-cargar las clases o los comandos de consola y otros puntos más que no vienen al caso ahora. La gran aportación de symfony2 es la nueva organización basada en paquetes (bundles). En symfony2, todo el código de la aplicación vive y ha de vivir dentro de un paquete (aproximadamente equivalente a lo que venía siendo un plugin en symfony1). De modo que ya no se instalan plugins, si no bundles. Y, en realidad, esto hace la vida más sencilla, sobre todo para el mantenimiento de la aplicación, gracias a que están mucho más desacoplados respecto del código que los antiguos plugins. Uno de los bundles estrella de symfony2 es FOSUserBundle, un paquete para gestionar usuarios, algo así como el sfGuardPlugin de symfony 1.x. Este bundle utiliza el ORM Doctrine y viene con un esquema y un mapeo de las clases, predefinidos en una serie de archivos. De ahí que nos podamos encontrar con un pequeño escollo al intentar cambiar alguna propiedad de las clases mapeadas o el nombre de un tabla, en caso de querer, por ejemplo, adaptar el mapeo a una base de datos heredada. Obviamente no podemos cambiarlo directamente en el bundle de FOSUserBundle, pues los cambios quedarían sobrescritos en la siguiente actualización del bundle. Además, ninguno de los proyectos de Doctrine permite actualmente sobrescribir parte de la asignación de una superclase mapeada en una entidad hijo. ¿Cómo proceder entonces si, por ejemplo, quiero quitar la clave única de una columna? La gente de FOSUserBundle no son muy locuaces al respecto, pero algo de información puedes encontrar en su página de github. Básicamente dicen que hay que volver a escribir el mapeo de la superclase mapeada, que la entidad ha de extender directamente a FOS\UserBundle\Model\User y aconsejan que se respeten todos los campos asignados en el bundle por lo que pueda pasar en futuras actualizaciones. Con la poca información proporcionada (tampoco he encontrado ningún ejemplo que pudiera guiarme), y después de pelearme un ratito, he llegado a la conclusión que básicamente estos son los ficheros que hay que tocar.
  1. /src/Application/MiSuperAPP/UserBundle/Entity/User.php
  2. /src/Application/MiSuperInvento/UserBundle/Entity/Group.php
  3. /src/Application/MiSuperInvento/UserBundle/Resources/config/doctrine/User.orm.xml
  4. /src/Application/MiSuperInvento/UserBundle/Resources/config/doctrine/Group.orm.xml
En el primer archivo hay que sustituir el alias del BaseUser en el use utilizado para importar la clase base de User por Luego hay que traerse todas las propiedades y métodos de la clase /vendor/sonata-project/user-bundle/Sonata/UserBundle/Model/User.php y añadirlas a la clase de la entidad User de nuestra aplicación.
Nótese que, en nuestro caso, hemos utilizado el FOSUserBundle integrado en el bundle de sonata. En caso de utilizar el bundle sin sonata, la ruta sería: /vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Model/User.php
Después hacemos exactamente lo mismo con la entidad Group, teniendo en cuenta que donde pone user hay que poner group; por ejemplo en la entidad Group Los siguientes ficheros que tenemos que modificar son los XML donde se define la asignación del esquema de la base de datos respecto al modelo de clases:
  • /src/Application/MiSuperInvento/UserBundle/Resources/config/doctrine/User.orm.xml
  • /src/Application/MiSuperInvento/UserBundle/Resources/config/doctrine/Group.orm.xml
Estos archivos son fundamentales a la hora actualizar la base de datos a partir del modelo ( php app/console doctrine:schema:update --force), pues los campos que no estén definidos no se replicarán en la base de datos y viceversa. El fichero /src/Application/MiSuperInvento/UserBundle/Resources/config/doctrine/User.orm.xml es el que va a tener en cuenta la entidad de nuestra aplicación para las asignaciones del ORM: ¿Y dónde se encuentra el resto de propiedades de nuestro modelo? Un sitio interesante para ir a echar un vistazo es en /vendor/sonata-project/user-bundle/Sonata/UserBundle/Resources/config/doctrine/User.orm.xml
Recuerda que, en caso de no utilizar el bundle de sonata, la ruta sería: /vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Resources/config/doctrine/User.orm.xml
En este fichero se define el mapeo de la superclase. Como en los primeros pasos, cambiamos las entidades /src/Application/MiSuperAPP/UserBundle/Entity/User.php y de /src/Application/MiSuperInvento/UserBundle/Entity/Group.php para que no herederan de la superclase, ahora sólo tenemos que añadir las propiedades que nos faltan de /vendor/sonata-project/user-bundle/Sonata/UserBundle/Resources/config/doctrine/User.orm.xml. Con lo que nuestro fichero User.orm.xml quedaría así: Seguimos los mismos pasos con Group.orm.xml y ya estamos listos para poder modificar nuestro esquema y modelo sin perjuicio de futuras actulizaciones. Por ejemplo, en este caso he quitado la clave única de emailCanonical y usernameCanonical. De modo que, después de ejecutar php app/console doctrine:schema:update --force, los cambios se ven reflejados en la base de datos. Por último recordar que, a partir de ahora, los cambios en el esquema han de ser modificados en el User.orm.xml de la aplicación y los del modelo en el User.php de la entidad de la aplicación.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *