Laravel Eloquent
Laravel EloquentはLaravelフレームワークのActive Record実装ORMです。エレガントで流暢なAPIによりデータベース操作を直感的に記述可能で、リレーションシップ、イベント、アクセサ・ミューテータ等の豊富な機能を提供します。
GitHub概要
laravel/framework
The Laravel Framework.
スター33,844
ウォッチ958
フォーク11,444
作成日:2013年1月10日
言語:PHP
ライセンス:MIT License
トピックス
frameworklaravelphp
スター履歴
データ取得日時: 2025/7/19 09:31
ライブラリ
Laravel Eloquent
概要
Laravel EloquentはLaravelフレームワークのActive Record実装ORMです。エレガントで流暢なAPIによりデータベース操作を直感的に記述可能で、リレーションシップ、イベント、アクセサ・ミューテータ等の豊富な機能を提供します。
詳細
Eloquent ORMは、データベース操作を美しく表現力豊かなPHPコードで記述できるように設計されています。Active Recordパターンを採用し、各データベーステーブルに対応するモデルクラスを通じてCRUD操作を実行します。Laravelエコシステムとの深い統合により、マイグレーション、ファクトリー、シーダーなどの関連機能と連携し、効率的なWeb開発を支援します。
主な特徴
- 流暢なAPI: 直感的で読みやすいメソッドチェーン
- リレーションシップ: 豊富なリレーション定義機能
- Eloquentコレクション: 強力なデータ操作メソッド
- イベント: モデルライフサイクルでのフック機能
- キャスト: 自動的な型変換機能
メリット・デメリット
メリット
- PHP開発者にとって学習しやすい直感的なAPI
- Laravel エコシステムとの完全な統合
- 豊富なリレーションシップ機能により複雑なデータ構造も簡潔に表現
- アクセサ・ミューテータによる柔軟なデータ変換
- 中小規模プロジェクトでの高い開発生産性
デメリット
- 大規模システムでのパフォーマンス課題
- Active Recordパターンによるビジネスロジックとデータアクセスの密結合
- 複雑なクエリの表現に制限がある場合がある
- Laravel フレームワーク依存のため他のフレームワークでは使用困難
参考ページ
書き方の例
インストールと基本セットアップ
# Laravel プロジェクト作成
composer create-project laravel/laravel myproject
cd myproject
# データベース設定
php artisan make:migration create_users_table
php artisan make:migration create_posts_table
// .env ファイル
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_app
DB_USERNAME=root
DB_PASSWORD=
// config/database.php(必要に応じて調整)
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'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', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
],
基本的なCRUD操作(モデル定義、作成、読み取り、更新、削除)
// app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Model
{
use HasFactory;
protected $fillable = [
'name',
'email',
'email_verified_at',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
// リレーションシップ
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
// app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'content',
'user_id',
'published_at',
];
protected $casts = [
'published_at' => 'datetime',
];
// リレーションシップ
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
// マイグレーション実行
// php artisan migrate
// 基本的なCRUD操作
use App\Models\User;
use App\Models\Post;
// 作成
$user = User::create([
'name' => '田中太郎',
'email' => '[email protected]',
'password' => bcrypt('password123'),
]);
// 読み取り
$allUsers = User::all();
$userById = User::find(1);
$userByEmail = User::where('email', '[email protected]')->first();
// 更新
$user = User::find(1);
$user->name = '田中次郎';
$user->save();
// 一括更新
User::where('name', 'like', '%田中%')->update(['status' => 'active']);
// 削除
$user = User::find(1);
$user->delete();
// 一括削除
User::where('status', 'inactive')->delete();
高度なクエリとリレーションシップ
// 複雑な条件クエリ
$activeUsers = User::where('status', 'active')
->where('created_at', '>=', now()->subDays(30))
->where('email', 'like', '%@company.com')
->orderBy('created_at', 'desc')
->limit(10)
->get();
// リレーションシップクエリ
$usersWithPosts = User::with('posts')->get();
$usersWithRecentPosts = User::with(['posts' => function ($query) {
$query->where('created_at', '>=', now()->subDays(7))
->orderBy('created_at', 'desc');
}])->get();
// 条件付きリレーション読み込み
$users = User::when(request('include_posts'), function ($query) {
return $query->with('posts');
})->get();
// 集約クエリ
$userStats = User::selectRaw('
COUNT(*) as total_users,
AVG(posts_count) as avg_posts_per_user,
MAX(created_at) as latest_user_date
')
->withCount('posts')
->first();
// サブクエリ
$activeUsers = User::whereHas('posts', function ($query) {
$query->where('published_at', '>=', now()->subDays(30));
})->get();
// 結合クエリ
$postsWithAuthors = Post::join('users', 'posts.user_id', '=', 'users.id')
->select('posts.*', 'users.name as author_name')
->where('posts.published_at', '>=', now()->subDays(7))
->get();
// スコープクエリ
class User extends Model
{
public function scopeActive($query)
{
return $query->where('status', 'active');
}
public function scopeWithRecentPosts($query, $days = 30)
{
return $query->whereHas('posts', function ($q) use ($days) {
$q->where('created_at', '>=', now()->subDays($days));
});
}
}
// スコープ使用例
$activeUsersWithRecentPosts = User::active()
->withRecentPosts(7)
->get();
マイグレーションとスキーマ管理
# マイグレーション作成
php artisan make:migration create_users_table
php artisan make:migration add_status_to_users_table
# マイグレーション実行
php artisan migrate
# マイグレーション巻き戻し
php artisan migrate:rollback
php artisan migrate:rollback --step=3
# マイグレーション状態確認
php artisan migrate:status
// database/migrations/xxxx_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->enum('status', ['active', 'inactive'])->default('active');
$table->rememberToken();
$table->timestamps();
$table->index(['status', 'created_at']);
$table->index('email');
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};
// database/migrations/xxxx_create_posts_table.php
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamp('published_at')->nullable();
$table->timestamps();
$table->index(['user_id', 'published_at']);
$table->index('published_at');
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
パフォーマンス最適化と高度な機能
// トランザクション
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$user = User::create([
'name' => '山田花子',
'email' => '[email protected]',
'password' => bcrypt('password123'),
]);
Post::create([
'title' => '最初の投稿',
'content' => 'Laravel Eloquentを使った投稿です',
'user_id' => $user->id,
'published_at' => now(),
]);
});
// バッチ操作
$userData = [
['name' => 'ユーザー1', 'email' => '[email protected]', 'password' => bcrypt('password')],
['name' => 'ユーザー2', 'email' => '[email protected]', 'password' => bcrypt('password')],
['name' => 'ユーザー3', 'email' => '[email protected]', 'password' => bcrypt('password')],
];
User::insert($userData);
// バッチ更新(Laravel 8+)
User::whereIn('id', [1, 2, 3])->update(['status' => 'verified']);
// チャンク処理(大量データ)
User::chunk(100, function ($users) {
foreach ($users as $user) {
// 処理ロジック
$user->process();
}
});
// イーガーローディングでN+1問題を回避
$posts = Post::with('user')->get();
// 遅延イーガーローディング
$posts = Post::all();
$posts->load('user');
// カスタムキャスト
class User extends Model
{
protected $casts = [
'preferences' => 'array',
'last_login_at' => 'datetime',
'is_admin' => 'boolean',
];
}
// アクセサとミューテータ
class User extends Model
{
// アクセサ
public function getFullNameAttribute(): string
{
return $this->first_name . ' ' . $this->last_name;
}
// ミューテータ
public function setPasswordAttribute($value): void
{
$this->attributes['password'] = bcrypt($value);
}
}
// モデルイベント
class User extends Model
{
protected static function boot()
{
parent::boot();
static::creating(function ($user) {
$user->uuid = Str::uuid();
});
static::created(function ($user) {
// ユーザー作成後の処理
Mail::to($user)->send(new WelcomeEmail());
});
}
}
// クエリビルダー最適化
$users = User::select(['id', 'name', 'email'])
->where('status', 'active')
->orderBy('created_at', 'desc')
->paginate(15);
フレームワーク統合と実用例
// API リソースコントローラー
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class UserController extends Controller
{
public function index(): JsonResponse
{
$users = User::with('posts')
->paginate(15);
return response()->json($users);
}
public function show(User $user): JsonResponse
{
$user->load('posts');
return response()->json($user);
}
public function store(Request $request): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8',
]);
$user = User::create($validated);
return response()->json($user, 201);
}
public function update(Request $request, User $user): JsonResponse
{
$validated = $request->validate([
'name' => 'sometimes|string|max:255',
'email' => 'sometimes|email|unique:users,email,' . $user->id,
]);
$user->update($validated);
return response()->json($user);
}
public function destroy(User $user): JsonResponse
{
$user->delete();
return response()->json(['message' => 'User deleted successfully']);
}
}
// ジョブキューとの統合
<?php
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessUserData implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
private User $user
) {}
public function handle(): void
{
// 重い処理をバックグラウンドで実行
$this->user->update([
'processed_at' => now(),
'status' => 'processed',
]);
}
}
// ジョブディスパッチ
ProcessUserData::dispatch($user);
// ファクトリーとシーダー
// database/factories/UserFactory.php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('password'),
'remember_token' => Str::random(10),
];
}
}
// database/seeders/UserSeeder.php
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
public function run(): void
{
User::factory()
->count(50)
->hasPosts(3)
->create();
}
}
// Bladeテンプレートでの使用
{{-- resources/views/users/index.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<h1>ユーザー一覧</h1>
@foreach ($users as $user)
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">{{ $user->name }}</h5>
<p class="card-text">{{ $user->email }}</p>
<p class="card-text">
<small class="text-muted">
投稿数: {{ $user->posts_count }}
</small>
</p>
</div>
</div>
@endforeach
{{ $users->links() }}
</div>
@endsection
// コントローラー
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index()
{
$users = User::withCount('posts')
->paginate(10);
return view('users.index', compact('users'));
}
}