Настройка Eloquent ORM для Laravel веб-застосунку
Eloquent — реалізація паттерну Active Record поверх PDO з підтримкою PostgreSQL, MySQL, SQLite та SQL Server. У Laravel 10/11 він вже вбудований, але правильна конфігурація — це не просто .env. Розглядаємо весь шлях: від конфігу підключення до advanced-технік.
Конфігурація підключення
config/database.php — змінюємо тільки критичні параметри, решту з .env:
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'search_path' => 'public',
'sslmode' => env('DB_SSLMODE', 'prefer'),
]
Для production за reverse proxy встановлюємо persistent connections на false — вони конфліктують з pgBouncer.
Модель
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
class Product extends Model
{
use SoftDeletes;
protected $table = 'products';
protected $fillable = ['title', 'slug', 'price', 'status', 'category_id'];
protected $casts = [
'price' => 'decimal:2',
'meta' => 'array',
'published_at' => 'datetime',
];
public function scopePublished(Builder $query): Builder
{
return $query->where('status', 'published');
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class, 'product_tags')
->withTimestamps();
}
}
Міграції
<?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('products', function (Blueprint $table) {
$table->id();
$table->string('title', 500);
$table->string('slug', 520)->unique();
$table->foreignId('category_id')->constrained()->restrictOnDelete();
$table->decimal('price', 12, 2);
$table->string('status', 20)->default('draft');
$table->timestamps();
$table->index(['status', 'created_at']);
});
}
};
Жадна загрузка
$products = Product::query()
->published()
->with(['category', 'tags'])
->orderBy('created_at', 'desc')
->paginate(24);
Використовуємо preventLazyLoading() у локальній розробці для виявлення N+1 проблем:
if (app()->isLocal()) {
Model::preventLazyLoading();
}
Транзакції
DB::transaction(function () use ($orderId, $items) {
$order = Order::findOrFail($orderId);
$order->update(['status' => 'processing']);
foreach ($items as $item) {
Product::find($item['product_id'])
->decrement('stock', $item['quantity']);
}
});
Терміни
Настройка Eloquent для нового Laravel-проекту: 1 день. Аудит та рефакторинг існуючого проекту з N+1 проблемами: 1–2 дні.







