Лінива темізація в Yii підключення тем у стилі Drupal

drupal

Використання тем у Yii

Відомо, що для включення теми оформлення необхідно вказати її ім'я у параметрі theme:

Робота з темами описується у посібнику, але ми розглянемо кілька моментів і тут.

Отже, якщо ми маємо контролер ShopController

то ми можемо покласти уявлення index.php або вихідну директорію protected/views :

або в директорію уявлень теми protected/views:

Сподіваюся, Ви вже перейшли на використання модулів у своїх проектах, тому далі говоритимемо про них.

Нехай у нас є модуль shop, що містить три контролери:

Уявлення для модуля можна також поміщати або в папку views самого модуля, або в папку views/shop теми.

Якщо у модулі є файл подання

то для його заміни потрібно створити однойменний файл у папці теми:

замість подання модуля підставиться уявлення з теми.

Тут "/shop/" – ім'я модуля, а "/default/" – ім'я контролера.

Тобто якщо нам потрібно зробити кілька тем для одного сайту (наприклад, повна та мобільна версія) або декілька сайтів на одному движку, то достатньо створити кілька тем і перекривати у них уявлення будь-яких модулів.

Які нюанси нам потрібно знати

Використовуючи $this->render(. ) або $this->renderPartial(. ), можна часом піти на деякі хитрощі.

Стандартне включення – вказівка ​​імені файлу подання:

Якщо уявлень багато, то їх можна розкласти по папках і викликати відносною дорогою, використовуючи точку або слеш:

Краще використовувати відразу слеши, так як інакше Yii спробує по точках розібрати псевдонім (а саме пробуватиме різні варіанти: шукати модуль formsі т.д.).

Аналогічно можна «гуляти» ієрархіями папок:

Можна в папці protected/views або themes/classic/views натворювати папок і накидати туди загальних шаблонів, і включати їх викликом від кореня, використовуючи два слеша:

Наприклад, там зручно зберігати лейаути та сайдбари для них. Ми, до речі, вже розглядали для організації різних сайдбарів.

У найпростішому випадку можна просто скопіювати контролери та подання у кожен модуль. Але замість цього можна використовувати один загальний контролер та загальні уявлення з модуля comment.

Тепер у модулях блогу, новин та товарів помістимо порожні контолери-спадкоємці:

Потрібно мати на увазі той факт, що при доступі до уявлень модулів за жорсткими псевдонімами

Від цього тепер можна перейти безпосередньо до суті проблеми.

Де вказувати layout у Yii

Від окремих уявлень настав час перейти до роботи з шаблонами. На різних сайтах та й часом у різних розділах одного сайту можуть бути різні шаблони. Стандартної пари column1.php та column2.php тут явно не вистачить. Де зберігати шаблони? У спільній папці layouts або всередині модулів? Де саме вказувати, який шаблон не потрібен?

Розглянемо кілька підходів до завдання та оберемо найбільш зручний.

Вказівка ​​шаблону в контролері

Демо-блог та керівництво вчить нас вказувати layout у контролері. Це природно, оскільки це насправді і є громадське поле контролера. Стандартне підключення шаблону column2.php з папки protected/views/layouts або themes/

Всі наші контролери успадковуються від Controller, тому ми можемо легко змінити шаблон оформлення будь-якого контролера. Наприклад, магазин ми виведемо у шаблоні views/layouts/shop.php :

І навіть більше: для кошика, замовлення, пошуку та сторінкитовару зробимо свої шаблони:

А ще ми використовуємо модулі, тому можемо запросто створити папку protected/modules/shop/views/layouts усередині модуля, накидати туди наші лейаути та брати прямо звідти:

Тепер для іншої теми можна перевизначити необхідні файли в папці теми, а саме themes/ /views/shop/layouts .

Але якщо в іншій темі для іншого сайту потрібно вказати специфічний шаблон для виведення списку виробників (дія actionBrand)?

Прийде помістити рядок

у метод DefaultController::actionBrand і додати заглушку brand.php до всіх інших сайтів. щоб на них не вискакувала помилка, що уявлення brand.php не знайдено.

Ось ми й наблизилися до проблеми. Одному сайту потрібно «прикрасити» десять дій у трьох контролерах, другому лише кошик магазину, а третьому та одного шаблону вистачить. Але все одно до кожної теми потрібно додати десять. Якщо нова тема «захоче» використовувати одинадцятий лейаут, то контролер знову зміниться, і всі інші теми знову доведеться додавати одинадцяту заглушку.

