使用视图

最后更新于:2022-04-02 05:14:59

                        [TOC]

使用视图

视图表示应用程序的用户界面。视图通常是带有嵌入式PHP代码的HTML文件,这些代码执行仅与数据表示相关的任务。视图处理向Web浏览器或用于从您的应用程序发出请求的其他工具提供数据的工作。

Phalcon\Mvc\ViewPhalcon\Mvc\View\Simple 负责管理MVC应用程序的视图层。

将视图与控制器集成

一旦特定控制器完成其循环,Phalcon就会自动将执行传递给视图组件。视图组件将在views文件夹中查找名称与执行的最后一个控制器的名称相同的文件夹,然后查找名为最后执行的操作的文件。例如,如果请求URL http://127.0.0.1/blog/posts/show/301,Phalcon将按如下方式解析URL:

服务地址 127.0.0.1
Phalcon 目录 blog
Controller posts
Action show
Parameter 301

调度程序将查找PostsController及其动作showAction。此示例的简单控制器文件:

<!--?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction($postId)
    {
        // Pass the $postId parameter to the view
        $this--->view-&gt;postId = $postId;
    }
}

setVar() 方法允许我们按需创建视图变量,以便可以在视图模板中使用它们。上面的示例演示了如何将$postId参数传递给相应的视图模板。

分层渲染

Phalcon\Mvc\View 支持文件层次结构,是Phalcon中视图呈现的默认组件。此层次结构允许公共布局点(常用视图),以及定义相应视图模板的控制器命名文件夹。

默认情况下,此组件使用PHP本身作为模板引擎,因此视图应具有.phtml扩展名。如果views目录是app/views,则视图组件将自动查找这3个视图文件。

名称 文件 描述
动作视图 app/views/posts/show.phtml 这是与操作相关的视图。只有在执行show动作时才会显示它。
控制器布局 app/views/layouts/posts.phtml 这是与控制器相关的视图。它仅针对控制器“posts”内执行的每个动作显示。布局中实现的所有代码都将重用于此控制器中的所有操作。
主布局 app/views/index.phtml 这是针对应用程序中执行的每个控制器或操作显示的主要操作。

您不需要实现上面提到的所有文件。Phalcon\Mvc\View简单地移动到文件层次结构中的下一个视图级别。如果实现了所有三个视图文件,则将按如下方式处理它们:

<!-- app/views/posts/show.phtml -->

<h3>This is show view!</h3>

<p>I have received the parameter <!--?php echo $postId; ?--></p>
<!-- app/views/layouts/posts.phtml -->

<h2>This is the "posts" controller layout!</h2>

<!--?php echo $this--->getContent(); ?&gt;
<!-- app/views/index.phtml -->

    
        <title>Example</title>
    
    

        <h1>This is main layout!</h1>

        <!--?php echo $this--->getContent(); ?&gt;

    

注意调用方法$this-&gt;getContent()的行。此方法指示Phalcon\Mvc\View在哪里注入层次结构中执行的上一个视图的内容。对于上面的示例,输出将是:

.. figure:: ../_static/img/views-1.png :align: center

请求生成的HTML将是:

<!-- app/views/index.phtml -->

    
        <title>Example</title>
    
    

        <h1>This is main layout!</h1>

        <!-- app/views/layouts/posts.phtml -->

        <h2>This is the "posts" controller layout!</h2>

        <!-- app/views/posts/show.phtml -->

        <h3>This is show view!</h3>

        <p>I have received the parameter 101</p>

    

使用模板

模板是可用于共享公共视图代码的视图。它们充当控制器布局,因此您需要将它们放在layouts目录中。

模板可以在布局之前呈现(使用$this-&gt;view-&gt;setTemplateBefore()),也可以在布局之后渲染(this-&gt;view-&gt;setTemplateAfter())。在以下示例中,模板(layouts/common.phtml)在控制器布局(layouts/posts.phtml)之后渲染:

<!--?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function initialize()
    {
        $this--->view-&gt;setTemplateAfter('common');
    }

    public function lastAction()
    {
        $this-&gt;flash-&gt;notice(
            'These are the latest posts'
        );
    }
}
<!-- app/views/index.phtml -->


    
        <title>Blog's title</title>
    
    
        <!--?php echo $this--->getContent(); ?&gt;
    
