Acceder Al Contenedor Servicios Desde Cualquier Lado Symfony2

58 views
Skip to first unread message

helysm

unread,
Jun 1, 2012, 4:08:07 PM6/1/12
to symfony-es, symfo...@googlegroups.com, symfony-2...@googlegroups.com, symfony_...@googlegroups.com
Saludos Colegas Symfoneros.

Luego de varias horas de consultas infructuosas en donde buscaba la manera de terner acceso al contenedor de servicios desde cualquier lado diferente del controlador solo encontraba opciones como esta:

Pasar como parametros el servicio o dato que se necesitaba al contructor de la clase ya sea un formulario o una entidad, inicialmente no esta mal solo que cuando va haciendo necesario con mayor uso, esta practica termina siendo molesta => "Opinion Personal". Por lo que vi que hay una forma de poder acceder al contenedor de servicios desde cualquier lado de la aplicacion puede ser una clase de formulario o una clase dentro de una entidad.

Esta busqueda me llevo a la necesidad de que requeria que en una entidad desde el constructor un campo que esta asociado a otra entidad tuviese asociado un objeto especifico que ya existe previamente, pero las unicas opciones que habian era que esto debia hacerlo desde el controlador osea instanciar entidad1 y luego obtener la entidad2 ya sea a traves del entitymanager para luego asociarla a la entidad1; cuando desde el mismo constructor de la entidad1 ya el campo tuviese asociado la entidad2, y esto obedece al concepto de constructor en el paradigma de objetos.

Asi que encontre que la forma de poder acceder al contenedor de servicios desde cualquier lado de la aplicacion seria haciendo esto:

$em = $GLOBALS['kernel']->getContainer()->get('doctrine')->getEntityManager();

Esto lo uso para poder tener acceso al entity manager desde el constructor de una entidad.

y ya con eso puedo realizar la consulta de manera normal a como lo haria desde un controlador; haciendo esto me permite mantener la logica encapsulada dentro de la misma clase de la entidad sin necesidad de pasar parametros adicionales en el constructor.

Ahora el motivo del correo es pedir sus opiniones al respecto, en donde si esta practica es correcta para acceder al entity manager desde mi caso por ejemplo , la clase de una entidad, o si el procedimiento correcto seria que debe ser pasado como parametros al contructor desde la entidad, aunque eso amerite mas trabajo.

Gracias por sus opiniones.

Si encuentras la solución a tu problema no olvides postearla, es por el beneficio de todos en la lista.

Atentamente,

Hely Suarez Marin
Desarrollador PHP Symfony
Miembro del Semillero de Investigación y Desarrollo de Software Libre UFPS
No a la Piratería de Software !Sea Legal con Colombia! Usa Software Libre...
Cúcuta

theUniC

unread,
Jun 1, 2012, 5:31:35 PM6/1/12
to symfony_...@googlegroups.com, symfony-es, symfo...@googlegroups.com, symfony-2...@googlegroups.com
Hola Hely,

Es una mala práctica pasar todo el contenedor de servicios cómo parámetro o en tu caso acceder a él desde el array de globals, no hay que hacerlo. Y mucho menos hacer que la entidades tengan acceso al mismo, pues se incumplen varios principios SOLID y las dependencias entre componentes (aka servicios), ya sean mandatorias o opcionales, dejan de ser explícitas y se pervierte el patrón. Ello comporta que dejes de tener visibilidad sobre qué es lo que necesita el servicio para poder ejecutarse y te sea imposible hacer unit test sobre el mismo. De hecho la recomendación oficial de Symfony2 al respecto del uso del contenedor de servicios, es evitar acoplar nuestro código con el contenedor (de hecho no hay ningún ejemplo, almenos que haya visto yo, en la documentación de Symfony2 que acople el contenedor de servicios)

http://symfony.com/doc/current/components/dependency_injection/introduction.html#avoiding-your-code-becoming-dependent-on-the-container

En general (y no solo para Symfony2), una capa de servicios consta de varias subcapas: lógica de negocio o capa de servicio (en Symfony2 serían services y repositories, por ese orden) => capa entidades del modelo de dominio (en Symfony2 serían las Entities) => capa de acceso a datos (Doctrine 2 & PDO) => Data source (MySQL, Solr, MongoDB y un largo etc). Además debe cumplirse que un servicio debería poderse ejecutar tanto por CLI, como por el front de la aplicación o por dónde se quiera, por lo que no debe estar ligado a componentes intrínsecos a la request HTTP, a la request de CLI, etc.

