Example プロジェクトの作成
Eloquent リレーションの動きを tinker で試すための Example プロジェクトの作成をまとめてみた。
このプロジェクトは次の記事で練習台として使う。
まずは、Laravel の新規プロジェクトの作成から。
/var/www/sutdy/project をアプリケーションルートする場合:
$ mkdir -p /var/www/study
$ cd /var/www/study
$ composer create-project laravel/laravel:^8.0 example
$ cd example
$ chmod -R a+w storage
$ chmod -R a+w bootstrap/cache
あらかじめ database を作成し、.env にデータベース接続に必要な記述を行う。
ブラウザでの動作確認を行うならドキュメントルートを定義する。
Laravel の public フォルダをドキュメントルートにするわけだが、httpd.conf でのドキュメントルート指定は固定しておき、シンボリックリンクで参照すると練習用のプロジェクトの切り替えが楽。
/var/www/sutdy/html がドキュメントルートの場合:
$ cd /var/www/study/
$ ln -s example/public html
$ ll
total 4
drwxrwxr-x 12 vagrant vagrant 4096 Jun 21 18:07 example
lrwxrwxrwx 1 vagrant vagrant 14 Jun 21 18:09 html -> example/public
マイグレーションの作成
Laravel の新規プロジェクトを作成したら、マイグレーションを編集する。練習なのでテーブルごとにマイグレーションを分けていない。
ユーザーに company_id
を追加し、会社とプロジェクトのテーブルを追加した。
マイグレーションのルールは、Eloquent 前提の MySQL データベース設計 を参照のこと。
database\migrations\2014_10_12_000000_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name')->default('')->commen('ユーザー名');
$table->string('email')->default('')->unique()->comment('メールアドレス');
$table->integer('company_id')->default(0)->index()->comment('会社');
$table->datetime('email_verified_at')->nullable()->comment('メール確認日時');
$table->string('password')->default('')->comment('パスワード');
$table->rememberToken()->comment('リメンバートークン');
$table->datetime('created_at')->nullable();
$table->datetime('updated_at')->nullable();
});
DB::statement("ALTER TABLE users COMMENT 'ユーザー';");
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name')->default('')->comment('会社名');
$table->datetime('created_at')->nullable();
$table->datetime('updated_at')->nullable();
});
DB::statement("ALTER TABLE companies COMMENT '会社';");
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->string('name')->default('')->comment('プロジェクト名');
$table->datetime('created_at')->nullable();
$table->datetime('updated_at')->nullable();
});
DB::statement("ALTER TABLE projects COMMENT 'プロジェクト';");
Schema::create('project_user', function (Blueprint $table) {
$table->integer('project_id')->default(0)->comment('プロジェクト');
$table->integer('user_id')->default(0)->comment('ユーザー');
$table->primary(['project_id', 'user_id']);
$table->index('user_id');
});
DB::statement("ALTER TABLE project_user COMMENT 'プロジェクト・ユーザー';");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
Schema::dropIfExists('projects');
Schema::dropIfExists('companies');
Schema::dropIfExists('project_user');
}
}
マイグレーションを実行してみる。データベース接続に失敗したなら .env を確認する。
php artisan migration
モデルの追加
php artisan make:model Project
php artisan make:model Company
artisan コマンド作成したモデルには、最低でも protected $nullabl = ['id'];
を追加しておく。$fillable
か $nullable
のどちらかがないとデータが保存されない。
User と Project にリレーションを定義する。
app/Models/User.php
public function company()
{
return $this->belongsTo(Company::class);
}
public function projects()
{
return $this->belongsToMany(Project::class, 'project_user');
}
app/Models/Project.php
public function users()
{
return $this->belongsToMany(User::class, 'project_user');
}
app/Models/Company.php
public function users()
{
return $this->hasMay(User::class);
}
ファクトリー
UserFactory はそのままでも問題ないので、ProjectFactory と CompanyFactory を追加する。
php artisan make:factory ProjectFactory
php artisan make:factory CompanyFactory
マイグレーションに必ず DEFAULT を定義する ならば、ファクトリーの中身は空でも問題なくレコード作成に成功する。
それでは味気ないので、それぞれ name の指定だけ書き加える。
Project は faker->city()
、Company は faker->company()
でよいかな。faker のメソッドについては「faker チートシート」等で検索しよう。
public function definition()
{
return [
'name' => $this->faker->city() . 'プロジェクト',
];
}
これでダミーレコードが作成できるようになった。tinker で動作を確認する。
$ php artisan tinker
Psy Shell v0.11.4 (PHP 7.4.11 — cli) by Justin Hileman
>>> App\Models\Project::factory()->create()
=> App\Models\Project {#3624
name: "吉本市プロジェクト",
updated_at: "2022-06-25 01:09:23",
created_at: "2022-06-25 01:09:23",
id: 1,
}
>>> App\Models\Company::factory()->create()
=> App\Models\Company {#3623
name: "有限会社 坂本",
updated_at: "2022-06-25 01:11:14",
created_at: "2022-06-25 01:11:14",
id: 1,
}
シーダー
ファクトリーはあくまで1ダミーレコードの雛形にすぎない。
モデル同士の有機的な結びつきを考慮してテストデータを作成するためにシーダーを書く。
database/seeders/DatabaseSeeder.php
public function run()
{
// プロジェクトを先に作成して、その id を取得しておく
\App\Models\Project::factory(10)->create();
$project_ids = \App\Models\Project::pluck('id');
// 会社を10社作成
\App\Models\Company::factory(10)->create()->each(function ($company) use ($project_ids) {
// それぞれの会社にランダムな人数のユーザーを作成
\App\Models\User::factory(rand(3, 10))->create([
'company_id' => $company->id,
])->each(function ($user) use ($project_ids) {
// それぞれのユーザーにプロジェクトを紐づけ
// プロジェクトはシャッフルして、ランダムな数でカット
$ids = $project_ids->shuffle()->slice(rand(0, $project_ids->count()));
foreach ($ids as $project_id) {
DB::table('project_user')->insert([
'user_id' => $user->id,
'project_id' => $project_id,
]);
}
});
});
}
準備ができたらマイグレーションを実行しテストデータも同時に作成だ。
php artisan migrate:fresh --seed --step