Modification de la migration de Laravel pour rendre une colonne annulable

194

J'ai créé une migration avec non signé user_id. Comment puis-je modifier user_idune nouvelle migration pour la réaliser également nullable()?

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    // this needs to also be nullable, how should the next migration be?
    $table->integer('user_id')->unsigned();
}
user391986
la source

Réponses:

263

Laravel 5 prend désormais en charge la modification d'une colonne; voici un exemple de la documentation officielle:

Schema::table('users', function($table)
{
    $table->string('name', 50)->nullable()->change();
});

Source: http://laravel.com/docs/5.0/schema#changing-columns

Laravel 4 ne prend pas en charge la modification des colonnes, vous devrez donc utiliser une autre technique telle que l'écriture d'une commande SQL brute. Par exemple:

// getting Laravel App Instance
$app = app();

// getting laravel main version
$laravelVer = explode('.',$app::VERSION);

switch ($laravelVer[0]) {

    // Laravel 4
    case('4'):

        DB::statement('ALTER TABLE `pro_categories_langs` MODIFY `name` VARCHAR(100) NULL;');
        break;

    // Laravel 5, or Laravel 6
    default:                

        Schema::table('pro_categories_langs', function(Blueprint $t) {
            $t->string('name', 100)->nullable()->change();
        });               

}
MURATSPLAT
la source
3
Merci pour cela. Mais comment faire le contraire? Comment changer une colonne pour qu'elle ne soit pas annulable? Des idées?
algorhythm
@algorhythm Essayez-vous cette '$ t-> chaîne (' nom ', 100) -> change ();'
MURATSPLAT
7
Vous devez exiger la doctrine \ dbal pour migrer
younes0
33
@algorhythm ->nullable(false)vous permettra de modifier à nouveau la colonne.
Colin
9
-> change () vous oblige à installer le paquet Doctrine DBAL, et il ne reconnaît pas intrinsèquement tous les mêmes types de colonnes qui sont disponibles à la sortie de laravel .. par exemple, double n'est pas un type de colonne reconnu pour DBAL.
Will Vincent
174

Voici la réponse complète pour le futur lecteur. Notez que cela n'est possible que dans Laravel 5+.

Tout d'abord, vous aurez besoin du package doctrine / dbal :

composer require doctrine/dbal

Maintenant, dans votre migration, vous pouvez le faire pour rendre la colonne nullable:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Vous vous demandez peut-être comment annuler cette opération. Malheureusement, cette syntaxe n'est pas prise en charge:

// Sadly does not work :'(
$table->integer('user_id')->unsigned()->change();

Voici la syntaxe correcte pour annuler la migration:

$table->integer('user_id')->unsigned()->nullable(false)->change();

Ou, si vous préférez, vous pouvez écrire une requête brute:

public function down()
{
    /* Make user_id un-nullable */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

J'espère que vous trouverez cette réponse utile. :)

Dmitri Chebotarev
la source
4
C'est la réponse la plus complète pour L5, mais il convient de mentionner que si 'user_id' est une clé étrangère, ce qu'elle devrait être, vous ne pourrez pas la changer à moins d'exécuter 'DB :: statement (' SET FOREIGN_KEY_CHECKS = 0 ');' première. Et remettez-le à 1 lorsque vous avez terminé.
rzb
1
Merci, cela nullable(false)m'a évité de me tirer les cheveux, car cela nullable()n'est pas bien documenté et il n'y a pas de notNull()fonction.
Zack Morris
cela ne fonctionne pas pour les clés étrangères avec postgres. essayer SET FOREIGN_KEY_CHECKS = 0donne une erreur. vous devrez probablement modifier les contraintes de la table à l'aide d'une requête brute. voir ici: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz
Cela brise mes tests. Les tests commencent à s'exécuter puis se bloquent. Je suppose que le premier rollback provoque cela. Provoque des tests de suspension pour MySQL ainsi que pour SQLite.
Thomas Praxl
155

Je suppose que vous essayez de modifier une colonne sur laquelle vous avez déjà ajouté des données, il est donc impossible de supprimer une colonne et de l'ajouter à nouveau en tant que colonne nullable sans perdre de données. Nous allons alterla colonne existante.

Cependant, le générateur de schéma de Laravel ne prend pas en charge la modification des colonnes autre que le changement de nom de la colonne. Vous devrez donc exécuter des requêtes brutes pour les faire, comme ceci:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

Et pour vous assurer que vous pouvez toujours annuler votre migration, nous ferons down()de même.

function down()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Une note est que puisque vous convertissez entre nullable et non nullable, vous devrez vous assurer de nettoyer les données avant / après votre migration. Faites donc cela dans votre script de migration dans les deux sens:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE `throttle` SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down()
{
    DB::statement('UPDATE `throttle` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Unnawut
la source
7
Pour Laravel 4, remplacez queryparstatement
Razor
2
Merci @Razor. Mis à jour ma réponse en conséquence.
Unnawut
1
Dans la downfonction du deuxième bloc de code, l'instruction SQL doit se terminer par NOT NULL. (La downfonction dans le troisième exemple est correcte.)
Scott Weldon
46

Il est la migration complète pour Laravel 5 :

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable()->change();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable(false)->change();
    });
}

Le fait est que vous pouvez supprimer nullableen passant falsecomme argument.

Yauheni Prakopchyk
la source
16

S'il vous arrive de changer les colonnes et de trébucher

'Doctrine\DBAL\Driver\PDOMySql\Driver' not found

puis installez simplement

composer require doctrine/dbal

ken
la source
1
Cela m'a mordu alors j'ai continué et rendu l'exception / solution plus facile à suivre: github.com/laravel/framework/pull/10002
Beau Simensen
9

Ajout à la réponse de Dmitri Chebotarev, comme pour Laravel 5+.

Après avoir requis le paquet doctrine / dbal :

composer require doctrine/dbal

Vous pouvez ensuite effectuer une migration avec des colonnes nullables, comme ceci:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Pour annuler l'opération, procédez comme suit:

public function down()
{
    /* turn off foreign key checks for a moment */
    DB::statement('SET FOREIGN_KEY_CHECKS = 0');
    /* set null values to 0 first */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    /* alter table */
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
    /* finally turn foreign key checks back on */
    DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
rzb
la source
3

Ajout à Dmitri Chebotarev Answer,

Si vous souhaitez modifier plusieurs colonnes à la fois, vous pouvez le faire comme ci-dessous

DB::statement('
     ALTER TABLE `events` 
            MODIFY `event_date` DATE NOT NULL,
            MODIFY `event_start_time` TIME NOT NULL,
            MODIFY `event_end_time` TIME NOT NULL;
');
Sameer
la source
2

Essayez-le:

$table->integer('user_id')->unsigned()->nullable();
Adil
la source
1
Il ne modifie pas la colonne existante
dVaffection
9
vous avez oublié ->changeà la fin et pour le mentionner seulement Laravel 5+
Alexander Malakhov
Vous devez exigercomposer require doctrine/dbal
Lizesh Shakya
2

Pour Laravel 4.2, la réponse d'Unnawut ci-dessus est la meilleure. Mais si vous utilisez le préfixe de table, vous devez modifier un peu votre code.

function up()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

Et pour vous assurer que vous pouvez toujours annuler votre migration, nous ferons down()de même.

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Debiprasad
la source