Модели в Yii 2: первые шаги для новичка
За полчаса вы создадите модель ActiveRecord, свяжете её с таблицей, добавите правила валидации и сохраните первую запись в базу через веб-форму на Yii 2.

К концу этого гайда у вас будет рабочая модель, привязанная к таблице в базе, с валидацией полей и формой, которая сохраняет данные. На всё уйдёт 30–40 минут, если база уже подключена. Пишем под Yii 2.0.49+ и PHP 8.1 — команды и синтаксис одинаковы для всей ветки 2.0.x.
Что нужно иметь до начала
Проверьте это заранее — иначе застрянете на середине.
- Установленный проект на Yii 2 (Basic или Advanced template) через Composer;
- работающее подключение к базе — в
config/db.phpпрописаныdsn,username,password, иyii migrateотрабатывает без ошибок; - доступ к консоли: команду генератора мы запускаем через
./yiiв корне проекта; - таблица в базе, для которой создаём модель. Если её нет — сделаем миграцией на первом шаге.
Если ./yii не запускается с ошибкой прав, выполните chmod +x yii в корне проекта.
Что такое модель в Yii
В Yii модель — это класс, который отвечает за данные и их проверку. Есть два вида. yii\base\Model — базовая модель без привязки к базе, годится для форм поиска или логина. yii\db\ActiveRecord — модель, которая соответствует одной строке таблицы: одна запись в базе равна одному объекту в коде. Мы работаем со вторым видом, потому что новичку чаще нужно именно хранить данные.
ActiveRecord — паттерн, при котором объект класса напрямую отражает строку таблицы: свойства объекта — это колонки, а методы вроде save() и delete() сразу пишут в базу. В Yii его реализует класс yii\db\ActiveRecord.
Шаг 1. Создаём таблицу миграцией
Пусть модель хранит статьи блога. Сначала таблица. Создаём миграцию:
./yii migrate/create create_article_table
Откройте созданный файл в migrations/ и приведите метод safeUp() к такому виду:
<?php
use yii\db\Migration;
class m240101_000000_create_article_table extends Migration
{
public function safeUp()
{
$this->createTable('{{%article}}', [
'id' => $this->primaryKey(),
'title' => $this->string(255)->notNull(),
'body' => $this->text(),
'status' => $this->smallInteger()->defaultValue(0),
'created_at' => $this->integer(),
]);
}
public function safeDown()
{
$this->dropTable('{{%article}}');
}
}
Применяем:
./yii migrate
Проверка: в консоли появится строка *** applied m240101_... и Migrated up successfully. В базе появится таблица article (с префиксом, если он задан в конфиге).
Шаг 2. Генерируем модель через Gii
Gii — встроенный генератор кода. В Basic-шаблоне он доступен по адресу http://ваш-сайт/index.php?r=gii только с локального адреса (127.0.0.1). Откройте его, выберите Model Generator.
Заполните поля:
| Поле | Значение |
|---|---|
| Table Name | article |
| Model Class | Article |
| Namespace | app\models |
| Base Class | yii\db\ActiveRecord |
Нажмите Preview, затем Generate. Gii создаст файл models/Article.php.
Проверка: файл появился в models/, внутри есть метод tableName(), возвращающий '{{%article}}', и метод rules() с уже сгенерированными правилами на основе типов колонок.
Шаг 3. Смотрим, что сгенерировалось
Открытый Article.php будет содержать примерно это:
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
class Article extends ActiveRecord
{
public static function tableName()
{
return '{{%article}}';
}
public function rules()
{
return [
[['title'], 'required'],
[['body'], 'string'],
[['status', 'created_at'], 'integer'],
[['title'], 'string', 'max' => 255],
];
}
public function attributeLabels()
{
return [
'id' => 'ID',
'title' => 'Заголовок',
'body' => 'Текст',
'status' => 'Статус',
'created_at' => 'Создано',
];
}
}
rules() — это правила валидации: что title обязателен и не длиннее 255 символов, что status — целое число. Gii выводит их из структуры таблицы, но дальше вы правите их руками под свою логику.
Шаг 4. Сохраняем первую запись
Проверим модель прямо из контроллера. Добавьте временный экшен в любой контроллер, например controllers/SiteController.php:
public function actionTestCreate()
{
$article = new \app\models\Article();
$article->title = 'Первая статья';
$article->body = 'Тело статьи';
$article->created_at = time();
// save() сначала прогоняет валидацию, потом пишет в базу
if ($article->save()) {
return 'Сохранено, id=' . $article->id;
}
// если валидация не прошла — покажем ошибки
return print_r($article->getErrors(), true);
}
Откройте index.php?r=site/test-create.
Проверка: в браузере появится строка вида Сохранено, id=1. В таблице article добавилась запись. Удалите этот экшен после проверки — он был только для теста.
Шаг 5. Правила валидации под себя
Gii даёт базовые правила, но настоящую проверку задаёте вы. Допустим, status должен быть только 0 или 1, а title — не короче трёх символов. Правьте rules() руками:
public function rules()
{
return [
[['title'], 'required'],
[['title'], 'string', 'min' => 3, 'max' => 255],
[['body'], 'string'],
[['status'], 'in', 'range' => [0, 1]],
[['created_at'], 'integer'],
];
}
Теперь при попытке сохранить title из одного символа save() вернёт false, а getErrors() покажет причину. Валидация в Yii не срабатывает сама по себе при присвоении свойства — она запускается в момент save() или явного вызова validate().
Главное правило первых шагов:save()без проверки результата — источник тихих багов. Всегда смотрите, что вернул метод, и вызывайтеgetErrors(), если вернулсяfalse.
Шаг 6. Читаем данные обратно
Модель ActiveRecord умеет и доставать записи. Пара базовых запросов:
// одна запись по первичному ключу
$article = \app\models\Article::findOne(1);
// все опубликованные статьи (status = 1)
$published = \app\models\Article::find()
->where(['status' => 1])
->orderBy(['created_at' => SORT_DESC])
->all();
findOne() вернёт объект Article или null. find()->all() вернёт массив объектов. Дальше обращаетесь к полям через $article->title.
Если не получилось
Table 'article' doesn't exist— миграция не применилась или в базе другой префикс таблиц. Проверьте./yii migrate/historyи настройкуtablePrefixвconfig/db.php.- Gii отдаёт
Forbidden (#403)— вы открываете его не с 127.0.0.1. По умолчанию Gii разрешён только для локальных адресов. НастройкаallowedIPsживёт в секцииmodules -> giiфайлаconfig/web.php— не открывайте его на боевом сервере. save()возвращаетfalse, а базы не касается — не прошла валидация. Выведите$article->getErrors(): там будет поле и текст проблемы.Class 'app\models\Article' not found— не совпал namespace или имя файла. Файл должен лежать вmodels/Article.phpс объявлениемnamespace app\models;.SQLSTATE[HY000] ... Field 'title' doesn't have a default value— вы пишете напрямую в базу мимо валидации либо колонка обязательна, а значение не задано. Убедитесь, что присваиваетеtitleдоsave().
Что делать дальше
Модель у вас есть. Следующие логичные шаги: связать модели между собой через hasOne() и hasMany() (например, статья и её автор), автоматически проставлять created_at через TimestampBehavior вместо ручного time(), а форму создания сгенерировать через CRUD Generator в том же Gii. Про поведения (behaviors) и связи читайте в разделе Active Record официального гайда — там показано, как убрать ручную возню, которую мы делали для наглядности.
Защитник прав потребителей: Досудебные претензии на возврат товара со ссылками на ЗоЗПП.
Спросить за 15 ₽Источники: Yii 2.0 Guide — Active Record, Yii 2.0 Guide — Creating Models
Частые вопросы
А если у меня Yii 2.0.15, а не свежая версия?
Обязательно ли генерировать модель через Gii?
Почему save() вернул true, но в базе ничего нет?
Чем Model отличается от ActiveRecord и что выбрать новичку?
Где на боевом сервере опасность с Gii?
Как проставлять created_at автоматически, без time() в коде?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.