今回の講義では、Laravelとデータベースを繋ぐ方法〜モデルの構築まで行っていきます。
今回の講義内容が一通り実践できるようになると、下記のようなことができるようになります!
- アプリケーションのデータ保存機能がつくれるようになる!
- アプリケーションのユーザ登録機能の根幹部分が完成できる!
- アプリケーションのサンプルユーザを一括して大量に増やすことができる!
つまり、アプリケーションの要である「ユーザ登録機能」について深く知ることができ、
実際のアプリのユーザ登録機構の一部を機能化することができるということです。
●今回のキーポイント
- MySQLとLaravelの接続設定
- 環境変数の理解
- tinkerの操作を学ぶ
- Modelの構築(Userモデル)
- マイグレーションの実行
- シーディングでユーザを一括登録
前回の内容はこちら
https://prog.quest-academia.com/laravel-quest-1/
MySQLとLaravelを接続しよう!
Laravelの使い方を学んでアプリケーションを動かすのが、この講座のメインなのですが
データベースがなければ、ユーザの名前などのアプリケーション上の情報を保存できません。
アプリケーション上で非常に重要となる、Laravelとデータベース(MySQL)の接続方法を学んでいきましょう!
データベース設定を確認しよう
今回のLaravelプロジェクトのconfigフォルダにある、database.phpというファイルに接続設定が記されています。
Laravel-quest > config > database.php
database.phpファイルに下記のような記述があることを確認して下さい。
database.php(一部抜粋)
'default' => env('DB_CONNECTION', 'mysql'),
このコードは、
「通常は、このようなデータベースを呼び出します」
という内容が書かれています。
例えば、
※サンプルコードにつき入力不要です
'default' => env(' ① ', ' ② '),
なら、
原則’①’という「環境変数(※後ほど解説)」を呼び出すけれども
もし’①’が設定されていなかったら、’②’が呼び出されるという仕組みです。
つまり、上記コードでは
「通常、’DB_CONNECTION’を呼び出しますが、
万一’DB_CONNECTION’が定義されていなかったら、
‘mysql’=MySQLというデータベースを呼び出しますよ」
という内容が書かれているということです。
なお、env()というのは、前述の「環境変数」を呼び出す関数です。
この「環境変数」について少し解説します。
環境変数って何?
環境変数とは、一言でいうと
「ユーザの環境によって変えることができる変数」
です。
上記のデータベース設定においても、「環境変数」を変更する事によって
ユーザが「自分の好きな(MySQL以外の)データベース」を設定することも可能になります。
更に、通常のプログラミングでは、プログラミングの停止と同時に変数は消えてしまうのですが、この環境変数は保存することができます。
そのため、毎回システムを利用するたびに
「利用するデータベースを指定しないといけない」ということにもなりません。
では、あなたのLaravelプロジェクトの環境変数はどこで決められているのでしょう?
環境変数を決めているのは、
プロジェクト内の「.env」ファイルになります。
.envファイルの編集
早速、env.ファイルを開いてみましょう。
プロジェクトの直下にあるファイルです。
Laravel-quest > .env
.env(一部抜粋)
DB_CONNECTION=mysql
ファイルの中を見ると、そのうちの1行におそらく DB_CONNECTION の記載があり、
上記のように最初から設定されていると思います。
記述が異なれば、上記のように値が「mysql」となるよう書き換えて下さい。
今回はデータベースをMySQLと設定して話を進めますが、
もしもMySQLでないデータベースを使いたい場合、.env ファイルの DB_CONNECTION=mysql の mysql 部分を使いたいデータベース名に変更することになります。
ここで、先ほどのdatabase.phpに戻ってMySQLの他の設定はどのようになっているか、見ていきましょう。
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', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
env.ファイルのDB_CONNECTION に’mysql’と値の記載がある場合、上記のコードが適用されます。
上記のコードのうち、
database.php(一部抜粋)
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
これら3行のコードがカギとなります。
それぞれ、env()という「環境変数」を呼び出す関数が当てられていますので、
それぞれに代入したい値を.envファイルに記載していきましょう。
初期設定では下記のようになっているかと思います。
.env(一部抜粋)
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
これを、下記のように書き換えてみましょう。
DB_DATABASE=laravel-quest
DB_USERNAME=root
DB_PASSWORD=
このように書き換えると、
- データベース名:laravel-quest
- ユーザ名 :root
- パスワード :(なし:パスワード入力なしでログイン可能)
という様に設定したことになります。
laravel-questデータベースをつくろう
では早速、作ったデータベースにログインしてみましょう!
まず、データベースサーバが起動しているかどうかを確認して、
ターミナル
$ sudo service mysqld status
データベースサーバがまだ起動していない場合は起動して下さい。
ターミナル
$ sudo service mysqld start
データベースサーバの自動起動設定をしておきましょう。
ターミナル
sudo chkconfig mysqld on
そして、下記コマンドでMySQLにログインします。
(rootは先ほど設定したユーザ名ですね)
ターミナル
$ mysql -u root
ログインできたら、下記の「データベース作成」コマンドを打ち込みましょう。
ターミナル
mysql> CREATE DATABASE `laravel-quest`;
「laravel-quest」の様に、ハイフン「-」 が含まれる文字列をデータベース名とする場合は、バッククオート「`」で前後を閉じないといけません。
(通常のアルファベット等の文字列のみをタイトルとする場合は、バッククオートで囲う必要はありません)
これで、LaravelとMySQLを接続するための準備完了です。
一旦、MySQLから下記コマンドでログアウトしましょう。
control(Ctrl)キー + Cキー を押す
tinkerとは?
ここまでできたかを確認するために、Laravelの対話型のPHP実行環境「tinker」で、
データベースの接続を確認してみましょう。
(Laravelのtinkerは、railsのconsoleに対応します。)
「tinker」は、このプロジェクトで今後よく使うことになりますので、
後々分かってくると思いますが、ここで簡単に解説します。
tinkerとは、ターミナル上にコマンドを打ち込むことで、
Laravelプロジェクトの「処理→実行→実行結果の表示」まで行ってくれる環境だと
大まかに捉えておいて下さい。
実際のウェブアプリ上で処理を実行しなくても、データベースにログインして直接操作しなくても
簡単に処理を行い、その結果の成否を確認することができます。
tinkerを利用するには、下記のコマンドを実行して下さい。
ターミナル
$ php artisan tinker
tinkerの環境に入ることができたら
tinkerを利用して、簡単なデータベース接続確認を行います。
下記コマンドを実行して下さい。
ターミナル
>>> DB::connection();
実行後、下記の様な表示となれば、データベースとの接続は成功です。
ターミナル
=> Illuminate\Database\MySqlConnection {#xxx}
データの保存時間を日本時間にしよう!
さらに、タイムゾーンを変更しましょう。
下記の通り、タイムゾーンを「東京」にすると、
データベースに記載されるレコードの保存時間などが日本時間で記録されます。
laravel-quest > config > app.php
app.php(一部抜粋)
'timezone' => 'Asia/Tokyo',
モデルの構築
モデル(Model)とは、MVCにおける「データベース」関連の処理を担当する部分です。
例えば、今回のアプリケーションでは、主に下記の2種類のモデルが登場します。
- ユーザ(利用者)モデル
- ムービー(動画)モデル
今回構築するのはユーザーモデルとなります。
このアプリはいろいろなユーザさんが利用されることを想定して作りますので、
1人だけでなく、各ユーザの名前・メールアドレスなどをデータベース上に保存する必要があります。
そのユーザ情報を保存するに当たって肝心なのが、ユーザモデルです。
このユーザモデルがしっかり作れていないと、ユーザはアプリケーションの利用以前にログイン(ユーザ登録)できないということになりかねません。
早速、重要な項目であるモデル構築について、アプリケーションを作成しながらみていきましょう。
最大文字数の制限設定
モデル・テーブル作成前の準備として、下記のファイルを変更します。
laravel-quest > app > Providers > AppServiceProvider.php
AppServiceProvider.php(一部抜粋)
public function boot()
{
\URL::forceScheme('https'); //←1章で追記したコード
}
上記のbootという関数の中身を以下のように追記しましょう。
データベースにMySQL(バージョンにもよる)を使う場合、文字列の最大文字数を191文字までに制限する必要があります。
(これがないと、次のマイグレーション実行時にエラーとなってしまいます)
AppServiceProvider.php(一部抜粋)
public function boot()
{
\URL::forceScheme('https');
\Schema::defaultStringLength(191);
}
マイグレーションでテーブル管理
上の項で、データベースとあなたのLaravelプロジェクトは連携が可能となりました。
しかし、データベースとあなたのプロジェクトを全く同じ構造で作成しないと、それぞれが上手く動作しなくなります。なので、この連携が非常に重要と言えます。
そこで登場するのが、マイグレーション機能です。
マイグレーション機能では、テーブルを新規に作成するためのマイグレーションファイルと呼ばれるファイルを作成してマイグレーションを実行することで、
マイグレーションファイルに書かれたテーブルの定義がMySQLなどのデータベースに間接的に反映されるのです。
また、マイグレーション機能を使ってテーブルを変更すれば、履歴がマイグレーションファイルとして積み上がっていくので、
「○日前の状態まで戻したい」
といった希望があった場合に、それを叶えることも可能なわけです。
ユーザテーブル設計のマイグレーション
早速マイグレーションを利用して、ユーザ(あなたのLaravelアプリケーションの利用者)を登録するためのテーブルを作っていきたいと思います。
ですが、Laravelプロジェクト開始と同時に、ユーザテーブル作成のためのマイグレーションファイルが既に準備されています。
これを利用すれば、ユーザを登録するためのテーブルが簡単に作成できるわけです。
では、users テーブルの中身をみていきましょう。
下記のファイルを探して、開いてみて下さい。
laravel-quest > database > migrations > 2014_10_12_000000_create_users_table.php
ちなみに、(データの作成日時)create(テーブル名)_table.php という命名ルールでマイグレーションファイルの名前が決められています。
2014_10_12_000000_create_users_table.php(一部抜粋)
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
上記コードを解説します。
ユーザテーブルには、最初からいくつかのカラムが与えられており
中でも下記の4つのカラムが重要です。
・id ID:ユーザに原則自動で割り振られる番号です。
・name 名前:ユーザの名前
・email Eメール:ユーザのメールアドレス
・password パスワード:ログイン時に利用できるパスワード
また、up() と down() 2つのメソッドが記載されているかと思います。
●upメソッド
up() はテーブルを生成するときに実行されるものです。
●downメソッド
down() は生成を戻すとき(例えば、php artisan migrate:resetなど)に実行されるものです。
つまり、Schema::dropIfExists(‘users’);というのは、
「もし’users’テーブルが存在したら、削除を実行する」
という意味です。
上記のマイグレーションファイルを実際に動かして、 usersテーブルをつくっていきましょう。
ターミナル
$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
ユーザテーブルの実行と同時に実行される、create_password_resets_tableというのは
パスワードリセット用のマイグレーションファイルです。
Userモデルについて
Userモデルも、プロジェクトを作成した時点で自動で作られています。
laravel-quest > app > User.php
User.php(一部抜粋)
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
ここで注目して欲しいのが、
「fillable」 「hidden」
という2つの配列です。
少し話が飛びますが、通常、Laravelプロジェクトからデータベースにレコードを保存する場合には、save()関数を利用します。
試しにtinkerにて、以下のようなsave()関数を利用して、ユーザを作成してみましょう。
作成前に、MySQLが起動しているかどうかを必ず確認するようにして下さい。
ターミナル
>>> use App\User
>>> $user=new User;
=> App\User {#xxx}
>>> $user->name='sample-name';
=> "sample-name"
>>> $user->email='sample@sample.com';
=> "sample@sample.com"
>>> $user->password=bcrypt('sample-password')
=> "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
>>> $user->save();
=> true
>>> $user;
=> App\User {#xxx
id: 1,
name: "sample-name",
email: "sample@sample.com",
updated_at: "2020-04-01 09:25:07",
created_at: "2020-04-01 09:25:07",
}
(注釈※bcrypt()は、暗号化する関数で、tinker上には結果として暗号化された値が表示されます)
このように、save()関数を利用するときは、インスタンスを作ってそのインスタンスにレコードを代入して保存するしかありません。
多くのレコードを保存したい場合、インスタンスを作るという作業は手間が掛かってしまいます。
ここで登場するのが、create()関数です。
create()はsave()と近く、データベースに情報をINSERTする役割があると同時に、
インスタンスを作成せずに多くのレコードを一括してデータベースに書き込むことができる利点があります。
ここで話が元に戻るのですが
$fillableに、「一括で保存したいパラメータ」を入れておきます。
(usersテーブルの場合、’name’, ‘email’, ‘password’の3つが既に$fillableに入っているかと思います)
User.php(一部抜粋)
protected $fillable = [
'name', 'email', 'password',
];
すると、create()関数を使って、下記の様に一気に複数のレコードを保存できる様になります。
※サンプルコードにつき入力不要です
User::create([
'name' => 'sample',
'email' => 'sample@sample.com',
'password' => bcrypt('sample'),
]);
また、hiddenについても少し触れておきます。
User.php(一部抜粋)
protected $hidden = [
'password', 'remember_token',
];
この様に指定すると、パスワードなど、開発時においても原則表示すべきでないデータが隠されます。
以下のtinkerでのユーザ登録の際も、passwordは表示されていないのが分かると思います。
tinker上でcreate()関数を用いた、ユーザの登録をやってみましょう。
ターミナル
>>> use App\User
>>> User::create([
... 'name' => 'sample',
... 'email' => 'sample2@sample2.com',
... 'password' => bcrypt('sample') ])
>>> $user=User::find(2)
=> App\User {#xxx
id: 2,
name: "sample",
email: "sample2@sample2.com",
created_at: "2020-04-01 09:25:07",
updated_at: "2020-04-01 09:25:07",
}
$user=User::find(2)は、「2番目に登録されたUserのレコードを探して取得する」という意味です。
$user=User::find(2)で取得された値には、passwordは表示されていません。
次に、作ったデータを削除する方法を試してみましょう。
ユーザを代入した変数を宣言し、delete()すれば削除されます。
ターミナル
>>> $user->delete()
=> true
>>> $user=User::find(2)
=> null
$user=User::find(2)でもう一度確認すると、「null」となって
削除されたのが確認できると思います。
delete()は、一つ一つデータを消去する方法ですが、
作ったデータを「全て一度に削除」してしまいたい場合もあるかと思います。
そんな時には、tinker上で下記コマンドを実行してみてください。
ターミナル
>>> use App\User;
>>> User::truncate();
ユーザのレコードを全て削除するコードとなります。
もしくは、レコード消去には別の方法もあります。migrate:refresh のArtisanコマンドを使用する方法です。
上記と同じsampleデータで構いませんので、もう一度新規Userを作成し、
一旦、tinkerから下記コマンドで離脱しましょう。
control(Ctrl)キー + Cキー を押す
その後、ターミナルでArtisanコマンドを実行します。
ターミナル
$ php artisan migrate:refresh
上記いずれかのコマンド実行すると、データベースは初期化され、マイグレーションも1から実行されて、レコードは全て消えます。
上記いずれかのコマンド実行後、今一度tinkerに入って、
$user=User::find(2)で確認すると、作成したUserが全て消えていると思います。
なお、作成したいユーザを一度に全て表示したい場合は、tinkerで下記コマンドを打ち込めば、一括して全てのUserを表示できます。
ターミナル
>>> use App\User
>>> User::all()
シーディングで一括データ登録を行おう!
「1つ1つデータを登録するのは手前だし、一括でデータ登録をしたい」
ということもあると思います。
テストデータやダミーデータを自動生成するためのプログラムをシード、
それらのデータを自動生成する機能をシーディングと呼びます。
シーディングを行う方法を説明していきましょう。
ここでは、usersテーブルにシーディングにて新規ユーザを一括して作成していきます。
下記コマンドを実行してみましょう。
ターミナル
$ php artisan make:seeder UsersTableSeeder
実行すると下記のフォルダに UsersTableSeeder.php が生成されます。
laravel-quest > database > seeds > UsersTableSeeder.php
UsersTableSeeder.php(一部抜粋)
<?php
use Illuminate\Database\Seeder;
class MessagesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//
}
}
run()にusersテーブルとして、レコードをinsertする処理を書き加えます。
試しに、5件一括して登録してみましょう。
UsersTableSeeder.php(一部抜粋)
<?php
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('users')->insert([
'name' => 'sample1',
'email' => 'sample1@sample.com',
'password' => bcrypt('sample1')
]);
DB::table('users')->insert([
'name' => 'sample2',
'email' => 'sample2@sample.com',
'password' => bcrypt('sample2')
]);
DB::table('users')->insert([
'name' => 'sample3',
'email' => 'sample3@sample.com',
'password' => bcrypt('sample3')
]);
DB::table('users')->insert([
'name' => 'sample4',
'email' => 'sample4@sample.com',
'password' => bcrypt('sample4')
]);
DB::table('users')->insert([
'name' => 'sample5',
'email' => 'sample5@sample.com',
'password' => bcrypt('sample5')
]);
}
}
またここで、下記ファイルを開きましょう。
laravel-quest > database > seeds > DatabaseSeeder.php
DatabaseSeeder.phpの run()関数には、既に$this->call(UsersTableSeeder::class)がコメントとして記述されているかと思います。
丁寧にUsersTableSeederを実行する準備がなされています。
こちらのコメントアウトを解除してください。
DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$this->call(UsersTableSeeder::class);
}
}
では、準備は完了しましたので、ユーザ情報の一括登録を実行していきましょう。
ターミナル
$ php artisan db:seed --class=UsersTableSeeder
こちらのコマンドが問題なく実行されれば、5名分のサンプルユーザ情報がテーブルに保存されているはずです。
tinkerに入って、レコードが保存されているか確認してみましょう。
ターミナル
>>> use App\User
>>> User::all()
=> Illuminate\Database\Eloquent\Collection {#2895
all: [
App\User {#xxx
id: 1,
name: "sample1",
email: "sample1@sample.com",
created_at: null,
updated_at: null,
},
App\User {#xxx
id: 2,
name: "sample2",
email: "sample2@sample.com",
created_at: null,
updated_at: null,
},
App\User {#xxx
id: 3,
name: "sample3",
email: "sample3@sample.com",
created_at: null,
updated_at: null,
},
App\User {#xxx
id: 4,
name: "sample4",
email: "sample4@sample.com",
created_at: null,
updated_at: null,
},
App\User {#xxx
id: 5,
name: "sample5",
email: "sample5@sample.com",
created_at: null,
updated_at: null,
},
],
}
このように5件のユーザ情報が登録されていれば、実行完了です。
ちなみに、–class=UsersTableSeederは、当該シーダーを実行する場合のみに必要なコマンドです。
DatabaseSeederの中で記述したシーダーを全て一括で実行する場合は、記述しなくてOKです。
補足:エラーをクリアするためのコマンド
マイグレーションを実行する際に、下記のようなエラーが出たのではないでしょうか。
could not find driver (SQL: select * from information_schema.tables where table_schema = larave
l-quest and table_name = migrations)
以下で、データベースを操作する仕組み:PDO (PHP Data Objects)のドライバがインストールされているかどうかを確認しましょう。
ちなみに、PDOを使うと統一された方法でデータベースにアクセスができるので、便利なのです。
さらにPDOを扱うには、各データベースに応じたドライバ(部品)をインストールしないといけません。
下記コマンドでドライバが存在するか確認できます。
ターミナル
php -m | grep pdo
上記を入力しても、pdo_mysql が表示されなければ、MySQLのドライバのインストールが必要です。
原因は、PHP7.2にバージョンをアップデートしたのに
PDOのドライバが PHP7.2バージョンに追いついていないからです。
以下のように、ドライバをインストールしましょう。
sudo yum -y install php72 php72-mbstring php72-pdo php72-mysqlnd
もう一度以下のコマンドを実行して、
php -m | grep pdo
pdo_mysql が表示されるのを確認できたら、マイグレーションが実行できるようになっているはずです。
最後に
いかがだったでしょうか?
データベースとの接続〜モデルの構築まで、今回はデータベースと関わる部分を重点的に学習しました。
データベースとの関わりが、PHP/Laravelなどのサーバサイド言語の肝といっても過言ではありません。
MVCの流れを理解する上でも、重要な項目ですので、特に「テーブル作成→レコード保存」の流れを繰り返し行ってみて下さい。