Laravel Tips集 ~Eloquent & Databaseの便利技大全~
Laravel & Database チートシート
各セクションでは、Laravel の便利な機能とその使い方を簡潔にまとめています。コード例はそのままご利用いただけます。
1. オリジナル属性の取得
Laravel のアクセサは、取得時に属性を変換できますが、元の値を知りたい場合は getRawOriginal
を使います。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class User extends Model
{
protected function username(): Attribute
{
return Attribute::make(
function (string $value, array $attributes) {
return sprintf('%s#%s', $value, $attributes['app_id']);
}
);
}
}
$user = User::create([
'username' => 'oussama',
]);
$user->getOriginal('username'); // oussama#1234
$user->getRawOriginal('username'); // oussama
2. カスタムファクトリパスの指定
モデルファクトリの場所をカスタマイズしたい場合、newFactory
メソッドを定義して、独自のロジックでファクトリを返すことができます。
<?php
namespace App\Models;
use Database\Factories\UserFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
// ...
protected static function newFactory()
{
// ... custom logic
return new UserFactory();
}
}
3. 特定のカラムだけを eager load する
リレーションを eager load するとき、必要なカラムのみ指定することでメモリ使用量を抑えられます。
<?php
$users = Post::with('author:id,name')->get();
is()
メソッドでモデル同士の同一性を確認
4. is()
ヘルパーを使えば、2つのモデルが同じかどうか簡単に確認できます。
<?php
$user = User::find(1);
$sameUser = User::find(1);
$differentUser = User::find(2);
$user->is($sameUser); // true
$user->is($differentUser); // false
5. 短縮形の whereHas(whereRelation)の利用
従来の whereHas
の代わりに、whereRelation
を使うと、コードがより簡潔になります。
<?php
// 旧:whereHas を使う場合
User::whereHas('comments', function ($query) {
$query->where('created_at', '>', now()->subDay());
})->get();
// 新:whereRelation を使う場合
User::whereRelation('comments', 'created_at', '>', now()->subDay())->get();
6. ダイナミックな where 条件
Laravel では、メソッド名に条件を含めることで、動的な where 条件を定義できます。
※IDEの補完のため、PHPDocにメソッド名を追加するとよいでしょう。
<?php
// 例:name と last_name に対して条件を指定する場合
User::whereNameAndLastName('oussama', 'mater')->first();
7. モデルイベントを発火せずに更新・削除する方法
saveQuietly()
や deleteQuietly()
を使えば、モデルのイベントを発火させずに更新・削除できます。
<?php
$user = Auth::user();
$user->name = 'Oussama Mater';
// モデルイベントを発火させずに更新
$user->saveQuietly();
$user->deleteQuietly();
$user->forceDeleteQuietly();
$user->restoreQuietly();
8. BelongsToMany 関係の関連IDを取得する
allRelatedIds()
を使えば、belongsToMany リレーションの全ての関連IDを簡単に取得できます。
<?php
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
$user = User::find(1);
$roleIds = $user->roles()->pluck('id')->toArray();
$roleIds = $user->roles()->allRelatedIds()->toArray();
9. 実行された全クエリの取得
DB::listen
を使うことで、実行された SQL、バインディング、実行時間などを取得し、デバッグや通知に活用できます。
<?php
DB::listen(function (QueryExecuted $query) {
dump($query->sql); // 例: select * from `users` where `users`.`id` = ? limit 1
dump($query->bindings); // バインディング内容
dump($query->time); // 実行時間(ミリ秒)
});
10. Prunable トレイトでレコードを削除
Prunable トレイトを使えば、特定条件に合致したレコード(ソフトデリート済みも含む)を自動で削除できます。
<?php
// 削除条件を定義
class User extends Authenticatable
{
use Prunable;
public function prunable()
{
return static::query()
->whereNull('email_verified_at')
->where('created_at', '<', now()->subMonths(6));
}
}
// スケジュールに PruneCommand を追加して定期実行します
$schedule->command(PruneCommand::class)->daily();
11. whereBelongsTo メソッド
whereBelongsTo
を使うと、親モデルに基づいたクエリをより読みやすく記述できます。
<?php
// 従来の書き方
$posts = Post::where('user_id', $user->id)->get();
// より読みやすい書き方
$posts = Post::whereBelongsTo($user)->get();
12. whenQueryingForLongerThan メソッドで遅いクエリを検出
指定したミリ秒以上かかるクエリが発生した場合に、特定の処理(例:通知など)を実行できます。
<?php
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
// クエリが遅い場合の処理(例:通知やログ出力)
});
}
}
13. foreignIdFor メソッド
モデル名をスネークケースに変換し、「id」を付加した外部キーを簡単に定義できます。
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->foreignIdFor(User::class); // user_id が自動で作成される
$table->timestamps();
});
14. whereYear() の注意点と範囲検索の推奨
whereYear() はインデックスが使われない場合があるため、範囲検索を利用する方が高速です。
<?php
// whereYear() を使用した例
DB::table('user_posts')
->select('user_id', DB::raw('COUNT(*) as count'))
->whereYear('created_at', 2023)
->groupBy('user_id')
->get();
// 範囲検索を使用した例
DB::table('user_posts')
->select('user_id', DB::raw('COUNT(*) as count'))
->whereBetween('created_at', ['2023-01-01 00:00:00', '2024-01-01 00:00:00'])
->groupBy('user_id')
->get();
15. withCount メソッド
リレーションの件数を取得する場合、実際にリレーションをロードせずにカウントのみを取得できます。
<?php
$users = User::withCount(['posts'])->get();
// 結果は $users->posts_count としてアクセス可能
16. toQuery メソッド
取得したコレクションに対して、1回のクエリで一括更新を行う際に便利です。
<?php
$users = User::where('status', 'VIP')->get();
// 各モデルを個別に更新する代わりに…
foreach ($users as $user) {
$user->update(['status' => 'Administrator']);
}
// これを一括で実行
$users->toQuery()->update(['status' => 'Administrator']);
17. whenTableDoesntHaveColumn / whenTableHasColumn メソッド
スキーマが環境ごとに異なる場合、特定のカラムが存在しない(または存在する)場合にだけ処理を実行できます。
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
// email カラムが存在しない場合のみ追加
Schema::whenTableDoesntHaveColumn('users', 'email', function(Blueprint $table){
$table->string('email')->unique();
});
// email カラムが存在する場合のみ削除
Schema::whenTableHasColumn('users', 'email', function(Blueprint $table){
$table->dropColumn('email');
});
18. withoutTimestamps メソッド
更新時に updated_at
カラムの更新を抑えたい場合に使用します。
<?php
// updated_at が更新されない
Post::withoutTimestamps(fn () => $post->increment(['reads']));
19. ランダム順での取得(Random Ordering)
inRandomOrder()
を使って、結果をランダムに並べ替えられます。
$randomUser = DB::table('users')
->inRandomOrder()
->first();
20. リレーションのタイムスタンプ更新(Touching Relationships)
setTouchedRelations()
を使って、関連リレーションの updated_at
をまとめて更新できます。
<?php
$user = User::firstOrFail();
$user->setTouchedRelations(['posts']);
// 関連する posts の updated_at が更新される
$user->save();
21. 関連モデルとそのリレーションを再帰的に保存
push()
メソッドを使用すると、関連する全てのモデルを再帰的に保存できます。
<?php
$post = Post::find(1);
$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';
// 従来の個別保存をせず…
$post->push();
22. saveMany メソッド
複数の関連モデルを一括して保存する際に利用します。
<?php
$post = Post::find(1);
$post->comments()->saveMany([
new Comment(['message' => 'A new comment.']),
new Comment(['message' => 'Another new comment.']),
]);
23. JSON フィールドのクエリ
JSON 型のカラムに対して、特定の値や配列の条件で検索できます。
<?php
// preferences→dining→meal が 'salad' のユーザーを取得
DB::table('users')
->where('preferences→dining→meal', 'salad')
->get();
// options→languages 配列に 'en' と 'de' が含まれるユーザーを取得
DB::table('users')
->whereJsonContains('options→languages', ['en', 'de'])
->get();
// options→languages 配列の要素数が1より多いユーザーを取得
DB::table('users')
->whereJsonLength('options→languages', '>', 1)
->get();
24. toBase() メソッド
膨大なデータをモデル化せず、シンプルなオブジェクトのコレクションとして取得することでメモリ使用量を節約できます。
<?php
// PHP オブジェクトのコレクションとして取得(モデルはハイドレートされない)
$users = User::toBase()->get();
25. value() メソッド
特定のカラムの単一の値だけを直接取得する方法です。
<?php
$email = DB::table('users')->where('name', 'John')->value('email');
dd($email); // john@example.com
26. whereAll と whereAny メソッド
複数カラムに同じ条件を適用でき、全て(whereAll)またはいずれか(whereAny)の条件にマッチするかを確認できます。
<?php
$search = 'ous%';
// whereAll:全てのカラムが条件に一致する場合
User::query()
->whereAll(['first_name', 'last_name'], 'LIKE', $search)
->get();
// whereAny:いずれかのカラムが条件に一致する場合
User::query()
->whereAny(['first_name', 'last_name'], 'LIKE', $search)
->get();
27. eager load 時のリレーション件数の制限
Laravel 11 から、ネストしたリレーションにも件数制限が可能になりました。
<?php
User::with([
'posts' => fn ($query) => $query->limit(5)
])->paginate();
28. キャスト定義をメソッドで記述
Laravel 11 以降、キャストの定義をプロパティではなくメソッドで記述でき、引数の指定がより簡潔になります。
<?php
namespace App\Models;
use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// Laravel ≤ 10 の場合
protected $casts = [
'statuses' => AsEnumCollection::class.':'.ServerStatus::class,
];
// Laravel 11 の場合
protected function casts(): array
{
return [
'statuses' => AsEnumCollection::of(ServerStatus::class),
];
}
}
29. withExists メソッド
リレーションの存在有無を確認し、結果を属性として取得できます。
<?php
$user = User::query()
->withExists('posts as is_author')
->get();
// $user->is_author は true か false
30. whereKey メソッド
主キーに対して、WHERE IN の条件をシンプルに記述できます。
<?php
// 従来の書き方
Post::whereIn('id', [1,2,3])->get();
// 新しい書き方
Post::whereKey([1,2,3])->get();
Post::whereKeyNot([1,2,3])->get();
31. カラム名の曖昧さを防ぐ
qualifyColumn
を使って、カラム名が他のテーブルと衝突しないようにテーブル名をプレフィックスできます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Team extends Model
{
use HasFactory;
protected $fillable = [
'name',
];
public function servers(): HasMany
{
return $this->hasMany(Server::class)->orderBy(
(new Server)->qualifyColumn('name')
);
}
}
32. doesntHave メソッド
リレーションを持たないレコードを取得する際に使用します。
<?php
use App\Models\Post;
$posts = Post::doesntHave('comments')->get();
33. モデルイベントを全てミュートする
withoutEvents
を使うことで、ブロック内の処理中に発火するモデルイベントを抑制できます。
<?php
use App\Models\User;
$user = User::withoutEvents(function () {
User::findOrFail(1)->delete();
return User::find(2);
});
34. unguard を利用する
Model::unguard()
を使うと、一時的に全モデルで guard(保護)が解除され、fillable に含まれていない属性も一括で設定できます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
protected $fillable = ['name'];
}
Model::unguard();
Flight::create([
'name' => 'flight',
'not_in_fillable' => true,
]);
Model::reguard();
35. ピボット属性名のカスタマイズ
多対多リレーションで、中間テーブルの属性名(pivot)を変更できます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class User extends Model
{
public function podcasts(): BelongsToMany
{
return $this->belongsToMany(Podcast::class)
->as('subscription')
->withTimestamps();
}
}
$users = User::with('podcasts')->get();
foreach ($users->flatMap->podcasts as $podcast) {
echo $podcast->subscription->created_at;
}
36. インクリメント・デクリメントメソッド
数値カラムの値を増減させるためのメソッドが用意されています。
<?php
// 1ずつ増加
DB::table('users')->increment('votes');
// 5ずつ増加
DB::table('users')->increment('votes', 5);
// 1ずつ減少
DB::table('users')->decrement('votes');
// 5ずつ減少
DB::table('users')->decrement('votes', 5);
// 増加と同時に他のカラムを更新
DB::table('users')->increment('votes', 1, ['name' => 'John']);
// 複数カラムを同時に増加
DB::table('users')->incrementEach([
'votes' => 5,
'balance' => 100,
]);
// Eloquent での利用例
User::query()->incrementEach([
'votes' => 5,
'balance' => 100
]);
37. モデルの属性が変更されたか確認する
originalIsEquivalent()
を使って、特定の属性が変更されたかどうかを判断できます。
<?php
$user = User::firstOrFail(); // ['name' => 'old']
$user->name = 'old'; // 同じ値を再設定
$user->originalIsEquivalent('name'); // true
$user->name = 'new'; // 値を変更
$user->originalIsEquivalent('name'); // false
38. getOrPut メソッド(コレクション操作)
コレクション内にキーが存在しない場合、指定した値を設定して取得できます。
$collection = collect(['price' => 100]);
$value = $collection->getOrPut('name', 'Desk');
39. Higher Order "orWhere" メソッド
コレクションで使う高階メソッドと同様に、クエリでも高階な記法が使えます。
<?php
User::popular()->orWhere->active()->get();
40. whereIntegerInRaw で高速クエリ
数値の whereIn を高速化するために、whereIntegerInRaw を利用できます。
<?php
// 従来の書き方
Product::whereIn('id', range(1, 10000))->get();
// 新しい書き方
Product::whereIntegerInRaw('id', range(1, 10000))->get();
41. upsert メソッド
存在すれば更新、存在しなければ挿入する一括操作を行えます。
<?php
Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], uniqueBy: ['departure', 'destination'], update: ['price']);
42. タイムスタンプがないテーブルの指定
テーブルに created_at
や updated_at
が存在しない場合、モデルで $timestamps
を false に設定します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
public $timestamps = false;
}
43. simplePaginate メソッド
次へ・前へボタンのみのシンプルなページネーションを利用する方法です。
<?php
$users = User::simplePaginate(15);
44. doesntExist メソッド
レコードが存在しないかどうかを簡潔にチェックできます。
if (User::doesntExist()) {
// レコードが存在しない場合の処理
}
45. クエリのクローン作成
同じ基本条件を使ったクエリを複数作成する場合に、clone()
を使えます。
<?php
$query = User::query()->where('created_at', '<', now()->subMonths(3));
$verified_users = $query->clone()->whereNotNull('email_verified_at')->get();
$unverified_users = $query->clone()->whereNull('email_verified_at')->get();
46. 指定属性の一時非表示
makeHidden()
を使うと、指定した属性を一時的に隠すことができます。
<?php
$users = User::all()->makeHidden(['address', 'phone_number']);
47. グローバルスコープの無効化
特定または全てのグローバルスコープを除外してクエリを実行できます。
<?php
// 全てのグローバルスコープを無効化
User::withoutGlobalScopes()->get();
// 特定のスコープのみ無効化
User::withoutGlobalScope(FirstScope::class)->get();
48. パスワードの自動ハッシュ化
hashed
キャストを使うことで、パスワードが自動的にハッシュ化されます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected function casts(): array
{
return [
'password' => 'hashed',
];
}
}
$user = User::create([
'password' => 'password', // 自動的にハッシュ化される
]);
49. firstOr メソッド
レコードが存在しない場合に、追加のロジックを実行して新しいレコードを作成できます。
<?php
$user = User::where('email', $request->input('email'))->firstOr(function () {
return User::create([
// 新規作成時のデータ
]);
});
50. latest と oldest メソッド
最新または最古のレコードを簡単に取得できます。カラム指定も可能です。
<?php
User::latest()->get();
User::oldest()->get();
User::latest('id')->get();
User::oldest('id')->get();
51. insertOrIgnore メソッド
挿入時に重複エラーなどを無視して処理を実行できます。
<?php
DB::table('users')->insertOrIgnore([
['id' => 1, 'email' => 'sisko@example.com'],
['id' => 2, 'email' => 'archer@example.com'],
]);
52. findMany メソッド
複数のIDに一致するレコードを一度に取得できます。
<?php
$users = User::findMany([1, 2, 3]);
53. モデルが前回取得時から変更されたか確認する
isDirty()
を使って、特定の属性が変更されたかどうか確認できます。
<?php
$user = User::create([
'first_name' => 'John',
'last_name' => 'Doe',
'age' => 20,
]);
$user->age = 21;
$user->isDirty(); // true
$user->isDirty('age'); // true
$user->isDirty('first_name'); // false
54. タイムスタンプカラムのカスタマイズ
既存テーブルに合わせて、デフォルトのタイムスタンプカラム名を変更できます。
<?php
class Flight extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}
55. 塗りつぶし不可属性への値割り当ての防止
preventSilentlyDiscardingAttributes()
を利用して、fillable に含まれない属性の割り当て時に例外を発生させられます。
<?php
use Illuminate\Database\Eloquent\Model;
Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
56. updateOrCreate メソッド
指定条件に一致するレコードがあれば更新し、なければ新規作成できます。
<?php
$flight = Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);
57. destroy メソッドでレコード削除
主キーを指定して、簡単にレコードを削除できます。複数のIDにも対応。
<?php
Flight::destroy(1);
Flight::destroy(1, 2, 3);
Flight::destroy([1, 2, 3]);
58. withCasts メソッドで実行時にキャスト
クエリ実行時にキャストを動的に適用できます。
<?php
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->withCasts([
'last_posted_at' => 'datetime'
])->get();
59. valueOrFail メソッド
レコードが存在しない場合に例外を投げながら、単一のカラム値を取得できます。
<?php
$flightName = Flight::where('legs', '>', 3)->valueOrFail('name');
60. firstWhere メソッド
指定した条件に一致する最初のレコードを取得する簡潔な方法です。
<?php
$user = User::query()->firstWhere('name', 'john');
61. N+1 問題の防止
eager loading を徹底させるため、開発時に lazy loading を禁止する設定が可能です。
<?php
use Illuminate\Database\Eloquent\Model;
Model::preventLazyLoading(! $this->app->isProduction());
Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) {
info("Attempted to lazy load [{$relation}] on model [".get_class($model)."].");
});
62. JSON の妥当性チェック
Str::isJson()
を使って、文字列が有効な JSON かどうか確認できます。
<?php
use Illuminate\Support\Str;
Str::isJson('[1,2,3]'); // true
Str::isJson('{"first": "John", "last": "Doe"}'); // true
Str::isJson('{first: "John", last: "Doe"}'); // false
63. 単語出現回数のカウント
substrCount()
を利用して、文中に特定の単語が何回出現するか数えられます。
<?php
use Illuminate\Support\Str;
Str::substrCount('My name is Bond, James Bond', 'Bond'); // 2
64. カラム削除のショートカット
Laravel は特定のカラム削除のためのショートカットメソッドを提供しています。
<?php
Schema::table('users', function (Blueprint $table) {
$table->dropTimestamps();
$table->dropSoftDeletes();
$table->dropRememberToken();
$table->dropMorphs('morphable');
});
65. 非表示カラム(Invisible Columns)
MySQL/MariaDB で、SELECT * で自動的に取得されないカラムを作成できます。
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('secret')->nullable()->invisible();
$table->string('posts_count')->default(0)->invisible();
});
$user = User::first();
$user->secret; // null
// 明示的に選択する必要がある
$user = User::select('secret')->first();
66. 生成カラム(Generated Columns)
マイグレーションで、計算結果を自動生成するカラムを定義できます。
<?php
return new class extends Migration
{
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->decimal('unit_price');
$table->integer('quantity');
$table->decimal('full_price')->storedAs('unit_price * quantity');
});
}
};
67. シーディング時のモデルイベント無効化
シーディング処理中はモデルイベントを発火させず、処理速度を向上させることができます。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
class DatabaseSeeder extends Seeder
{
use WithoutModelEvents;
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
}
68. デフォルトモデルの利用
リレーションが null の場合でも、withDefault() を使えばデフォルトのモデルを返せます。
<?php
public function user(): BelongsTo
{
return $this->belongsTo(User::class)->withDefault([
'name' => 'Guest Author',
]);
}
// 以降は $post->user->name が常に値を返す
69. ソフトデリート済みモデルの完全削除
forceDelete()
または Laravel 11.21 以降は forceDestroy()
で、ソフトデリート済みのレコードを完全に削除できます。
<?php
// Laravel < v11.20
$flight = Flight::find(1);
$flight->forceDelete();
// Laravel v11.21 以降
Flight::forceDestroy(1);
70. ゴミ箱のレコードのみ取得(onlyTrashed)
ソフトデリートされたレコードだけを取得できます。
<?php
$trashedUsers = User::query()->onlyTrashed()->get();
71. 複数カラムをまとめて追加(Add Multiple Columns After Another)
既存カラムの後ろに複数カラムを追加する際に、after() を使えます。
<?php
Schema::table('users', function (Blueprint $table) {
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
});
72. アクセサ結果のキャッシュ
計算コストの高いアクセサの場合、shouldCache()
を使って結果をキャッシュできます。
<?php
protected function hash(): Attribute
{
return Attribute::make(
get: fn (string $value) => bcrypt(gzuncompress($value)),
)->shouldCache();
}
73. whereLike メソッド
大文字小文字の区別を調整可能な LIKE クエリを簡潔に記述できます。
<?php
// 例:通常の LIKE
User::query()->whereLike('name', 'Jo%')->get();
// 大文字小文字を区別する場合
User::query()->whereLike('name', 'Jo%', caseSensitive: true)->get();
74. 複数IDと特定カラムでの find の使い方
find() に配列でIDを渡し、特定のカラムだけ取得できます。
<?php
User::find(id: [1, 2], columns: ['email']);
75. リレーションの件数を動的にロード(loadCount)
loadCount()
を使えば、取得後にリレーションの件数を追加でロードできます。
<?php
$user = User::first();
$user->loadCount('posts');
76. カラムを先頭に移動する
first()
を使うと、後から追加したカラムをテーブルの先頭に移動できます。
※大量データの場合、テーブルの再構築に時間がかかる可能性があります。
<?php
Schema::table('posts', function (Blueprint $table) {
$table->string('uuid')->first();
});
77. 最新のレコードを取得(latestOfMany)
一対多リレーションで、最新の関連レコードを簡単に取得できます。
<?php
class User extends Model
{
public function latestOrder()
{
return $this->hasOne(Order::class)->latestOfMany('created_at');
}
}
$latestOrder = $user->latestOrder;
78. クリーンなネストされた eager loading の記法
ドット記法の代わりに、配列を使ってネストしたリレーションを指定できます。
<?php
$books = Book::with([
'author' => [
'contacts',
'publisher'
]
])->get();
79. insertGetId メソッド
レコード挿入後に、新規挿入したレコードのIDを取得できます。
<?php
$id = DB::table('users')->insertGetId(
['email' => 'john@example.com', 'votes' => 0]
);
dd($id);
80. ddRawSql メソッド
SQL文とバインディング済みの状態をダンプし、デバッグを容易にします。
<?php
DB::table('users')->where('votes', '>', 100)->ddRawSql();
81. 重複クエリの回避
loadMissing()
を使えば、既にロード済みのリレーションを再取得しないようにできます。
<?php
$users->loadMissing(['comments', 'posts']);
82. 新しい CollectedBy 属性
Laravel 11.28 以降、newCollection
の代わりに CollectedBy 属性を使用してカスタムコレクションを指定できます。
<?php
use Illuminate\Database\Eloquent\Attributes\CollectedBy;
#[CollectedBy(PostCollection::class)]
class Post
{
public function newCollection(array $models = [])
{
return new PostCollection($models);
}
}
83. 集約関数
withSum
、withMax
、withAvg
、withMin
を使って、リレーションの集計結果を取得できます。
<?php
Post::withSum('comments', 'votes')->first();
Post::withMax('comments', 'votes')->first();
Post::withAvg('comments', 'votes')->first();
Post::withMin('comments', 'votes')->first();
84. toggle メソッド
多対多リレーションで、指定したIDの関連をオンオフ切り替えできます。
<?php
// 例:like 機能の切り替え
$user->likes()->toggle($tweet->id);
$user->products()->toggle([1, 2, 3]);
85. 完全なクエリログの取得
enableQueryLog()
と getRawQueryLog()
を使って、実行された全クエリとその実行時間を確認できます。
<?php
use Illuminate\Support\Facades\DB;
DB::enableQueryLog();
User::whereNotNull('email_verified_at')->get();
DB::getRawQueryLog();
86. 新しい rawColumn メソッド
生の SQL 文を直接書く代わりに、rawColumn()
を使ってカラム定義ができます。
<?php
new class extends Migration {
public function up()
{
Schema::create('table', function (Blueprint $table) {
$table->id();
$table->rawColumn('legacy_boolean', 'int(1)')->default(0);
$table->index(['id', 'legacy_boolean']);
});
}
};
87. Eloquent クエリの EXPLAIN 実行
explain()
をチェーンして、クエリの実行計画を確認できます。
<?php
User::query()
->where('email', 'john@example.com')
->explain()
->dd();
88. firstOrNew メソッド
条件に一致するレコードがなければ、インスタンスだけを生成(保存はしない)できます。
<?php
use App\Models\User;
User::firstOrCreate(['email' => 'name@example.com']);
User::firstOrNew(['email' => 'name@example.com']);
89. withWhereHas メソッド
リレーションの存在条件を絞り込んだ上で、同時に eager load できます。
<?php
User::query()
->withWhereHas('posts', fn (Builder $query) => $query->where('featured', true))
->get();
90. ピボットテーブルのカラム更新
updateExistingPivot()
を使えば、既に存在するピボットレコードのカラムを更新できます。
<?php
$user = User::first();
$roleId = Role::value('id');
$user->roles()->updateExistingPivot($roleId, [
'active' => false,
]);
91. 存在しない属性へのアクセス防止
preventAccessingMissingAttributes()
を利用して、存在しない属性へアクセスした際に例外を発生させることができます。
<?php
use Illuminate\Database\Eloquent\Model;
Model::preventAccessingMissingAttributes(! app()->isProduction());
$user = User::select('name')->first();
$user->email; // 存在しないため例外が発生
92. incrementOrCreate メソッド
レコードが存在すれば指定カラムの値をインクリメントし、存在しなければ新規作成できます。
<?php
PromoCodeUsage::incrementOrCreate(
attributes: ['code' => 'oussama-25-off'],
column: 'usage_count',
default: 1,
step: 1,
extra: ['last_used_at' => now()]
);
93. オープンな DB 接続の監視
db:monitor
コマンドを使い、オープンなデータベース接続数を監視し、閾値を超えた場合にイベントを発火できます。
<?php
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
public function boot(): void
{
Event::listen(function (DatabaseBusy $event) {
// 通知などの処理
});
}
// cron で php artisan db:monitor --databases=mysql --max=100 を実行
元記事
Discussion