<!-- app/views/layouts/common.phtml -->

<ul class="menu">
    <li><a href="/">Home</a></li>
    <li><a href="/articles">Articles</a></li>
    <li><a href="/contact">Contact us</a></li>
</ul>

<div class="content"><!--?php echo $this--->getContent(); ?&gt;</div>
<!-- app/views/layouts/posts.phtml -->

<h1>Blog Title</h1>

<!--?php echo $this--->getContent(); ?&gt;
<!-- app/views/posts/last.phtml -->

<article>
    <h2>This is a title</h2>
    <p>This is the post content</p>
</article>

<article>
    <h2>This is another title</h2>
    <p>This is another post content</p>
</article>

最终输出如下:

<!-- app/views/index.phtml -->


    
        <title>Blog's title</title>
    
    

        <!-- app/views/layouts/common.phtml -->

        <ul class="menu">
            <li><a href="/">Home</a></li>
            <li><a href="/articles">Articles</a></li>
            <li><a href="/contact">Contact us</a></li>
        </ul>

        <div class="content">

            <!-- app/views/layouts/posts.phtml -->

            <h1>Blog Title</h1>

            <!-- app/views/posts/last.phtml -->

            <article>
                <h2>This is a title</h2>
                <p>This is the post content</p>
            </article>

            <article>
                <h2>This is another title</h2>
                <p>This is another post content</p>
            </article>

        </div>

    

如果我们使用了$this-&gt;view-&gt;setTemplateBefore('common'),那么这将是最终输出:

<!-- app/views/index.phtml -->


    
        <title>Blog's title</title>
    
    

        <!-- app/views/layouts/posts.phtml -->

        <h1>Blog Title</h1>

        <!-- app/views/layouts/common.phtml -->

        <ul class="menu">
            <li><a href="/">Home</a></li>
            <li><a href="/articles">Articles</a></li>
            <li><a href="/contact">Contact us</a></li>
        </ul>

        <div class="content">

            <!-- app/views/posts/last.phtml -->

            <article>
                <h2>This is a title</h2>
                <p>This is the post content</p>
            </article>

            <article>
                <h2>This is another title</h2>
                <p>This is another post content</p>
            </article>

        </div>

    

控制渲染级别

如上所示,Phalcon\Mvc\View支持视图层次结构。您可能需要控制视图组件生成的渲染级别。方法Phalcon\Mvc\View::setRenderLevel()提供此功能。

可以从控制器或从上级视图层调用此方法以干扰渲染过程。

<!--?php

use Phalcon\Mvc\View;
use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function findAction()
    {
        // This is an Ajax response so it doesn't generate any kind of view
        $this--->view-&gt;setRenderLevel(
            View::LEVEL_NO_RENDER
        );

        // ...
    }

    public function showAction($postId)
    {
        // Shows only the view related to the action
        $this-&gt;view-&gt;setRenderLevel(
            View::LEVEL_ACTION_VIEW
        );
    }
}

可用的渲染级别为:

类常量 描述 顺序
LEVEL_NO_RENDER 表示避免生成任何类型渲染。
LEVEL_ACTION_VIEW 生成与操作关联的视图。 1
LEVEL_BEFORE_TEMPLATE 在控制器布局之前生成模板。 2
LEVEL_LAYOUT 生成渲染到控制器布局。 3
LEVEL_AFTER_TEMPLATE 在控制器布局之后生成到模板的渲染。 4
LEVEL_MAIN_LAYOUT 生成显示到主布局。文件views/index.phtml 5

禁用渲染级别

您可以永久或暂时禁用渲染级别。如果在整个应用程序中根本不使用某个级别,则可以永久禁用该级别:

<!--?php

use Phalcon\Mvc\View;

$di--->set(
    'view',
    function () {
        $view = new View();

        // Disable several levels
        $view-&gt;disableLevel(
            [
                View::LEVEL_LAYOUT      =&gt; true,
                View::LEVEL_MAIN_LAYOUT =&gt; true,
            ]
        );

        return $view;
    },
    true
);

或者在应用程序的某些部分暂时禁用:

<!--?php

