Nuevo en Symfony 2.7: mejoras en la Inyección de Dependencias

El componente DependencyInjection permite centralizar la creación de los objetos en las aplicaciones PHP. Symfony utiliza este componente para crear su contenedor de servicios, que es el máximo responsable de que el framework Symfony sea tan extensible y se adapte a cualquier necesidad que tengas. En Symfony 2.7 se ha mejorado este componente añadiendo nuevas funcionalidades y eliminando algunas funcionalidades existentes.

Añadido soporte para crear alias automáticos

Esta nueva funcionalidad ha surgido a partir de las necesidades del proyecto Drupal. El problema a resolver era el siguiente: considerando los siguientes servicios:

lock:
    class: Drupal\Core\Lock\Lock...
mysql.lock:
    class: Drupal\Core\Lock\Lock...
sqlite.lock:
    class: Drupal\Core\Lock\Lock...

La idea es que cuando el administrador del sitio cambia por ejemplo el valor de la opción de configuración default_backend a mysql, el servicio genérico lock debería ser un alias del servicio mysql.lock.

En Symfony 2.7 se ha creado un nuevo compiler pass llamado auto_alias que permite hacer precisamente esto. Para ello, simplemente aplica a tu servicio la nueva etiqueta auto_alias y define el formato del alias (puedes usar cualquier parámetro del contendor para definir el valor del alias):

# app/config/services.yml
lock:
    class: Drupal\Core\Lock\Lock...
    tags:
        - { name: auto_alias, format: "%default_backend%.lock" }

Esta funcionalidad ha sido desarrollada por Daniel Wehner en el pull request #12526 de Symfony.

Mejorada la creación de servicios inline en el dumper XML

Para mejorar el rendimiento de la aplicación, el contenedor de servicios busca todos los servicios privados que solamente se utilizan una vez. Después, elimina esos servicios y e incluye su código directamente dentro del único servicio que los utilizan. Técnicamente eso se conoce como crear servicios "inline".

Por otra parte, cuando se crea la caché de la aplicación Symfony, el contenedor se vuelca a un archivo XML utilizando lo que se conoce como el XML dumper (mira por ejemplo el archivo appDevDebugProjectContainer.xml dentro del directorio app/cache/ de cualquier aplicación Symfony que tengas).

No obstante, este volcado del contenedor a XML tenía dos limitaciones que impedían crear servicios inline: cuando usas un configurador de servicios y cuando defines una factoría privada usando la nueva sintaxis de las factorías.

En Symfony 2.7 todos estos problemas desaparecen y el contenedor es capaz ahora de crear servicios inline en todos los casos, lo que aumenta muy ligeramente el rendimiento de la aplicación.

Esta funcionalidad ha sido desarrollada por Christian Flothmann en el pull request #14030 de Symfony.

Improved YAML service definition syntax

YAML es uno de los tres formatos de configuración que se pueden usar para definir los servicios en las aplicaciones Symfony. En las versiones actuales de Symfony, cuando defines un servicio complejo con YAML, tiene la siguiente pinta:

# app/config/services.yml
services:
    manager:
        class:     AppBundle\Manager\UserManager
        arguments: [true]
        calls:
            - [setLogger, ["@logger"]]
            - [setClass, ["User"]]
        tags:
            -  { name: twig.extension, alias: user }

En Symfony 2.7 se ha mejorado la sintaxis YAML para que puedas usar una configuración más expresiva si así lo prefieres (por supuesto el anterior formato sigue funcionando perfectamente):

# app/config/services.yml
services:
    manager:
        class: AppBundle\Manager\UserManager
        arguments:
          - true
        calls:
          - method: setLogger
            arguments:
              - "@logger"
          - method: setClass
            arguments:
              - User
        tags:
          - name: manager
            alias: user

Esta funcionalidad ha sido desarrollada por Martin Hasoň en el pull request #13892 de Symfony.

Los servicios sincronizados se han declarado obsoletos

En las aplicaciones Symfony, un servicio no puede depender de otros servicios cuyo scope sea más restringido. En la práctica esto significa que si intentas inyectar el servicio request en cualquier otro servicio, verás un error de tipo ScopeWideningInjectionException.

Symfony 2.3 introdujo el concepto de servicios sincronizados para tratar de resolver este problema. Por eso el servicio request está definido como de tipo synchronized:

services:
    request:
        scope: request
        synchronized: true
        # ...

De esta manera ahora sí que puedes inyectar el servicio request usando la inyección mediante setter:

namespace AppBundle\Mail;
 
use Symfony\Component\HttpFoundation\Request;
 
class Mailer
{
    protected $request;
 
    public function setRequest(Request $request = null)
    {
        $this->request = $request;
    }
 
    // ...
}
# app/config/services.yml
services:
    mailer:
        class: AppBundle\Mail\Mailer
        calls:
            - [setRequest, ["@?request"]]

En cualquier caso, el verdadero problema es que request no debería ser un servicio, ya que la petición debería ser simplemente un value object. En Symfony 3 este problema se solucionará de una vez por todas porque desaparece el servicio request.

Mientras tanto, en Symfony 2.7 se han declarado obsoletos los servicios sincronizados, porque también se van a eliminar en Symfony 3. El motivo es que es una funcionalidad bastante compleja que realmente no necesitamos y además, no es la forma correcta de solucionar el problema. La solución alternativa, como seguramente sabes, es inyectar el servicio request_stack en vez de request.

Esta funcionalidad ha sido desarrollada por Fabien Potencier en el pull request #13289 de Symfony.

Comentarios

Este artículo ya no permite añadir más comentarios.
¿Por qué? Los artículos cierran sus comentarios automáticamente unos meses después de su publicación para asegurar que estos sigan siendo relevantes.

Publicada el

28 de abril de 2015

Etiquetas

Proyectos Symfony destacados

La forma más sencilla de generar el backend de tus aplicaciones Symfony. Ver más

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