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

Yii 1.1 получил последний релиз в 2015 году и с тех пор официальной поддержки не имеет — в него не приходят исправления безопасности. Проекты на нём продолжают крутиться в проде, и рано или поздно встаёт вопрос перехода на Yii 2. Плохая новость: это не обновление, а переписывание. Yii 2 — другой фреймворк с тем же именем. Ниже — где ломается больше всего и во что это обходится по времени.
Здесь разбираем именно точки поломки при миграции 1.1 → 2. Переход между минорными версиями Yii 2 (2.0.x) — отдельная тема, там ломается несоизмеримо меньше.
Почему это не «обновить composer»
Yii 1.1 и Yii 2 несовместимы на уровне ядра. Разные пространства имён, разный автозагрузчик, разный синтаксис почти всех базовых операций. Официальный путь миграции, описанный в документации Yii, — держать оба фреймворка в одном приложении и переносить код по частям, а не переключать рубильник за одну ночь.
Основные слои, которые придётся трогать:
- Пространства имён и автозагрузка. Yii 1.1 использовал префиксы классов (
CActiveRecord) и собственный импорт черезYii::import(). Yii 2 построен на PSR-4 и namespaces. Ни один класс приложения не переедет без правки. - Active Record. Синтаксис запросов, отношения, поведения, валидация — переписаны полностью.
- Виджеты и виды. API виджетов другой, хелперы формы (
CHtml) заменены наyii\helpers\Htmlс иной сигнатурой. - Конфигурация приложения. Структура
main.php, компоненты, роутинг — новый формат.
Active Record: где ломается тише всего и дороже всего
Это самый коварный слой, потому что синтаксис похож, но семантика отличается. Код может не упасть при запуске, но начать возвращать не то.
Поиск записей
В 1.1 модель искала сама себя:
// Yii 1.1
$post = Post::model()->findByPk($id);
$posts = Post::model()->findAll('status = :s', array(':s' => 1));
В Yii 2 статический метод find() возвращает объект запроса, а не результат:
// Yii 2 (2.0.x)
$post = Post::findOne($id);
$posts = Post::find()
->where(['status' => 1])
->all();
Прямая замена findAll() на find() без вызова ->all() даёт объект ActiveQuery, а не массив. Место, где на этом ловятся почти все, — циклы foreach по результату: в 1.1 итерировался массив моделей, в Yii 2 при отсутствии ->all() вы итерируете совсем не то.
Отношения
В 1.1 отношения описывались массивом в методе relations(). В Yii 2 каждое отношение — отдельный метод модели, возвращающий ActiveQuery:
// Yii 2
public function getAuthor()
{
return $this->hasOne(User::class, ['id' => 'author_id']);
}
Обращение $post->author работает через магический геттер по имени метода без префикса get. Массив relations() просто игнорируется — молча, без ошибки. Это второй по частоте источник «данные пропали, а исключения нет».
Валидация и safe-атрибуты
Правило 'safe' и понятие сценариев остались, но massive assignment работает иначе. В 1.1 атрибут заполнялся через форму, если попадал в safe-правило текущего сценария. В Yii 2 логика сценариев переработана: проверьте каждый scenarios() вручную, потому что молчаливое незаполнение поля формы — типичная поломка после переноса модели.
Хелперы и виды
Класс CHtml в Yii 2 стал yii\helpers\Html, но это не переименование. Сигнатуры методов другие. Например, генерация поля ввода для модели теперь идёт через Html::activeTextInput() или через ActiveForm, а порядок и состав аргументов не совпадают с CHtml::activeTextField(). Точные сигнатуры сверяйте в документации класса yii\helpers\Html для вашей версии 2.0.x — они дополнялись между минорными релизами.
Что почти всегда переписывается в видах:
- формы:
CActiveForm→yii\widgets\ActiveFormс блокомbegin()/end(); - ссылки:
CHtml::link()→Html::a(), маршруты теперь массивы вида['controller/action', 'id' => 5]; - вывод пользовательских данных: в Yii 2 обязательно оборачивайте в
Html::encode()— автоэкранирования нет, и перенос старого кода без этого открывает XSS.
Конфигурация и точка входа
Файл конфигурации меняет структуру целиком. Компоненты (db, user, urlManager) переезжают в секцию components с новыми именами классов. Роутинг: правила urlManager остались похожими, но формат маршрутов и enablePrettyUrl ведут себя иначе. Точка входа index.php переписывается под новый bootstrap.
Yii 2 с именем Yii 1.1 роднит только автор и общая философия. Планируя миграцию, считайте её переписыванием приложения на новом фреймворке, а не апгрейдом — тогда оценка сроков не развалится на середине.
Что где ломается: сводка
| Слой | Yii 1.1 | Yii 2 (2.0.x) | Риск |
|---|---|---|---|
| Классы ядра | Префикс C (CActiveRecord) | Namespaces yii\* | Падение сразу, видно |
| Поиск AR | model()->findAll() | find()->all() | Тихая ошибка типа |
| Отношения | Массив relations() | Методы getX() | Молча не работает |
| Хелперы форм | CHtml | yii\helpers\Html | Другая сигнатура |
| Экранирование | частично авто | ручное Html::encode() | XSS при переносе |
| Конфиг | main.php свой формат | components новый формат | Не стартует |
Стратегия перехода
Официальная документация Yii описывает совместное существование двух версий. На практике порядок такой:
- Разверните чистое приложение Yii 2 рядом со старым, на той же базе данных. Проверка:
yii serve(или обращение кweb/index.php) отдаёт стартовую страницу. - Сгенерируйте модели Active Record через Gii по существующим таблицам — так вы получите корректные namespaces и правила без ручного переписывания. Проверка:
Post::find()->count()в консоли возвращает число строк из таблицы. - Переносите по одному контроллеру с его видами, начиная с наименее связанных. После каждого — прогон реального сценария в браузере.
- Отношения и сценарии проверяйте отдельным ручным тестом на каждой модели: обращение к связанному объекту и заполнение формы. Именно здесь прячутся тихие ошибки.
Если после переноса ведёт себя странно
- «Class 'CActiveRecord' not found» — остался код, не переведённый на namespaces. Ищите классы с префиксом C.
- foreach по результату падает или пуст — забыли
->all()послеfind(). Вы итерируете объект запроса. - $model->author вернул null, хотя данные есть — отношение не переписано в метод
getAuthor(), старыйrelations()игнорируется. - поле формы не сохраняется — атрибут не попал в
rules()илиscenarios()текущего сценария. - в выводе появился HTML пользователя как разметка — потерян
Html::encode()при переносе вида.
Что делать дальше
После того как приложение полностью переехало, зафиксируйте версию Yii 2 в composer.json и включите обновление по минорным релизам 2.0.x — они совместимы между собой и приносят исправления безопасности. Смотрите в проде на два показателя: количество PHP-ошибок в логе после каждого перенесённого контроллера и разницу в данных между старой и новой выборкой по одной и той же таблице — именно она выявляет тихие ошибки Active Record, которые не видны по exception.
Аудитор договоров: Word/PDF договоры: скрытые штрафы и пени, протокол разногласий.
Спросить за 20 ₽Источники: Yii 2 Guide — Upgrading from Version 1.1, Yii 2 API — yii\helpers\Html
Частые вопросы
Можно ли обновиться с 1.1 на 2 автоматически, одной командой?
Что если у меня версия Yii 2.0.x старше, чем в примерах?
А если проект большой и переносить целиком нет ресурсов?
Почему запрос выполняется, но данные не те?
Нужно ли переписывать базу данных при миграции?
Сколько времени занимает такая миграция?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.