PHPのフレームワークLaravelで、フレームワークのインストールから、DBの設定とcliでのDB操作まで行ってみます。
今回、接続先のDBはVagrant上に構築したMySQLを利用しています。
VagrantでのMySQLデータベース作成は、下記の記事を参考にするとvagrant up
のコマンド1つで環境構築することができます。
- VagrantでCentOS7.3+MySQL5.6環境をコマンド1つで構築する
Laravelプロジェクトの作成
Laravelのプロジェクトは、composerから下記のコマンドを1つたたくだけで用意できます。
ここで、comopserに指定している"my-project"は、プロジェクトの名前(ディレクトリ名)です。
> composer create-project laravel/laravel my-project
Installing laravel/laravel (v5.5.0)
- Installing laravel/laravel (v5.5.0): Downloading (100%)
create-projectが完了したら、下記のコマンドでプロジェクトdのディレクトリに移動してPHPのビルドインWebサーバを立ち上げます。
> cd my-project
> php -S localhost:80 public/index.php
その後、ブラウザからhttp://localhost/へアクセスして、以下のようにLaravelのページが表示されればプロジェクトの準備はOKです。
データベースの設定
Laravelでのデータベース設定は、config/database.phpで指定します。
MySQLの定義は以下のようにconnections->mysqlで指定します。接続先ホストやユーザパスワードはphp標env()関数を利用して、環境変数から取得するようになっています。
'connections' => [
'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,
],
それでは環境変数をどうやってセットするかというと、Laravelでは環境変数の設定の管理にvlucas/phpdotenvパッケージを利用しています。
phpdotenvパッケージでは、プロジェクトディレクトリ直下にある".env"ファイルで環境変数を指定するため、このファイルをエディタで開きます。
ファイル".env"の中身を見るとMySQLの接続設定は、以下のようになっています。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
今回はパスワード指定なしのrootユーザでDB接続できるよう準備しているので、DBの接続情報を以下のように変更します。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=root
DB_PASSWORD=
設定を書き換えましたが、現状では書き換えた設定が正しく反映されたか確認する方法が無いので、routes/web.phpを一時的に書き換えて、デバッグ出力させてみます。
Route::get('/', function () {
echo "database = " . env("DB_DATABASE") . "<br />"; // 追加
echo "username = " . env("DB_USERNAME") . "<br />"; // 追加
return view('welcome');
});
env()の結果をechoで出力する処理を加えて、ブラウザでhttp://localhost/を再表示させます。
Laravelが提供しているCSSの都合で文字が薄く読みづらいですが、以下のように表示されれば.envに書いた内容が正しく設定が反映されています。
MySQLへテーブルを作成する
LaravelのDB接続設定が終わったので、次はMySQLデータベースへテーブルを作成します。
マイグレーションのひな型ファイルを作る
Laravelでは、DBのテーブル作成や構造変更の変更管理のために、Ruby on Railsなどと同様マイグレーションの機能を持っています。
マイグレーションファイルを作成するには、以下のようにします。この例ではMySQL上にpostsテーブルをcreate tableするためのひな型を作成しています。
php artisan make:migration create_posts_table --create=posts
コマンドを実行すると、database/migrationsディレクトリに、以下のようなファイルが作成されます。(YYYY_MM_DD_HHMMSSの部分は、コマンドを実行した時刻が入ります)
// YYYY_MM_DD_HHMMSS_create_posts_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
マイグレーションを実行する
ひな型の状態のまま、何も変更せずにMySQLにテーブルを作ってみます。Laravelでのマイグレーションはphp artisan migrate
コマンドを実行すればよいです。
$ php artisan migrate
Migration table created successfully.
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter
table `users` add unique `users_email_unique`(`email`))
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
エラーが出てしましました。この問題の解消をするために、app\Providers\AppServiceProvider.phpのboot()メソッドをを編集します。
※このエラーが発生する理由は、以下の記事を参考にしてください。
- Laravel5.5でphp artisan migrateした時にエラー「1071 Specified key was too long; max key length is 767 bytes」が発生
変更前
// app\Providers\AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
//
}
...
↓
変更後
// app\Providers\AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
\Illuminate\Support\Facades\Schema::defaultStringLength(191);
}
...
この変更を行ったのち再度php artisan migrate
コマンドを実行すると、以下のようにマイグレーションが成功します。
$ php artisan migrate
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
Migrating: 2017_11_13_062445_create_posts_table
Migrated: 2017_11_13_062445_create_posts_table
作成されたテーブルを確認する
MySQLに接続して、作成されたDBのテーブル定義を確認してみます。
以下の列を持つpostsテーブルができたことが分かります。
$ mysql -u root test -e "desc posts;"
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| deleted_at | timestamp | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------+------------------+------+-----+---------+----------------+
create tableを実行しただけなので、まだテーブルにデータは入っていません。
$ mysql -u root test -e "select count(*) from posts;"
+----------+
| count(*) |
+----------+
| 0 |
+----------+
作成したテーブルへデータを登録するバッチを作る
MySQLにテーブルを作成できたので、次はこのテーブルにバッチ処理でデータを登録してみます。
バッチスクリプトのひな型phpファイルを作る
Laravelではバッチのプログラムのひな型をphp artisan command:make
コマンドで作成します。今回は、AddPostsという名前のバッチを作成します。
$ php artisan make:command AddPosts
Console command created successfully.
コマンドの実行に成功すると、バッチスクリプトのひな型ファイルapp\Console\Commands\AddPosts.phpが作成されます。
中は以下のようになっており、handle()メソッドに処理の本体を書きます。
// app\Console\Commands\AddPosts.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AddPosts extends Command
{
protected $signature = 'command:name';
protected $description = 'Command description';
public function __construct()
{
parent::__construct();
}
public function handle()
{
//
}
}
動作確認の為にバッチスクリプトを編集
動作確認のためhandle()関数を修正し、echo関数でメッセージを出力させてみます。
protected $signature = 'command:addpost';
protected $description = 'Add New Post';
public function handle()
{
echo "hello world" . PHP_EOL;
}
編集したバッチスクリプトを登録
ファイルを編集したらこのバッチを実行させたいのですが、Laravelではバッチの登録処理という作業が必要です。
作成したバッチの登録は、作成したAddPosts.phpファイルの1つ上のディレクトリに、app/Console/Kernel.phpというファイルがあるので、このファイルを編集して登録します。$commandsという配列があるので、ここにクラス名を追加します。
変更前
// app/Console/Kernel.php
class Kernel extends ConsoleKernel
{
protected $commands = [
//
];
↓
変更後
protected $commands = [
Commands\AddPosts::class,
];
バッチを登録したら、php artisan list command
コマンドで、登録内容が正しく認識されたかを確認します。
$ php artisan list command
Laravel Framework 5.5.19
Usage:
command [options] [arguments]
Options:
...
Available commands for the "command" namespace:
command:addpost Add New Post
登録したバッチスクリプトを実行
ヘルプに表示されている通り、php artisan command:addpost
で作成したプログラムを実行できます。
$ php artisan command:addpost
hello world
バッチ内でDBにデータを登録する
バッチスクリプトのひな型作成から登録、実行までの流れを確認したので、次はバッチ内でDB処理を行います。今回はLaravelが用意しているORマッパーであるEloquentを使ってみます。
モデルクラスを作る
ORマッパーのEloquentでは、各テーブルごとに1つ、モデルクラスを用意します。モデルクラスのひな型もartisanコマンドで作成できます。
コマンドラインからphp artisan make:model
コマンドを実行して、postsテーブルに対するモデルを作成します。ここで注意が必要なのは、テーブル名は"posts"と複数形にするのに対して、クラス名は"Post"と単数形で指定することです。
$ php artisan make:model Post
Model created successfully.
作成されたPostクラスは、下記の通り空っぽです。この状態で特に変更を行う必要はありません。Ruby On RailsのActiveRecordなどと同様に、継承元のModelクラスが、このモデルのクラス名"Post"を複数名にした"posts"が管理対象のMySQLテーブルであるという事を自動で認識します。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
//
}
先ほど作ったAddPostsのバッチで、今作ったモデルを使ってみます。バッチのクラスとモデルクラスはネームスペースが異なるので、ここでは"\App\Post"とネームスペースを明示しています。
ここでは、Postオブジェクトを生成して何も値をセットせずにsave()しています。save()メソッドではMySQLへのinsert文が走ります。insertする列の値を指定していませんが、idはAutoIncrementによる自動採番、create_at, update_at列にはデータの登録時刻がEloquentによって自動セットされます。
<?php
...
class AddPosts extends Command
{
...
public function handle()
{
$post = new \App\Post;
$post->save();
}
}
ファイルを変更したら再度php artisan command:addpost
コマンドでバッチを実行します。バッチを実行してから、MySQLでpostsテーブルを検索すると1レコード作成されたことが分かります。
$ php artisan command:addpost
$ mysql -u root test -e "select * from posts;"
+----+------------+---------------------+---------------------+
| id | deleted_at | created_at | updated_at |
+----+------------+---------------------+---------------------+
| 1 | NULL | 2017-11-13 06:30:33 | 2017-11-13 06:30:33 |
+----+------------+---------------------+---------------------+
当たり前ですが、もう一回実行すると2レコードに増えます
$ php artisan command:addpost
$ mysql -u root test -e "select * from posts;"
+----+------------+---------------------+---------------------+
| id | deleted_at | created_at | updated_at |
+----+------------+---------------------+---------------------+
| 1 | NULL | 2017-11-13 06:30:33 | 2017-11-13 06:30:33 |
| 2 | NULL | 2017-10-30 03:35:19 | 2017-10-30 03:35:19 |
+----+------------+---------------------+---------------------+
これで、バッチスクリプトからDBの操作が行えました。
登録されたデータを検索するバッチを作る
バッチ作成の復習も兼ねて、もう1つバッチスクリプトを作ってみます。
今度は、先ほど登録したデータを検索して、一覧表示させるバッチです。
$ php artisan make:command ShowPosts
Console command created successfully.
作成されたバッチのひな型であるapp/Console/Commands/ShowPosts.phpをエディタで編集します。今回は登録(insert)ではなく検索(select)なので、\App\Postクラスのall()メソッドを呼び出しています。
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ShowPosts extends Command
{
protected $signature = 'command:showpost';
protected $description = 'Show All Posts';
...
public function handle()
{
$posts = \App\Post::all();
foreach ($posts as $post) {
echo "--------------------------" . PHP_EOL;
echo " id " . $post->id . PHP_EOL;
echo " created_at " . $post->created_at . PHP_EOL;
echo " updated_at " . $post->updated_at . PHP_EOL;
}
}
...
app/Console/Kernel.phpに、作成したバッチをを追加します。
class Kernel extends ConsoleKernel
{
protected $commands = [
Commands\AddPosts::class,
Commands\ShowPosts::class,
];
...
バッチが登録されたかphp artisan list command
で確認します。
$ php artisan list command
Laravel Framework 5.5.19
Available commands for the "command" namespace:
command:addpost Add New Post
command:showpost Show All Posts
登録されたバッチを実行します。
php artisan command:showpost
$ php artisan command:showpost
--------------------------
id 1
created_at 2017-10-30 03:30:33
updated_at 2017-10-30 03:30:33
--------------------------
id 2
created_at 2017-10-30 03:35:19
updated_at 2017-10-30 03:35:19
登録されたデータを取得できたことが分かりました。
まとめ
Laravelでは、cliツールであるartisanを使うことで、クラスのひな型作成やDBのテーブル作成など頻繁に行う作業を手助けしてくれます。
またMySQLデータベースへのアクセスを行う場合はORマッパーであるEloquentを利用することで、検索処理を簡単に作成できます。
もちろんORマッパーには、SQLを生で書くのに比べてオーバーヘッドが大きかったり、複雑なクエリが書きづらいなどのデメリットもあります。
ですがWebサービスの場合、一旦シンプルな形でサービスをリリースさせてみて、ニーズがありそうなら処理の最適化を行う方が、結果的に素早く顧客のニーズがあるサービスを作っていくことができる為、開発初期はEloquentを使って素早くサービスを作ることに集中する方が良いです。
サービスがヒットしたら、LaravelではORマッパーやモデルクラスを使わずにSQLを直接書く方法もあるので、サービス稼働を継続させつつ、負荷が高い処理を順次チューニングさせていくこともできます。