База данных в Laravel: Eloquent, Query Builder и продвинутые техники
Основы взаимодействия с БД в Laravel
Как организовать работу с таблицами в Laravel без написания сложного SQL?
Наиболее эффективным способом является использование Eloquent ORM - встроенного Active Record реализации. Каждая таблица соответствует модели, а строки - объектам модели. Пример модели User:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
}Laravel database php (база данных в laravel php)
Для получения всех пользователей:
$users = User::all();Создание записи:
$user = User::create([
'name' => 'Иван',
'email' => 'ivan@example.com',
'password' => bcrypt('secret')
]);Типичная ошибка - MassAssignmentException, если не указать $fillable или $guarded. Решение: явно разрешить массовое заполнение в модели.
Как выполнить простые SQL-запросы, когда Eloquent избыточен?
Используйте Query Builder - фасад DB. Пример выборки с условием:
$users = DB::table('users')->where('active', 1)->get();Вставка:
DB::table('users')->insert([
'name' => 'Петр',
'email' => 'petr@example.com'
]);Ошибка: забыли экранировать параметры - использовать whereRaw без биндов может привести к SQL-инъекции. Всегда передавайте массив значений:
DB::select('SELECT * FROM users WHERE id = ?', [$id]);Как выполнить сложный запрос с объединением таблиц?
Query Builder поддерживает join:
$posts = DB::table('posts')
->join('users', 'posts.user_id', '=', 'users.id')
->select('posts.*', 'users.name as author')
->get();Альтернатива в Eloquent - через отношения:
$posts = Post::with('user')->get();Как управлять структурой БД без потери данных?
Миграции - версионирование схемы. Создание таблицы:
php artisan make:migration create_posts_tableВнутри файла:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->foreignId('user_id')->constrained();
$table->timestamps();
});Ошибка: попытка создать уже существующую таблицу - используйте Schema::hasTable() или флаг --create. Откат миграции: php artisan migrate:rollback.
Как наполнить базу тестовыми данными?
Сиды (Seeders) и фабрики (Factories). Пример фабрики для User:
php artisan make:factory UserFactory --model=UserФайл:
public function definition() {
return [
'name' => fake()->name(),
'email' => fake()->safeEmail(),
'password' => bcrypt('password'),
];
}Выполнение:
php artisan db:seed --class=UserSeederКак организовать связи между таблицами?
Eloquent отношения: hasOne, hasMany, belongsTo. Пример модели Post с отношением к User:
class Post extends Model {
public function user() {
return $this->belongsTo(User::class);
}
}
// Использование:
$commentAuthor = Post::find(1)->user->name;Проблема N+1 запроса - решается жадной загрузкой (with):
$posts = Post::with('user')->get();Как выполнить транзакционные операции?
Для гарантии целостности:
DB::transaction(function () {
$user = User::create([...]);
$post = Post::create(['user_id' => $user->id, ...]);
});Или через DB::beginTransaction() / commit() / rollBack() для большего контроля.
Как оптимизировать работу с большими наборами данных?
Используйте чанки (chunks) или курсоры:
User::chunk(100, function ($users) {
foreach ($users as $user) {
// Обработка 100 записей за раз
}
});Курсор для итерации по миллионам:
foreach (User::cursor() as $user) {
// низкое потребление памяти
}Ошибка: использование all() на огромных таблицах - приводит к нехватке памяти. Всегда применяйте пагинацию или чанки.
Расширенные примеры работы с базой данных
Как выполнить сырой SQL запрос с параметрами и получить результат в виде коллекции?
$users = DB::select('SELECT * FROM users WHERE age > ? AND status = ?', [18, 'active']);
// Результат - массив stdClass объектов
foreach ($users as $user) {
echo $user->name;
}Результат вывода (если есть пользователи):
Анна Иван
Как создать отношение многие-ко-многим с дополнительными полями в pivot-таблице?
// В модели User
public function roles() {
return $this->belongsToMany(Role::class)->withPivot('expires_at')->withTimestamps();
}
// Запись с дополнительным полем
$user->roles()->attach($roleId, ['expires_at' => now()->addYear()]);
// Чтение pivot-данных
foreach ($user->roles as $role) {
echo $role->pivot->expires_at;
}Вывод:
2026-01-15 12:00:00
Как использовать глобальные scope для фильтрации запросов?
// Scope в модели Post
protected static function booted() {
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('status', 'published');
});
}
// Использование без явной фильтрации
$posts = Post::all(); // только опубликованныеРезультат - коллекция только опубликованных постов.
Как выполнить кастомную агрегацию с группировкой?
$stats = DB::table('orders')
->select('product_id', DB::raw('COUNT(*) as total_sold'), DB::raw('SUM(amount) as total_revenue'))
->groupBy('product_id')
->having('total_sold', '>', 10)
->get();Результат:
[{"product_id": 3, "total_sold": 25, "total_revenue": 1250.00}]Как использовать подзапросы в WHERE?
$latestPosts = Post::whereIn('user_id', function ($query) {
$query->select('id')
->from('users')
->where('active', 1);
})->get();Вариант через Eloquent:
$latestPosts = Post::whereHas('user', function ($q) {
$q->where('active', 1);
})->get();Эквивалентный SQL:
SELECT * FROM posts WHERE user_id IN (SELECT id FROM users WHERE active = 1)
Как обновить связанные записи в транзакции с обработкой ошибок?
try {
DB::beginTransaction();
$order = Order::find($orderId);
$order->status = 'completed';
$order->save();
// Уменьшение количества товаров на складе
foreach ($order->items as $item) {
$product = Product::find($item->product_id);
$product->stock -= $item->quantity;
$product->save();
}
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
Log::error('Order processing failed: ' . $e->getMessage());
}Как использовать мутаторы и аксессоры для преобразования данных?
// В модели User
public function setPasswordAttribute($value) {
$this->attributes['password'] = bcrypt($value);
}
public function getFullNameAttribute() {
return $this->first_name . ' ' . $this->last_name;
}
// Использование
$user->password = 'plaintext'; // автоматически хешируется
echo $user->full_name; // аксессорКак выполнить поиск по json полю в PostgreSQL?
$users = User::where('attributes->age', '>', 18)
->where('attributes->city', 'Москва')
->get();SQL эквивалент:
SELECT * FROM users WHERE attributes->>'city' = 'Москва' AND (attributes->>'age')::int > 18
Как использовать сырые выражения в select для оптимизации?
$users = DB::table('users')
->selectRaw('name, email, DATE(created_at) as signup_date')
->get();Каждый элемент будет содержать поле signup_date только с датой.