1. Code
  2. Coding Fundamentals
  3. Design Patterns

Cómo usar el Despachador de Eventos de Symfony para PHP

Scroll to top

Spanish (Español) translation by Rene Soto (you can also view the original English article)

En este artículo, veremos algunos ejemplos de uso del componente Symfony DependencyInjection. Aprenderás los conceptos básicos de la inyección de dependencia, que permite un código más limpio y más modular, y verás cómo usarlo en tu aplicación PHP con el componente Symfony.

¿Qué es el Componente Symfony DependencyInjection?

El componente Symfony DependencyInjection proporciona una manera estándar de crear instancias de objetos y manejar la administración de dependencias en tus aplicaciones PHP. El corazón del componente DependencyInjection es un contenedor que contiene todos los servicios disponibles en la aplicación.

Durante la fase de arranque de su aplicación, debes registrar todos los servicios en tu aplicación en el contenedor. En una etapa posterior, el contenedor es responsable de crear los servicios según sea necesario. Más importante aún, el contenedor también es responsable de crear e inyectar dependencias de los servicios.

El beneficio de este enfoque es que no tiene que codificar el proceso de creación de instancias de objetos, ya que las dependencias se detectarán e inyectarán automáticamente. Esto crea un acoplamiento suelto entre las partes de su aplicación.

En este artículo, exploraremos cómo puede liberar el poder del componente DependencyInjection. Como es habitual, comenzaremos con las instrucciones de instalación y configuración, e implementaremos algunos ejemplos reales para demostrar los conceptos clave.

Instalación y Configuración

En esta sección, seguiremos adelante e instalaremos el componente DependencyInjection. Supongo que ya ha instalado Composer en su sistema, ya que lo necesitaremos para instalar el componente DependencyInjection disponible en Packagist.

Continúe e instale el componente DependencyInjection utilizando el siguiente comando.

1
$composer require symfony/dependency-injection

Eso debería haber creado el archivo composer.json, que debería tener este aspecto:

1
{
2
    "require": {
3
        "symfony/dependency-injection": "^4.1",
4
    }
5
}

También instalaremos algunos otros componentes que serán útiles en nuestros ejemplos.

Si deseas cargar servicios desde un archivo YAML en lugar de definirlo en el código PHP, el componente Yaml es el que lo rescata, ya que lo ayuda a convertir cadenas YAML a tipos de datos compatibles con PHP y viceversa.

1
$composer require symfony/yaml

Finalmente, instalaremos el componente Config, que proporciona varias clases de utilidades para inicializar y tratar los valores de configuración que se definen en diferentes tipos de archivos como YAML, INI y XML. En nuestro caso, lo usaremos para cargar servicios desde el archivo YAML.

1
$composer require symfony/config

Modifiquemos el archivo composer.json para que se vea como el siguiente.

1
{
2
    "require": {
3
        "symfony/dependency-injection": "^4.1",
4
        "symfony/config": "^4.1",
5
        "symfony/yaml": "^4.1"
6
    },
7
    "autoload": {
8
         "psr-4": {
9
             "Services\\": "src"
10
         },
11
         "classmap": ["src"]
12
    }
13
}

Como hemos agregado una nueva entrada de mapa de clase, avancemos y actualicemos el cargador automático del compositor ejecutando el siguiente comando.

1
$composer dump -o

Ahora, puede usar el espacio de nombres de Services para cargar automáticamente las clases en el directorio src.

Así que esa es la parte de instalación, pero ¿cómo se supone que debes usarla? De hecho, solo es cuestión de incluir el archivo autoload.php creado por Composer en su aplicación, como se muestra en el siguiente fragmento de código.

1
<?php
2
require_once './vendor/autoload.php';
3
4
// application code

5
?>

Cómo Trabajar con un Contenedor

En esta sección, veremos un ejemplo para demostrar cómo podría inyectar servicios en un contenedor Un contenedor debe actuar como un repositorio central que contiene todos los servicios en su aplicación. Más adelante, podríamos usar el contenedor para buscar servicios según sea necesario.

Para empezar, avancemos y definamos un servicio bastante básico en src/DemoService.php con los siguientes contenidos.

1
<?php
2
// src/DemoService.php

3
namespace Services;
4
5
class DemoService
6
{
7
  public function helloWorld()
8
  {
9
    return "Hello World!\n";
10
  }
11
}

Este es un servicio muy simple que solo implementa el método helloWorld por el momento.

A continuación, siga adelante y cree el archivo basic_container.php con los siguientes contenidos en la raíz de su aplicación.

1
<?php
2
// basic_container.php

3
require_once './vendor/autoload.php';
4
use Symfony\Component\DependencyInjection\ContainerBuilder;
5
6
// init service container

7
$containerBuilder = new ContainerBuilder();
8
9
// add service into the service container

10
$containerBuilder->register('demo.service', '\Services\DemoService');
11
12
// fetch service from the service container

13
$demoService = $containerBuilder->get('demo.service');
14
echo $demoService->helloWorld();

Para empezar, inicializamos el objeto ContainerBuilder con el nuevo constructor ContainerBuilder(). Luego, utilizamos el método de register del objeto ContainerBuilder para inyectar nuestro servicio personalizado \Services\DemoService en el contenedor. El demo.service actúa como un alias para nuestro servicio.

