Eloquent в Laravel 11: создаём, читаем и обновляем записи
Пошаговый гайд по базовым операциям Eloquent для тех, кто только начал работать с Laravel: как создать модель, вставить строку, прочитать её обратно и обновить без лишнего SQL.

За полчаса вы научитесь работать с базой через Eloquent — ORM, встроенную в Laravel: создадите модель, вставите первую запись, прочитаете её по условию и обновите поле. Всё это без единой строки сырого SQL. Примеры даны для Laravel 11.x и PHP 8.2+, база — MySQL или PostgreSQL, разницы для этих операций почти нет.
Что нужно иметь до начала
Проверьте, что у вас уже есть, прежде чем копировать код. Иначе споткнётесь на первом же шаге.
- Установленный проект Laravel 11 (проверить:
php artisan --versionдолжно показатьLaravel Framework 11.x). - Настроенное подключение к базе в файле
.env: заполненыDB_CONNECTION,DB_HOST,DB_DATABASE,DB_USERNAME,DB_PASSWORD. - Созданная база данных на сервере (Eloquent таблицы создаёт, а базу — нет).
- Доступ к терминалу в корне проекта, где лежит файл
artisan.
Дальше работаем с таблицей articles — статьи блога с полями заголовка и текста.
Шаг 1. Создаём модель и миграцию
Модель — это PHP-класс, через который вы обращаетесь к таблице. Флаг -m заодно создаёт миграцию — файл с описанием структуры таблицы.
php artisan make:model Article -m
Команда создаст два файла: app/Models/Article.php и миграцию в database/migrations/ с именем вроде 2024_01_01_000000_create_articles_table.php. По умолчанию Eloquent свяжет модель Article с таблицей articles — множественное число в нижнем регистре.
Проверка: оба файла появились, терминал вывел строки INFO Model [app/Models/Article.php] created и INFO Migration ... created.
Шаг 2. Описываем поля таблицы
Откройте свежую миграцию и добавьте колонки в метод up:
<?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('articles', function (Blueprint $table) {
$table->id();
$table->string('title'); // заголовок
$table->text('body'); // текст статьи
$table->boolean('published')->default(false);
$table->timestamps(); // created_at и updated_at
});
}
public function down(): void
{
Schema::dropIfExists('articles');
}
};
Метод timestamps() добавляет два поля, которые Eloquent заполняет и обновляет сам — это пригодится позже.
Применяем миграцию:
php artisan migrate
Проверка: в терминале появится строка DONE напротив имени миграции. В базе появится таблица articles с шестью колонками.
Шаг 3. Разрешаем массовое заполнение
Eloquent по умолчанию защищает от массового присвоения: если вы передаёте в модель массив полей, нужно явно перечислить, какие поля разрешено заполнять. Иначе получите исключение. Откройте app/Models/Article.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
// поля, которые можно заполнять массово
protected $fillable = [
'title',
'body',
'published',
];
}
Без свойства $fillable следующий шаг упадёт с ошибкой MassAssignmentException. Это не баг, а защита от того, чтобы через форму нельзя было записать поле, которое вы не ждали.
Шаг 4. Создаём запись (Create)
Есть два способа. Первый — через статический метод create, он вставляет строку сразу:
use App\Models\Article;
$article = Article::create([
'title' => 'Первая запись',
'body' => 'Текст моей первой статьи через Eloquent.',
'published' => true,
]);
// в $article->id уже лежит ID новой строки
Второй способ — создать объект, задать поля вручную и сохранить. Он удобен, когда значения приходят по частям:
$article = new Article();
$article->title = 'Вторая запись';
$article->body = 'Собираю поля по одному, потом сохраняю.';
$article->save();
Разница: create() требует $fillable, потому что принимает массив; при ручном присвоении через ->title = ... защита массового заполнения не срабатывает.
Проверка: в таблице articles появились строки, поля created_at и updated_at заполнены текущим временем автоматически.
Пока вы пишетеcreate()с ручным массивом в контроллере — держите$fillableв порядке. В реальном коде массив чаще приходит из$request->validated(), и тогда защита от массового присвоения — ваш единственный барьер между формой и таблицей.
Шаг 5. Читаем записи (Read)
Самое частое: достать одну запись по ID.
// вернёт модель или null, если не найдено
$article = Article::find(1);
// вернёт модель или бросит 404-исключение, если не найдено
$article = Article::findOrFail(1);
findOrFail удобен в контроллере: если записи нет, Laravel сам отдаст страницу 404, вам не нужно проверять на null.
Выборка нескольких записей с условием:
// все опубликованные, свежие сверху
$published = Article::where('published', true)
->orderBy('created_at', 'desc')
->get();
// первая подходящая запись или null
$latest = Article::where('published', true)
->latest()
->first();
// сколько всего опубликовано
$count = Article::where('published', true)->count();
Метод get() возвращает коллекцию моделей, по которой можно итерироваться в цикле foreach. Метод first() — одну модель или null. Всё, что не завершается get(), first(), find() или count(), остаётся построителем запроса и в базу ещё не ходит.
Проверка: $published->count() покажет число найденных строк; dd($published) в браузере выведет читаемую структуру коллекции.
Шаг 6. Обновляем запись (Update)
Сначала находим запись, потом меняем поля и сохраняем:
$article = Article::findOrFail(1);
$article->title = 'Обновлённый заголовок';
$article->save(); // UPDATE только изменённых полей
Eloquent отслеживает, какие поля вы поменяли, и в SQL уйдёт UPDATE только по ним. Поле updated_at при этом обновится само.
Обновить сразу несколько полей массивом — метод update(), он тоже уважает $fillable:
$article = Article::findOrFail(1);
$article->update([
'title' => 'Новый заголовок',
'published' => false,
]);
Массовое обновление без предварительной загрузки моделей — когда нужно поменять много строк за один запрос:
// снять публикацию со всех старых черновиков
Article::where('published', false)
->update(['published' => false]);
Осторожно: массовый update() на построителе не трогает updated_at так же аккуратно и не запускает события модели — он идёт прямым SQL. Для точечных изменений с событиями загружайте модель через find().
Проверка: перечитайте запись через Article::find(1) и посмотрите новые значения; поле updated_at изменилось при варианте с save().
Если не получилось
SQLSTATE[HY000] [1049] Unknown database— базы с указанным именем нет. Создайте её вручную или проверьтеDB_DATABASEв.env. После правки.envвыполнитеphp artisan config:clear.Add [title] to fillable property to allow mass assignment— вы вызвалиcreate()илиupdate()с массивом, но не перечислили поле в$fillable. Добавьте его в модель (Шаг 3).Base table or view not found: 1146 Table ... doesn't exist— миграция не применена. Запуститеphp artisan migrate, а если правили уже применённую миграцию —php artisan migrate:fresh(сотрёт данные).Class "App\Models\Article" not found— забылиuse App\Models\Article;в начале файла или опечатка в неймспейсе.- Метод вернул
null, а запись есть — вы ищете по несуществующему ID или условие вwhere()не совпадает по типу (например, ищете строку'1'там, где булево значение).
Что делать дальше
Базовый CRUD освоен — delete() для удаления работает по той же логике: Article::findOrFail(1)->delete(). Дальше стоит посмотреть на связи между таблицами (hasMany, belongsTo) — это то, ради чего Eloquent и придуман. Отдельная большая тема — фабрики и сидеры для наполнения базы тестовыми данными через php artisan make:factory. Когда дойдёте до вывода списков на страницу — изучите пагинацию через paginate() вместо get(), чтобы не грузить тысячу строк разом. Точный набор методов сверяйте с документацией вашей минорной версии: между 10.x и 11.x поведение базового CRUD не менялось, но мелочи в билдере запросов иногда уточняют.
IT-архитектор / SQL-оптимизатор: Поиск N+1, оптимизация запросов, code review, поиск багов.
Спросить за 20 ₽Источники: Laravel 11.x — Eloquent: Getting Started, Laravel 11.x — Database: Migrations
Частые вопросы
У меня Laravel 10, а не 11 — код сработает?
Чем create() отличается от save()?
Почему падает MassAssignmentException, хотя код правильный?
Обновил модель через save(), но updated_at не изменился — почему?
find() возвращает null, хотя запись в таблице точно есть — что не так?
Как удалить запись после того, как научился создавать и обновлять?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.