Laravel5 モデルとマイグレーション(1)

2017.4.26 (水)

テーブルを作成する

データベーステーブルの作成と管理、モデルとがいっかんして管理できるというのがいいところ。舶来品のLaravelは、model名が単数形(キャメルケース)、テーブル名が複数形(スネークケース)となります。
ここでは以下のように作成します。

term name
table名 data_projects
model名 DataProject
model file app/DataProject.php
migration file database/migrations/yyyy_mm_dd_hhiiss_create_data_projects_table.php

モデルを作成する

Laravel5の解説書にはモデルとマイグレーションは別々に作成することになっていますが、どっちにしろ両方つくるので一緒につくった方が楽です。–migrationで一緒に作成します。

php artisan make:model DataProject --migration
(php artisan make:model DataProject --m)

app/DataProject.php
database/migrations/yyyy_mm_dd_hhiiss_create_data_projects_table.php
が作成されます。
まだモデルとしてもテーブルとしても雛形ができただけで中身は空っぽですが、ここでmigrationしてみます。

php artisan migrate

これでdata_projectsテーブルが自動的に作成されます。
※migrationに失敗したらたいていの場合はキャッシュだったりオプティマイズがうまくできてなかったりするのが原因なのでここらあたりをやってみるといいです。
実際のマイグレーションの内容(database/migrations/yyyy_mm_dd_hhiiss_create_data_projects_table.php)を見てみると、コマンド(メソッド)は、

$table->increments('id');
$table->timestamps();

の2つだけです。
テーブルカラムとしては、

column Are
id int(10) AUTO_INCREMENT
created_at timestamp
updated_at timestamp

が自動的に作られている筈です。

マイグレーションファイルを作成する

上記の手順だけでは全然駄目なので必要なカラムを追加してゆきます。
すでに準備されているコマンド(メソッド)は以下の一覧になります。殆どこれで事足りると思います。また、ちゃんとしたマイグレーションファイルを作成する前に

php artisan migrate:rollback

して作成したテーブルを削除しておきます。
カラムは以下のコマンドで作成可能です。migrationファイルに追加してartisanでmigration

コマンド 説明
$table->bigIncrements(‘id’); 「符号なしBIGINT」を使用した自動増分ID(主キー)
$table->bigInteger(‘votes’); BIGINTカラム
$table->binary(‘data’); BLOBカラム
$table->boolean(‘confirmed’); BOOLEANカラム
$table->char(‘name’, 4); 長さを指定するCHARカラム
$table->date(‘created_at’); DATEカラム
$table->dateTime(‘created_at’); DATETIMEカラム
$table->dateTimeTz(‘created_at’); タイムゾーン付きDATETIMEカラム
$table->decimal(‘amount’, 5, 2); 有効/小数点以下桁数指定のDECIMALカラム
$table->double(‘column’, 15, 8); 15桁、小数点以下8桁のDOUBLEカラム
$table->enum(‘choices’, [‘foo’, ‘bar’]); ENUMカラム
$table->float(‘amount’, 8, 2); 8桁、小数点以下2桁のFLOATカラム
$table->increments(‘id’); 「符号なしINT」を使用した自動増分ID(主キー) default
$table->integer(‘votes’); INTEGERカラム
$table->ipAddress(‘visitor’); IPアドレスカラム (*1)
$table->json(‘options’); JSONフィールド
$table->jsonb(‘options’); JSONBフィールド
$table->longText(‘description’); LONGTEXTカラム
$table->macAddress(‘device’); MACアドレスカラム
$table->mediumIncrements(‘id’); 「符号なしMEDIUMINT」を使用した自動増分ID(主キー) レコード数が多い場合は$table->increments(‘id’);の代替で利用(*1)
$table->mediumInteger(‘numbers’); MEDIUMINTカラム
$table->mediumText(‘description’); MEDIUMTEXTカラム
$table->morphs(‘taggable’); 符号なしINTERGERのtaggable_idと文字列のtaggable_typeを追加
$table->nullableMorphs(‘taggable’); Nullableなmorphs()カラム
$table->nullableTimestamps(); Nullableなtimestamps()カラム
$table->rememberToken(); VARCHAR(100) NULLのremember_tokenを追加
$table->smallIncrements(‘id’); 「符号なしSMALLINT」を使用した自動増分ID(主キー)
$table->smallInteger(‘votes’); SMALLINTカラム
$table->softDeletes(); ソフトデリートのためにNULL値可能なdeleted_atカラム追加 (*1)
$table->string(‘email’); VARCHARカラム (*1)
$table->string(‘name’, 100); 長さ指定のVARCHARカラム 普通のvarcharはこれを使うといいです(*1)
$table->text(‘description’); TEXTカラム (*1)
$table->time(‘sunrise’); TIMEカラム
$table->timeTz(‘sunrise’); タイムゾーン付きTIMEカラム
$table->tinyInteger(‘numbers’); TINYINTカラム
$table->timestamp(‘added_on’); TIMESTAMPカラム
$table->timestampTz(‘added_on’); タイムゾーン付きTIMESTAMPカラム
$table->timestamps(); NULL値可能なcreated_atとupdated_atカラム追加 default
$table->timestampsTz(); タイムゾーン付きでNULL値可能なcreated_atとupdated_atカラム追加
$table->unsignedBigInteger(‘votes’); 符号なしBIGINTカラム
$table->unsignedInteger(‘votes’); 符号なしINTカラム
$table->unsignedMediumInteger(‘votes’); 符号なしMEDIUMINTカラム
$table->unsignedSmallInteger(‘votes’); 符号なしSMALLINTカラム フラグ的なものに利用(*1)
$table->unsignedTinyInteger(‘votes’); 符号なしTINYINTカラム フラグ的なものに利用(*1)
$table->uuid(‘id’); データベース向けのUUID類似値