Finalmente, usamos el método get del objeto ContainerBuilder para obtener nuestro servicio del contenedor y lo usamos para llamar al método helloWorld.

Así que eso fue una demostración básica de cómo trabajar con un contenedor. En la siguiente sección, ampliaremos este ejemplo para explorar cómo se resuelven las dependencias de clase utilizando un contenedor.

Un Ejemplo Practicante

En esta sección, crearemos un ejemplo que demuestre cómo se resuelven las dependencias de clase usando el componente DependencyInjection.

Para demostrarlo, crearemos un nuevo servicio DependentService que requiere DemoService service, creado en la sección anterior, como una dependencia. Por lo tanto, veremos cómo el servicio DemoService se inyecta automáticamente como una dependencia cuando se crea una instancia DependentService

Continúe y cree el archivo src/DependentService.php con el siguiente contenido para definir el servicio DependentService.

1
<?php
2
// src/DependentService.php

3
namespace Services;
4
5
class DependentService
6
{
7
  private $demo_service;
8
9
  public function __construct(\Services\DemoService $demoService)
10
  {
11
    $this->demo_service = $demoService;
12
  }
13
14
  public function helloWorld()
15
  {
16
    return $this->demo_service->helloWorld();
17
  }
18
}

Como puedes ver, se requiere el servicio \Service\DemoService para crear una instancia del servicio DependentService.

A continuación, siga adelante y cree el archivo di_container.php con el siguiente contenido.

1
<?php
2
// di_container.php

3
require_once './vendor/autoload.php';
4
use Symfony\Component\DependencyInjection\ContainerBuilder;
5
use Symfony\Component\DependencyInjection\Reference;
6
7
// init service container

8
$containerBuilder = new ContainerBuilder();
9
10
// add demo service into the service container

11
$containerBuilder->register('demo.service', '\Services\DemoService');
12
13
// add dependent service into the service container

14
$containerBuilder->register('dependent.service', '\Services\DependentService')
15
                 ->addArgument(new Reference('demo.service'));
16
17
// fetch service from the service container

18
$dependentService = $containerBuilder->get('dependent.service');
19
echo $dependentService->helloWorld();

Estamos utilizando el mismo método de register para inyectar nuestro servicio personalizado \ Servicies \ DependentService en el contenedor.

Además de eso, también hemos utilizado el método addArgument para informar al contenedor sobre la dependencia del servicio DependentService. Hemos utilizado la clase Reference para informar al contenedor que necesita inyectar el servicio demo.service cuando se inicializa el servicio depend.service. De esa manera, una dependencia se inyecta automáticamente según sea necesario.

Finalmente, hemos utilizado el método get del objeto ContainerBuilder para obtener el servicio depend.service del objeto ContainerBuilder y lo hemos utilizado para llamar al método helloWorld.

De esta manera, el componente DependencyInjection proporciona una manera estándar de instanciar objetos e inyectar dependencias en tu aplicación.

Cómo Cargar Dinámicamente Servicios Usando el Archivo YAML

En esta última sección, exploraremos cómo puedes cargar dinámicamente servicios desde el archivo YAML. Básicamente, actualizaremos el ejemplo discutido en la sección anterior.

Además del componente DependencyInjection, también necesitaremos dos componentes Symfony más para implementar el ejemplo de YAML: Config y Yaml. Recuerde que ya hemos instalado estos dos componentes en la sección de Instalación y Configuración junto con el componente DependencyInjection. Así que estamos bien para empezar!

Continúe y cree el archivo services.yaml con el siguiente contenido en la raíz de su aplicación.

1
services:
2
    demo.service:
3
        class:     \Services\DemoService
4
    dependent.service:
5
        class:     \Services\DependentService
6
        arguments: ["@demo.service"]

Como puede ver, es bastante sencillo definir los servicios utilizando la sintaxis YAML. Para definir las dependencias de su servicio, deberá utilizar la clave arguments.

A continuación, siga adelante y cree el archivo di_yaml_container.php con el siguiente contenido.

1
<?php
2
// di_yaml_container.php

3
require_once './vendor/autoload.php';
4
use Symfony\Component\DependencyInjection\ContainerBuilder;
5
use Symfony\Component\Config\FileLocator;
6
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
7
8
// init service container

9
$containerBuilder = new ContainerBuilder();
10
11
// init yaml file loader

12
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__));
13
14
// load services from the yaml file

15
$loader->load('services.yaml');
16
17
// fetch service from the service container

18
$serviceOne = $containerBuilder->get('dependent.service');
19
echo $serviceOne->helloWorld();

Casi todo es lo mismo, excepto que estamos cargando servicios del archivo services.yaml en lugar de definirlo en el propio código PHP. Esto permite definir dinámicamente las dependencias de la aplicación.

Conclusión

El componente Symfony DependencyInjection tomó el centro de atención en este tutorial. Vimos cómo instalar y configurar DependencyInjection, así como algunos ejemplos reales de cómo se puede usar.

Estoy realmente fascinado y entusiasmado con los componentes desacoplados del marco de trabajo de Symfony que puedes elegir para tu aplicación. ¡Conéctalos a tu código y simplemente funcionan! En general, solo puedo ver los beneficios de este nuevo enfoque de marco para nuestra comunidad de PHP.

Comparte tus opiniones y sugerencias utilizando los comentarios abajo. Me encantaría platicar contigo mas!