Tutoriel Vidéo PHP Phinx Migrer sa base de données avec Phinx

Télécharger la vidéo

Versionner son projet PHP permet de garder en mémoire l'historique des modifications et permet aussi de simplifier le travail en équipe gràce au système de fusion. Mais un projet PHP ce n'est pas forcément que du code, il y a aussi la partie base de données qu'il faut faire évoluer avec le temps ce qui entraîne pas mal de problèmes lorsqu'il s'agit de synchroniser les changements. En effet, si vous rajoutez un champs en local, il faudra penser à reporter la modification sur le serveur mais aussi chez les différents collaborateurs. Pour solutionner ce problème il est possible d'utiliser un système de migration.

Migrer une base de données

Le principe des migrations est assez proche du principe de versionning. Lorsque l'on souhaite faire évoluer notre base de données on va créer une migration qui va définir les différents changements à effectuer au niveau de notre base de données pour passer à l'étape suivante. Ces changements peuvent être inversés afin d'effectuer un rollback pour revenir en arrière en cas de problème.

Lorsque l'on souhaite déployer le projet il suffira alors de lancer les nouvelles migrations pour migrer la base de données vers la version la plus récente.

Phinx

Phinx est une librairie PHP qui permet justement de mettre en place un tel système de migration. Pour l'utiliser il suffit de passer par composer :

composer require robmorgan/phinx

Puis d'initialiser la configuration via la commande phinx init

./vendor/bin/phinx init

Cette commande aura pour effet de créer un fichier phinx.yml à la racine de votre projet. Ce fichier permet de définir les différents environnements (base de données) à utiliser, mais aussi les chemins vers les dossiers de migrations et de seedings. Il est aussi possible de se passer de ce fichier yml au profit d'un fichier PHP si vous souhaitez réutiliser une connexion PDO déjà initialisée par votre application.

Enfin, il vous faudra créer les dossiers qui vont accueillir les migrations avant de pouvoir commencer.

mkdir -p db/migrations db/seeds

Migrations

Une fois la configuration modifiée et les dossiers créés vous pourrez créer votre première migration à l'aide de la commande phinx create.

./vendor/bin/phinx create CreatePostsTable

Cette commande génèrera un fichier php dans le dossier de migration. Le nom du fichier sera préfixé par un timestamp correspondant à la date de création de la migration. Ce timestamp permet à Phinx de définir l'ordre d'éxécution des migrations. Par défaut, le fichier contient une classe avec une méthode change() que vous devrez remplir pour définir les changements à effectuer.

<?php
use Phinx\Migration\AbstractMigration;

class CreatePostsTable extends AbstractMigration
{ 
    public function change()
    {
        $this->table('posts')
            ->addColumn('name', 'string')
            ->addColumn('slug', 'string')
            ->addColumn('content', 'text', ['limit' => \Phinx\Db\Adapter\MysqlAdapter::TEXT_LONG])
            ->addColumn('created_at', 'datetime')
            ->addColumn('updated_at', 'datetime')
            ->create();
    }
}

Cette méthode change() permet, à elle seule, de définir les changements à effectuer dans les 2 sens. Mais pour des cas plus complexes il est aussi possible d'utiliser les méthodes run() et migrate().

<?php
use Phinx\Migration\AbstractMigration;

class CreatePostsTable extends AbstractMigration
{ 
    public function up()
    {
      // Code à éxécuter en cas de migration (pour avancer)
    }

    public function down()
    {
      // Code à éxécuter en cas de rollback (pour reculer)
    }
}

Une fois la migration définie on peut migrer notre base de données à l'aide de la commande phinx migrate.

./vendor/bin/phinx migrate -e development

Le drapeau -e permet de spécifier l'environnement à utiliser (un environnement par défaut peut être spécifié dans le fichier de configuration). Si vous souhaitez revenir en arrière vous pouvez utiliser la commande rollback

# Revenir un cran en arrière
./vendor/bin/phinx rollback
# Revenir au tout début
./vendor/bin/phinx rollback -t 0
# Revenir à une version spécifique
./vendor/bin/phinx rollback -t 20120103083322
# Revenir à une date spécifique
./vendor/bin/phinx rollback -d 2017
./vendor/bin/phinx rollback -d 20170103

Si je souhaite maintenant rajouter des catégories à mes articles il suffit de créer une nouvelle migration.

./vendor/bin/phinx create CreateCategoriesTable

Puis de la modifier.

<?php

use Phinx\Migration\AbstractMigration;

class CreateCategoriesTable extends AbstractMigration
{
    public function change()
    {
        $this->table('categories')
            ->addColumn('name', 'string')
            ->addColumn('slug', 'string')
            ->create();

        $this->table('posts')
            ->addColumn('category_id', 'integer', [
                'null' => true
            ])
            ->addForeignKey('category_id', 'categories', 'id', [
                'delete' => 'SET_NULL',
                'update' => 'NO_ACTION'
            ])
            ->update();
    }
}

Et enfin de la lancer.

./vendor/bin/phinx migrate

Et voila le tour est joué !

Seeds

Les seeds permettent de préremplir votre base de données afin d'avoir un environnement de développement plus simple à utiliser. Le système de seeding s'utilise un peu de la même façon que les migrations à l'aide de la commande seed:create qui aura pour effet de créer un fichier PHP dans le dossier seeds.

./vendor/bin/phinx seed:create FillPostTable

Ce fichier PHP est une simple classe PHP avec une méthode run() qui définit les insertions à faire en base de données. Vous pouvez vous aider d'une autre librairie pour générer des données de tests.

<?php
use Phinx\Seed\AbstractSeed;

class FillPostTable extends AbstractSeed
{
    public function run()
    {
        $faker = \Faker\Factory::create();
        $categories = [];
        for ($i = 0; $i < 10; ++$i) {
            $categories[] = [
                'name' => $faker->sentence(4),
                'slug' => $faker->slug
            ];
        }
        $this->insert('categories', $categories);

        $categories = array_map(
            function ($category) { return $category['id']; },
            $this->fetchAll('SELECT id FROM categories')
        );

        $posts = [];
        for ($i = 0; $i < 100; ++$i) {
            $timestamp = $faker->unixTime('now');
            $posts[] = [
                'name' => $faker->sentence(6),
                'slug' => $faker->slug,
                'content' => $faker->text(300),
                'created_at' => date('Y-m-d H:i:s', $timestamp),
                'updated_at' => date('Y-m-d H:i:s', $timestamp),
                'category_id'=> $categories[rand(0, 9)]
            ];
        }

        $this->insert('posts', $posts);
    }
}

Enfin vous pouvez lancer votre seeding

./vendor/bin/phinx seed:run -s FillPostTable

Voila pour ce petit tour d'horizon de Phinx, n'hésitez pas à faire un tour sur la documentation pour voir l'ensemble des fonctionnalités offertes par la librairie.