Laravel 5 チュートリアル - Database

ここまでで、アプリケーションのURIに対してページを表示するということができるようになったので、今回はデータベースとの連携をしていきます。Homesteadで作ったVMではそのままMySQLが利用できます。

今回から、サンプルアプリケーションとして企業サイトを想定して作ることにします。

サンプルサイトの骨子を作る

corporate.exampleディレクトリにソースをインストールし、corporate.example.devというURLで開発していくようにします。

$ homestead edit

# Homestead.yml
folders:  
    - map: /path/to/workdir/
      to: /home/vagrant/Code

sites:  
    - map: corporate.example.dev
      to: /home/vagrant/Code/corporate.example/public

databases:  
    - corporate.example

---------

% sudo vi /etc/hosts

## 追加
192.168.10.10 corporate.example.dev

---------

% homestead provision
% composer create-project laravel/laravel corporate.example --prefer-dist
% cd corporate.example
% php artisan app:name Corporate
Application namespace set!

---------

## config/app.phpのtimezoneとlocaleを設定
'timezone' => 'Asia/Tokyo',  
'locale' => 'ja',  

DBの設定

Composerでプロジェクトを作ると、プロジェクトのルートディレクトリに.envが生成されます。developmentproductionなど、環境ごとの設定を記述するファイルです。.env内のDB_から始まる行がDB関連の設定です。

DB_HOST=localhost  
DB_DATABASE=homestead  
DB_USERNAME=homestead  
DB_PASSWORD=secret  

homesteadというデータベースはHomestead.ymlで定義されているデフォルトのデータベースです。アプリケショーン用のデータベースをVM上に作成するにはHomestead.ymldatabaseセクションにDB名を追加し、プロビジョニングし直します。

% homestead edit

// Homestead.yml
databases:  
    - corporate.example

$ homestead provision

DBが作成されているか確認しておきます。

% homestead ssh

$ mysql -u homestead -p
Enter password: secret

mysql> show databases;  
+-------------------------+
| Database                |
+-------------------------+
| information_schema      |
| corporate.example       |
| homestead               |
| mysql                   |
| performance_schema      |
+-------------------------+

corporate.exampleデータベースを使うので、.envファイルで設定します。

DB_HOST=127.0.0.1  
DB_DATABASE=corporate.example  
DB_USERNAME=homestead  
DB_PASSWORD=secret  
DB_PORT=33060 #追加  

実際のデータベースの設定はconfig/database.phpです。この中で、.envの定義を読み込んで設定されるようになっています。

// config/database.php

'mysql' => [  
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', '127.0.0.1'),
            'port'      => env('DB_PORT', 3306),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],

ここまでで、アプリケーションからデータベースへアクセスする準備が整いました。次にアプリケーションで利用するモデルを考えます。

今回は企業サイトということで、「お知らせ」「お知らせのカテゴリ」モデルだけ考えます。

Eloquent ORM

LaravelではEloquentと呼ばれるORMを使用します。基本的なルールとしては、モデルの定義は単数形で定義し、マップされるテーブル名は複数形します。

Eloquent Modelを定義する

モデルはクラスとしてapp/以下に置きます。「お知らせ = Information」、「カテゴリ = Tag」とします。モデルのクラスファイルは手動で作っても良いですが、artisanコマンドで生成させることもできます。

% php artisan make:model Information
% php artisan make:model Tag

それぞれapp/以下にモデルクラスのファイルが生成されます。

<?php

namespace Corporate;

use Illuminate\Database\Eloquent\Model;

class Information extends Model  
{
    //
}

早速モデル間の関係を定義していきます。Informationモデルは1つのカテゴリに属するということで、"Information belongs to Tag"、"Tag has many Information"とします。

// app/Information.php
<?php

namespace Corporate;

use Illuminate\Database\Eloquent\Model;

class Information extends Model  
{
    public function tag()
    {
        return $this->belongsTo('Corporate\Tag');
    }
}
// app/Tag.php
<?php

namespace Corporate;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model  
{
    protected $timestamps = false;
    public function informations()
    {
        return $this->hasMany('Corporate\Information');
    }
}

デフォルトではcreated_atupdated_atというタイムスタンプのフィールドがテーブルに作られますが、Tagには要らないのでprotected $timestamps = false;としておきます。

データベースのスキーマを作る

簡単なモデルの定義をしたので、対応するデータベースのスキーマを作ります。Eloquentのマイグレーションを使います。

% php artisan make:migration create_tags_table --create=tags

マイグレーションのファイルはdatabase/migrations以下に生成されます。既にusersテーブル関連のファイルができていますがLaravelが予め生成するものなので、今は放っておきます。

マイグレーションのファイルのクラスには常にup()down()メソッドが定義され、それぞれスキーマの変更時、スキーマ変更のやり直しのステップで実行されます。

モデルのフィールドを定義していきます。Tagなのでidnameだけ定義しておきます。

public function up()  
{
    Schema::create('tags', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
    });
}

同様にInformationに対応するinformationsテーブルのスキーマを定義していきます。

% php artisan make:migration create_informations_table --create=informations
public function up()  
{
    Schema::create('informations', function (Blueprint $table) {
        // idフィールドは自動的にインクリメントする
        $table->increments('id');
        // titleフィールドはVARCHAR
        $table->string('title');
        // publish_dateフィールドはDATE
        $table->date('publish_date');
        // tag_idフィールドはUNSIGNED INTEGER
        $table->integer('tag_id')->unsigned();
        // Foreignキーの設定。
        $table->foreign('tag_id')->references('id')->on('tags');
        // created_at, updated_at
        $table->timestamps();
    });
}

フィールド名は慣習的に_でつなげます。とりあえずマイグレーションを実行して、実際のテーブルを生成してみます。

% php artisan migrate

homestead sshでVMにログインし、テーブルができていることを確認しておきます。

mysql> show tables;  
+-------------------------------------+
| Tables_in_corporate.example         |
+-------------------------------------+
| informations                        |
| migrations                          |
| password_resets                     |
| tags                                |
| users                               |
+-------------------------------------+

tagsテーブルを作るためのマイグレーションは、foreignキーを設定しているためinformationsテーブルのマイグレーションよりも先に作る必要があることに注意して下さい。

モデルに対応するテーブルができたので、tagsテーブルに予めデータを入れて置くようにします。database/seeds/Seederクラスを使ってtagsテーブルの初期データを入れておくようにします。

<?php  
use Illuminate\Database\Seeder;

class TagsTableSeeder extends Seeder {  
    public function run()
    {
        DB::table('tags')->insert([
            ['id'=>1, 'name'=>'プレスリリース'],
            ['id'=>2, 'name'=>'リリース情報'],
            ['id'=>3, 'name'=>'お知らせ'],
            ['id'=>4, 'name'=>'その他']
        ]);
    }
}

Seederの管理は同ディレクトリ内のDatabaseSeeder.phprun()メソッド内に記述します。

public function run()  
{
    Model::unguard();

    // $this->call(UserTableSeeder::class);
    $this->call('TagsTableSeeder');

    Model::reguard();
}
% php artisan db:seed

で、データベースにデータを挿入します。