да, туплю, простите!
через метод transactions() получается совершенно непредсказуемая хрень в худших кетайских традициях с гарантией выстрела в ногу, ибо о поддержке вложенных транзакций речи нет, тем более во всех БД.
Если мы сделаем транзакцию в модели - через некоторое время надо будет вызвать модель в ситуации, когда транзакция уже запущена. Даже при условии, что фреймворк это отследит - получается, что модель в разном окружении ведет себя по-разному, и есть шанс ловить баги со внезапным преждевременным коммитом.
Если транзакции нужны - их надо планировать комплексно на уровне проектирования приложения в целом.
Только ручками.
http://www.yiiframework.com/doc-2.0/guide-db-dao.html#transactions
Я делаю специальный класс-обертку, который начинает транзакцию, вызывает нужные методы моделей, коммитит или откатывает по ситуации. Для каждого действия контроллера - свой метод или даже отдельный класс.