Adjunto aquí el enlace al patrón Service Layer, inicialmente propuesto por Randy Stafford en el libro de Patterns of Enterprise Application Arquitecture


Y por supuesto, Symfony2 por su arquitectura, te obliga un poco a no usar truquillos piratillas cómo el de la $GLOBALS['kernel'] y a usar algo más acorde con la OOP que ahora por ahora permite PHP en su actual versión. Esto es muy "phpquatro" !! :)

Espero que te sirva!
Un saludo!
Christian.

helysm

unread,
Jun 1, 2012, 6:43:04 PM6/1/12
to symfony_...@googlegroups.com

Colegas symfoneros ismael y cristian muchas gracias por sus opiniones, el objetivo del post era precisamente esto conocer los puntos de vista de otros compañeros y las razones expuestas es lo que buscaba, buscare otra forma mas acorde con los objetivos de symfony de hacer lo que busco. Gracias a los dos.

El jun 1, 2012 4:31 p.m., "theUniC" <the...@gmail.com> escribió:

Hola Hely,

Es una mala práctica pasar todo el contenedor de servicios cómo parámetro o en tu caso acceder a él desde el array de globals, no hay que hacerlo. Y mucho menos hacer que la entidades tengan acceso al mismo, pues se incumplen varios principios SOLID y las dependencias entre componentes (aka servicios), ya sean mandatorias o opcionales, dejan de ser explícitas y se pervierte el patrón. Ello comporta que dejes de tener visibilidad sobre qué es lo que necesita el servicio para poder ejecutarse y te sea imposible hacer unit test sobre el mismo. De hecho la recomendación oficial de Symfony2 al respecto del uso del contenedor de servicios, es evitar acoplar nuestro código con el contenedor (de hecho no hay ningún ejemplo, almenos que haya visto yo, en la documentación de Symfony2 que acople el contenedor de servicios)

http://symfony.com/doc/current/components/dependency_injection/introduction.html#avoiding-your-code-becoming-dependent-on-the-container

En general (y no solo para Symfony2), una capa de servicios consta de varias subcapas: lógica de negocio o capa de servicio (en Symfony2 serían services y repositories, por ese orden) => capa entidades del modelo de dominio (en Symfony2 serían las Entities) => capa de acceso a datos (Doctrine 2 & PDO) => Data source (MySQL, Solr, MongoDB y un largo etc). Además debe cumplirse que un servicio debería poderse ejecutar tanto por CLI, como por el front de la aplicación o por dónde se quiera, por lo que no debe estar ligado a componentes intrínsecos a la request HTTP, a la request de CLI, etc.

Adjunto aquí el enlace al patrón Service Layer, inicialmente propuesto por Randy Stafford en el libro de Patterns of Enterprise Application Arquitecture


Y por supuesto, Symfony2 por su arquitectura, te obliga un poco a no usar truquillos piratillas cómo el de la $GLOBALS['kernel'] y a usar algo más acorde con la OOP que ahora por ahora permite PHP en su actual versión. Esto es muy "phpquatro" !! :)

Espero que te sirva!
Un saludo!

Christian.

El 1 de junio de 2012 22:08, helysm <hel...@gmail.com> escribió:


>
> Saludos Colegas Symfoneros.
>
> Luego de varias horas de consultas infructuosas en donde buscab...


Francesc Rosàs

unread,
Jun 4, 2012, 8:50:53 AM6/4/12
to symfony_...@googlegroups.com, symfony-es, symfo...@googlegroups.com, symfony-2...@googlegroups.com
Gran explicación Christian.

Hay un caso bastante claro donde sí se inyecta el contenedor entero: en los controllers. Podrían haber hecho que en el routing se tuvieran que especificar los servicios a utilizar pero supongo que prefirieron simplificar para no espantar demasiado a los que empiezan con el framework ;)

Oriol Jiménez

unread,
Jun 5, 2012, 9:37:33 AM6/5/12
to symfony_...@googlegroups.com, symfony-es, symfo...@googlegroups.com, symfony-2...@googlegroups.com
como dice Christian, en resumen: es una mala prática, incumple varios principios, pierdes visibilidad e imposibilitas el unit test.

qué problema hay en trabajar en el Controller y pasar como parámetros al constructor lo necesario, o mucho mejor hacer un XXXManager vía DIC con un método que realice dicha operación, y reutilizable desde otros sitios?

Falta ver el código de todo pero a primera vista acceder al $GLOBALS desde un constructor de una Entity no suena nada bien, no?


Salu2
Oriol
Reply all
Reply to author
Forward
0 new messages