だいたいいつも使うものは充分に揃っております。
こんな感じで書ければOKです。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateDataProjectsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('data_projects', function (Blueprint $table) {
            $table->increments('id');
            $table->string('project_name', 100);
            $table->string('uniq_hash', 32);
            $table->text('remark');
            $table->text('tag');
            $table->softDeletes('delFlag');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('data_projects');
    }
}

そこそこ書いたら

php artisan migrate

を実行してまともなテーブルを作成します。
これで一応モデルがコントローラで取り込めるようになってます。モデルの中身をいろいろカスタマイズ必要な方はLaravel 5.4 Eloquent:利用の開始からやってみてください。

また直感的に適当に書くと比較的エラーが頻発します。私はinitに長さを適当に設定したら、設定してもいないプライマリキーがついてしまったので、上記メソット内のオブジェクトは厳粛にそのまま使った方が無難です。

コントローラ側でモデルを取り込む

コントローラからモデルを利用するには対象のモデルを

use App\DataProject;

こんな感じでuseしないといけません。
あとはクエリビルダーの扱いと限りなく同じなので、そこそこ直感的に書いてゆける感じになってます。data_projectsテーブルにデータを挿入して一行目をセレクトしてみます。

use App\DataProject;
....
$data_projects = DataProject::all();

    // model where
    $data_projects = DataProject::where('id', 1)->get();
    foreach($data_projects as $key=>$val) {
        echo "{$key}=>{$val}<br>\n";
    }

なるほど便利ですね。Symfony2より構築が軽くていいですね。

モデルに関するいろいろ

「php artisan make:model tableName」という便利なコマンドでモデルの雛形を作成するわけですが、このファイルはデフォルトではapp/*に入ってきます。これは結構気持ちがわるいので、app/Model/tableName.phpというふうにモデルファイルを集めてあげることにしてます。しかしちょっとソースをまだちゃんと読んでいないので申し訳ないところですが、useするときには、

use App\tableName;

という風にデフォルトのパスでよんであげないとエラーになりました。おや、と思っていろいろ見てみると、

.//vendor/composer/autoload_classmap.php:31:    'App\\tableName' => $baseDir . '/app/Model/tableName.php',
.//vendor/composer/autoload_static.php:311:        'App\\tableName' => __DIR__ . '/../..' . '/app/Model/tableName.php',

というわけで、autoload_classmapとautoload_staticにはApp\tableNameで登録されてるんですね。
なので、これもこれで気持ちがわるいのですが特に修正してあげる必要もないかといったところです。artisanでモデルを作成する際にパスも指定できると思うので、そのときにやった方が懸命ということでしょうか。

https://readouble.com/laravel/5.4/ja/eloquent.html

日本語がUTF8のエスケープシーケンスで表示されてしまう

幾つかの環境で試してみましたが、モデルを通して日本語を取り込むとUTF8のエスケープシーケンスで表示されてしまうというがありました。例えば、

あ → \u3042

と表示されてしまうわけです。やや強引なPHPコードでデコードすることは可能は可能ですが、これはmysqlの設定の問題なのかもしれません。

$val = preg_replace_callback('|\\\\u([0-9a-f]{4})|i',
    function($matched){
        return mb_convert_encoding(pack('H*', $matched[1]), 'UTF-8', 'UTF-16');
    }, $val);

と思ったら取得したデータがobjectとarrayが混在しているために適当にforeachしたらこうなっちゃうという話で正しく取得したら普通に日本語取得できました。


Laravel 5.4 データベース:マイグレーション
Laravel 5.4 Eloquent:利用の開始