Nuevo en Symfony 3.4: servicios privados por defecto

En las aplicaciones Symfony, los servicios y los alias son públicos por defecto. Esto significa que cuando tienes acceso al contenedor de servicios, puedes obtener cualquier servicio directamente. Por ejemplo, en un controlador que extiende del controlador base de Symfony puedes hacer $this->get('app.mi_servicio') y si inyectas el servicio service_containeren tus clases (algo que desaconsejamos totalmente) puedes hacer $container->get('app.mi_servicio').

Aunque esta forma de trabajar es muy cómoda, usar el contenedor directamente no se considera una buena práctica porque enmascara las dependencias reales de tus clases y hace que tu aplicación esté acoplada al contenedor, lo que dificulta los tests y el mantenimiento a largo plazo.

En Symfony 3.3 añadimos muchas utilidades para no tener que inyectar nunca el contenedor entero. Así que poco a poco estamos eliminando la práctica de usar el contenedor directamente en tus clases.

En Symfony 3.4 hemos ido un paso más allá y ahora los servicios y los alias son privados por defecto. Así que no podrás acceder a los servicios mediante el atajo get() ni aunque inyectes el contenedor entero. La solución consiste en utilizar la inyección de dependencias tradicional.

Si utilizas autowiring, este cambio prácticamente no te va a afectar, ya que tus servicios ya se están inyectando en vez de obtenerlos mediante get(). Gracias a los últimos cambios de Symfony, esto funciona en todas partes: servicios normales, comandos de consola, controladores, etc.

Si no quieres utilizar el autowiring, tienes que actualizar la configuración de tus servicios para hacerlos públicos explícitamente. Si utilizas YAML:

services:
    # hacer públicos todos los servicios definidos en este archivo
    _defaults: { public: true }
 
    # hacer público solamente algún servicio en particular
    App\Manager\UserManager:
        public: true

Si utilizas XML:

<services>
    <!-- hacer públicos todos los servicios definidos en este archivo -->
    <defaults public="true" />
 
    <!-- hacer público solamente algún servicio en particular -->
    <service id="App\Manager\UserManager" public="true"></service>
</services>

Si utilizas PHP, añade una llamada a ->setPublic(true) cuando definas el servicio.

Este cambio también podría afectar a los bundles de terceros que utilizas en tus proyectos. Si alguno de esos bundles utiliza el contenedor de servicios directamente, crea un pull request para corregírselo. A partir de Symfony 3.4 ya no hay ninguna razón válida para seguir utilizando el contenedor directamente.

En el propio código de Symfony ya hemos hecho este cambio y todos nuestros alias y servicios son ahora privados, salvo por unos pocos que Symfony obliga a que sean públicos por alguna razón interna. En el futuro, si esta tendencia continúa, podríamos plantearnos prohibir la inyección del contenedor de servicios completo. Pero eso no se podrá hacer antes de Symfony 5.

Esta funcionalidad fue contribuida por Nicolas Grekas en el Pull Request #24238.

Fuente: New in Symfony 3.4: Services are private by default

Comentarios

Publicada el

13 de octubre de 2017

Etiquetas

Proyectos Symfony destacados

La plataforma de eCommerce 100% Symfony que rivaliza con Magento y PrestaShop. Ver más

Síguenos en @symfony_es para acceder a las últimas noticias.