Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

debug:container y cómo funciona el autowiring

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Vale, he mentido. Antes de hablar de los entornos, tengo que confesar algo: no te he enseñado todos los servicios de Symfony. Ni de lejos.

Dirígete a tu terminal y ejecuta nuestro comando favorito:

php bin/console debug:autowiring

Sabemos que todos estos servicios están flotando en Symfony, esperando que los pidamos. Y sabemos que los bundles nos dan servicios. El servicio Twig de aquí abajo proviene de TwigBundle.

Y como cada servicio es un objeto, algo en algún lugar debe ser responsable de instanciar estos objetos. La pregunta es: "¿Quién?" Y la respuesta es... ¡el contenedor de servicios!

Hola contenedor de servicios

Resulta que todos los servicios no están realmente... "flotando": todos viven dentro de algo llamado "contenedor". Y hay muchos más servicios en el contenedor de los que nos ha contado debug:autowiring. Ooh... ¡secretos! Esta vez, ejecuta:

php bin/console debug:container

Y... ¡guau! Esto imprime una lista enorme. Es tan grande que es difícil verlo todo. Déjame hacer la fuente más pequeña. ¡Mucho mejor!

Esta es la lista completa de todos los servicios de nuestra aplicación... o del "contenedor". El contenedor es básicamente un "array" gigante donde cada servicio tiene un nombre único que apunta a su objeto de servicio. Por ejemplo, aquí abajo... ahí vamos... podemos ver que hay un servicio cuyo nombre único - o "id" es twig.

Saber que el id del servicio Twig es twig no suele ser importante, pero es útil entender que cada servicio tiene un id único... y que puedes verlos todos dentro del comando debug:container.

El contenedor crea objetos

En realidad, el contenedor podría describirse mejor como un gran conjunto de instrucciones sobre cómo instanciar servicios, siempre y cuando algo los pida. Por ejemplo, el contenedor sabe exactamente cómo instanciar este servicio Twig. Sabe que su clase es Twig\Environment. Y aunque no lo veas en esta lista, conoce los argumentos exactos que debe pasar a su constructor. En el momento en que alguien necesite el servicio Twig, el contenedor lo instanciará y lo devolverá.

Sí, cuando autocontratamos un servicio, básicamente estamos diciendo

Oye, contenedor, ¿puedes darme el servicio Cliente HTTP?

Si nada en nuestro código ha pedido aún ese servicio durante esta petición, el contenedor lo creará. Pero si algo ya lo ha pedido, entonces el contenedor simplemente devolverá el que ya ha creado. Esto significa que si pedimos el servicio Cliente HTTP en diez lugares diferentes, el contenedor sólo creará y devolverá la misma instancia. ¡Muy bonito!

Cómo funciona el autocableado

De todos modos, debug:container nos muestra todos los servicios que el contenedor sabe instanciar. Pero debug:autowiring sólo nos muestra una parte de esos servicios. ¿Por qué?

Bueno, resulta que no todos los servicios son autocableables. Muchos de los elementos de esta lista son servicios de bajo nivel que sólo existen para ayudar a otros servicios a hacer su trabajo. Probablemente nunca necesitarás utilizar estos servicios de bajo nivel directamente... y en realidad no puedes obtenerlos mediante autoconexión.

Pero, retrocedamos un momento. Ahora que sabemos un poco más, podemos saber exactamente cómo funciona el sistema de autoconexión de Symfony. Es maravillosamente sencillo.

Como hemos visto, el contenedor es realmente un array donde cada servicio tiene un id que apunta a ese objeto servicio. Cuando Symfony ve este tipo HttpClientInterface-este es el tipo completo que ve, gracias a nuestra declaración use - para averiguar qué servicio del contenedor debe pasarnos, simplemente busca un servicio cuyo ID coincida exactamente con esta cadena. ¡Deja que te lo enseñe!

Desplázate hacia la parte superior de la lista para encontrar... ¡un servicio cuyo ID esSymfony\Contracts\HttpClient\HttpClientInterface! La gran mayoría de los servicios del contenedor utilizan la estrategia de nomenclatura "caso serpiente". Pero si un servicio está pensado para que lo utilicemos en nuestro código, Symfony añadirá dentro un servicio adicional que coincida con su nombre de clase o interfaz.

Gracias a ello, cuando escribimos HttpClientInterface, Symfony busca en el contenedor un servicio cuyo id esSymfony\Contracts\HttpClient\HttpClientInterface, lo encuentra y nos lo pasa.

Alias de servicio

Pero fíjate en el lado derecho: dice que se trata de un alias para un ID de servicio diferente. Un "alias" es como un enlace simbólico. Significa que cuando alguien pregunte por el servicio HttpClientInterface, Symfony nos pasará en realidad este otro servicio.

Podemos utilizar la misma lógica aquí abajo para el tipo CacheInterface. Si comprobamos la lista, aquí está el servicio cuyo id coincide con ese tipo. Pero, en realidad, es sólo un alias de un servicio llamado cache.app. Así que cuando autoconectamos CacheInterface, el servicio cache.app es lo que realmente se nos pasa.

Si te sientes inseguro, aquí tienes las tres grandes conclusiones. Uno: hay un montón de objetos de servicio flotando por ahí y todos viven dentro de algo llamado "contenedor". Cada servicio tiene un identificador único.

Dos: sólo un pequeño porcentaje de ellos nos resulta útil... y esos están configurados para que podamos autocablearlos. El autocableado funciona buscando en el contenedor un servicio cuyo id coincida exactamente con el tipo. Cuando ejecutamos debug:autowiring, básicamente nos muestra los servicios de esta lista cuyo id es un nombre de clase o interfaz. Ésos son los "servicios autoconducibles".

La tercera y última conclusión es que los servicios también tienen un sistema de alias... lo que significa que cuando pedimos el servicio CacheInterface, lo que realmente nos dará es el servicio cuyo id es cache.app.

Si te preguntas cómo podríamos utilizar en nuestro código un servicio no autoconvocable, ¡es una gran pregunta! Es algo raro, pero aprenderemos a hacerlo más adelante.

A continuación, vamos a hablar de la utilización de una configuración diferente a nivel local y a nivel de producción. Vamos a hablar de los entornos.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "symfony/asset": "6.1.*", // v6.1.0-RC1
        "symfony/console": "6.1.*", // v6.1.0-RC1
        "symfony/dotenv": "6.1.*", // v6.1.0-RC1
        "symfony/flex": "^2", // v2.1.8
        "symfony/framework-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/http-client": "6.1.*", // v6.1.0-RC1
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/runtime": "6.1.*", // v6.1.0-RC1
        "symfony/twig-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/ux-turbo": "^2.0", // v2.1.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.14.1
        "symfony/yaml": "6.1.*", // v6.1.0-RC1
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.0
    },
    "require-dev": {
        "symfony/debug-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/maker-bundle": "^1.41", // v1.42.0
        "symfony/stopwatch": "6.1.*", // v6.1.0-RC1
        "symfony/web-profiler-bundle": "6.1.*" // v6.1.0-RC1
    }
}