Migraciones
¡Hemos creado una clase de entidad! Pero... eso es todo. La tabla correspondiente aún no existe en nuestra base de datos.
Pensemos. En teoría, Doctrine conoce nuestra entidad, todas sus propiedades y sus atributos ORM\Column
. Entonces... ¿no debería Doctrine ser capaz de crear esa tabla por nosotros automáticamente? Sí Puede hacerlo.
El comando make:migration
Cuando instalamos Doctrine anteriormente, venía con una biblioteca de migraciones que es increíble. ¡Échale un vistazo! Cada vez que hagas un cambio en la estructura de tu base de datos, como añadir una nueva clase de entidad, o incluso añadir una nueva propiedad a una entidad existente, debes ir a tu terminal y ejecutar
symfony console make:migration
En este caso, estoy ejecutando symfony console
porque esto va a hablar con nuestra base de datos. Ejecuta eso y... ¡perfecto! Se ha creado un nuevo archivo en el directorio migrations/
con una marca de tiempo para la fecha de hoy. Vamos a comprobarlo! Busca migrations/
y abre el nuevo archivo.
// ... lines 1 - 12 | |
final class Version20220718170654 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 SEQUENCE vinyl_mix_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); | |
$this->addSql('CREATE TABLE vinyl_mix (id INT NOT NULL, title VARCHAR(255) NOT NULL, description TEXT DEFAULT NULL, track_count INT NOT NULL, genre VARCHAR(255) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); | |
$this->addSql('COMMENT ON COLUMN vinyl_mix.created_at IS \'(DC2Type:datetime_immutable)\''); | |
} | |
public function down(Schema $schema): void | |
{ | |
// this down() migration is auto-generated, please modify it to your needs | |
$this->addSql('CREATE SCHEMA public'); | |
$this->addSql('DROP SEQUENCE vinyl_mix_id_seq CASCADE'); | |
$this->addSql('DROP TABLE vinyl_mix'); | |
} | |
} |
Esto contiene una clase con los métodos up()
y down()
... aunque nunca ejecuto las migraciones en sentido "descendente", así que nos centraremos sólo en up()
. Y... ¡esto es genial! El comando de migraciones vio nuestra entidad VinylMix
, se dio cuenta de que faltaba su tabla en la base de datos y generó el SQL necesario en Postgres para crearla, incluyendo todas las columnas. Ha sido muy fácil.
Ejecutar la migración
Bien... ¿cómo ejecutamos esta migración? De vuelta a tu terminal, ejecuta:
symfony console doctrine:migrations:migrate
Di y
para confirmar y... ¡precioso! Nos dice que es Migrating up to
esa versión específica. Parece... ¡que ha funcionado! Para asegurarte, puedes probar con otro comando bin/console
: symfony console doctrine:query:sql
con SELECT * FROM vinyl_mix
.
symfony console doctrine:query:sql 'SELECT * FROM vinyl_mix'
Cuando probamos eso... ¡Ups! Perdona mi error tipográfico... aquí no hay nada que ver. Inténtalo de nuevo y... ¡perfecto! ¡No nos da ningún error! Sólo dice queThe query yielded an empty result set
. Si esa tabla no existiera, comovinyl_foo
, Doctrine nos habría gritado.
Así pues, ¡la migración se ha ejecutado!
Cómo funcionan las migraciones
Este hermoso sistema merece algunas explicaciones. Ejecuta
symfony console doctrine:migrations:migrate
de nuevo. ¡Compruébalo! ¡Es lo suficientemente inteligente como para evitar ejecutar esa migración por segunda vez! Sabe que ya lo hizo. Pero... ¿cómo? Prueba a ejecutar otro comando:
symfony console doctrine:migrations:status
Esto da alguna información general sobre el sistema de migración. La parte más importante está en Storage
donde dice Table Name
y doctrine_migration_versions
.
El asunto es el siguiente: la primera vez que ejecutamos la migración, Doctrine creó esta tabla especial, que almacena literalmente una lista de todas las clases de migración que se han ejecutado. Entonces, cada vez que ejecutamos doctrine:migrations:migrate
, busca en nuestro directorio migrations/
, encuentra todas las clases, comprueba en la base de datos cuáles no se han ejecutado ya, y sólo llama a esas. Una vez que las nuevas migraciones terminan, las añade como filas a la tabla doctrine_migration_versions
.
Puedes visualizar esta tabla ejecutando:
symfony console doctrine:migrations:list
Ve nuestra única migración y sabe que ya la ha ejecutado. ¡Incluso tiene la fecha!
Esto es genial... pero vamos a ir más allá. A continuación, añadamos una nueva propiedad a nuestra entidad y generemos una segunda migración para añadir la columna.
Hi. Is there any restriction (with symfony 6) for executing an $entityManager->flush() inside a migration?
With symfony 5.4, I have no errors, but with 6.1 a PDOException is thrown like this:
[PDOException (42000)] <br /> SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT DOCTRINE_9 does not exist