Yii2: Event for content in yii\web\View->endPage

Created on 11 Jan 2017  ·  21Comments  ·  Source: yiisoft/yii2

I have content with shortcodes in some views ($model->text, $model->intro, etc). For example

[code] ..... [\code]
[youtube code="WKHGWghjh"] 
[gallery id=50] // etc.

I can replaced it in yiibase\View::EVENT_AFTER_RENDER in $event->output from handler for every Shorcode

class YoutubeHandler{

public static function parseShortcode($event){
    if (isset($event->output)) {
        $shorcodes = new Shorcodes();
        $event->output = $shorcodes->parse('youtube', $event->output);
   }
}

}

But also on page I have listview, many widgets, gallery etc... (more 50 view files).
My shortcode handlers start parsing every view, but shorcodes has only one view!

Will be better have EVENT, where I can get all content from all parts views.

need more info

All 21 comments

So do you want to support shortcodes in all views on just in the main content which is taken from database?

Thanks for posting in our issue tracker.
In order to properly assist you, we need additional information:

  • When does the issue occur?
  • What do you see?
  • What was the expected result?
  • Can you supply us with a stacktrace? (optional)
  • Do you have exact code to reproduce it? Maybe a PHPUnit tests that fails? (optional)

Thanks!

_This is an automated comment, triggered by adding the label status:need more info._

I suggest create

namespace yii\web;
use yii\base\Event;

class ViewEvent extends Event
{
    /**
     * @var string the view file being rendered.
     */
    public $output;
}

and change yii\web\View

/**
     * Marks the ending of an HTML page.
     * @param bool $ajaxMode whether the view is rendering in AJAX mode.
     * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
     * will be rendered at the end of the view like normal scripts.
     */
    public function endPage($ajaxMode = false)
    {
        $content = ob_get_clean();

        $event = new ViewEvent([
            'output' => $content
        ]);

        $this->trigger(self::EVENT_END_PAGE, $event);

        $content = $event->output;

        echo strtr($content, [
            self::PH_HEAD => $this->renderHeadHtml(),
            self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
            self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
        ]);

        $this->clear();
    }

I've got what you suggest but I don't get what's your exact use case for it.

@samdark , yes, I have want to support shortcodes in all views, but parsing in one place.
Info on russian - http://yiiframework.ru/forum/viewtopic.php?f=27&t=42112&p=207963

i think you should create renderer for special views and set other extension, example:

$this->render('index', [/data/]);

//index.php
...
$this->render('my.file', []);
...

and add renderer for file extension

@lynicidn, I have parse shorcode from all modules - my and in vendor from other authors

I have module, where I can install, activate, deactivate shorcodes
https://github.com/loveorigami/yii2-plugins-system

and have baseShorcode event
https://github.com/loveorigami/yii2-plugins-system/blob/master/src/BaseShortcode.php#L26

Now all handlers parse more empty views.

From this module I can very easy create shortcode and configured widget from database!!!
example
https://github.com/loveorigami/yii2-plugins-system/blob/master/src/plugins/code/Code.php
and widget
https://github.com/loveorigami/yii2-plugins-system/blob/master/src/plugins/code/CodeWidget.php

for module you can use aliases for view

ты пытаешься 1 рендерером сделать 2 разные логики - не примут же такой ишью - все в кучу зачем совать

твиг шаблон с нативным пых шаблоном в одной вьюхе же тоже не будут работать

Какие 2 логики? Есть на выходе HTML контент, УЖЕ полученный из рендеров (php, твиг - без разницы), который сейчас содержится в https://github.com/yiisoft/yii2/blob/master/framework/web/View.php#L176

echo $content

даст

<!DOCTYPE HTML>
<html>
 <head>
  <title>Тег BODY</title>
  <meta charset="utf-8">
 </head>
 <body onload="alert('Документ загружен')">

  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem 
  nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.</p>
  <p>Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper 
  suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>

<p> [gallery id=1] </p>

 </body>
</html>

где и содержатся шорткоды, которые мне нужно заменить.

сейчас я эту обработку веду на каждое срабатывание события в базовом View при ренеринге каждого файла. Страница состоит из 50 файлов, а шорткоды - в одном - двух из них.
Получаю 49 пустых циклов. Еще умножаем на количество самих шорткодов, если таковых будет на 1, а десяток итого = 490 холостых срабатываний события.

Вот я и хочу заменитять их не в частях, а в уже готовой отрендеренной странице.

OK. I've got an idea. Checking for possible solutions.

Выше я предложил решение для yii\web\View.
Вполне логично получить доступ к контенту в уже сформированном Html в endPage.

Если ему тут не место - тогда добавить такое событие. например EVENT_WITH_CONTENT

@samdark thanks!
See my solutions in second post. For me, work fine

@lynicidn Спасибо большое!
точнее, $event->sender->content.
И это похоже то, что нужно.

@lynicidn Yes, indeed it works well so there's no new event needed:

 Yii::$app->getResponse()->on(Response::EVENT_AFTER_PREPARE, function() {
            $event->sender->content = str_replace('[test]', 'Hello, this is a test shortcode', $event->sender->content);
});

Подыму вопрос еще раз.
Перенастроил замену шорткодов. Все работает.
НО есть проблема!

Есть шорткод [gallery id=1], который через виджет формирует галерею. Виджет же через ассет добавляет ей стили и скрипты (лайтбокс).

Сейчас в Request происходит просто замена. Ассеты не добавляются...

По видимому - нужно цепляться где то в другом месте.

Мое решение, кстати, тоже имеет этот недостаток. Ассеты не регистрируются.

Потому что после рендера ассеты цеплять поздно.

Да, я и сам понял.... Я когда открывал issue - пропустил этот момент.
Получается тогда нужна другая возможность прицепиться в base/View, чтобы иметь доступ ко всем фрагментам, можно и массивом. Чтобы событие сработало 1 раз и в нем провести замену всех щорткодов, в которых будут виджеты.
Тогда ассеты добавятся.

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

Was this page helpful?
0 / 5 - 0 ratings