Las cookies nos permiten ofrecer nuestros servicios. Al utilizar nuestros servicios, aceptas el uso que hacemos de las cookies. Más Información. Aceptar

Symfony2 tutorial: Servicios e inyección de dependencias

Sergio Yamuza
  • Escrito por Sergio Yamuza el 03 de Noviembre de 2015
  • 6 min de lectura | Backend
Symfony2 tutorial:  Servicios e inyección de dependencias

Las aplicaciones PHP modernas gestionan las distintas funcionalidades mediante objetos, cada uno destinado a una funcionalidad concreta.

El contenedor de servicios es un objeto PHP propio de Symfony2. Permite estandarizar y centralizar de la forma se construyen los objetos de una aplicación.

Su principal objetivo es la organización y modularización del código. Así, podemos crear un servicio para un primer proyecto y reutilizarlo después en otros trabajos.

Es un componente que trabaja de forma muy rápida, lo que explica en gran parte la velocidad de ejecución de Symfony, su flexibilidad y la posibilidad de desacoplar y refactorizar gran parte del código.

Servicios

Un servicio es un objeto PHP que realizar algún tipo de funcionalidad global. Por ejemplo, el envío de email es una tarea que muy probablemente se ejecute desde distintas áreas de la aplicación.

La diferencia con una entidad, que también es un objeto PHP, es que un servicio realiza acciones concretas de forma global. La ventaja de utilizarlos es que te ves obligado a desacoplar cada uno de ellos. Al ser globales, son fácilmente accesibles desde cualquier parte de la aplicación.

Para acceder a uno de ellos se utiliza el objeto mencionado anteriormente, el contenedor de servicios: componente DependencyInjection de Symfony.

Creación y configuración de Servicios

Para nuestra aplicación de ejemplo vamos a crear un servicio que nos envíe un email avisándonos de que un usuario ha realizado un comentario en una noticia.

Lo primero que hay que hacer es definir el servicio en el apartado services . Para ello lo mejor es crear un nuevo archivo services.yml , dentro de /app/config/

Después, en config.yml importamos el archivo que contiene los servicios. De esta forma tenemos el código de la aplicación mejor organizado.

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

Para definir el servicio lo primero es asignarle un nombre: my_mailer .

Después hay que indicar la clase a la que referencia el servicio: AppBundle\Services\Mailer .

En el apartado arguments se establecen los argumentos que va a recibir el servicio. Equivalen a los parámetros que recibe un método.

services:
    my_mailer:
        class:        AppBundle\Services\Mailer
        arguments:    [post]

El contenedor de servicios está disponible en todos los controladores. Por tanto, ahora ya podemos acceder al servicio. Se obtiene a través del método get() , pasando como parámetro el nombre del servicio que queremos obtener:

<?php

public function sendEmailAction()
{
    $mailer = $this->get('my_mailer');
}

Al solicitar el servicio, el contenedor construye el objeto y lo devuelve. Es otra de las ventajas de modularizar nuestro código en servicios, ya que si en una petición el servicio no se utiliza, directamente no lo crea, lo que supone un ahorro en memoria y aumenta la velocidad de ejecución en nuestra aplicación.

Parámetros de un Servicio

Se utilizan para hacer que un servicio sea flexible a la hora de configurarlo. Los bundles de terceros casi siempre utilizan parámetros para permitir un cierto grado de personalización.

Algunos son parámetros de configuración, como por ejemplo, mailer_transport . En otras ocasiones son llamadas a otros servicios que contiene dicho bundle.

Los argumentos pueden ser de 3 tipos, y cada tipo tiene su notación para definirlo.

  1. Servicio como argumento: “@NOMBRE_DEL_SERVICIO”
  2. Texto plano como argumento: “CADENA_DE_TEXTO”
  3. Parámetro como argumento: “%NOMBRE_DEL_PARAMETRO%”
arguments: ["@nombre_servicio", "texto_plano", "%nombre_parametro%"]

En definiva, permiten que los servicios se puedan configurar. Su utilización tiene varias ventajas:

  1. Separar y organizar las opciones del servicio.
  2. Los valores de los parámetros se pueden reutilizar en otras partes de la aplicación.
  3. Si creas un bundle desacoplado, te será posible personalizarlo de varias formas en distintas aplicaciones.

Inyección de Servicios

Supongamos que tenemos un servicio en el que necesitamos inyectar otro. Se podría hacer de la siguiente forma:

<?php

$mailer = $this->get('my_mailer');
$newsletter = new NewsletterManager($mailer);

Esto es perfectamente válido, pero no está modularizado.

services:
    my_mailer:
        # ...
    newsletter_manager:
        class:     AppBundle\Service\NewsletterManager
        arguments: ["@my_mailer"]

De esta forma el servicio newsletter_manager siempre pasa como argumento el servicio my_mailer , por lo que no es necesario instanciar a este último cada vez, como en el ejemplo anterior.

Dependencias opcionales

En algunos casos, los servicios pasado como argumentos puede que sean opcionales. Hay dos formas de establecer esta condición.

En la definición del argumento, añadir el carácter ? después de @ :

services:
    my_mailer:
        # ...
    newsletter_manager:
        class:     AppBundle\Service\NewsletterManager
        arguments: ["@?my_mailer"]

En el constructor de la clase(servicio) indicar que, por defecto, el valor del parámetro es igual a null .

<?php

public function __construct(Mailer $mailer = null)
{
    // ...
}


Este post ha sido producido gracias a la colaboración de Sopinet Software .

Estas son algunas de las empresas que ya confían en OpenWebinars

Profesores y profesionales

Nuestros docentes son profesionales que trabajan día a día en la materia que imparten

Conviértete en profesor de OpenWebinars