use Phalcon\Mvc\View;
use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function findAction()
    {
        $this--->view-&gt;disableLevel(
            View::LEVEL_MAIN_LAYOUT
        );
    }
}

选择视图

如上所述,当 Phalcon\Mvc\ViewPhalcon\Mvc\Application管理时,渲染的视图是与最后一个控制器和执行的操作相关的视图。您可以使用 Phalcon\Mvc\View::pick() 方法覆盖它:

<!--?php

use Phalcon\Mvc\Controller;

class ProductsController extends Controller
{
    public function listAction()
    {
        // Pick 'views-dir/products/search' as view to render
        $this--->view-&gt;pick('products/search');

        // Pick 'views-dir/books/list' as view to render
        $this-&gt;view-&gt;pick(
            [
                'books',
            ]
        );

        // Pick 'views-dir/products/search' as view to render
        $this-&gt;view-&gt;pick(
            [
                1 =&gt; 'search',
            ]
        );
    }
}

禁用视图

如果您的控制器在视图中没有产生任何输出(或者甚至没有输出),您可以禁用视图组件以避免不必要的处理:

<!--?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function closeSessionAction()
    {
        // Close session
        // ...

        // Disable the view to avoid rendering
        $this--->view-&gt;disable();
    }
}

或者,您可以返回false以产生相同的效果:

<!--?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function closeSessionAction()
    {
        // ...

        // Disable the view to avoid rendering
        return false;
    }
}

您可以返回response对象以避免手动禁用视图:

<?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function closeSessionAction()
    {
        // Close session
        // ...

        // A HTTP Redirect
        return $this--->response-&gt;redirect('index/index');
    }
}

简单的渲染

Phalcon\Mvc\View\SimplePhalcon\Mvc\View的替代组件。 它保留了Phalcon\Mvc\View的大部分哲学,但缺乏文件层次结构,事实上,它是对应文件的主要特征。

该组件允许开发人员控制何时呈现视图及其位置。此外,该组件可以利用模板引擎(如Volt等)中可用的视图继承。

必须在服务容器中替换默认组件:

<!--?php

use Phalcon\Mvc\View\Simple as SimpleView;

$di--->set(
    'view',
    function () {
        $view = new SimpleView();

        $view-&gt;setViewsDir('../app/views/');

        return $view;
    },
    true
);

必须在Phalcon\Mvc\Application中禁用自动渲染(如果需要):

<!--?php

use Exception;
use Phalcon\Mvc\Application;

try {
    $application = new Application($di);

    $application--->useImplicitView(false);

    $response = $application-&gt;handle();

    $response-&gt;send();
} catch (Exception $e) {
    echo $e-&gt;getMessage();
}

要渲染视图,必须显式调用render方法,指示要显示的视图的相对路径:

<!--?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {
        // Render 'views-dir/index.phtml'
        echo $this--->view-&gt;render('index');

        // Render 'views-dir/posts/show.phtml'
        echo $this-&gt;view-&gt;render('posts/show');

        // Render 'views-dir/index.phtml' passing variables
        echo $this-&gt;view-&gt;render(
            'index',
            [
                'posts' =&gt; Posts::find(),
            ]
        );

        // Render 'views-dir/posts/show.phtml' passing variables
        echo $this-&gt;view-&gt;render(
            'posts/show',
            [
                'posts' =&gt; Posts::find(),
            ]
        );
    }
}

这与Phalcon\Mvc\View 不同,它的render() 方法使用控制器和动作作为参数:

<!--?php

$params = [
    'posts' =--> Posts::find(),
];

// Phalcon\Mvc\View
$view = new \Phalcon\Mvc\View();
echo $view-&gt;render('posts', 'show', $params);

// Phalcon\Mvc\View\Simple
$simpleView = new \Phalcon\Mvc\View\Simple();
echo $simpleView-&gt;render('posts/show', $params);

使用Partials

部分模板是将渲染过程分解为更简单,更易于管理的块的另一种方法,可以由应用程序的不同部分重用。使用partial,您可以移动代码以将特定的响应片段呈现给自己的文件。

使用partials的一种方法是将它们视为子例程的等价物:作为一种将细节移出视图的方法,以便更容易理解代码。例如,您可能有一个如下所示的视图:

<div class="top"><!--?php $this--->partial('shared/ad_banner'); ?&gt;</div>

<div class="content">
    <h1>Robots</h1>

    <p>Check out our specials for robots:</p>
    ...
</div>

<div class="footer"><!--?php $this--->partial('shared/footer'); ?&gt;</div>

partial() 方法接受第二个参数作为变量/参数数组,它们只存在于partial的范围内:

<!--?php $this--->partial('shared/ad_banner', ['id' =&gt; $site-&gt;id, 'size' =&gt; 'big']); ?&gt;

将值从控制器传输到视图

Phalcon\Mvc\View在每个控制器中都可以使用视图变量($this-&gt;view)。您可以使用该对象通过使用setVar() 方法从控制器操作直接将变量设置到视图。

<!--?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction()
    {
        $user  = Users::findFirst();
        $posts = $user--->getPosts();

        // Pass all the username and the posts to the views
        $this-&gt;view-&gt;setVar('username', $user-&gt;username);
        $this-&gt;view-&gt;setVar('posts', $posts);

        // Using the magic setter
        $this-&gt;view-&gt;username = $user-&gt;username;
        $this-&gt;view-&gt;posts    = $posts;

        // Passing more than one variable at the same time
        $this-&gt;view-&gt;setVars(
            [
                'username' =&gt; $user-&gt;username,
                'posts'    =&gt; $posts,
            ]
        );
    }
}

将在视图中创建具有 setVar() 的第一个参数名称的变量,以供使用。变量可以是任何类型,从简单的字符串,整数等变量到更复杂的结构,如数组,集合等。

<h1>
    {{ username }}'s Posts
</h1>

<div class="post">
<!--?php

    foreach ($posts as $post) {
        echo '<h2-->', $post-&gt;title, '';
    }

?&gt;
</div>

缓存视图片段

有时,当您开发动态网站并且其中某些区域不经常更新时,请求之间的输出完全相同。Phalcon\Mvc\View 提供缓存部分或整个渲染输出以提高性能。

Phalcon\Mvc\ViewPhalcon\Cache 集成,提供了一种缓存输出片段的简便方法。您可以手动设置缓存处理程序或设置全局处理程序:

<!--?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function showAction()
    {
        // Cache the view using the default settings
        $this--->view-&gt;cache(true);
    }

    public function showArticleAction()
    {
        // Cache this view for 1 hour
        $this-&gt;view-&gt;cache(
            [
                'lifetime' =&gt; 3600,
            ]
        );
    }

    public function resumeAction()
    {
        // Cache this view for 1 day with the key 'resume-cache'
        $this-&gt;view-&gt;cache(
            [
                'lifetime' =&gt; 86400,
                'key'      =&gt; 'resume-cache',
            ]
        );
    }

    public function downloadAction()
    {
        // Passing a custom service
        $this-&gt;view-&gt;cache(
            [
                'service'  =&gt; 'myCache',
                'lifetime' =&gt; 86400,
                'key'      =&gt; 'resume-cache',
            ]
        );
    }
}

当我们没有定义缓存的key时,组件使用控制器名称的MD5哈希和当前以controller/view格式呈现的视图自动创建一个键。为每个操作定义一个键是一个好习惯,这样您就可以轻松识别与每个视图关联的缓存。

当View组件需要缓存某些内容时,它将从服务容器中请求缓存服务。此服务的服务名称约定是viewCache

<!--?php

use Phalcon\Cache\Frontend\Output as OutputFrontend;
use Phalcon\Cache\Backend\Memcache as MemcacheBackend;

// Set the views cache service
$di--->set(
    'viewCache',
    function () {
        // Cache data for one day by default
        $frontCache = new OutputFrontend(
            [
                'lifetime' =&gt; 86400,
            ]
        );

        // Memcached connection settings
        $cache = new MemcacheBackend(
            $frontCache,
            [
                'host' =&gt; 'localhost',
                'port' =&gt; '11211',
            ]
        );

        return $cache;
    }
);

>[warning] 前端必须始终为Phalcon\Cache\Frontend\Output,并且服务viewCache必须在服务容器(DI)中注册为始终打开(不共享)。

使用视图时,可以使用缓存来防止控制器需要在每个请求上生成视图数据。

