Различные сайдбары для разделов сайта в Yii

Пингвин в раздумьях

На официальном форуме Yii Framework встретил вопрос об организации работы с сайдбарами на сайте. Вопрос возник в связи с требованиями автора выводить разное содержимое панелей в разных разделах сайта. Автор пробует выделить место для сайдбара в главном шаблоне views/layouts/main.php и генерировать содержимое сайдбаров в самих конкретных представлениях. Поделюсь своей организацией шаблонов.

Вариант автора мне показался избыточным необходимостью собирать сайдбар в каждом представлении.

По умолчанию в папке /views/layouts/ создаются шаблон main.php и подшаблоны column_1.php и column_2.php, наследуюемые от main.php. В главном шаблоне main.php мы оставим каркас.

Главный шаблон layouts/main.php:

<!doctype html>
<html>
<head>...<head>
<body>
    <header>...<header>
    <div id="container">
        <?php echo $content; ?>
    </div>
    <footer>...</footer>
</body>
</html>

Теперь просто соберём в отдельную папку /views/layouts/page/, раскопируем и переименуем невразумительные column_1.php и column_2.php во что-то вроде default.php, blog.php, shop.php, portfolio.php и т.д. Вот код нескольких из таких подшаблонов:

Шаблон layouts/page/default.php в две колонки:

<?php $this->beginContent('//layouts/main'); ?>
    <aside class='sidebar left_sidebar'>
        <?php $this->renderPartial('//layouts/sidebar/default'); ?>
    </aside>
    <section class='main right_main'>
        <?php echo $content; ?>
    </section>
<?php $this->endContent(); ?>

Шаблон layouts/page/blog.php в две колонки:

<?php $this->beginContent('//layouts/main'); ?>
    <aside class='sidebar left_sidebar'>
        <?php $this->renderPartial('//layouts/sidebar/blog'); ?>
    </aside>
    <section class='main center_main'>    
        <!-- В блоге перед постами можно поместить красивый слайдер -->    
        <?php $this->widget('application.widgets.BlogSliderWidget');?>    
        <?php echo $content; ?>
    </section>
<?php $this->endContent(); ?>

Шаблон layouts/page/fullpage.php на всю ширину:

<?php $this->beginContent('//layouts/main'); ?>
    <section class='main'>
        <?php echo $content; ?>
    </section>
<?php $this->endContent(); ?>

Код подшаблонов минимален, поэтому копипаст не страшен.

Как можно заметить, нужно добавить папку /views/layouts/sidebar/ и сделать внутри несколько файлов сайдбаров. Повторяющиеся виджеты можно либо вписать вручную в каждый файл, либо отнаследовать сайдбары друг от друга. Например, сайдбар для блога упрощённо выглядит так:

Сайдбар для блога layouts/sidebar/blog.php:

<?php $this->beginWidget('СPortlet', array('title'=>'Следите за мной'));?>
    <?php $this->widget('application.widgets.FollowWidget');?>
<?php $this->endWidget();?>
 
<?php $this->beginWidget('СPortlet', array('title'=>'Разделы блога'));?>
    <?php $this->widget('zii.widgets.CMenu', array('items'
        =>BlogCategory::model()->getMenuArray()));?>
<?php $this->endWidget();?>
 
<?php $this->beginWidget('СPortlet', array('title'=>'Метки'));?>
    <?php $this->widget('application.widgets.TagCloudWidget');?>
<?php $this->endWidget();?>
 
<?php $this->beginWidget('СPortlet');?>
    <?php $this->widget('application.widgets.CalendarWidget');?>
<?php $this->endWidget();?>
 
<?php $this->beginWidget('СPortlet', array('title'=>'Профиль'));?>
    <?php $this->widget('application.widgets.LoginFormWidget');?>
<?php $this->endWidget();?>

В итоге получаем коллекцию лёгких подшаблонов для разных разделов сайта и коллекцию сайдбаров со своими виджетами.

Шаблон по умолчанию указываем в базовом контроллере:

class Controller extends СController 
{
    // по умолчанию для всего сайта
    public $layout = '//layouts/page/default'; 
 
    // ...
}

Потом просто выставляем специфические шаблоны в нужных контроллерах или экшенах:

class BlogController extends Controller 
{
    // у раздела Блог шаблон другой, поэтому укажем его
    public $layout = '//layouts/page/blog';
 
    // экшен вывода поста
    public function actionView($id)
    {
        // пост мы выведем с немного другим шаблоном без фотогалереи, 
        // имеющим другой сайдбар с виджетом популярных постов
        $this->layout = '//layouts/page/blogpost';
 
        $post = $this->loadModel();
 
        // ...
    }    
}

Таким образом, процесс переключения сайдбаров мы повысили до процесса переключением шаблонов, что избавило нас от рутинной генерации сайдбара в контроллере или его представлении, а также дало дополнительную гибкость изменения шаблонов для различных разделов сайта. При необходимости для любого раздела достаточно сделать новый сайдбар и новый подшаблон, в котором через renderPartial этот сайдбар будет включён.

