前のページまでの作業で,メールアドレスとパスワードでログインができるようになりました.ここではメールアドレスの代わりにログイン ID でログインできるようにするためにデータベースのテーブルにログイン ID (とついでに学籍番号も)の属性(列)を追加します.
まず,users テーブルに login_id
列を追加する必要があります.まだ開発段階であるので,すでにあるマイグレーションファイルを修正して,ロールバックとマイグレーションを実行しても構いません.一方ですでに本番環境で運用段階にある場合は,ロールバックしてデータを削除することはできません.今回はすでにあるテーブルに列を追加するために新たなマイグレーションファイルを生成することにします.
vagrant@ubuntu2204 laravelAuth $ php artisan make:migration add_login_id_to_users_table --table=users ⏎
INFO Migration [database/migrations/2023_11_03_101930_add_login_id_to_users_table.php] created successfully.
vagrant@ubuntu2204 laravelAuth $
上のコマンドで次のようなファイルが生成されました.
database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};
これを次のように修正して,ログイン ID と学籍番号の属性を追加するようにします.なお,すでにデータが投入されていることを前提にどちらの属性も NULL 値を許可し,一意性制約は設定していません(が後で変更します).すでに users テーブルにレコードがある状況で,一意性制約を持ち NULL 値を許可しない属性(列)を追加することができないのは直感的にも理解できることだと思います.またロールバックしたときに追加した属性が削除されるようにもしています.
database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->integer('student_id')->nullable();
$table->string('login_id')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('student_id');
$table->dropColumn('login_id');
});
}
};
マイグレーションの状況を確認しながら,(1) マイグレーションを実行して列を追加します.その後,(2) ロールバックを一度実行して列が削除されることを確認します.(3) もう一度ロールバックを実行すると全てのテーブルが削除されます.その後,(4) マイグレーションを実行すると列の追加まで一気に実行されます.以降はロールバックで一気に全てのテーブルが削除されるようになります.
vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... [1] Ran 2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran 2019_08_19_000000_create_failed_jobs_table ................. [1] Ran 2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran 2023_11_03_101930_add_login_id_to_users_table .............. Pending vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎ # (1) INFO Running migrations. 2023_11_03_101930_add_login_id_to_users_table ............ 17ms DONE vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... [1] Ran 2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran 2019_08_19_000000_create_failed_jobs_table ................. [1] Ran 2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran 2023_11_03_101930_add_login_id_to_users_table .............. [2] Ran vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎ # (2) INFO Rolling back migrations. 2023_11_03_101930_add_login_id_to_users_table ............ 17ms DONE vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... [1] Ran 2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran 2019_08_19_000000_create_failed_jobs_table ................. [1] Ran 2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran 2023_11_03_101930_add_login_id_to_users_table .............. Pending vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎ # (3) INFO Rolling back migrations. 2019_12_14_000001_create_personal_access_tokens_table .... 14ms DONE 2019_08_19_000000_create_failed_jobs_table ................ 5ms DONE 2014_10_12_100000_create_password_reset_tokens_table ...... 5ms DONE 2014_10_12_000000_create_users_table ...................... 5ms DONE vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... Pending 2014_10_12_100000_create_password_reset_tokens_table ....... Pending 2019_08_19_000000_create_failed_jobs_table ................. Pending 2019_12_14_000001_create_personal_access_tokens_table ...... Pending 2023_11_03_101930_add_login_id_to_users_table .............. Pending vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎ # (4) INFO Running migrations. 2014_10_12_000000_create_users_table ..................... 15ms DONE 2014_10_12_100000_create_password_reset_tokens_table ...... 4ms DONE 2019_08_19_000000_create_failed_jobs_table ................ 9ms DONE 2019_12_14_000001_create_personal_access_tokens_table .... 11ms DONE 2023_11_03_101930_add_login_id_to_users_table ............. 7ms DONE vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... [1] Ran 2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran 2019_08_19_000000_create_failed_jobs_table ................. [1] Ran 2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran 2023_11_03_101930_add_login_id_to_users_table .............. [1] Ran vagrant@ubuntu2204 laravelAuth $
上の作業の途中で随時テーブルの状況を確認すると次のようになります.
sqlite> .headers on ⏎ sqlite> .schema users ⏎ # (1) の実行前 CREATE TABLE IF NOT EXISTS "users" ( "id" integer primary key autoincrement not null, "name" varchar not null, "email" varchar not null, "email_verified_at" datetime, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime ); CREATE UNIQUE INDEX "users_email_unique" on "users" ("email"); sqlite> select * from users; ⏎ id|name|email|email_verified_at|password|remember_token|created_at|updated_at 1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01 2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01 3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01 sqlite> sqlite> sqlite> sqlite> sqlite> .schema users ⏎ # (1) の実行後で,(2) の実行前 CREATE TABLE IF NOT EXISTS "users" ( "id" integer primary key autoincrement not null, "name" varchar not null, "email" varchar not null, "email_verified_at" datetime, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime, "login_id" varchar, "student_id" integer ); CREATE UNIQUE INDEX "users_email_unique" on "users" ("email"); sqlite> select * from users; ⏎ id|name|email|email_verified_at|password|remember_token|created_at|updated_at|login_id|student_id 1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01|| 2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01|| 3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01|| sqlite> sqlite> sqlite> sqlite> .schema users ⏎ # (2) の実行後 CREATE TABLE IF NOT EXISTS "users" ( "id" integer primary key autoincrement not null, "name" varchar not null, "email" varchar not null, "email_verified_at" datetime, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime ); CREATE UNIQUE INDEX "users_email_unique" on "users" ("email"); sqlite> select * from users; ⏎ id|name|email|email_verified_at|password|remember_token|created_at|updated_at 1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01 2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01 3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01 sqlite>
上の SQLite の実行結果を確認すると,(1) の実行後に login_id
と student_id
の属性(列)が追加されていることがわかります.しかしながら,これらの属性には UNIQUE
制約(一意性制約)が設定されていないことも分かります.ログイン ID や学籍番号は他の学生と重複した値を持つことが許されないことから UNIQUE 制約を追加しなければなりません.
実際のところまだ本番環境には移行していないので,データベースのテーブルを完全にロールバックしても問題はありません.したがって,マイグレーションファイルを次のように修正して,UNIQUE 制約を追加して,さらに NULL 値も許可しないようにします.また,このマイグレーションだけをロールバックする必要性も今後ないことから down
の定義は削除しています.
database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('login_id')->unique();
$table->integer('student_id')->unique();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};
この状態でロールバックとマイグレーションを実行します.
vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎ Migration name ...................................... Batch / Status 2014_10_12_000000_create_users_table ....................... [1] Ran 2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran 2019_08_19_000000_create_failed_jobs_table ................. [1] Ran 2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran 2023_11_03_101930_add_login_id_to_users_table .............. [1] Ran vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎ INFO Rolling back migrations. 2023_11_03_101930_add_login_id_to_users_table ............ 15ms DONE 2019_12_14_000001_create_personal_access_tokens_table ..... 5ms DONE 2019_08_19_000000_create_failed_jobs_table ................ 5ms DONE 2014_10_12_100000_create_password_reset_tokens_table ...... 6ms DONE 2014_10_12_000000_create_users_table ...................... 5ms DONE vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎ INFO Running migrations. 2014_10_12_000000_create_users_table ..................... 14ms DONE 2014_10_12_100000_create_password_reset_tokens_table ...... 4ms DONE 2019_08_19_000000_create_failed_jobs_table ................ 8ms DONE 2019_12_14_000001_create_personal_access_tokens_table .... 13ms DONE 2023_11_03_101930_add_login_id_to_users_table ............ 16ms DONE vagrant@ubuntu2204 laravelAuth $
すると login_id
と student_id
属性に NOT NULL 制約と一意性制約が設定されてことも分かります.
sqlite> .schema users ⏎ CREATE TABLE IF NOT EXISTS "users" ( "id" integer primary key autoincrement not null, "name" varchar not null, "email" varchar not null, "email_verified_at" datetime, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime, "login_id" varchar not null, "student_id" integer not null); CREATE UNIQUE INDEX "users_email_unique" on "users" ("email"); CREATE UNIQUE INDEX "users_login_id_unique" on "users" ("login_id"); CREATE UNIQUE INDEX "users_student_id_unique" on "users" ("student_id"); sqlite>
テーブル定義の修正を終えたので,次はシーダを修正します.
database/seeders/UsersTableSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
use Carbon\Carbon;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
DB::table('users')->delete();
User::create([
'name' => 'A. Sample',
'email' => 'a@sample.com',
'login_id' => 'user_a',
'student_id' => 6300997,
'password' => bcrypt('abc'),
'created_at' => '2023-11-03 00:01:01',
'updated_at' => '2023-11-03 00:01:01'
]);
User::create([
'name' => 'B. Sample',
'email' => 'b@sample.com',
'login_id' => 'user_b',
'student_id' => 6300998,
'password' => bcrypt('abc'),
'created_at' => '2023-11-03 00:02:01',
'updated_at' => '2023-11-03 00:02:01'
]);
User::create([
'name' => 'C. Sample',
'email' => 'c@sample.com',
'login_id' => 'user_c',
'student_id' => 6300999,
'password' => bcrypt('abc'),
'created_at' => '2023-11-03 00:03:01',
'updated_at' => '2023-11-03 00:03:01'
]);
}
}
データベースはロールバックのあとマイグレーションが実行された状態のはずですので,そのままデータを投入します.
vagrant@ubuntu2204 laravelAuth $ php artisan db:seed ⏎
INFO Seeding database.
Database\Seeders\UsersTableSeeder .......................... RUNNING
Database\Seeders\UsersTableSeeder ................... 658.81 ms DONE
vagrant@ubuntu2204 laravelAuth $
SQLite で投入されたデータを確認します.
sqlite> select * from users; ⏎ id|name|email|email_verified_at|password|remember_token|created_at|updated_at|login_id|student_id 1|A. Sample|a@sample.com||$2y$12$xKLWZJSJqxcu8bLNA/o2X.CvZlDWsi0t3tIVVzcFS7RzELoVQWhzC||2023-11-03 00:01:01|2023-11-03 00:01:01|user_a|6300997 2|B. Sample|b@sample.com||$2y$12$RjXhibG00aYYv8pvZ2.5MOHvdsvDlfxtdWdyoz3zUx0074MHLbBQS||2023-11-03 00:02:01|2023-11-03 00:02:01|user_b|6300998 3|C. Sample|c@sample.com||$2y$12$LGBYC5Pi5eezXPbSLVAutuNWpd8u7M/T4lVaUC3vGpp6qqF3Y65Hi||2023-11-03 00:03:01|2023-11-03 00:03:01|user_c|6300999 sqlite>