If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeEn la práctica, rara vez tienes que hacer algo dentro de services.yaml
. La mayoría de las veces, cuando añades un argumento al constructor de un servicio, es autoconductible. Así que añades el argumento, le das una pista de tipo... ¡y sigues codificando!
Pero el argumento de $isDebug
no es autoconductible... ya que no es un servicio. Y eso nos obligó a anular por completo el servicio para poder especificar ese único argumento con bind
. Funciona, pero... ¡eso era... mucho teclear para hacer una cosa tan pequeña!
_defaults
Así que aquí tienes una solución diferente. Copia esa tecla bind
, borra el servicio por completo, y arriba, bajo _defaults
, pega.
Cuando nos movemos y probamos esto... ¡la página sigue funcionando! ¿No es genial? Y tiene sentido. Esta sección registrará automáticamente MixRepository
como servicio... y entonces todo lo que esté bajo _defaults
se aplicará a ese servicio. Así que el resultado final es exactamente el que teníamos antes.
¡Me encanta hacer esto! Me permite establecer convenciones para todo el proyecto. Ahora que tenemos esto, podemos añadir un argumento $isDebug
al constructor de cualquier servicio y funcionará al instante.
Por cierto, si quieres, también puedes incluir el tipo con el bind.
Así, ahora sólo funcionaría si utilizamos la sugerencia de tipo bool
con el argumento. Si utilizáramos string
, por ejemplo, Symfony no intentaría pasar ese valor.
Así que el bind global es genial. Pero a partir de Symfony 6.1, hay otra forma de especificar un argumento no autoconductible. Comenta el global bind
. Todavía me gusta hacer esto... pero probemos la nueva forma.
Si actualizamos ahora, obtendremos un error porque Symfony no sabe qué pasar al argumento $isDebug
. Para solucionarlo, entra en MixRepository
y, por encima del argumento (o antes del argumento si no estás usando varias líneas), añade un atributo de PHP 8 llamado Autowire
. Normalmente, los atributos de PHP 8 se autocompletan, pero este no se autocompleta para mí. Esto se debe a un error en PhpStorm. Para evitarlo, voy a escribir Autowire
... luego iré a la parte superior y empezaré a añadir la declaración use
para esto manualmente, lo que sí nos da una opción de autocompletar. Pulsa "tab" y... ¡tah dah! Si quieres hacerlos por orden alfabético, puedes moverlo.
También puedes observar que está subrayado con un mensaje
No se puede aplicar el atributo a una propiedad [...]
De nuevo, PhpStorm está un poco confundido porque esto es tanto una propiedad como un argumento.
De todos modos, sigue adelante y pasa esto como un argumento %kernel.debug%
.
Actualiza ahora y... ¡lo tienes! Bastante bien, ¿verdad?
Siguiente: la mayoría de las veces, cuando se autoconduce un argumento como HttpClientInterface
, sólo hay un servicio en el contenedor que implementa esa interfaz. Pero, ¿y si hubiera varios clientes HTTP en nuestro contenedor? ¿Cómo podríamos elegir el que queremos? Es hora de hablar del autocableado con nombre.
This Autowire
Annoation is very cool. I like to use the ParameterBag (ParameterBagInterface) object whenever I need some parameter inside my services.
But when I think about it more, it might be better for testing reasons to use the parameter itself inside the constructor.
Anyways I love to watch symfonycast videos even after all these years. It doesn't stop to be interesting.
Hey Braunstetter,
Yeah, it's always a trade-off :) That service is cool, but passing parameters into the constructor might be more straightforward and so simpler to test. Probably it depends on the number of parameters you need, if it's 1-3 params - I'd go with passing them into the constructor. If you need a lot of them - the service would be better in this case.
Cheers!
// 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
}
}
The Autowire annotation is amazing!
Heads-up for anyone else who might have trouble using the
#[Autowire()]
attribute:It requires Symfony 6.1 (and PHP 8.1)
My dev environment used PHP 8.0.8, and as a result always installed Symfony 6.0.
After upgrading PHP to v 8.1.11, my new Symfony project start out using Symfony 6.2, and the annotation works.