Nuevo en Symfony 4.3: Configurando servicios con setters inmutables

Resulta habitual en algunas aplicaciones Symfony el uso de servicios inmutables que usas traits de PHP para definir sus funcionalidades opcionales. Aunque el contenedor de servicios de Symfony soporta la inyección vía setters, esta tiene algunos inconvenientes importantes (por ejemplo, los setters se pueden llamar más de una vez durante la ejecución de la aplicación, por lo que las dependencias del objeto podrían cambiar).

Una posible solución a este problema es lo que se llama los "métodos wither". Estos métodos (por ejemplo, withPropertyName()) suelen usar la palabra with como prefijo (de ahí su nombre) y devuelven una copia de la instancia de un objeto inmutable, pero con alguna de sus propiedades cambiadas:

class MyService
{
    use LoggerAwareTrait;
 
    // ...
}
 
trait LoggerAwareTrait
{
    private $logger;
 
    public function withLogger(LoggerInterface $logger)
    {
        $new = clone $this;
        $new->logger = $logger;
 
        return $new;
    }
}
 
$service = new MyService();
$service = $service->withLogger($logger);

Esto resuelve los principales problemas de la inyección vía setters y por eso Symfony 4.3 va a añadir soporte para los "métodos wither" en el contenedor de servicios.

Si defines los servicios usando YAML, pasa true como el tercer parámetro de la llamada al método:

# config/services.yaml
services:
    MyService:
        # ...
        calls:
            # el argumento TRUE hace que esto sea un método "wither"
            - ['withLogger', ['@logger'], true]

Si usas XML para definir los servicios, utiliza la opción returns-clone y pon su valor a true en la llamada al método:

<!-- config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <services>
        <service id="MyService">
            <!-- ... -->
            <call method="withLogger" returns-clone="true">
                <argument type="service" id="logger"/>
            </call>
        </service>
    </services>
</container>

Cuando utilizas autowiring de servicios, añade la anotación @return static para convertir el método en un "método wither":

class MyService
{
    // ...
 
    /**
     * @required
     * @return static
     */
    public function withLogger(LoggerInterface $logger)
    {
        // ...
    }
}

Esta funcionalidad fue contribuida por Nicolas Grekas en el pull request #30212.

Fuente: New in Symfony 4.3: Configuring services with immutable setters

Comentarios

Publicada el

24 de mayo de 2019

Etiquetas

Proyectos Symfony destacados

La plataforma de eCommerce 100% Symfony que rivaliza con Magento y PrestaShop. Ver más

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