Cómo crear un framework web propio mediante componentes de Symfony (I)
Muchas veces te habrás enfrentado al problema de tener que mantener una aplicación antigua construida en php plano sin ningún tipo de framework o utilizando algunas librerías pero no de una manera segura y estándar.
En esta serie de dos artículos, vamos a convertir un pequeño proyecto de ejemplo construido en php plano, a uno usando componentes estándar de Symfony. La aplicación trata de un listado de Personas con una ficha personal por cada una, con algunos datos.
En esta primera parte, vamos a modificar conceptos básicos de una página web (Creación de proyecto standard, control de base de datos y motor de renderizado de datos o plantillas).
Todo el código se puede consultar aquí y para probarlo puedes utilizar este proyecto de docker web.
Creación del proyecto
Lo primero que necesitamos para empezar el refactor es iniciar composer en nuestro proyecto para así poder incluir la gestión de dependencias y la carga del espacio de nombres.
Para ello simplemente necesitamos abrir una terminal en la raíz de nuestro proyecto e introducir el comando: composer init.
El comando nos irá pidiendo la información del proyecto para ir construyendo el fichero composer.json
Una vez hecho esto nos quedará un fichero composer.json similar a este:
Ahora vamos a crear el directorio en el que almacenaremos todo el código de nuestra aplicación y lo incluiremos en nuestro composer.json para hacer uso del autoload propio de composer.(Esto es posible gracias a la especificación PSR-4 de php que puedes consultar aquí para más información).
Para realizar esto vamos a incluir esta información en nuestro composer.json
En el cual customFramework es nuestro namespace base y src la carpeta, ubicada en la raíz del proyecto, en la que ubicaremos todo nuestro código.
Una vez hecho esto nos vamos a la raíz de nuestro proyecto y ejecutamos: composer install.
Esta orden es la encargada de descargar todas las dependencias y en este caso de generar la carpeta vendor y el autoload.
Cabe destacar que la carpeta vendor no debe comitearse y para ello hemos incluído un .gitignore en nuestro proyecto:
Por último ya simplemente nos queda hacer un require_once del autoload de composer en casa uno de nuestros ficheros:
Todo lo realizado en este punto puede consultarse en este commit.
Inclusión de un sistema ORM
Vayamos con el siguiente paso muy común en un sitio web, la base de datos. Hoy en día apenas quedan sitios web que no dispongan de una base de datos detrás para almacenar datos o configuraciones.
Todo este trabajo con la base de datos en proyectos antiguos solía hacerse utilizando directamente las funciones propias del SGBD provocando que nuestro sitio web estuviese sujeto a una dependencia del SGBD, como por ejemplo mysql,postgree,etc. Otro problema añadido a esto es que en las aplicaciones modernas es cada vez más común encontrarnos el uso de objetos en el propio código y que al almacenarlo en la base de datos tengamos que preocuparnos de realizar una correcta adaptación de los datos.
Con el fin de solventar estos problemas nacieron los sistemas ORM o lo que es lo mismo Object-Relational mapping. Un ORM es un sistema que se encarga de adaptar objetos para que puedan ser almacenados fácilmente en una base de datos del tipo relacional (Mysql,postgre,oracle,etc). En nuestro caso vamos a hablar de Doctrine.
Doctrine es una librería construida en php que se encarga de este mapeo objeto-relacional mediante modelos, esto significa que nosotros crearemos clases que representarán nuestras entidades y mediante ciertos comentarios de tipo phpdoc le indicaremos a doctrine cómo mapear dichos objetos a la base de datos.
Otra gran funcionalidad de la que dispone Doctrine es que es independiente del sistema gestor de bases de datos, simplemente modificando en la configuración el sistema utilizado podemos cambiar de uno a otro. Lo cual nos permite trabajar con múltiples sistemas gestores de bases de datos sin tener que modificar el código de nuestra aplicación.
Una vez explicado esto pasemos a integrarlo en nuestro proyecto para continuar con la refactorización del mismo.
El primer paso es indicar en nuestro composer del proyecto que vamos a tener una nueva dependencia (Doctrine), para esto hay dos maneras de hacerlo:
- Mediante línea de comandos ejecutando composer require doctrine/orm en el directorio en el que se encuentra composer.json
- Introduciendo la dependencia en el fichero composer.json a mano y ejecutando después composer install
De ambas maneras el resultado debe ser una línea en el composer.json indicando la nueva dependencia y la versión y la propia librería descargada dentro del directorio vendor (esto es un paso automático que realiza composer utilizando cualquiera de los métodos).
Nota: En este punto se ha añadido al composer.json la restricción de que la aplicación necesita una versión de php mayor o igual a 7.1 por compatibilidad con la versión de doctrine actual (2.6)
Una vez hecho esto ya tenemos el orm como dependencia en nuestro proyecto y podemos empezar a hacer uso del mismo.
Pasemos ahora a refactorizar los usos de la base de datos y ordenar esa parte del código.
Lo primero es definir una parte común que sea la encargada de trabajar con la base de datos y que sea el punto de inicialización. de esta forma evitamos código duplicado.
Vamos a crear una clase llamada DoctrineHelper con espacio de nombres customFramework\helper\doctrine en el directorio raiz_proyecto/src/helper/doctrine. Esta será nuestra clase encargada de devolvernos cada una de las entidades con las que trabajaremos mediante un entityManager
Ahora vamos a crear el modelo para la tabla de nuestro ejemplo, por supuesto en una aplicación real habrá muchos modelos y entidades, pero en nuestro ejemplo tendremos uno.
Para ello crearemos una clase en el directorio que hemos indicado al entity manager para los modelos (
También deberemos crear métodos setters y getters para poder cambiar y obtener los datos. Como por ejemplo:
Este indicando la tabla en la que se almacena esta entidad
Este indicando que el campo es el id, que es autoincrementado y que es de tipo entero. Una vez tengamos esto podemos pasar por fin a modificar las llamadas a bases de datos que teníamos en el código para usar la nueva estructura con doctrine.
Todo el código realizado en este punto puede verse en este commit.
Inclusión de un sistema de template
Pasemos ahora al siguiente punto importante, el modo en el que se muestran los datos desde nuestro código.
La mejor manera de crear una aplicación es mediante el uso del patrón MVC (Modelo-Vista-Controlador. Esto significa separar el código para almacenar los datos (modelo) del trabajo a realizar con los datos (controlador) y del modo en que se muestran los mismos (vista).
El modelo ya se separó en el punto anterior y en este vamos a separar la vista, para lo cual vamos a sustituir el sistema de template por defecto de php por uno llamado Twig
Este sistema de template presenta ventajas como lenguaje específico para la visualización de datos, mayor velocidad de procesamiento gracias a un sistema de caché, herencia entre templates y muchas otras que pueden ser consultadas en su web oficial.
Para integrar este sistema de templates en primer lugar deberemos indicarle a composer la dependencia:
composer require twig/twig.
Tras esto tendremos algo como esto en nuestro composer.json:
Ahora vamos a crear una clase llamada TwigHelper con espacio de nombres customFramework\helper\twig en el directorio raiz_proyecto>/src/helper/twig. Esta clase será la encargada de renderizar la template que le indiquemos o de devolvernos el objeto twigRender si queremos hacer algo más personalizado.
En esta clase inicializamos el sistema twig indicando la ruta en la que se encuentran nuestras templates y la carpeta en la que queremos almacenar las cachés.
Una vez tenemos esto el siguiente paso es quitar todo el html de nuestros ficheros index.php y persons.php y llevarlo a ficheros twig en la carpeta que hemos indicado.
Para ello vamos a aprovechar la herencia de plantillas de twig, esto significa que vamos a crear una plantilla base (base.twig) con el html básico y otras dos (index.twig y person.twig) que únicamente van a incluir el contenido necesario en el bloque cuerpo.
Una vez hecho esto ya podremos realizar las llamadas a esas plantillas desde nuestro código utilizando la clase que creamos anteriormente. De esta manera nuestro código en los archivos index.php y persons.php se ve reducido a unas cuantas líneas como estas.
Todo el código realizado en este punto puede verse en este commit.
En esta primera entrega, hemos cambiado las partes más básicas de una web para convertirla en algo un poco más standard, cambiando el modo de cargar datos desde una base de datos, además de la manera de mostrar los datos al usuario para hacerlo más extensible y limpio.
¡No te pierdas la segunda entrega!