マイグレーションはあったほうが当然良いツールなのですが、レガシーな現場には意外と現場に浸透していないと感じます。
運良く、Laravelのような若いフレームワークで開発する機会に恵まれたのならば、是非ともマイグレーションを使ってテーブル構成を管理していきたいものです。
ということで、Laraveのマイグレーションで覚えておいがほうが良さそうなことをまとめてみました。
確認した環境
- Cloud9 (PHP5.5.9)
- Laravel 5.2
テーブル構成を定義する
マイグレーションファイルを作成する
マイグレーションファイルを新規作成するにはプロジェクトルート以下で次のコマンドを実行します。
1$ php artisan make:migration create_posts_table
artisanがこんな返答を返してくれればコマンド実行OKです。
1Created Migration: 2016_11_17_011700_create_posts_table
ファイルは、プロジェクトルート以下のdatabase/migrations
に生成されます。
出来上がったファイルをチェックしてみましょう。
このディレクトリには、Laravelのプロジェクトをnewした際、すでに2つのマイグレーションファイルが生成されているので、こんな感じになると思います。
1$ ls -la database/migrations
2total 28
3drwxr-xr-x 2 ubuntu ubuntu 4096 Nov 19 01:06 ./
4drwxr-xr-x 5 ubuntu ubuntu 4096 Apr 27 2016 ../
5-rw-r--r-- 1 ubuntu ubuntu 1 Apr 27 2016 .gitkeep
6-rw-r--r-- 1 ubuntu ubuntu 699 Apr 27 2016 2014_10_12_000000_create_users_table.php
7-rw-r--r-- 1 ubuntu ubuntu 633 Apr 27 2016 2014_10_12_100000_create_password_resets_table.php
8-rw-r--r-- 1 ubuntu ubuntu 373 Nov 17 01:17 2016_11_17_011700_create_posts_table.php
マイグレーションファイルの命名ルール
上記の通り [日付]_[任意の名称].php
というフォーマットです。
項目 | フォーマット | 説明 |
---|---|---|
日付 | YYYY_MM_DD_HHIISS | 日付の小さいものから実行される |
名称 | [create/update]_[テーブル名]_table | そのままクラス名に利用されます |
名称は、実はなんでも良いのですが、マイグレーションの実行内容がわかる名前をつけたほうが、当然良いわけですね。
また、マイグレーションの中でクラス名の重複がある場合はPHPがエラーを吐いてしまいますから、それっぽい名前をつけておきましょう。
結局、運用段階でテーブル構成を変更する可能性を考慮すると、create
なのかalter table(update)
なのかは明確にしておいたほうが良いので、上記の表のようにいたしました。
マイグレーションファイルを編集する
先ほど作成したファイルを編集してスキーマを定義していきましょう。
これが作成した直後のマイグレーションファイルです。
1<?php
2
3use Illuminate\Database\Schema\Blueprint;
4use Illuminate\Database\Migrations\Migration;
5
6class CreatePostsTable extends Migration
7{
8 /**
9 * Run the migrations.
10 *
11 * @return void
12 */
13 public function up()
14 {
15 //
16 }
17
18 /**
19 * Reverse the migrations.
20 *
21 * @return void
22 */
23 public function down()
24 {
25 //
26 }
27}
主キーと投稿本文、タイムスタンプのフィールドを追加します。
1public function up()
2{
3 Schema::create('posts', function (Blueprint $table) {
4 $table->increments('id');
5 $table->string('post_body');
6 $table->timestamps();
7 });
8}
9public function down()
10{
11 Schema::drop('posts');
12}
コマンド | 説明 |
---|---|
increments | int(10) unsignedでautoincrementなprimaryKeyフィールドを生成 |
string | varchar(255)のフィールドを生成 |
timestamps | timestamp型のフィールドcreated_at, updated_atを生成 |
Laravelでは常に主キーとして$table->increments('id');
を定義しておくのが吉です。
また、timestampsを入れるとEloquent ORM
側で自動更新してくれますから、こちらも常に定義しておくのが良いと思います。
利用可能なコマンドと、生成されるフィールドの対応は、私はいつも以下を確認しております。
Laravel 5.2 データベース:マイグレーション
https://readouble.com/laravel/5.2/ja/migrations.html
マイグレーションを実行する
マイグレーションファイルを用意したら、定義を実行してDBに反映していきましょう。 プロジェクトルートで以下を実行すると、DBが更新されます。
1$ php artisan migrate
マイグレーションを実行すると、デフォルトデータベースのmigrationsテーブルにデータが残ります。
とは言っても、テーブルの内容はいたってシンプルなものです。
SELECT * FROM migrations
すると以下のような結果が得られます。
id | migration | batch |
---|---|---|
1 | 2014_10_12_000000_create_users_table.php | 1 |
2 | 2014_10_12_100000_create_password_resets_table.php | 1 |
3 | 2016_11_17_011700_create_posts_table.php | 1 |
Eloquent ORMのクラスを作成する
テーブルを作成したら、PHPから対象テーブルにアクセスするためのORM
を作成しましょう。
次のコマンドを打って、空のクラスを生成します。
テーブル名はposts
で複数形だけれども、ORMはPost
で単数系なのに注意です。
1$ php artisan make:model Model/Post
artisanより以下の応答があればファイルの作成は成功です。
1Model created successfully.
(2014年12月14日にこの辺りを修正)
Model
を指定しないとappディレクトリ直下にファイルが生成されてしまい、「気がつけばapp以下に大量のファイルが、、、」状態になってしまうので注意です!
生成直後のモデルクラスはこんな感じです。
1<?php
2
3namespace App\Model;
4
5use Illuminate\Database\Eloquent\Model;
6
7class Post extends Model
8{
9 //
10}
上記のファイルに、テーブル名の定義を追加します。
1<?php
2namespace App\Model;
3
4use Illuminate\Database\Eloquent\Model;
5
6class Post extends Model
7{
8 protected $table = 'posts';
9}
ORMを作成すれば、以下のようにDBへの問い合わせができるようになります。
1$posts = App\Model\Post::all();
Eloquentを細かく見ていくと長くなります。とりあえずこれで。
なお、以下のコマンドでマイグレーションとモデルを同時に生成してくれます。
1$ php artisan make:model Model/Post -m
初期データを用意する
管理画面の初期アカウントやデバッグデータの準備に活躍するのがシーディング
です。
次のartisanコマンドを実行して、空のシーダーを用意します。
1$ php artisan make:seeder UsersTableSeeder
コマンドを実行して、次のおとうが得られるとdatabase/seeds
にファイルが生成されます。
1Seeder created successfully.
こちらが生成直後のファイルです。
1<?php
2
3use Illuminate\Database\Seeder;
4
5class UsersTableSeeder extends Seeder
6{
7 /**
8 * Run the database seeds.
9 *
10 * @return void
11 */
12 public function run()
13 {
14 //
15 }
16}
シーダーの書き方はいろいろありますが、ここではORMを呼び出し、1レコードをCreateしててみましょう。
1<?php
2
3use Hash;
4use Illuminate\Database\Seeder;
5use App\Model\User;
6
7class UsersTableSeeder extends Seeder
8{
9 public function run()
10 {
11 UserModel::create([
12 'account' => 'Atuweb',
13 'password' => Hash::make('password'),
14 ]);
15 }
16}
シーダーを作成したら、あらかじめ保存されているdatabase/seeds/DatabaseSeeder.php
に新しいシーダー呼び出しを追加します。
1<?php
2
3use Illuminate\Database\Seeder;
4use Illuminate\Database\Eloquent\Model;
5
6class DatabaseSeeder extends Seeder
7{
8 /**
9 * Run the database seeds.
10 *
11 * @return void
12 */
13 public function run()
14 {
15 Model::unguard();
16
17 $this->call('UsersTableSeeder');
18 $this->call('PostsTableSeeder');
19
20 Model::reguard();
21 }
22}
最後にシーディングを実行すれば、データの登録は完了です。
1$ php artisan db:seed
シーダーを使えば、ダミーや検証用データの共有が楽にできますので、私は使い勝手が良いと感じました。
注意点として、シーダークラスはdatabaseディレクトリ以下に保存されますので、オートロードの対象外です。
そのため、ファイル追加後にcomposer dump-autoload
してあげないと、シーダーから見つけることができずにClassNotFound
が発生することがあますよ。
Laravel 5.2 : シーディング
https://readouble.com/laravel/5.2/ja/seeding.html
課題:シーダーで環境を判別したい
例えば「公開環境用にはデバッグデータを含みたくない」など、環境によって登録したいデータには差があるものです。
シーダーの中でConfig::get()
し、app.envをチェックすることができれば、環境ごとに実行ファイルを切り分けることができると思ったのですが、今の所うまくできずに調べ中です。
(やり方をご存知の方教えてください)
取り急ぎは、次のように、実行ファイルを指定することで対処しました。
1$ php artisan db:seed --class=UserTableSeeder
テーブルの構成を変更する
開発初期
開発初期は設計が不味かったり、仕様に調整が入ったりと、やはりテーブルの構成が変わってくるものです。
シーディングでデータの復活が容易な状況では、既存のマイグレーションファイルを更新してしまうのが手っ取り早いでしょう。
マイグレーションをゼロからやりなおすには以下のコマンドを実行します。
1$ php artisan migrate:reset
テーブルをリセットして、マイグレーション、シーディングをやり直すとこうですね。
1$ php artisan migrate:reset
2$ php artisan migrate
3$ php artisan db:seed
上記を一発で実行する便利コマンドが以下です。
1$ php artisan migrate:refresh --seed
リセットの注意点
マイグレーションのリセットは、ファイルの増減前に実行しましょう。
というのは、database/migrations
以下のファイル名と、migrationsテーブル
に保存されている内容で、ファイルの増減やファイル名が異なっているなど、何らかの差があると、リセットが失敗してしまうためです。
マイグレーションをリセットresetする際にファイルが増減していたり、フィル名が異なっている場合はエラーが発生してしまうので注意です。
収拾不可能な状態に陥った場合は、データベース内の全てのテーブルをdropするという荒治療を行わなければなりません。
開発後期、運用段階
マイグレーションのリセットが難しくなってきましたら、既存のテーブルをdropしたい気持ちを抑えてマイグレーションファイルを追加していく段階に入ります。
ここで、ライブラリの追加が必要です。
dinoteの追加
既存のテーブル変更を入れる場合はdinote
に依存しております。
dinoteがインストールされていない場合はエラーとなりインストールが促されますよ。
プロジェクトルートのcomposer.json
を編集して、dinoteを追加しましょう。
1{
2 :
3 "require": {
4 "php": ">=5.5.9",
5 "laravel/framework": "5.2.*",
6 "doctrine/dbal": "2.*"
7 },
ファイルを編集後、お決まりのコマンドでライブラリの更新を実行しましょう。
1$ composer update
マイグレーションファイルの追加
先程と同様にコマンドを打つなりしてマイグレーションファイルを作成します。
1$ php artisan make:migration add_title_and_tag_posts_table
多少ファイル名が長くても、何度かテーブル構成を変更することを考えると、「どういった変更を行うか」がわかる名称が良さそうです。
1<?php
2
3use Illuminate\Support\Facades\Schema;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Database\Migrations\Migration;
6
7class AddTitleAndTagPostsTable extends Migration
8{
9 public function up()
10 {
11 Schema::table('posts', function ($table) {
12 $table->string('title')->after('id');
13 $table->string('tags')->after('post_body');
14 });
15 }
16}
フィールドの追加は、テーブルの新規作成時と同様でOKです。
単純に追加すると、一番下にフィールドが追加されてしまうため、after()
などを利用してフィールドの位置を指定すると美しいですね。
ファイル作成後にphp artisan migrate
を実行するのは今までと同じです。
migrationsテーブルにはbatch=2のレコードが追加されていることが確認いただけると思います。
コマンドは覚えなくても
色々とartisanコマンド
をご紹介いたしましたが、これらを覚える必要は全くありませんよ。
それは、引数なしでartisanコマンドを打てば、manが表示されるためです。
1$ php artisan
2
3Laravel Framework version 5.2.45
4
5Usage:
6 command [options] [arguments]
7
8Options:
9 -h, --help Display this help message
10 -q, --quiet Do not output any message
11 -V, --version Display this application version
12 --ansi Force ANSI output
13 --no-ansi Disable ANSI output
14 -n, --no-interaction Do not ask any interactive question
15 --env[=ENV] The environment the command should run under.
16 -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
17
18Available commands:
19 clear-compiled Remove the compiled class file
20 down Put the application into maintenance mode
21 env Display the current framework environment
22 help Displays help for a command
23 list Lists commands
24 migrate Run the database migrations
25 optimize Optimize the framework for better performance
26 serve Serve the application on the PHP development server
27 tinker Interact with your application
28 up Bring the application out of maintenance mode
29 app
30 app:name Set the application namespace
31 auth
32 auth:clear-resets Flush expired password reset tokens
33 cache
34 cache:clear Flush the application cache
35 cache:table Create a migration for the cache database table
36 config
37 config:cache Create a cache file for faster configuration loading
38 config:clear Remove the configuration cache file
39 db
40 db:seed Seed the database with records
41 event
42 event:generate Generate the missing events and listeners based on registration
43 key
44 key:generate Set the application key
45 make
46 make:auth Scaffold basic login and registration views and routes
47 make:console Create a new Artisan command
48 make:controller Create a new controller class
49 make:event Create a new event class
50 make:job Create a new job class
51 make:listener Create a new event listener class
52 make:middleware Create a new middleware class
53 make:migration Create a new migration file
54 make:model Create a new Eloquent model class
55 make:policy Create a new policy class
56 make:provider Create a new service provider class
57 make:request Create a new form request class
58 make:seeder Create a new seeder class
59 make:test Create a new test class
60 migrate
61 migrate:install Create the migration repository
62 migrate:refresh Reset and re-run all migrations
63 migrate:reset Rollback all database migrations
64 migrate:rollback Rollback the last database migration
65 migrate:status Show the status of each migration
66 queue
67 queue:failed List all of the failed queue jobs
68 queue:failed-table Create a migration for the failed queue jobs database table
69 queue:flush Flush all of the failed queue jobs
70 queue:forget Delete a failed queue job
71 queue:listen Listen to a given queue
72 queue:restart Restart queue worker daemons after their current job
73 queue:retry Retry a failed queue job
74 queue:table Create a migration for the queue jobs database table
75 queue:work Process the next job on a queue
76 route
77 route:cache Create a route cache file for faster route registration
78 route:clear Remove the route cache file
79 route:list List all registered routes
80 schedule
81 schedule:run Run the scheduled commands
82 session
83 session:table Create a migration for the session database table
84 vendor
85 vendor:publish Publish any publishable assets from vendor packages
86 view
87 view:clear Clear all compiled view files
とりあえず引数なしで打ってみる。これ大切です。
おわりに
細かいことはたくさんありますが、この辺りまで対応できるようになると、困ることはぐっと減ると思います。
また、マイグレーション
といってもライブラリによって思想、実装に差があると感じます。
まあ「テーブル構成をファイルをで管理して_環境差異をなくそう_ 」と、ざっくり考えていただければいいのかなと考えています。
大切なことは、 コードで管理するという思想 です。 プロジェクトに関わるすべてのものをコードで管理しましょう!