Вказівка ​​шаблонів у поданні

Контролери у нас спільні для всіх сайтів, тому чіпати їх не варто. А якщо вказувати шаблон у самих уявленнях?

Справді, у поданні themes/

Тепер замість themes/

Таке звільнення від жорстко вписаних літералів у контролері дозволяє нам використовувати той самий контролер у різних сайтах без зміни його коду.

Але ось у чому парадокс:

Ми домовилися раніше, що у нас є три контролери

Насправді у модулі інтернет-магазину їх може бути набагато більше. Але так як присвоєння значення полю $this->layout проводиться в уявленнях, то щоб змінити шаблон всього модуля магазину в нашій теміНеобхідно перевизначити всі уявлення всіх наших контролерів. Тобто не один-два, а кілька десятків! І так за потреби для кожного модуля.

Недоліки статичної темізації

Отже, ми розглянули надання імені шаблону в контролері та у поданні.

Перший спосіб надто «хардкорний», тому що літерали (імена шаблонів) вписані прямо в код нашої програми. А це сама по собі не дуже хороша практика у розробці системи, яку очікується використовувати у більш ніж одному проекті.

Другий спосіб більш гнучкий, оскільки уявлення легко перевизначаються у темі (на відміну контролерів). Але уявлень дуже багато, і часом їх треба перевизначати великими пачками, оскільки, щоб змінити тему будь-якого розділу сайту, потрібно перевизначити всі уявлення цього модуля.

Який може бути вихід?

Вихід – наявність можливості вказувати шаблон поза конкретним контролером і поза уявленням.

Це може бути таблиця відповідності шаблонів конкретним модулям, контролерам та діям, оформлена у вигляді хеш-масиву в конфігураційному файлі:

Відповідно, ця таблиця повинна зберігатися у файлі, поміщеному в папку теми, а базовий контролер у події beforeRender повинен вибрати по цій таблиці потрібний шаблон.

Автозавантаження layout'ів

В ідеалі система темизації має все робити автоматично. З однойменними уявленнями та шаблонами це так і відбувається. Достатньо закинути в папку з темою перевизначене уявлення, так воно одразу використовується замість оригінального.

Таким шляхом «автопідхоплення» ми й підемо.

Для початку приберемо привласнення $this->layout з контролерів та з уявлень.

У найпростішому випадку наш модуль магазину матиме такуструктуру:

І в поточній темі ми перевизначили, наприклад, уявлення дії DefaultController::actionIndex:

А тепер було б непогано створити папку layouts для шаблонів та помістити їх туди:

Для зручності ми назвали файли за принципом

Така нотація дозволяє з одного погляду зрозуміти, до чого повинен застосовуватися кожен шаблон: до всього модуля, конкретного контролера або певної дії.

Тепер напишемо систему автопідвантаження шаблону:

Ця поведінка додає до контролера метод initLayout, який, як ми бачимо, по черзі шукає відповідний шаблон у темі та в оригінальному модулі і надає перший знайдений. Останні два рядки списку повинні вказувати на шаблон за промовчанням. Також, щоб не шукати щоразу заново, історія знайдених файлів кешується.

Поведінку ми повинні підключити до базового контролера і викликати його метод перед генерацією сторінки, тобто в події передпочатком контролера:

Зауважимо, що метод спрацює лише коли CController::layout порожній. Так що Ви, як і раніше, зможете привласнити $this->layout будь-яке значення в контролері або в поданні вручну і воно не перезапишеться.

Якщо Ви не хочете возитися з поведінкою, то скопіюйте код методу initLayout прямо в контролер, замінивши $onwer на $this .

Отже, щоб замінити шаблон магазину на сайті з двоколонного на триколонок, просто додайте в тему один файл:

А щоб зробити сторінку кошика на всю ширину додайте один шаблон безпосередньо для відповідної дії:

У результаті тепер шаблони підхоплюються з папки layuots самого модуля та з папки layuots теми цього модуля автоматично, і майже все оформлення будь-якого з ваших сайтів можна налаштувати прямо в темі.

Не пропускайтенові статті, бонуси та майстер-класи з Yii, Laravel та Symfony: