Symfony: tutorial 4: el día a día con las bases de datos

2018-08-14 - Categorías: PHP / Symfony
Symfony4 Doctrine Migrations

Otra vez más traigo de nuevo otro HOWTO de la serie de tutoriales de iniciación a Symfony, esta vez trabajando día a día con bases de datos en Symfony. En el tutorial anterior empecé con cómo empezar a crear una base de datos. Ahora lo extiendo ya que trabajar con la base de datos es un tema muy extenso.

En este minitutorial me centro más en cómo modificar la base de datos, cómo es el día a día. Cómo desplegar estos cambios en producción sin temor a dejar sin servicio todo el sistema por haber hecho un cambio inesperado. Es importante que tengas un plan B por si lo último modificado rompe producción, y así puedas hechar atrás los últimos cambios de la base de datos.

Creando un proyecto para hacer pruebas

Doy por sentado de que nos manejamos bien con PHP, Composer y los comandos de Symfony, así que vamos a la línea de comandos y creamos el proyecto con todos los módulos que vamos a usar. En versiones anteriores a Symfony 5 se hace con:

composer create-project symfony/skeleton symfony-tutorial-4
cd symfony-tutorial-4
composer require maker --dev
composer require doctrine server

Con la versión de Symfony 5 podemos hacer:

symfony new symfony-tutorial-4
cd symfony-tutorial-4
composer require maker --dev
composer require doctrine

Con esto ya tenemos algunas cosas básicas, pero vamos a añadir el sistema de plantillas Twig, y algunos extras para hacer automáticamente la interfaz web:

composer require annotations form validator twig-bundle security-csrf

Creando una primera estructura de base de datos

Para jugar con el proyecto, y ver todas estas cosas del post, vamos a crear una agenda de contactos. Así podremos ir haciendo modificaciones, guardando datos, etc. Para esto usamos el comando make:entity y creamos una entidad que se llame Contact, con los siguientes campos:

  • name: una cadena de tipo string, que tiene por defecto 255 caracteres.
  • mobileNumber: también cadena string.
  • address: y de nuevo string.

Para esto ejecutamos:

php bin/console make:entity

..y seguimos las instrucciones. No pongas tildes ni mayúsculas para los nombres de los campos. Con esto se nos creará el fichero de entidad src/Entity/Contact.php

Creando por primera vez la estructura

Ahora para guardar en la base de datos estos cambios tendremos que modificar el fichero .env para decirle donde tenemos la BD. En mi caso tengo una BD Mysql instalada en local con la siguiente cadena de conexión:

DATABASE_URL=mysql://root@127.0.0.1:3306/test

Y finalmente ejecutaremos por primera vez el creado de la base de datos, y el creado de la estructura de tablas. Para esto tenemos que usar:

php bin/console doctrine:database:create
php bin/console doctrine:schema:create

A lo bruto o sin historial

Ahora viene el día a día, vamos modificando la base de datos y tenemos que pasar estos cambios a producción. Añadimos un par de campos nuevos llamados email y fijo también de tipo string por defecto de 255 caracteres. Así ejecutamos:

php bin/console make:entity Contact

Ahora tendremos que actualizar la base de datos para que añada estas dos columnas. Antiguamente, a lo bruto, o sin user ningún módulo para llevar historial de modificaciones, podemos ejecutar:

php bin/console doctrine:schema:update --dump-sql

Y veremos qué cambios se necesitan aplicar en la base de datos para que se corresponda con lo que tenemos ya añadido en el PHP de la entidad:

ALTER TABLE contact ADD email VARCHAR(255) DEFAULT NULL, ADD fijo VARCHAR(255) DEFAULT NULL;

Con esto comenzamos con los posibles problemas. Imaginemos, por ejemplo, que añadimos un campo que debe ser obligatorio, y que referencia a otra tabla. Si ejecutáramos esto en producción, si hacer un recorrido de los datos inicializándolos, tendríamos un serio problema de integridad de datos, ya que quedarían estos sin ser los correctos. Deberíamos de modificar la sentencia SQL anterior, añadirle todo lo necesario, guardarlo en un fichero .sql por si acaso, para posteriormente ejecutarlo en producción y mantener la integridad de los datos.

No es el caso porque simplemente quedarán en blanco las nuevas columnas y no supone un problema. Podemos entonces ejecutar lo siguiente:

php bin/console doctrine:schema:update --dump-sql --force

Con Doctrine Migrations

Doctrine Migrations es un sistema de versionado de la base de datos. Con ésto podremos ir guardando versiones de la base de datos, o mejor dicho, scripts de SQL que hacen que una base de datos pase de una versión a otra. Ya lo teníamos antes disponible como bundle instalable. Ahora es más sencillo ya que viene en el pack al haber instalado Doctrine con Composer.

