Laravel 编码技巧 - 迁移文件
迁移顺序
如果你想改变数据库迁移的顺序,只需要将文件按时间戳记命名, 就像 2018_08_04_070443_create_posts_table.php 改为 2018_07_04_070443_create_posts_table.php (从 2018_08_04 改成了 2018_07_04)。
迁移是以字母顺序执行。
带时区的迁移字段
你知道吗?在迁移中不止有 timestamps() 还有带时区的 timestampsTz() 。
Schema::create('employees', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email');
    $table->timestampsTz();
});
同样,还有这么些列 dateTimeTz() , timeTz() , timestampTz() , softDeletesTz()。
数据库迁移字段类型
迁移中有一些有趣的字段类型,下面是一些示例。
$table->geometry('positions');
$table->ipAddress('visitor');
$table->macAddress('device');
$table->point('position');
$table->uuid('id');
在 官方文档 中你可以找到全部的字段类型列表.
默认时间戳
当创建迁移文件时,你可以使用带 useCurrent() 和 useCurrentOnUpdate() 可选项的 timestamp() 类型,这将会设置使相应字段以 CURRENT_TIMESTAMP 作为默认值。
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrentOnUpdate();
迁移状态
如果你想检查哪些迁移已经执行或者还没有执行,不需要查看数据库的 migrations 表,你可以启动 php artisan migrate:status 命令。
结果示例:
Migration name .......................................................................... Batch / Status  
2014_10_12_000000_create_users_table ........................................................... [1] Ran  
2014_10_12_100000_create_password_resets_table ................................................. [1] Ran  
2019_08_19_000000_create_failed_jobs_table ..................................................... [1] Ran    
创建带空格的迁移
当输入 make:migration 命令时,你不必像 create_transactions_table 这样在部分之间使用下划线符号。你可以将名称放在引号中,然后使用空格而不是下划线。
// 这种方式可以工作
php artisan make:migration create_transactions_table
// 但是这种方式也可以工作
php artisan make:migration "create transactions table"
在另一列之后创建列
如果你正在向现有的表中添加新列,它不一定必须在列表中的最后。你可以指定在其之后创建:
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->after('email');
});
如果你正在向现有的表中添加新列,它不一定必须在列表中的最后。你可以指定在其之前创建:
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->before('created_at');
});
如果你想让你的列成为你的表中的第一个,那么使用第一个方法。
Schema::table('users', function (Blueprint $table) {
    $table->string('uuid')->first();
});
此外,现在可以使用after()方法来添加多个字段。
Schema::table('users', function (Blueprint $table) {
    $table->after('remember_token', function ($table){
        $table->string('card_brand')->nullable();
        $table->string('card_last_four', 4)->nullable();
    });
});
为已存在的表生成迁移文件
如果你为现有的表创建迁移,并希望 Laravel 为你生成 Schema::table(),那么在如果你为现有的表创建迁移,并希望 Laravel 为你生成Schema::table(),那么在末尾添加"_in_xxxxx_table"或"_to_xxxxx_table",或者指定"--table"参数。例如,运行php artisan change_fields_products_table会生成一个空的类:
如果你对已有的表进行了迁移,并且你希望 Laravel 为你生成 Schema::table() ,那么在末尾添加 _in_xxxxx_table 或 _to_xxxxx_table,或者指定 --table 参数。php artisan change_fields_products_table 生成空类
class ChangeFieldsProductsTable extends Migration
{
    public function up()
    {
        //
    }
}
但是,如果添加in_xxxxx_table,运行php artisan make:migration change_fields_in_products_table会生成一个带有预填充的Schema::table()的类:
class ChangeFieldsProductsTable extends Migration
{
    public function up()
    {
        Schema::table('products', function (Blueprint $table) {
            //
        })
    };
}
此外,你还可以使用--table参数指定表名,运行php artisan make:migration whatever_you_want --table=products:
class WhateverYouWant extends Migration
{
    public function up()
    {
        Schema::table('products', function (Blueprint $table) {
            //
        })
    };
}
在运行迁移之前输出SQL
当输入 migrate --pretend 命令,你可以得到将在终端中执行的 SQL 查询。如果有需要的话调试 SQL 的方法,这是个很有趣的方法。
// Artisan command
php artisan migrate --pretend
匿名迁移
Laravel团队发布了Laravel 8.37版本 支持匿名迁移,它解决了GitHub上的迁移类名冲突问题。问题的核心是,如果多个迁移具有相同的类名,则在尝试从头开始重新创建数据库时会导致问题。下面是一个pull request 测试的例子:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
    public function up(
    {
        Schema::table('people', function (Blueprint $table) {
            $table->string('first_name')->nullable();
        });
    }
    public function down()
    {
        Schema::table('people', function (Blueprint $table) {
            $table->dropColumn('first_name');
        });
    }
};
你可以在迁移中添加有关列的“注释”
你可以在迁移文件中为某一列添加 "comment",并提供有用的信息。
如果数据库由其他人管理而非开发人员,他们可以在执行任何操作之前查看表结构中的注释。
$table->unsignedInteger('interval')
    ->index()
    ->comment('此列用于索引。');
检查表/列是否存在
你可以使用 hasTable 和 hasColumn 方法来检查数据库中是否存在某个表或列:
if (Schema::hasTable('users')) {
    // "users"表存在...
}
if (Schema::hasColumn('users', 'email')) {
    // "users"表存在并且有一个"email"列...
}
对 After 方法中的列进行分组
对 After 方法中的列进行分组
Schema::table('users', function (Blueprint $table) {
    $table->after('password', function ($table) {
        $table->string('address_line1');
        $table->string('address_line2');
        $table->string('city');
    });
});
仅当列不存在时才将其添加到数据库表中,如果存在,则可以删除它
现在您可以在数据库表中添加列,只有当它不存在时才能添加,如果它存在,则可以删除它。为此,引入了以下方法:
👉 whenTableDoesntHaveColumn
👉 whenTableHasColumn
从 Laravel 9.6.0 可用
return new class extends Migration {
    public function up()
    {
        Schema::whenTableDoesntHaveColumn('users', 'name', function (Blueprint $table) {
            $table->string('name', 30);
        });
    }
    public function down()
    {
        Schema::whenTableHasColumn('users', 'name', function (Blueprint $table) {
            $table->dropColumn('name');
        });
    }
}
设置当前时间戳默认值的方法
您可以对自定义时间戳列使用 useCurrent() 方法,将当前时间戳存储为默认值。
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->timestamp('added_at')->useCurrent();
    $table->timestamps();
});