База данных в Laravel: Eloquent, Query Builder и продвинутые техники

Раздел: Laravel -> Базы данных в Laravel

Основы взаимодействия с БД в 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 только с датой.

База данных в Laravel PHP - comments

En
Laravel database php (php)