Si alguna vez habéis trabajado con Symfony + Twig seguramente habréis notado las mismas carencias que yo. Estas son el uso de componentes para la creación de nuestro frontend. Bien es cierto que podemos llegar a conseguir un resultado similar con la etiqueta macro pero no es del todo lo ideal. Gracias a los nuevos paquetes introducidos en Symfony UX tenemos más opciones para abordar este tipo de situaciones.
Actualmente, a fecha de escritura de este post tenemos disponibles dos tipos de componenentes: normales y live components. Si conocéis el ecosistema de Laravel, los live components están inspirados en Livewire, mientras que lo más próximo a los normales serían los componentes de Blade. Ahora procederemos a probarlos.
A partir de este punto yo ya tengo instalada una aplicación Symfony 6.1 limpia para proceder a probar.
Componentes normales
Vamos a empezar echando un ojo a los componentes estáticos. Para ello instalaremos el paquete symfony/ux-twig-component
composer require symfony/ux-twig-component
Una vez instalado crearemos nuestro primer componente, un mensaje de alert para informar a nuestros usuarios de las operaciones que hagamos en nuestros contenidos. Para acelerar el proceso, en mi aplicación he creado un CRUD de artículos.
En el directorio src/Twig creamos nuestro AlertComponent.php. Aprovechando el uso de atributos de PHP 8.0 definimos nuestra clase AlertComponent con el atributo #[AsTwigComponent('alert')] de esta manera lo registramos y definimos el nombre con el que lo llamaremos en nuestra plantilla. También le vamos a añadir dos propiedades: "type" y "message", añadiremos un método que devolverá la clase que se le tiene que asignar en función del type. De esta manera nuestro componente reaccionará de un color u otro según el estado. Este sería el código resultante:
// src/Twig/AlertComponent.php <?php namespace App\Twig; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; #[AsTwigComponent('alert')] class AlertComponent { public string $type = 'success'; public string $message; public function getAlertClass(): string { return match ($this->type) { 'success' => 'green', 'error' => 'red', 'warning' => 'yellow' }; } }
También tenemos que añadir el archivo de la plantilla. Esto lo haremos en templates/components/alert.html.twig Aquí definiremos la plantilla de nuestro componente y tendremos acceso a las propiedades y métodos que hemos definido en nuestra clase. He usado una plantilla sencilla para no generar mucho ruido pero se puede ampliar a merced.
{# templates/components/alert.html.twig #} <div class="alert alert-{{ type }} {{ this.alertClass }}" role="alert"> <span> {{ message }} </span> </div>
Ahora usaremos nuestro componente en la plantilla en la que se muestran todos los artículos. Aquí es donde podremos configurar las variables que hemos definido en la clase. Yo he añadido algunos estilos para que se vea como la imagen.
{{ component('alert', { message: 'Soy un mensaje feliz 😁' }) }} {{ component('alert', { type: 'error', message: 'Soy un mensaje enfadado 😠' }) }} {{ component('alert', { type: 'warning', message: 'Soy un mensaje dudoso 🤖' }) }}
Vamos a darle una vuelta más a la tuerca, nuestros mensajes van a ser dinámicos en función de la respuesta de nuestro controlador. Para ello al final de una operación CRUD añadiremos un mensaje flash que guardará en la sesión el estado para mostrarlo en la vista. En nuestro controlador al crear un artículo añadiremos esta línea, modificaremos nuestra plantilla para que lea estos mensajes y renderice nuestro componente.
$this->addFlash('success', 'Se ha creado un nuevo artículo');
{% for status, messages in app.flashes %} {% for message in messages %} {{ component('alert', { type: status, message: message }) }} {% endfor %} {% endfor %}
Así pues nuestro componente recibe los datos del controlador y los transmite al usuario mediante nuestro componente. De esta forma podemos reutilizarlo a lo largo de nuestra aplicación. Los componentes tienen muchas más opciones que podemos consultar en su documentación. Puede que próximamente los exploremos más a fondo.
Live components
Veamos ahora los live components. Estos se caracterizan por ser interactivos sin necesidad de escribir JS. Vamos a crear un buscador en tiempo real para nuestros artículos. Lo primero será instalar el paquete y compilar las dependencias del tema.
composer require ux symfony/ux-live-component npm install --force npm run watch
Cabe destacar que este paquete se basa en los componentes anteriormente vistos por lo que la sintaxis es muy parecida y podremos convertir cualquier Twig Component que tengamos a un Live Component.
Procederemos a crear nuestro component. En mi caso queda de esta manera:
// src/Components/PostSearchComponent.php <?php namespace App\Components; use App\Repository\PostRepository; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; use Symfony\UX\LiveComponent\Attribute\LiveProp; use Symfony\UX\LiveComponent\DefaultActionTrait; #[AsLiveComponent('post_search')] class PostSearchComponent { use DefaultActionTrait; #[LiveProp(writable: true)] public string $query = ''; public function __construct(private readonly PostRepository $postRepository) { } public function getPosts(): array { return $this->postRepository->search($this->query); } }
{# templates/components/post_search.html.twig #} <div {{ attributes }}> <input type="search" data-model="query" value="{{ query }}" data-action="live#update" > <ul> {% for post in this.posts %} <li>{{ post.title }}</li> {% endfor %} </ul> </div>
De esta manera ya tenemos un buscador a tiempo real y no hemos tocado nada de JS.
Los usos son bastante variados, pero desde luego pueden hacerse cosas muy potentes. En su propia página nos dan algunos ejemplos, este es uno de ellos. También, al igual que el anterior hay mucha documentación y casos de uso por lo que os recomiendo que la visitéis si os pica la curiosidad. Me gustaría entrar más a fondo pero el artículo ya se está haciendo muy largo así que lo dejaré para futuros artículos.
Sin duda el ecosistema Symfony se está poniendo las pilas en el frontend, veremos si la línea sigue así. En la SymfonyWorld apareció un paquete para realizar layouts y tenía bastante buena pinta así que habrá que probarlo, aunque será en un artícuo futuro. Si has llegado hasta aquí muchas gracias y recuerda que cada semana hay un nuevo artículo por cada uno de nuestros compañeros, el de la semana pasada: Por qué usar un Drupal desacoplado
Comentarios
Añadir nuevo comentario