Symfony2: El directorio Model, las Entities y los Documents

Una de las cosas que no hablé en la charla y que en un principio sí que quería era sobre el directorio Model. Es posible que en algunos bundles o proyectos hayáis visto este directorio, pero ¿para qué se usa? En el directorio Model tendremos nuestros objetos de dominio que serán agnósticos del tipo de persistencia que usemos.

Es decir, en este directorio estarán entre otras nuestras clases que luego usaremos como Entities o Documents. Este directorio es común en Bundles que van a ser distribuidos y ofrecen varios tipos de persistencia. Se puede echar un ojo al directorio Model de FOSUserBundle y vemos que tiene las siguientes clases:

Es muy interesante echarle un vistazo a estas clases para ver lo que contienen.

Las clases Group y User contienen una serie de atributos y los métodos que tienen manipulan sus propios atributos y sus las relaciones, pero nunca acceden a servicios externos.

Las clases UserManager y GroupManager se dedican a manipular las interfaces UserInterface y GroupInterface (que son las que implementan las clases User y Group). Estas clases son abstractas porque no implementan todos los métodos de la interfaz, se dejan por implementar los que tienen que ver con las persistencia, por lo que habrá otras clases que extiendan de éstas.

Pero, ¿por qué hacen esto? Porque de esta forma se puede reutilizar el código tanto para Entities como Documents. Este mismo código nos va a servir para cualquier tipo de persistencia que usemos, sólo hay que indicar cúal es el mapeo. En este mapeo (en xml es lo típico) indicaremos qué atributos vamos a persistir (se puede ver aquí en el FOSUserBundle).

Las clases UserManager y GroupManager dentro de Model se extienden en este caso dentro del directorio Doctrine o Propel para añadirle los métodos de persistencia.

Hasta ahora lo que se hacía también es crearse clases vacías en el directorio Entity o Document que extendían las clases de Model, de esta forma cuando usabas el bundle tenías que extender la clase de dentro de Entity o Document. Pero a partir de la versión 2.3 se hace uso de un Compiler Pass para que cuando uses el bundle extiendas directamente la clase dentro Model.

Por último quería comentar algo sobre las Entities. Una Entity es simplemente un objeto que tiene identidad, por ejemplo, un usuario que tiene un id único que podemos manipularlo, recuperarlo, etc. Por lo que lo único que diferencia una Entity de un Model es el mapeo y la identidad (id). Es por esto que para mí dentro de una Entity aparte de getters y setters (se deben añadir para cuando Doctrine crea clases Proxy para usar Lazy Loading) puede contener lógica relacionada con sus atributos y las relaciones. Por ejemplo si tuviera una Entity Alumno y otra Nota, se podría añadir un método en Alumno que calcule la media de las notas (esto no quita que en Alumno tengamos un campo calculado por eficiencia) o la nota más alta, etc.