为此,我们必须使用密钥唯一地标识每个缓存。首先,我们验证缓存不存在或已过期,以使计算/查询在视图中显示数据:

<!--?php

use Phalcon\Mvc\Controller;

class DownloadController extends Controller
{
    public function indexAction()
    {
        // Check whether the cache with key 'downloads' exists or has expired
        if ($this--->view-&gt;getCache()-&gt;exists('downloads')) {
            // Query the latest downloads
            $latest = Downloads::find(
                [
                    'order' =&gt; 'created_at DESC',
                ]
            );

            $this-&gt;view-&gt;latest = $latest;
        }

        // Enable the cache with the same key 'downloads'
        $this-&gt;view-&gt;cache(
            [
                'key' =&gt; 'downloads',
            ]
        );
    }
}

PHP替代站点是实现片段缓存的示例。

模板引擎

模板引擎可帮助设计人员在不使用复杂语法的情况下创建视图。Phalcon包括一个名为Volt的强大而快速的模板引擎。Phalcon\Mvc\View许您使用其他模板引擎而不是普通的PHP或Volt。

使用不同的模板引擎通常需要使用外部PHP库进行复杂的文本解析,以便为用户生成最终输出。这通常会增加应用程序将使用的资源数量。

如果使用外部模板引擎,Phalcon\Mvc\View提供完全相同的视图层次结构,并且仍然可以更加努力地访问这些模板中的API。

该组件使用适配器,这些帮助Phalcon以统一的方式与这些外部模板引擎对话,让我们看看如何进行这种集成。

创建自己的模板引擎适配器

有许多模板引擎,您可能希望集成或创建自己的模板引擎。开始使用外部模板引擎的第一步是为它创建一个适配器。

模板引擎适配器是一个类,它充当Phalcon\Mvc\View和模板引擎本身之间的桥梁。通常它只需要实现两个方法:__construct()render()。第一个接收Phalcon\Mvc\View实例,该实例创建引擎适配器和应用程序使用的DI容器。

方法 render() 接受视图文件的绝对路径和使用$this-&gt;view-&gt;setVar()设置的视图参数。您可以在必要时阅读或要求它。

<!--?php

use Phalcon\DiInterface;
use Phalcon\Mvc\Engine;

class MyTemplateAdapter extends Engine
{
    /**
     * Adapter constructor
     *
     * @param \Phalcon\Mvc\View $view
     * @param \Phalcon\Di $di
     */
    public function __construct($view, DiInterface $di)
    {
        // Initialize here the adapter
        parent::__construct($view, $di);
    }

    /**
     * Renders a view using the template engine
     *
     * @param string $path
     * @param array $params
     */
    public function render($path, $params)
    {
        // Access view
        $view = $this--->_view;

        // Access options
        $options = $this-&gt;_options;

        // Render the view
        // ...
    }
}

更改模板引擎

您可以完全替换模板引擎,也可以同时使用多个模板引擎。方法 Phalcon\Mvc\View::registerEngines() 接受包含定义模板引擎的数据的数组。每个引擎的关键是一个扩展,有助于区分彼此。与特定引擎相关的模板文件必须具有这些扩展名。

使用Phalcon\Mvc\View::registerEngines()定义模板引擎的顺序定义了执行的相关性。如果Phalcon\Mvc\View找到两个具有相同名称但扩展名不同的视图,则它只会呈现第一个视图。

如果要为应用程序中的每个请求注册模板引擎或其中一组。您可以在创建视图服务时注册它:

<!--?php

use Phalcon\Mvc\View;

// Setting up the view component
$di--->set(
    'view',
    function () {
        $view = new View();

        // A trailing directory separator is required
        $view-&gt;setViewsDir('../app/views/');

        // Set the engine
        $view-&gt;registerEngines(
            [
                '.my-html' =&gt; 'MyTemplateAdapter',
            ]
        );

        // Using more than one template engine
        $view-&gt;registerEngines(
            [
                '.my-html' =&gt; 'MyTemplateAdapter',
                '.phtml'   =&gt; 'Phalcon\Mvc\View\Engine\Php',
            ]
        );

        return $view;
    },
    true
);

Phalcon Incubator上有几个模板引擎可用的适配器

在View中注入服务

