Создание динамических блоков видов blocks  в шаблонах yii2.
  • 1211

Создание динамических блоков видов blocks в шаблонах yii2.

Автор: admin | 23 октября (Вт.) 2018г. в 23ч.15м.

В этой статье будет рассмотрен один из способов динамического изменения структуры шаблона layout в yii2 с помощью блоков Yii::$app->view->blocks('blockName'). Данный способ позволяет выводить нужные блоки в шаблонах, изменять структуру layout динамически, когда это нужно.

Веб страница сайта содержит контент, который состоит из каких-либо частей. Так, шаблон сайта состоит из таких компонентов, как header и footer, сайдбар и блок контента. Когда пользователь заходит на какую-либо страницу на сайте, то в yii2 сробатывает соответствующее правило роутинга и в дело вступает нужный экшен контроллера. В экшене производятся какие-то действия, например выборка данных из базы и эти данные передаются в файл вида view. Сам же файл вида является частью общего шаблона layout и является динамической частью сайта, которая меняется при переходе по разным url.

Простой пример применения blocks в видах.

В шаблон layout файл вида view, который рендерится из экшена помещается в переменной $content:
<?php

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use frontend\assets\AppAsset;


AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?= Html::csrfMetaTags() ?>
    <title><?= isset(Yii::$app->name; ?></title>
    <?php $this->head() ?>
</head>

<body>
<?php $this->beginBody() ?>
<div id="header">...</div>

<div id="center-content">
   <?= $content; ?>
</div>

<div id="sidebar">
    <div class="sidebar--block">#block1</div>
    <div class="sidebar--block">#block2</div>
    <div class="sidebar--block">#block3</div>
</div>​

<div id="footer">
...
</div>​

<?php $this->endBody() ?>
</body>

</html>
<?php $this->endPage() ?>

Вот так для примера в упращенном виде выглядит файл вида (пусть будет page.php), который попадает в $content:

<?php
use yii\helpers\Html;
use yii\helpers\Url;

?>

<h1><?= $h1; ?></h1>
<div class="content">
<?= $pageContent; ?>
</div>

А вот и сам экшен:

    public function actionPage($alias)
    {
        $page = PageMod::getPage("$alias");

        if($page === NULL)
        {
            throw new \yii\web\HttpException(404, 'Такой страницы не существует. ');
            //throw new \yii\web\NotFoundHttpException;
        }
        
        return $this->render('page',  [
                                           'h1' =>             $page->h1,
                                           'content' =>        $page->content,
                                       [
                             );
    }

Но что делать, если для разных страниц должен меняться не только контент из экшена в $content, но и нужно менять содержимое и структуру сайдбара или футера, а возможно и то и другое. Для того, чтобы реализовать такую потребность существуют блоки контента в yii2.

Изменим наш шаблон, чтобы в нем поддерживались блоки blocks:

<body>
<?php $this->beginBody() ?>
<div id="header">...</div>

<div id="center-content">
   <?= $content; ?>
</div>

<?php if (isset($this->blocks['sidebar'])): ?>
<!-- 
==================================Sidebar=======================================
 -->
<div id="sidebar">
    <?= $this->blocks['sidebar'] ?>
</div>
<!-- 
==================================end::Sidebar================================== 
=-->
<?php endif; ?>



<div id="footer">
...
</div>​

<?php $this->endBody() ?>
</body>

Теперь, если свойство $this->blocks['sidebar'] было где-то в коде оприделено, то в шаблоне выведется нужный код. Для примера сделаем два экшена actionIndex() и actionPage(), которые будут выводить свой контент и свои блоки в сайдбаре.

    public function actionIndex()
    {
        $pages = Page::getAllPages();

        //выбираем самые новые страницы для вывода в сайдбаре
        $sidebarBlock_1 = Page::getNewest(5);

        //выбираем самые популярные страницы для вывода в сайдбаре
        $sidebarBlock_2 = Page::getMostPopular(5);

        return $this->render('index',  compact('pages'));
    }

    public function actionPage($alias)
    {
        $page = Page::getPage("$alias");

        //выбираем самые новые страницы для вывода в сайдбаре
        $sidebarBlock_1 = Page::getNewest(5);

        //выбираем последние комментарии для вывода в сайдбаре
        $sidebarBlock_2 = Comments::getLastComments(5);

        if($page === NULL)
        {
            throw new \yii\web\HttpException(404, 'Такой страницы не существует. ');
            //throw new \yii\web\NotFoundHttpException;
        }
        
        return $this->render('page',  [
                                           'h1'             => $page->h1,
                                           'content'        => $page->content,
                                           'sidebarBlock_1' => $sidebarBlock_1,
                                           'sidebarBlock_2' => $sidebarBlock_2,                                           
                                       [
                             );
    }

Так у страницы index и page будут нужные блоки в сайдбаре. Теперь в видах нужно сформировать эти блоки для сайдбара. Для этого контент, который должен попасть в сайдбар нужно обернуть в блок $this->beginBlock('sidebar') ... $this->endBlock().Разместить его можно в любом месте файла view, я же помещаю этот блок в конец файла.

Первый параметр в $this->beginBlock('block_name', $renderInPlace = false)  - это название блока, а второй означает, что нужно ли выводить содержимое блока тут же, где он расположен (по умолчанию равно false). 

В index.php:

<?php
use yii\helpers\Html;
use yii\helpers\Url;

?>

<h1>Все страницы сайта</h1>
<div class="content">
  <?php foreach($pages as $page): ?>
       <div class="page-list">
            <?= $page; ?>
      </div>
  <?php endforeach; ?>
</div>

<!-- формируем блок сайдбара -->
<?php $this->beginBlock('sidebar'); ?>

<!-- новые страницы -->
<div class="sidebar--block new-pages">
   <h3><?= $sidebarBlock_1->h1; ?></h3>
   <p class="sidebar--block-description">
        <?= $sidebarBlock_1->text; ?>
   </p>
</div>

<!-- популярные страницы -->
<div class="sidebar--block popular-pages">
   <h3><?= $sidebarBlock_2->h1; ?></h3>
   <p class="sidebar--block-description">
        <?= $sidebarBlock_2->text; ?>
   </p>
</div>

<?php $this->endBlock();?>

Теперь поместим в page.php свой вариант сайдбара:

<?php
use yii\helpers\Html;
use yii\helpers\Url;

?>

<h1><?= $h1; ?></h1>
<div class="content">
<?= $content; ?>
</div>

<!-- формируем блок сайдбара -->
<?php $this->beginBlock('sidebar'); ?>

<!-- новые страницы -->
<div class="sidebar--block new-pages">
   <h3><?= $sidebarBlock_1->h1; ?></h3>
   <p class="sidebar--block-description">
        <?= $sidebarBlock_1->text; ?>
   </p>
</div>

<!-- популярные комментарии -->
<div class="sidebar--block popular-comments">
   <p class="sidebar--block-comments">
        <?= $sidebarBlock_2->comments; ?>
   </p>
</div>

<?php $this->endBlock();?>

Таким способом с помощью блоков можно сформировать любой контент и вывести его в нужном месте шаблона с помощью простой конструкции
вида <?= $this->blocks['sidebar'] ?>

Использование  $this->render внутри блоков.

Удобно создавать для разметки каждого блока отдельный файл и уже его подключать в нужном месте между $this->beginBlock('sidebar') ... $this->endBlock() .Так мы избежим дублирования кода, когда нужно будет в index.php и page.php выводить одинаковые блоки. Для этого создадим такую структуру папок и файлов в папке views:
- views
   -layouts
     -sideBar
       -blocks
         _pagesList.php
         _commentsList.php
   -site
     -index.php
     -page.php
​

Весь код блоков вынесем в файлы _pagesList.php  и _commentsList.php и подключать будем уже эти файлы:

<?php
use yii\helpers\Html;
use yii\helpers\Url;

?>

<h1><?= $h1; ?></h1>
<div class="content">
<?= $content; ?>
</div>

<!-- формируем блок сайдбара -->
<?php $this->beginBlock('sidebar'); ?>

<!-- новые страницы -->
<?= render('//layouts/sideBar/_pagesList.php', ['sidebarBlock_1' => $sidebarBlock_1]); ?>

<!-- популярные комментарии -->
<?= render('sideBar/_commentsList.php', ['sidebarBlock_2' => $sidebarBlock_2]); ?>

<?php $this->endBlock();?>

P.S.

Так как блоки сохраняются в свойстве  public $blocks; класса yii\base\View ,то можно передать данные блока не только из файла видов, но и из контроллера или даже из виджета:
//Где-нибудь в контроллере 
Yii::$app->view->blocks['sidebar'] = $this->renderPartial('_some_block',compact('someData'));

//Или так
$block = renderPartial('_some_block',compact('someData'));
array_push(Yii::$app->view->blocks['sidebar'], $block) ​

Пользуйтесь блоками, т.к. это удобный метод формирования шаблонов, который есть в yii2. Ну а если стоит задача реализовать вложенные layout блоки, то в yii2 также есть решение "из кробки", которое я описываю в статье по вложенные шаблоны в yii2.

Приветствую!

Меня зовут Сергей. Я - автор этого блога.

Если Вам был полезен материал на моем сайте, поддержите пожалуйста мой проект, чтобы о нем узнали другие люди - кликните plizz :) на иконку в соц. сети, чтобы поделиться материалом с другими.