Con esto podremos preparar estos pasos de versión, editando, revisando estos scripts que pasan la base de datos de una versión a otra. En caso de problemas podremos echar atrás también los cambios en la base de datos, igual que haríamos con Git y los códigos fuentes. Igual que si metemos un error un producción por códigos fuentes podemos echarlo atrás, con Doctrine Migrations también podremos ir versión atrás.

Para guardar la siguiente modificación tenemos el primer comando siguiente:

php bin/console make:migration

..el segundo comando siguiente ejecuta los cambios en la base de datos:

php bin/console doctrine:migrations:migrate

Más abajo explico cómo revertir cambios. Tenemos más comandos, para hacer lo dicho anteriormente, tal y como dice la ayuda de línea de comandos:

  • doctrine:migrations:diff Generate a migration by comparing your current database to your mapping information.
  • doctrine:migrations:execute Execute a single migration version up or down manually.
  • doctrine:migrations:generate Generate a blank migration class.
  • doctrine:migrations:latest Outputs the latest version number.
  • doctrine:migrations:migrate Execute a migration to a specified version or the latest available version.
  • doctrine:migrations:status View the status of a set of migrations.
  • doctrine:migrations:version Manually add and delete migration versions from the version table.

Si nos fijamos en el directorio migrations/ tendremos todos estos scripts. Este directorio se ha movido aquí en las últimas versiones de Symfony. En este caso tendremos sólo el script que añade o borra los últimos cambios. Es decir, tenemos:

<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
final class Version20210306104218 extends AbstractMigration
{
    public function getDescription() : string
    {
        return '';
    }

    public function up(Schema $schema) : void
    {
        // this up() migration is auto-generated, please modify it to your needs
        $this->addSql('CREATE TABLE contact (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) DEFAULT NULL, mobile_number VARCHAR(255) DEFAULT NULL, address VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
    }

    public function down(Schema $schema) : void
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->addSql('DROP TABLE contact');
    }
}

Aquí es donde podemos editarlo y añadir más acciones para mantener la integridad de los datos. Quizá hemos añadido un campo que siempre tiene que tener un valor, pero como es nuevo los registros existentes no lo tienen relleno, tendremos que rellenarlos aquí. Quizá es una relación entre entidades, o un largo etéctera.

Terminando, revirtiendo cambios

Fíjate que tenemos dos funciones, una función up que modifica la BD para pasar a la siguiente versión. Y la segunda función down que revierte los cambios. En mi caso, esta modificación de la BD se ha guardado como la versión 20200423185100. Entonces, para lanzar manualmente una migración arriba podemos ejecutar:

php bin/console doctrine:migrations:execute 'DoctrineMigrations\Version20210306104218' --up

..y para revertir esta migración:

php bin/console doctrine:migrations:execute 'DoctrineMigrations\Version20210306104218' --down

Dejo en GitHub el código fuente para este tutorial:
https://github.com/jaimenj/symfony-starter-tutorials

También me remito a la documentación oficial para el que quiera seguir:
https://symfony.com/doc/current/doctrine.html

Otro día más.. ¡Un saludo!

5 respuestas a “Symfony: tutorial 4: el día a día con las bases de datos”

  1. Enrique dice:

    Hola:
    ¿Hay alguna manera de eliminar el campo id y poner como clave primaria otro campo diferente?

    Por ejemplo, en una tabla de personas quiero poner el dni como pk y que no me cree el campo id que crea por defecto.

    Muchísimas gracias

    • Jnj dice:

      Hola Enrique!

      Doctrine siempre necesita un identificador. Puedes nombrar como identificador cualquier otra columna en la notación, si no me equivoco, pero no se puede usar una columna de tipo string como identificador por defecto, hay que crear un generador de identificadores.

      El camino más fácil es ignorar el campo $id, lo dejas tal cual, y haces único el campo $dni, luego simplemente hay que buscar por $dni haciendo cosas como findByDni($dniToSearch), findBy([‘dni’ => $dniToSearch]), etc..

      Espero haberte podido ayudar. No hay de que. Muchas gracias por dejar un comentario!

  2. Pablo dice:

    Me he pasado HORAS buscando como hacer un rollback específico de una versión de migración y solamente lo he encontrado en este tutorial. Ni Doctrine ni Symfony lo aclaran. Tan solo era poner en comillas simple junto con el namespace.

    php bin/console doctrine:migrations:execute ‘DoctrineMigrations\Version20210306104218’ –down
    php bin/console doctrine:migrations:execute ‘DoctrineMigrations\Version20210306104218’ –up

    Siempre me recuerda la opinión del creador de PHP acerca de los frameworks.

    Muchas gracias a quien hizo ésta documentación!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

© 2024 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.