Ver índice de contenidos del libro

16.3. Creando y configurando servicios en el contenedor

Una forma mucho mejor de hacer el ejemplo anterior es dejar que el contenedor de servicios cree el objeto Mailer por ti. Para que esto funcione, debes enseñar al contenedor cómo crear el servicio Mailer. Esto se hace a través de una configuración sencilla, que puedes definir con YAML, XML o PHP:

# app/config/config.yml
services:
    my_mailer:
        class:        Acme\HelloBundle\Mailer
        arguments:    [sendmail]
<!-- app/config/config.xml -->
<services>
    <service id="my_mailer" class="Acme\HelloBundle\Mailer">
        <argument>sendmail</argument>
    </service>
</services>
// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
 
$container->setDefinition('my_mailer', new Definition(
    'Acme\HelloBundle\Mailer',
    array('sendmail')
));

Nota Cuando se inicia, Symfony2 construye el contenedor de servicios usando por defecto la configuración del archivo app/config/config.yml. El archivo exacto que se carga es el que indica el método AppKernel::registerContainerConfiguration(), el cual carga un archivo de configuración que depende del entorno de ejecución (por ejemplo, config_dev.yml para el entorno dev o config_prod.yml para prod).

Con la configuración anterior, el contenedor de servicios ya dispone de una instancia del objeto Acme\HelloBundle\Mailer. El contenedor está disponible en cualquier controlador de Symfony2, donde puedes acceder al servicio del contenedor a través del método get():

class HelloController extends Controller
{
    // ...
 
    public function sendEmailAction()
    {
        // ...
        $mailer = $this->get('my_mailer');
        $mailer->send([email protected]', ...);
    }
}

Cuando solicitas el servicio my_mailer en el controlador, el contenedor construye el objeto y te lo devuelve. Esta es otra de las principales ventajas de utilizar el contenedor de servicios: un servicio nunca se construye hasta que alguien lo solicita. Si defines un servicio y no lo utilizas en una petición, el servicio no se crea. Esto ahorra memoria y aumenta la velocidad de tu aplicación. Esto también significa que la penalización en el rendimiento por definir muchos servicios es mínima o inexistente. Los servicios que nunca se usan, nunca se construyen.

Como ventaja añadida, el servicio Mailer se crea sólo una vez y esa misma instancia se vuelve a utilizar cada vez que solicites el servicio. Este es el comportamiento que casi siempre se necesita (es más flexible y potente) pero, más adelante, aprenderás cómo configurar un servicio que tiene varias instancias.

Nota En este ejemplo, el controlador extiende del controlador base de Symfony, que proporciona acceso directo al propio contenedor de servicios. Por eso puedes utilizar el método get() para localizar y obtener el servicio my_mailer. También es posible definir los controladores como servicios, que es algo más avanzado y totalmente opcional, pero te permite controlar con precisión qué servicios se inyectan en tus controladores.