Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Migraciones

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

¡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 toesa 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.

Leave a comment!

2
Login or Register to join the conversation
Benoit-L Avatar
Benoit-L Avatar Benoit-L | posted hace 3 meses

Hi there,

This line does not work as such : symfony console doctrine:query:sql 'SELECT * FROM vinyl_mix'

Too many arguments to "doctrine:query:sql" command, expected arguments "sql".

Benoit

Reply

Hey Benoit,

It seems like your terminal does not like single quotes ' try surrounding your SQL code with double quotes "SELECT * FROM vinyl_mix

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.12", // 2.12.3
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
        "pagerfanta/twig": "^3.6", // v3.6.1
        "sensio/framework-extra-bundle": "^6.2", // v6.2.6
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/asset": "6.1.*", // v6.1.0
        "symfony/console": "6.1.*", // v6.1.2
        "symfony/dotenv": "6.1.*", // v6.1.0
        "symfony/flex": "^2", // v2.2.2
        "symfony/framework-bundle": "6.1.*", // v6.1.2
        "symfony/http-client": "6.1.*", // v6.1.2
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.1.*", // v6.1.0
        "symfony/runtime": "6.1.*", // v6.1.1
        "symfony/twig-bundle": "6.1.*", // v6.1.1
        "symfony/ux-turbo": "^2.0", // v2.3.0
        "symfony/webpack-encore-bundle": "^1.13", // v1.15.1
        "symfony/yaml": "6.1.*", // v6.1.2
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "6.1.*", // v6.1.0
        "symfony/maker-bundle": "^1.41", // v1.44.0
        "symfony/stopwatch": "6.1.*", // v6.1.0
        "symfony/web-profiler-bundle": "6.1.*", // v6.1.2
        "zenstruck/foundry": "^1.21" // v1.21.0
    }
}