Siguiendo los tutoriales de iniciación a Symfony, aquí extendemos uno de los tutoriales anteriores sobre el enrutamiento. Lo desarrollaremos un poco más, y generaremos un controlador CRUD con el maker de Symfony. Las peticiones CRUD son el Create, Retrieve, Update y Delete. Estas peticiones las podemos recibir, y controlar, para hacer lo que necesitemos. Las operaciones CRUD son las operaciones básicas que toda unidad de información necesita gestionarse, y ¡Symfony nos trae un generador de código fuente para los CRUDs!
Con Symfony Flex se ha mejorado de nuevo otra de sus herramientas, el enrutamiento. Todo el enrutamiento se puede configurar dentro de los controladores con las últimas versiones: URLs, parámetros, tipo de petición.. dentro de los mismos ficheros de controladores. Esto es realmente cómodo en el día a día, porque así cuando hay que tocar un controlador, estará todo en el mismo sitio. También, tenemos un comando para listar tanto rutas como nombres y sus propiedades mediante la línea de comandos, así será más fácil trabajarlos.
En estas últimas versiones 4 y 5 del enrutador de Symfony, según rankings independientes a Symfony, disponemos de un enrutamiento 75 veces más rápido que en la versión anterior. Es el enrutador PHP más rápido que hay, de nuevo, otro referente en el mundo del PHP.
Si quieres puedes bajar el código para seguir el post desde:
https://github.com/jaimenj/symfony-starter-tutorials
Un poco de teoría
Para éste tutorial, lo único que hay que saber es que los controladores son lo que reciben y responden a las peticiones HTTP, utilizando todo lo que haga falta de otras partes del programa. Es decir, si el navegador pide cada página del sitio web, debe haber un controlador que reciba dicha URL, haciendo lo que tenga que hacer por dentro de la aplicación, y devolviendo lo que tenga que devolver.
Creando el proyecto de pruebas
En las versiones anteriores a Symfony 5 podíamos hacer lo siguiente:
composer create-project symfony/skeleton symfony-tutorial-5
Ahora con el nuevo comando symfony podemos hacer:
symfony new symfony-tutorial-5
Entramos dentro del directorio nuevo, y le instalamos algunos vendors que vamos a usar en este proyecto:
cd symfony-tutorial-5/ composer require --dev maker composer require annotations twig orm form validator security-csrf
Arrancamos el servidor local para comenzar a probar cosas con los controladores, antes de Symfony 5 hacíamos:
php bin/console server:start
A partir de symfony 5 tenemos que hacer lo siguiente:
symfony server:start
Si vamos a http://localhost:8000/ no veremos nada más que lo siguiente en nuestro navegador. Eso es que ha ido bien..
Esta es la página por defecto que nos sale cuando estamos en local. Es una página placeholder que se ve cuando todavía no hemos creado ningún controlador que reciba rutas del navegador.
Recapitulando, comenzamos a enrutar
Para esto simplemente necesitamos crear nuestro primer controlador en este proyecto:
php bin/console make:controller
..y le ponemos un nombre, por ejemplo DefaultController. Esto nos creará el fichero src/Controller/DefaultController.php que es el controlador, y el fichero templates/default/index.html.twig porque he instalado el vendor de Twig para usarlo en la vista. En el controlador podremos ver lo siguiente:
<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; class DefaultController extends AbstractController { /** * @Route("/default", name="default") */ public function index() { return $this->render('default/index.html.twig', [ 'controller_name' => 'DefaultController', ]); } }
Mirando el código podemos ver que ya con este controlador, tenemos enrutada la URL /default que apunta a este recién generado controlador. Y en la vista tendremos lo siguiente:
{% extends 'base.html.twig' %} {% block title %}Hello DefaultController!{% endblock %} {% block body %} <style> .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; } .example-wrapper code { background: #F5F5F5; padding: 2px 6px; } </style> <div class="example-wrapper"> <h1>Hello {{ controller_name }}! ?</h1> This friendly message is coming from: <ul> <li>Your controller at <code><a href="{{ '/home/usuario/projects-src/symfony-starter-tutorials/symfony-tutorial-5/src/Controller/DefaultController.php'|file_link(0) }}">src/Controller/DefaultController.php</a></code></li> <li>Your template at <code><a href="{{ '/home/usuario/projects-src/symfony-starter-tutorials/symfony-tutorial-5/templates/default/index.html.twig'|file_link(0) }}">templates/default/index.html.twig</a></code></li> </ul> </div> {% endblock %}
Sigamos y vamos a hacer cosas.
Rutas con parámetros, enrutamiento de URLs dinámicas
Para esto simplemente podemos poner como hemos visto en tutoriales anteriores los parámetros en las anotaciones. Por ejemplo, si queremos recibir en este controlador un parámetro de forma amigable con la URL /ruta-amigable/{parametro} podemos editar el controlador anterior así:
/** * @Route("/ruta-amigable/{parametro}", name="default") */ public function index($parametro) {
De esta forma ya podemos usar la variable $parametro dentro de la acción del controlador.
Los objetos Request and Session
Desde que se recibe la petición del navegador hasta que se devuelve la respuesta, en Symfony ocurren muchas cosas. Hay dos objetos muy interesantes para gestionar lo que nos llega del navegador del visitante. Por ejemplo tenemos el objeto Request que representa la petición al completo. En esta petición tenemos información como parámetros, tanto datos GET como POST, o el tipo de petición, URL, IPs de clientes o forwarding si pasa por proxys, puertos, idioma, etcétera..
En el objeto Session tenemos otra información relacionada con la sesión que ha abierto un usuario en nuestro navegador. Es decir, cuando un usuario llega al servidor, se crea una sessión. Cuando va haciendo varias peticiones, podemos seguirle, sabiendo si es anónimo, si se ha logueado sabemos quién es, podemos almacenar variables de sesión, mensajes, etcétera..
Todo esto entonces lo tenemos modificando el ejemplo anterior así:
<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\Session; class DefaultController extends AbstractController { /** * @Route("/ruta-amigable/{parametro}", name="default") */ public function index($parametro, Request $request, Session $session) { return $this->render('default/index.html.twig', [ 'controller_name' => 'DefaultController', ]); } }
Simplemente, con eso, ya tenemos estos dos objetos en el controlador.
Redirigiendo visitas
Hay dos funcionalidades muy útiles en los controladores. La primera es la redirección, la otra es el forwarding. Con la redirección le devolvemos una respuesta al cliente y éste se redirigirá a otra web de destino que le indiquemos. Por ejemplo, para redirigir a otra ruta se hace así:
return $this->redirectToRoute('route_name2', array('parameter' => $value));
Con el forwarding lo que hacemos es ejecutar un controlador final cuando inicialmente hemos llamado a uno. El visitante recibirá directamente la respuesta del segundo controlador, no sabrá que se le ha hecho forwarding, con lo que su URL no cambiará. Esto se hace así:
$response = $this->forward('App\Controller\DefaultController::otherRoute', array( 'parameter' => $value, ));
Generando controladores CRUD automáticamente
Recapitulando, vamos ahora a generar una entidad, y con esta, generaremos el código fuente del controlador y plantillas automáticamente. Vamos entonces a generar una entidad de prueba, ejecutamos:
php bin/console make:entity Address
..y generamos una entidad para guardar una agenda de teléfonos. Podemos llamar a la entidad Address con name y phonenumber como propiedades. Así ya tenemos 2 columnas. Luego configuramos el fichero .env para que tenga base de datos como hemos visto en los tutoriales anteriores sobre bases de datos si los hemos seguido.. y ejecutamos lo siguiente para crear localmente nuestra base de datos:
php bin/console doctrine:database:create php bin/console doctrine:schema:create
Y ahora vamos a generar el controlador y vistas de este CRUD, ejecutamos:
php bin/console make:crud Address
..y elegimos la entidad Direccion recién creada. Y ahora, ya tenemos la interfaz para gestionar las direcciones. ¡Ya está! ¡Brutal! ¿Cierto? Si esto lo hacemos para 8-10 entidades de un proyecto completo, tenemos un buen punto de partida en muy pocos minutos para una aplicación de gestión. Tendremos los controladores CRUD funcionales, podremos ir directos a maquetar las plantillas y trabajar los controladores para las funcionalidades accesorias.
Si vamos al controlador, podemos ver entonces cómo se reciben y se enrutan los tipos de peticiones:
<?php
namespace App\Controller;
use App\Entity\Address;
use App\Form\AddressType;
use App\Repository\AddressRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/address")
*/
class AddressController extends AbstractController
{
/**
* @Route("/", name="address_index", methods={"GET"})
*/
public function index(AddressRepository $addressRepository): Response
{
return $this->render('address/index.html.twig', [
'addresses' => $addressRepository->findAll(),
]);
}
/**
* @Route("/new", name="address_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$address = new Address();
$form = $this->createForm(AddressType::class, $address);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($address);
$entityManager->flush();
return $this->redirectToRoute('address_index');
}
return $this->render('address/new.html.twig', [
'address' => $address,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="address_show", methods={"GET"})
*/
public function show(Address $address): Response
{
return $this->render('address/show.html.twig', [
'address' => $address,
]);
}
/**
* @Route("/{id}/edit", name="address_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Address $address): Response
{
$form = $this->createForm(AddressType::class, $address);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('address_index');
}
return $this->render('address/edit.html.twig', [
'address' => $address,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="address_delete", methods={"DELETE"})
*/
public function delete(Request $request, Address $address): Response
{
if ($this->isCsrfTokenValid('delete'.$address->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($address);
$entityManager->flush();
}
return $this->redirectToRoute('address_index');
}
}
Una maravilla el generador de CRUDs de Symfony. Podemos arrancar proyectos en muy poco tiempo cosa que sin estas herramientas podríamos tardar muchos días o semanas incluso en tener un prototipo funcional. Ahora si vamos a la línea de comandos podemos listar todos los controladores disponibles con la instrucción de la siguiente imagen:
Además, si le ponemos el parámetro –show-controllers podremos ir al grano a encontrar los ficheros de los controladores donde está cada cosa:
php bin/console debug:router --show-controllers
Ahora sí que para terminar sólo me queda remitirte a la documentación oficial para seguir avanzando sobre este tema:
https://symfony.com/doc/current/routing.html
Dejo los códigos fuentes de este codekata en GitHub con el curso completo:
https://github.com/jaimenj/symfony-starter-tutorials
Ahora sí, otro día más.. ¡Un saludo!
Excelente Gracias por tomarte el tiempo de hacerlo y compartir.
No hay de qué, gracias por dejar un comentario!
Hola, estoy intentado usar el servidor symfony por defecto, pero desde el terminal cuando introduzco «symfony server:start», no me reconoce el comando symfony. Estoy usando la versión symfony 6.1. Sabrías cual es el fallo que estoy teniendo?…Gracias.
Buenas tardes Mattias.
Symfony es un comando que hay que instalar en el sistema operativo que estés usando. Las instrucciones oficiales para Linux, Mac y Windows las tienes en:
https://symfony.com/download
Saludos.