Другие статьи

Давным давно в тридевя... в шаблонизаторе моей второй по счёту старой CMS вставка виджетов в шаблон была релизована посредством использования старой доброй клинописи вида {{WidgetName|param1=val1;param2=val2}}. Этот код можно было встявлять даже в текст, что давало неоценимую возможность компоновать страницы любой сложности из виджетов прямо в текстовом редакторе админки.

При выводе новостей и комментариев на публичном или личном сайте возникает необходимость фильтрации HTML-кода от опасных XSS элементов. Компонент HTML Purifier, поставляемый в комплекте с Yii Framework, может сильно облегчить задачу фильтрации. Это действительно мощный и гибко настраиваемый инструмент. Рассмотрим способы работы с ним.

В одном из проектов потребовалось ввести в форму изменения профиля пользователя поле «Введите текущий пароль». Сначала был быстро сделан валидирующий метод в самой модели пользователя. В последующем для повторного использования в разных проектах было решено написать полноценный внешний валидатор.

Достаточно часто на тематических форумах по Yii встречаются вопросы новичков о организации хранения паролей пользователей в модели User. Вопрос звучит примерно так: «У меня в модели User есть поле password, в котором я храню хэш пароля. Как мне сделать так, чтобы пароль не перезаписывался при каждом сохранении модели?» Вопрос любопытный и для других фреймворков.

Комментарии

 

nike

Уважаемый Дмитрий!
Спасибо за статью. Скажите Вы не рассматривали реализацию вывода виджетов, как это реализовано в joomla.

Ответить

 

Дмитрий Елисеев

Вы имеете в виду динамическое распределение виджетов по зонам шаблона с указанием в админке на каких страницах какой выводить? Такой способ не реализовывал, так как не было необходимости в разработке полноценного конструктора для расстановки виджетов.

В классических самописных проектах (на фреймворках или без) каждый модуль живёт своей жизнью, а все виджеты и связи конструируются прямо в программном коде. Для перехода к визуальной схеме как в Joomla! нужно весь сайт делать на статических страницах и все модули переделывать в виджеты для привязки к страницам (а это мало кому нужно). Или, как вариант, можно привязывать виджеты по маске к URL.

В вопросе (по ссылке в статье) автор и намекает на динамический сбор наборов виджетов для всех зон (клипов) каждый раз в каждом действии контроллера, но это решение весьма избыточное и не очень удобное, так как для добавления каждого виджета в несколько разделов нужно изменить списки виджетов в десятках действий.

Ну это если я правильно понял ваш вопрос.

Ответить

 

nike

Спасибо за ответ.
Если не сложно расскажите как у вас организовано кеширование, используете ли тегирование кеша?

Ответить

 

Дмитрий Елисеев

Использую простое кэширование. Кеширую запросы find(), findAll() и т.д., каждый виджет оборачиваю в конструкцию

<?php if($this->beginCache(__FILE__.__LINE__, array('duration'=>3600*24))) { ?>
    <?php $this->beginWidget('СPortlet', array('title'=>'Следите за мной'));?>
        <?php $this->widget('application.widgets.FollowWidget');?>
    <?php $this->endWidget();?>
<?php $this->endCache(); } ?>

Я упоминал о ней раньше. Полную очистку кэша произвожу в админке.

Тегирование, конечно, удобнее, но пока легко обхожусь без него.

Ответить

 

Pavel

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

Ответить

 

Ильдар Асанов

Отлично. Большое спасибо за статью и вклад в развитие программирования. Хотелось бы видеть подобную реализацию теперь уже на Yii2.

Ответить

 

Алексей

Даешь примеры для yii2 !

Ответить

 

des

а как для второй версии сделать?

Ответить

 

Дмитрий Елисеев

Также через $this->render(...).

Ответить

 

Мастер Ремонт

А как же из контроллер передать переменную в сайдбар (для вывода там меню, например)?

Ответить

 

Дмитрий Елисеев

Можно через $this->params.

Ответить

 

Алекс

Дмитрий, а Вы бы не могли обновить статью с учетом Yii2?

Ответить

 

Вася Ветров

Столкнулся с таким вопросом.
Боковую панель подключал как вы описывали. Все хорошо, проблема решена. Однако, понадобилось показывать слайдер не на каждой странице. Как слайдер подключать выборочно?

Ответить

 

Дмитрий Елисеев
<?php if ($this->route == 'site/index): ?>
    ...
<?php endif; ?>
Ответить

 

Игорь Мастер

А я сделал так. В базовом контроллере, от которого наследуются все контроллеры указал

public $slider = false;

а в нужном экшене, где надо выводить слайдер - устанавливаю

$this->slider = true;

Ну и конечно в layout

<?php if(\Yii::$app->controller->slider):?>
    <?= $this->render('slider') ?>
<?php endif;?>
Ответить

Оставить комментарий

Войти | Завести аккаунт


(никто не увидит)



Можно использовать теги <p> <ul> <li> <b> <i> <a> <pre>