Декілька корисних прийомів для розробки на Yii 2
Для початку створимо просте CRUD-додаток з однією моделлю Product.

Декілька атрибутів в одній колонці гриду
Допустимо, ми хочемо об'єднати колонки «Created At» та «Updated At» в одну, для економії місця, але при цьому хочемо зберегти конфігурацію колонок і сортування за ними. Для цього треба створити окремий невеликий клас для комбінованої колонки, успадкований від звичайного DataColumn і вказати його в конфігурації.


Зробимо, щоб сортування за умовчанням було за id DESC.
Якщо робити через $dataProvider->sort->defaultOrder , то в гриді в назві колонки додається іконка сортування.
Виправлення навігації для активних пунктів меню
Додамо керування користувачами. Поставимо модуль «dektrium/yii2-user», застосуємо міграції, додамо користувача admin (з паролем 123456, як без нього), поправимо посилання в меню в «layouts/main.php». Зайдемо на сторінку "/user/login". Посилання «Login» у меню не активне.
Це тому, що модуль додає свої правила роутинга. Щоб такі посилання були активними, треба вказувати в них результуючий URL, який вийде після застосування цих правил (у даному випадку "/user/security/login"). Нам це не підходить, тому що навіщо тоді роути для красивих URL.
Зробимо клас common\components\bootstrap\Nav, успадкований від yii\bootstrap\Nav, і перевизначимо в ньому метод isItemActive(), в якому додамо пару перевірок на збіг з Yii::$app->request->getUrl() . У layouts/main.php в секції use вкажемо наш клас.
Додамо TimestampBehavior у модель Product
Поки що все працює нормально. Ми ще до цього повернемося.
Мапінг таблиць на інші назви
Зробимо додаток трохискладніше. Додамо зберігання сесій у базі даних та RBAC для управління правами доступу. Також додамо в таблицю "product" колонки "user_id" і "category_id".
Заглянемо до нашої бази даних

Щось багато у нас таблиць стало, так одразу й не зрозумієш, що звідки взялося, які до додатку належать, а які до другорядних модулів. Що якщо їх перейменувати? І бажано при цьому нічого не міняти у коді.

Для цього потрібно зробити свої класи для роботи зі з'єднанням БД та зі схемою, успадковані від стандартних, у яких перевизначити методи quoteSql() та getRawTableName(). У класі з'єднання буде нова властивість $tableMap , в якому можна задавати відповідність внутрішнього імені таблиці, що використовується в додатку, і реального, що використовується в базі даних.
Назва таблиці "__user__user" виглядає трохи дивно, можна її не перейменовувати, тут просто для наочності
Якщо конфігурація задається у файлі "config/main.php", то треба забрати з "config/main-local.php" рядок 'class' => 'yii\db\Connection' , оскільки він підключається пізніше, і цей параметр буде перевизначено. Або задавати весь конфіг у "config/main-local.php". Можливо, навіть краще, при розробці будуть зрозумілі назви, а в продакшені нормальні.
Перейменування таблиць не потрібно робити міграцією. Якщо схилювати проект із такими налаштуваннями та запустити міграції, то таблиці будуть створені вже з новими іменами. Також досить складно перейменувати в міграції саму таблицю migration. Можна потанцювати з бубном навколо копіювання таблиці та перевірки наявності її з новим ім'ям, але навряд це виправдано.
Чому TimestampBehavior оновлює властивість updated_at, якщо нічого не змінено
Це сталося, тому що ми додали"user_id" та "category_id". Ланцюжок наступний. Ми надсилаємо форму POST-запитом. Дані у ній, природно, у рядковому вигляді. На сервері викликається $model->load(Yii::$app->request->post()) . Він встановлює, наприклад, властивість user_id = "1" (string). Далі викликається $model->save() і спрацьовує TimestampBehavior (який extends AttributeBehavior ).
Значення $this->_oldAttributes[$name] завантажено з бази, і означає $this->_oldAttributes['user_id'] = 1 (int) . Суворе порівняння повертає false і властивість вважається зміненим.
Щоб це виправити, треба додати фільтрацію значень метод rules().
Для властивостей, які не null, все досить просто, наводимо їх до int. Для властивостей, які можуть бути null, треба написати callback. У нашому додатку є другий варіант.
Bootstrap DateTimePicker — 2 різні формати для показу в інтерфейсі та для надсилання значення на сервер
Додамо фільтри created_from, created_to, updated_from, updated_to . Для дати/часу я зазвичай використовую віджети kartik для Bootstrap Datepicker/Datetimepicker.
Але є одна проблема, в них не можна задати різні формати для відображення та зберігання значення. В результаті на сервер може надсилатися щось на кшталт «14 junio 2016, mar.». Виправити це можна, додавши до рендерингу hidden-поле з новим форматом. У Datetimepicker можна встановити опції linkField і linkFormat, а в Datepicker треба ловити подію changeDate і форматувати вручну. Також потрібно обробляти натискання на кнопку очищення значення.