每个执行的视图都包含在Phalcon\Di\Injectable 实例中,可以轻松访问应用程序的服务容器。

以下示例说明如何使用具有框架约定的URL编写jQuery ajax请求。通过访问具有相同名称的属性,在视图中注入服务url(通常是Phalcon\Mvc\Url):

<script type="text/javascript">

$.ajax({
    url: '<?php echo $this->url->get('cities/get'); ?>'
})
.done(function () {
    alert('Done!');
});

</script>

独立组件

Phalcon中的所有组件都可以单独用作胶水组件,因为它们彼此松散耦合:

分层渲染

在独立模式下使用Phalcon\Mvc\View可以在下面演示:

<!--?php

use Phalcon\Mvc\View;

$view = new View();

// A trailing directory separator is required
$view--->setViewsDir('../app/views/');

// Passing variables to the views, these will be created as local variables
$view-&gt;setVar('someProducts', $products);
$view-&gt;setVar('someFeatureEnabled', true);

// Start the output buffering
$view-&gt;start();

// Render all the view hierarchy related to the view products/list.phtml
$view-&gt;render('products', 'list');

// Finish the output buffering
$view-&gt;finish();

echo $view-&gt;getContent();

还提供了一个简短的语法:

<!--?php

use Phalcon\Mvc\View;

$view = new View();

echo $view--->getRender(
    'products',
    'list',
    [
        'someProducts'       =&gt; $products,
        'someFeatureEnabled' =&gt; true,
    ],
    function ($view) {
        // Set any extra options here

        $view-&gt;setViewsDir('../app/views/');

        $view-&gt;setRenderLevel(
            View::LEVEL_LAYOUT
        );
    }
);

简单的渲染

在独立模式下使用Phalcon\Mvc\View\Simple可以在下面演示:

<!--?php

use Phalcon\Mvc\View\Simple as SimpleView;

$view = new SimpleView();

// A trailing directory separator is required
$view--->setViewsDir('../app/views/');

// Render a view and return its contents as a string
echo $view-&gt;render('templates/welcomeMail');

// Render a view passing parameters
echo $view-&gt;render(
    'templates/welcomeMail',
    [
        'email'   =&gt; $email,
        'content' =&gt; $content,
    ]
);

视图事件

Phalcon\Mvc\ViewPhalcon\Mvc\View\Simple 能够将事件发送到EventsManager(如果存在)。 使用类型view触发事件。返回布尔值false时的某些事件可能会停止活动操作。支持以下事件:

事件名称 触发 Can stop operation?
beforeRender 在开始渲染过程之前触发 Yes
beforeRenderView 在渲染现有视图之前触发 Yes
afterRenderView 在渲染现有视图之后触发 No
afterRender 完成渲染过程后触发 No
notFoundView 未找到视图时触发 No

以下示例演示如何将侦听器附加到此组件:

<!--?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Mvc\View;

$di--->set(
    'view',
    function () {
        // Create an events manager
        $eventsManager = new EventsManager();

        // Attach a listener for type 'view'
        $eventsManager-&gt;attach(
            'view',
            function (Event $event, $view) {
                echo $event-&gt;getType(), ' - ', $view-&gt;getActiveRenderPath(), PHP_EOL;
            }
        );

        $view = new View();

        $view-&gt;setViewsDir('../app/views/');

        // Bind the eventsManager to the view component
        $view-&gt;setEventsManager($eventsManager);

        return $view;
    },
    true
);

以下示例显示如何使用Tidy创建一个清理/修复渲染过程生成的HTML的插件:

<!--?php

use Phalcon\Events\Event;

class TidyPlugin
{
    public function afterRender(Event $event, $view)
    {
        $tidyConfig = [
            'clean'          =--> true,
            'output-xhtml'   =&gt; true,
            'show-body-only' =&gt; true,
            'wrap'           =&gt; 0,
        ];

        $tidy = tidy_parse_string(
            $view-&gt;getContent(),
            $tidyConfig,
            'UTF8'
        );

        $tidy-&gt;cleanRepair();

        $view-&gt;setContent(
            (string) $tidy
        );
    }
}

// Attach the plugin as a listener
$eventsManager-&gt;attach(
    'view:afterRender',
    new TidyPlugin()
);
';