Eloquent ORM: модели и базовые запросы

Eloquent — это ORM Laravel, который превращает строки таблиц в PHP-объекты, позволяя работать с базой без единой строки SQL.

Суть: каждой таблице соответствует класс-модель. Через методы вроде User::all(), User::find(1), User::where(...) вы достаёте и сохраняете данные как обычные объекты.

Писать SQL вручную утомительно и опасно: легко ошибиться в синтаксисе или открыть дыру для инъекций. Eloquent (это ORM — Object-Relational Mapping) убирает эту боль. Он связывает таблицу базы с PHP-классом: таблица products — это модель Product, каждая строка — экземпляр объекта, каждая колонка — свойство. Вы работаете с данными как с обычными объектами, а Eloquent сам генерирует безопасный SQL.

Eloquent опирается на соглашения. Модель Product по умолчанию работает с таблицей products (множественное число, нижний регистр). Первичный ключ — id. Поля created_at и updated_at ведутся автоматически. Если следовать этим правилам, код становится минимальным.

Создание модели и запросы

# создать модель (с миграцией через -m)
php artisan make:model Product -m
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    // какие поля можно массово заполнять
    protected $fillable = ['name', 'price', 'is_active'];

    // приведение типов (Laravel 11 — метод casts)
    protected function casts(): array
    {
        return [
            'is_active' => 'boolean',
            'price'     => 'decimal:2',
        ];
    }
}
<?php
// чтение
$all   = Product::all();                 // все товары
$one   = Product::find(1);               // по первичному ключу
$first = Product::where('is_active', true)->first();
$cheap = Product::where('price', '<', 1000)->get();

// создание
$product = Product::create([
    'name'  => 'Клавиатура',
    'price' => 2500,
]);

// обновление
$product->price = 2300;
$product->save();

// удаление
$product->delete();

Как работает под капотом

Каждый метод Eloquent под капотом строит SQL. Product::find(1) превращается в SELECT * FROM products WHERE id = 1 LIMIT 1, а результат «оборачивается» в объект модели. Цепочка where()->get() накапливает условия и выполняет запрос только при вызове get(). Параметры всегда передаются через подготовленные выражения — поэтому SQL-инъекции невозможны.

  PHP-код Eloquent                 ->  SQL под капотом
  ----------------                     --------------
  Product::all()                   ->  SELECT * FROM products
  Product::find(1)                 ->  ... WHERE id = 1 LIMIT 1
  ->where('price','<',1000)->get() ->  ... WHERE price < 1000
  ->create([...])                  ->  INSERT INTO products ...
  $m->delete()                     ->  DELETE FROM products WHERE id=?

Смоделируем фильтрацию коллекции (аналог where()->get()) на Python — Eloquent под капотом делает то же самое, но в базе.

Попробуй сам ▶

# Аналог Product::where('price','<',1000)->get()
products = [
    {'name': 'Мышь',       'price': 800,  'active': True},
    {'name': 'Клавиатура', 'price': 2500, 'active': True},
    {'name': 'Коврик',     'price': 400,  'active': False},
]

def where(items, key, op, value):
    ops = {'<': lambda a, b: a < b, '=': lambda a, b: a == b}
    return [x for x in items if ops[op](x[key], value)]

cheap = where(products, 'price', '<', 1000)
for p in cheap:
    print(p['name'], '-', p['price'])

Частые ошибки

  • Забыть $fillable. Без него create() бросит ошибку защиты от массового присвоения.
  • Путать get() и first(). get() возвращает коллекцию, first() — одну модель (или null).
  • Сырой SQL без нужды. Конкатенация строк в запрос открывает SQL-инъекцию; пользуйтесь методами Eloquent.

Best practices

  • Описывайте приведение типов через метод casts() (новый стиль Laravel 11).
  • Используйте findOrFail(), чтобы автоматически отдавать 404 для несуществующих записей.
  • Не вытаскивайте лишнего: для больших таблиц применяйте paginate() и выборку нужных колонок.

Итог: Eloquent превращает работу с базой в работу с объектами и сам пишет безопасный SQL. Дальше разберём, как Eloquent связывает таблицы между собой через отношения.

Проверьте себя
1. С какой таблицей по умолчанию работает модель Product?
AProduct
Bproducts
Ctbl_product
Dproduct_table
2. Зачем нужно свойство $fillable в модели?
AЗадаёт имя таблицы
BРазрешает массовое заполнение указанных полей (защита от mass assignment)
CСоздаёт миграцию
DХранит пароль