https://github.com/conejerock/medium-fruit-bundle
Como crear un bundle de Symfony desde cero añadiendo frutas a las HTTP Response
https://github.com/conejerock/medium-fruit-bundle
Last synced: about 1 year ago
JSON representation
Como crear un bundle de Symfony desde cero añadiendo frutas a las HTTP Response
- Host: GitHub
- URL: https://github.com/conejerock/medium-fruit-bundle
- Owner: conejerock
- Created: 2024-01-14T11:54:51.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-01-14T11:57:01.000Z (over 2 years ago)
- Last Synced: 2024-10-19T07:16:24.355Z (over 1 year ago)
- Language: PHP
- Size: 21.5 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Creando un bundle de Symfony desde Cero
========
> Artículo completo en: https://medium.com/@conejerock/creando-un-bundle-de-symfony-desde-cero-5afa7669f830
Hace poco, trabajando en un proyecto que tiene dos instancias Symfony, se dio la necesidad crear un Bundle para tener aislada una funcionalidad y que fuera compartida por las dos instancias.
Así que me puse a leer [documentación oficial de Symfony](https://symfony.com/doc/current/bundles/best_practices.html) y me dispuse a montarlo. Como cometí algunos errores y algunos líos mentales mientras lo creaba, he aquí mi tutorial en Español a quien le pueda servir de ayuda.
Para no liar la madeja, vamos a crear un Bundle que inserte en cada _Response HTTP,_ una cabecera con una **fruta aleatoria** (sí, ya sé que no es muy útil. Pero es lo primero que se me ha ocurrido). El Bundle se llamará **FruitBundle** (y sí, soy muy original)
Requesitos
==========
* [PHP](https://php.watch/articles/php-8.3-install-upgrade-on-fedora-rhel-el#quick-start) instalado (v8.3)
* [Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos) instalado
* [Symfony CLI](https://symfony.com/download#step-1-install-symfony-cli) instalado
Creando la estructura
=====================
Vamos a suponer que tenemos el siguiente árbol de ficheros de nuestro proyecto Symfony:
```
base
├── symfony-project
│ ├── bin
│ ├── composer.json
│ ├── composer.lock
│ ├── config
│ ├── public
│ ├── src
│ ├── symfony.lock
│ └── vendor
└── symfony-project-2
├── bin
├── composer.json
├── composer.lock
├── config
├── public
├── src
├── symfony.lock
└── vendor
```
En mi caso, como quería que el Bundle fuera **compartido por ambos proyectos** (_symfony-project_ y _symfony-project-2_) cree el Bundle en un directorio paralelo a estos dos. No obstante, si tu Bundle sólo va a ser utilizado por un proyecto, puedes crearlo junto al resto de carpetas (_bin, config, public, src…_).
Situándonos en la carpeta `base` haremos lo siguiente:
```bash
symfony new --debug --php=8.3 FruitBundle
```
Vale y dirás… ¡si esto crea otro proyecto de Symfony!
¡Exacto! Un Bundle no deja de ser un **miniproyecto** de Symfony que fusiona las funcionalidades del Bundle con el proyecto principal.
Ahora bien, se han creado algunas cosas que no nos interesan en el Bundle. Vamos a **borrar** aquello que no nos haga falta y a **cambiar la rama de Git**:
```bash
cd FruitBundle
rm -rf bin public config/\* src/\*
git branch -M main
```
Ahora mismo nuestra estructura de ficheros tendría que ser algo tal que así:
```
base
├── symfony-project
├── symfony-project-2
└── FruitBundle <---- Nuestro bundle
├── composer.json
├── composer.lock
├── config
├── src
├── symfony.lock
├── var
└── vendor
```
Ahora, crearemos el **archivo de entrada del Bundle**. Crearemos un archivo `FruitBundle.php`en la carpeta `src`. Ya lo configuraremos más adelante:
```php
// base/FruitBundle/src/FruitBundle.php
Yeah! Bundle creado
Configurando el proyecto principal
==================================
Con nuestro Bundle creado, sólo nos queda instalarlo en nuestro proyecto principal.
Puesto que Composer busca los paquetes para instalar en [https://packagist.org/](https://packagist.org/) (y nuestro Bundle aún no está publicado), debemos indicar que además busque en otro sitio (concretamente en el directorio `/FruitBundle`)
En mi caso, en `composer.json`del proyecto `symfony-project` incluiremos lo siguiente:
```json5
// base/symfony-project/composer.json
"autoload": {
"psr-4": {
"App\\": "src/", //Tu aplicación principal
"BasketFruit\\FruitBundle\\": "../FruitBundle/src/"
}
},
"repositories": [
{
"type": "path",
"url": "../FruitBundle",
"canonical": true
}
]
```
Una vez hecho esto, procedemos a instalar nuestro Bundle:
```bash
cd ../symfony-project
composer require basket-fruit/fruit-bundle:1.0.0
```
Una vez instalado, añadimos el Bundle a nuestra lista de Bundles en `symfony-project/config/bundles.php` :
```php
//config/bundles.php
['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
// nuestro FruitBundle
BasketFruit\FruitBundle::class => ['all' => true],
];
```
Ahora sí, nuestro bundle está integrado con el proyecto principal de Symfony. Si ejecutamos el siguiente comando en la consola de nuestro proyecto principal:
```bash
./bin/console config:dump-reference
```
Veremos lo siguiente (te saldrán otros Bundles si ya lo tienes intalados):
```
------------------- -----------------
Bundle name Extension alias
------------------- -----------------
FrameworkBundle framework
FruitBundle fruit <-- Nuestro Bundle integrado
MakerBundle maker
TwigBundle twig
WebProfilerBundle web\_profiler
------------------- -----------------
```
Añadiendo frutas a las respuestas
=================================
Vamos al turrón. Hemos dicho que queremos añadir una fruta aleatoria como cabecera a las _Responses HTTP_ que ofrece Symfony. Vamos allá:
Añadiendo listeners
-------------------
Para añadir esta simple cabecera, bastará con crear un listener que escuche el evento Response, y añadirle la cabecera antes de enviarla.
Según la documentación oficial, para seguir una buena estructura del Bundle, los _listeners_ deben ir en la carpeta `src/EventListener` de nuestro bundle.
Así bien, creamos la siguiente estructura de carpetas dentro de **FruitBundle**:
```
FruitBundle
├── src
│ ├── EventListener <----------------------- NEW
│ │ └── AddFruitResponseListener.php
│ └── FruitBundle.php
└── tests
```
El contenido del Listener es muy simple:
```php
// ./FruitBundle/src/EventListener/AddFruitResponseListener.php
getResponse();
$response->headers->set(self::HEADER_KEY, self::FRUITS[array_rand(self::FRUITS)]);
}
}
```
Configurando el listener
------------------------
Para que Symfony fusione nuestro listener del bundle con el proyecto principal, hay que indicarle que nuestra clase es un listener y que se lanza con el evento _ResponseEvent (valga la redundancia):_
Así, crearemos el archivo `FruitBundle/config/services.yaml` con el siguiente contenido:
```yaml
# ./FruitBundle/config/services.yaml
services:
BasketFruit\FruitBundle\EventListener\AddFruitResponseListener:
tags:
- { name: kernel.event\_listener, event: kernel.response }
```
Finalmente, esta configuración se tiene que cargar desde algún sitio. ¿Recordáis nuestra clase `FruitBundle.php`? Es la entrada principal del Bundle. En esa misma clase crearemos la función `loadExtension` que hereda de AbstractBundle, y es la encargada de cargar el archivo de configuración de nuestro bundle.
```php
// FruitBundle/src/FruitBundle.php
import('../config/services.yaml');
}
}
```
¡Listo! Ya deberíamos tener nuestro Bundle, añadiendo una cabecera `X-Random-Fruit` a las respuestas de nuestras peticiones al proyecto principal.