遅延読み込み(Lazy Loading)
必要な時のみリレーションの情報を読み込みます。最も簡単な読み込み方です。
$user = User::find(1);
// Lazy load the user's posts when needed
$posts = $user->posts;
PHP上記を実行すると、以下の2つのクエリが発行されます。
SELECT * FROM `users` WHERE `users`.`id` = 1;
SELECT * FROM `posts` WHERE `posts`.`user_id` = 1;
SQLN+1問題
上記の例ではusersを1件だけ取得していますが、複数件取得した場合は、postsを取得するために取得したusersをforeachで回してpostsを取得する必要があります。
これは、いわゆるN+1問題というもので、posts取得(N) + users取得(1)件のクエリを発行してしまい、レコード数が多くなればなるほど重くなる問題があります。
これを行わないようにするのが以下のEager Loadingです。
積極的読み込み(Eager Loading)
先にリレーション先の情報を読み込みます。with
メソッドを利用します。
$users = User::with(['posts' => function ($query) {
$query->select('id', 'user_id', 'title');
}])->get();
PHP上記では、以下のクエリが発行されます。
SELECT * FROM `users`;
SELECT `id`, `user_id`, `title` FROM `posts` WHERE `posts`.`user_id` IN (1, 2);
SQLINの条件にusersで取得したレコードのIDが全部入るため、レコードが多くなっても上記2クエリのみの発行で済みます。
グローバルスコープ
グローバル・スコープを使用すると、指定されたモデルのすべてのクエリに自動的に適用される制約を定義できます。
// Define a global scope for soft-deleted records
protected static function boot()
{
parent::boot();
static::addGlobalScope('softDeleted', function ($builder) {
$builder->where('deleted', 0);
});
}
PHPSelectのサブクエリ
サブクエリを利用できます。生のSQLを書く前にお試しください。
$latestPosts = Post::select('title', 'created_at')
->whereIn('id', function ($query) {
$query->select('post_id')
->from('comments')
->where('approved', 1);
})
->get();
PHPポリモーフィックリレーション
ポリモーフィックな関係によって、1つのモデルが複数の他のタイプのモデルに属することができます。
class Comment extends Model
{
public function commentable()
{
return $this->morphTo();
}
}
PHPtapメソッドの利用
tap
メソッドを使用すると、コールバック内でクエリビルダのインスタンスをタップできます。
$users = User::where('active', 1)
->tap(function ($query) {
// Perform additional actions on the query builder
$query->orderBy('name');
})
->get();
PHP生の式の記述
複雑な条件や計算で生の式を利用する場合。
$users = User::select(DB::raw('COUNT(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
PHPモデルのファクトリ
モデルのテストデータなどを作成する。[Laravel]Factory(ファクトリ)を使ってテストデータを作るで詳しい使い方を紹介しています。
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
];
}
}
PHPクエリスコープ
再利用可能なクエリスコープをモデルに定義することで、クエリを整理することができます。
グローバルスコープに対して、こちらはローカルスコープとも呼ばれます。
class User extends Model
{
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
// Usage
$activeUsers = User::active()->get();
PHPクエリのキャッシュ
重いクエリなどはキャッシュを利用して、パフォーマンスの改善を図りましょう。
$users = Cache::remember('all_users', 60, function () {
return User::all();
});
PHPwhenメソッドを利用した動的リレーション
when
メソッドを利用して特定の条件の場合にリレーションを定義できます。
$relation = User::when($isAdmin, function ($query) {
return $query->hasMany('App\Post');
}, function ($query) {
return $query->hasMany('App\Comment');
})->get();
PHPカスタム ピボット
多対多のリレーションシップを扱う場合は、カスタム ピボット モデルを使用して追加のフィールドや動作を追加します。
class RoleUser extends Pivot
{
// Custom fields or methods
}
PHP結果の分割
巨大なデータをバッチ処理する際に、分割しながら読み込んで処理ができます。
User::orderBy('id')->chunk(200, function ($users) {
foreach ($users as $user) {
// Process each user
}
});
PHP条件付きのリレーション
unless
メソッドを使って条件付きで関係を定義できます。
$relation = User::unless($isGuest, function ($query) {
return $query->hasMany('App\Post');
})->get();
PHP匿名グローバルスコープ
グローバルスコープに匿名クラスも利用できます。
protected static function boot()
{
parent::boot();
static::addGlobalScope(new class implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('active', 1);
}
});
}
PHPキーバリューにpluckを利用する
pluck
メソッドを利用して効率的にキーバリューを作成できます。
$userRoles = User::pluck('role', 'id');
PHPJSONカラムのクエリ
JSON型のカラムを利用して柔軟なデータを表現できます。
$users = User::where('meta->status', 'active')->get();
PHPEloquentのリソースコレクション
EloquentモデルをAPIリソースに変換し、クリーンで一貫性のあるデータ出力を実現します。
class UserCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'meta' => ['key' => 'value'],
];
}
}
PHPリレーション先のカウント
関連するモデルのcountを取得できます。
$userCount = User::withCount('posts')->find(1);
echo $userCount->posts_count;
PHPピボットテーブルの名前を指定
多対多のリレーションシップにおけるピボット・テーブルのカスタムテーブル名を指定します。
class User extends Model
{
public function roles()
{
return $this->belongsToMany('App\Role', 'user_roles');
}
}
PHP最後に
紹介したこれらの高度な使い方をマスターすると、複雑な要件でもデータベースとのやり取りで最適なパフォーマンスを発揮できるようになります。是非マスターして素晴らしいアプリケーションを作成しましょう。
コメント