使用视图(Using Views)

视图代表了应用程序中的用户界面. 视图通常是在 HTML 文件里嵌入 PHP 代码,这些代码仅仅是用来展示数据。视图的任务是当应用程序发生请求时,提供数据给 web 浏览器或者其他工具。

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

集成视图到控制器(Integrating Views with Controllers)

当某个控制器已经完成了它的周期,Phalcon自动将执行传递到视图组件。视图组件将在视图文件夹中寻找一个文件夹名与最后一个控制器名相同,文件命名与最后一个动作相同的文件执行。例如,如果请求的URL http://127.0.0.1/blog/posts/show/301, Phalcon将如下所示的方式按解析URL:

|Server Address|127.0.0.1
|Phalcon Directory|blog
|Controller|posts
|Action|show
|Parameter|301

调度程序将寻找一个“PostsController”控制器及其“showAction”动作。对于这个示例的一个简单的控制器文件:

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends Controller
  6. {
  7. public function indexAction()
  8. {
  9.  
  10. }
  11.  
  12. public function showAction($postId)
  13. {
  14. // Pass the $postId parameter to the view
  15. $this->view->postId = $postId;
  16. }
  17. }

setVar允许我们创建视图变量,这样可以在视图模板中使用它们。上面的示例演示了如何传递 $postId 参数到相应的视图模板。

分层渲染(Hierarchical Rendering)

Phalcon\Mvc\View 支持文件的层次结构,在Phalcon中是默认的视图渲染组件。这个层次结构允许通用的布局点(常用的视图)和以控制器命名的文件夹中定义各自的视图模板

该组件使用默认PHP本身作为模板引擎,因此视图应该以.phtml作为拓展名。如果视图目录是 app/views ,视图组件会自动找到这三个视图文件。

名称 文件 解释
Action View app/views/posts/show.phtml 这是该动作相关的视图。它只会在执行 “show” 动作时显示。
Controller Layout app/views/layouts/posts.phtml 这是该控制器相关的视图。它只会 “posts” 控制器内每个动作执行时显示。这个控制器的所有动作将重用这个布局的全部代码。
Main Layout app/views/index.phtml 这是主布局,它将在应用程序的每个控制器或动作执行时显示。

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

  1. <!-- app/views/posts/show.phtml -->
  2.  
  3. <h3>This is show view!</h3>
  4.  
  5. <p>I have received the parameter <?php echo $postId; ?></p>
  1. <!-- app/views/layouts/posts.phtml -->
  2.  
  3. <h2>This is the "posts" controller layout!</h2>
  4.  
  5. <?php echo $this->getContent(); ?>
  1. <!-- app/views/index.phtml -->
  2. <html>
  3. <head>
  4. <title>Example</title>
  5. </head>
  6. <body>
  7.  
  8. <h1>This is main layout!</h1>
  9.  
  10. <?php echo $this->getContent(); ?>
  11.  
  12. </body>
  13. </html>

注意方法 $this->getContent() 被调用的这行。这种方法指示 Phalcon\Mvc\View 在这里注入前面视图层次结构执行的内容。在上面的示例中,输出将会是:
使用视图(Using Views) - 图1
请求生成的HTML的将为:

  1. <!-- app/views/index.phtml -->
  2. <html>
  3. <head>
  4. <title>Example</title>
  5. </head>
  6. <body>
  7.  
  8. <h1>This is main layout!</h1>
  9.  
  10. <!-- app/views/layouts/posts.phtml -->
  11.  
  12. <h2>This is the "posts" controller layout!</h2>
  13.  
  14. <!-- app/views/posts/show.phtml -->
  15.  
  16. <h3>This is show view!</h3>
  17.  
  18. <p>I have received the parameter 101</p>
  19.  
  20. </body>
  21. </html>

命名空间视图渲染(Namespace View Support)

默认启用,可以关闭命名空间视图渲染:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. $di->set('view', function () {
  6.  
  7. $view = new View();
  8.  
  9. // Disable namespace view render
  10. $view->disableNamespaceView();
  11.  
  12. return $view;
  13. }, true);

如果设置路由,对上述的URL做如下解析:

|Server Address|127.0.0.1
|Namespace|blog
|Controller|posts
|Action|show
|Parameter|301

视图组件会自动找到这四个视图文件。

名称 文件 解释
Action View app/views/blog/posts/show.phtml 这是该动作相关的视图。
Controller Layout app/views/layouts/blog/posts.phtml 这是该控制器相关的视图。
Namespace Layout app/views/layouts/namespace/blogs.phtml 这是该命名空间相关的视图。
Main Layout app/views/index.phtml 这是主布局。

多级命名空间,会从底层逐级向上层渲染视图,可以关闭多级渲染:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. $di->set('view', function () {
  6.  
  7. $view = new View();
  8.  
  9. $view->disableMultiNamespaceView();
  10.  
  11. return $view;
  12. }, true);

使用模版(Using Templates)

模板视图可以用来分享共同的视图代码。他们作为控制器的布局,所以你需要放在布局目录。

Templates can be rendered before the layout (using $this->view->setTemplateBefore()) or they can be rendered after the layout (using this->view->setTemplateAfter()). In the following example the template (layouts/common.phtml) is rendered after the main layout (layouts/posts.phtml):

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends Controller
  6. {
  7. public function initialize()
  8. {
  9. $this->view->setTemplateAfter('common');
  10. }
  11.  
  12. public function lastAction()
  13. {
  14. $this->flash->notice("These are the latest posts");
  15. }
  16. }
  1. <!-- app/views/index.phtml -->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Blog's title</title>
  6. </head>
  7. <body>
  8. <?php echo $this->getContent(); ?>
  9. </body>
  10. </html>
  1. <!-- app/views/layouts/common.phtml -->
  2.  
  3. <ul class="menu">
  4. <li><a href="/">Home</a></li>
  5. <li><a href="/articles">Articles</a></li>
  6. <li><a href="/contact">Contact us</a></li>
  7. </ul>
  8.  
  9. <div class="content"><?php echo $this->getContent(); ?></div>
  1. <!-- app/views/layouts/posts.phtml -->
  2.  
  3. <h1>Blog Title</h1>
  4.  
  5. <?php echo $this->getContent(); ?>
  1. <!-- app/views/posts/last.phtml -->
  2.  
  3. <article>
  4. <h2>This is a title</h2>
  5. <p>This is the post content</p>
  6. </article>
  7.  
  8. <article>
  9. <h2>This is another title</h2>
  10. <p>This is another post content</p>
  11. </article>

最终的输出如下:

  1. <!-- app/views/index.phtml -->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Blog's title</title>
  6. </head>
  7. <body>
  8.  
  9. <!-- app/views/layouts/common.phtml -->
  10.  
  11. <ul class="menu">
  12. <li><a href="/">Home</a></li>
  13. <li><a href="/articles">Articles</a></li>
  14. <li><a href="/contact">Contact us</a></li>
  15. </ul>
  16.  
  17. <div class="content">
  18.  
  19. <!-- app/views/layouts/posts.phtml -->
  20.  
  21. <h1>Blog Title</h1>
  22.  
  23. <!-- app/views/posts/last.phtml -->
  24.  
  25. <article>
  26. <h2>This is a title</h2>
  27. <p>This is the post content</p>
  28. </article>
  29.  
  30. <article>
  31. <h2>This is another title</h2>
  32. <p>This is another post content</p>
  33. </article>
  34.  
  35. </div>
  36.  
  37. </body>
  38. </html>

If we had used $this->view->setTemplateBefore('common'), this would be the final output:

  1. <!-- app/views/index.phtml -->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Blog's title</title>
  6. </head>
  7. <body>
  8.  
  9. <!-- app/views/layouts/posts.phtml -->
  10.  
  11. <h1>Blog Title</h1>
  12.  
  13. <!-- app/views/layouts/common.phtml -->
  14.  
  15. <ul class="menu">
  16. <li><a href="/">Home</a></li>
  17. <li><a href="/articles">Articles</a></li>
  18. <li><a href="/contact">Contact us</a></li>
  19. </ul>
  20.  
  21. <div class="content">
  22.  
  23. <!-- app/views/posts/last.phtml -->
  24.  
  25. <article>
  26. <h2>This is a title</h2>
  27. <p>This is the post content</p>
  28. </article>
  29.  
  30. <article>
  31. <h2>This is another title</h2>
  32. <p>This is another post content</p>
  33. </article>
  34.  
  35. </div>
  36.  
  37. </body>
  38. </html>

渲染级别控制(Control Rendering Levels)

如上所述,Phalcon\Mvc\View 支持视图分层。你可能需要控制视图组件的渲染级别。方法 Phalcon\Mvc\View::setRenderLevel() 提供这个功能。

这种方法可以从控制器调用或是从上级视图层干涉渲染过程。

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4. use Phalcon\Mvc\Controller;
  5.  
  6. class PostsController extends Controller
  7. {
  8. public function indexAction()
  9. {
  10.  
  11. }
  12.  
  13. public function findAction()
  14. {
  15. // This is an Ajax response so it doesn't generate any kind of view
  16. $this->view->setRenderLevel(View::LEVEL_NO_RENDER);
  17.  
  18. // ...
  19. }
  20.  
  21. public function showAction($postId)
  22. {
  23. // Shows only the view related to the action
  24. $this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
  25. }
  26. }

可用的渲染级别:

类常量 解释 顺 序
LEVEL_NO_RENDER 表明要避免产生任何形式的显示。
LEVEL_ACTION_VIEW 生成显示到视图关联的动作。 1
LEVEL_BEFORE_TEMPLATE 生成显示到控制器模板布局之前。 2
LEVEL_LAYOUT 生成显示到控制器布局。 3
LEVEL_NAMESPACE 生成显示到控制器命名空间模板布局。 4
LEVEL_AFTER_TEMPLATE 生成显示到控制器模板布局后。 5
LEVEL_MAIN_LAYOUT 生成显示到主布局。文件: views/index.phtml 6

关闭渲染级别(Disabling render levels)

你可以永久或暂时禁用渲染级别。如果不在整个应用程序使用,可以永久禁用一个级别:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. $di->set('view', function () {
  6.  
  7. $view = new View();
  8.  
  9. // Disable several levels
  10. $view->disableLevel(
  11. array(
  12. View::LEVEL_LAYOUT => true,
  13. View::LEVEL_MAIN_LAYOUT => true
  14. )
  15. );
  16.  
  17. return $view;
  18. }, true);

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

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4. use Phalcon\Mvc\Controller;
  5.  
  6. class PostsController extends Controller
  7. {
  8. public function indexAction()
  9. {
  10.  
  11. }
  12.  
  13. public function findAction()
  14. {
  15. $this->view->disableLevel(View::LEVEL_MAIN_LAYOUT);
  16. }
  17. }

选择视图(Picking Views)

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

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class ProductsController extends Controller
  6. {
  7. public function listAction()
  8. {
  9. // Pick "views-dir/products/search" as view to render
  10. $this->view->pick("products/search");
  11.  
  12. // Pick "views-dir/books/list" as view to render
  13. $this->view->pick(array('books'));
  14.  
  15. // Pick "views-dir/products/search" as view to render
  16. $this->view->pick(array(1 => 'search'));
  17. }
  18. }

关闭视图(Disabling the view)

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

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class UsersController extends Controller
  6. {
  7. public function closeSessionAction()
  8. {
  9. // Close session
  10. // ...
  11.  
  12. // A HTTP Redirect
  13. $this->response->redirect('index/index');
  14.  
  15. // Disable the view to avoid rendering
  16. $this->view->disable();
  17. }
  18. }

你可以返回一个“response”的对象,避免手动禁用视图:

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class UsersController extends Controller
  6. {
  7. public function closeSessionAction()
  8. {
  9. // Close session
  10. // ...
  11.  
  12. // A HTTP Redirect
  13. return $this->response->redirect('index/index');
  14. }
  15. }

简单渲染(Simple Rendering)

Phalcon\Mvc\View\SimplePhalcon\Mvc\View 的另一个组成部分。它保留 Phalcon\Mvc\View 的大多数的设计思想,但缺少文件的层次结构是它们的主要区别。

该组件允许开发人员控制渲染视图时,视图所在位置。此外,该组件可以利用从视图中继承的可用的模板引擎。

默认使用该的组件必须替换服务容器:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View\Simple as SimpleView;
  4.  
  5. $di->set('view', function () {
  6.  
  7. $view = new SimpleView();
  8.  
  9. $view->setViewsDir('../app/views/');
  10.  
  11. return $view;
  12. }, true);

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

  1. <?php
  2.  
  3. use Phalcon\Mvc\Application;
  4.  
  5. try {
  6.  
  7. $application = new Application($di);
  8.  
  9. $application->useImplicitView(false);
  10.  
  11. echo $application->handle()->getContent();
  12.  
  13. } catch (\Exception $e) {
  14. echo $e->getMessage();
  15. }

渲染一个视图必须显式地调用render方法来指定你想显示的视图的相对路径:

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends \Controller
  6. {
  7. public function indexAction()
  8. {
  9. // Render 'views-dir/index.phtml'
  10. echo $this->view->render('index');
  11.  
  12. // Render 'views-dir/posts/show.phtml'
  13. echo $this->view->render('posts/show');
  14.  
  15. // Render 'views-dir/index.phtml' passing variables
  16. echo $this->view->render('index', array('posts' => Posts::find()));
  17.  
  18. // Render 'views-dir/posts/show.phtml' passing variables
  19. echo $this->view->render('posts/show', array('posts' => Posts::find()));
  20. }
  21. }

This is different to Phalcon\Mvc\View who’s render() method uses controllers and actions as parameters:

  1. <?php
  2.  
  3. $params = array('posts' => Posts::find());
  4.  
  5. // Phalcon\Mvc\View
  6. $view = new \Phalcon\Mvc\View();
  7. echo $view->render('posts', 'show', $params);
  8.  
  9. // Phalcon\Mvc\View\Simple
  10. $simpleView = new \Phalcon\Mvc\View\Simple();
  11. echo $simpleView->render('posts/show', $params);

使用局部模版(Using Partials)

局部模板是把渲染过程分解成更简单、更好管理的、可以重用不同部分的应用程序块的另一种方式。你可以移动渲染特定响应的代码块到自己的文件。

使用局部模板的一种方法是把它们作为相等的子例程:作为一种移动细节视图,这样您的代码可以更容易地被理解。例如,您可能有一个视图看起来像这样:

  1. <div class="top"><?php $this->partial("shared/ad_banner"); ?></div>
  2.  
  3. <div class="content">
  4. <h1>Robots</h1>
  5.  
  6. <p>Check out our specials for robots:</p>
  7. ...
  8. </div>
  9.  
  10. <div class="footer"><?php $this->partial("shared/footer"); ?></div>

方法 partial() 也接受一个只存在于局部范围的变量/参数的数组作为第二个参数:

  1. <?php $this->partial("shared/ad_banner", array('id' => $site->id, 'size' => 'big')); ?>

关闭局部模版自动渲染(Disables Partial Auto Render)

通过方法 partial() 第三个参数关闭自动渲染:

  1. <?php $result = $this->partial("shared/ad_banner", array('id' => $site->id, 'size' => 'big'), TRUE); ?>

控制器传值给视图(Transfer values from the controller to views)

Phalcon\Mvc\View 可以在每个控制器中使用视图变量 ($this->view)。 你可以在控制器动作中使用视图对象的 setVar() 方法直接设置视图变量。

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends Controller
  6. {
  7. public function indexAction()
  8. {
  9.  
  10. }
  11.  
  12. public function showAction()
  13. {
  14. // Pass all the posts to the views
  15. $this->view->setVar(
  16. "posts",
  17. Posts::find()
  18. );
  19.  
  20. // Using the magic setter
  21. $this->view->posts = Posts::find();
  22.  
  23. // Passing more than one variable at the same time
  24. $this->view->setVars(
  25. array(
  26. 'title' => $post->title,
  27. 'content' => $post->content
  28. )
  29. );
  30. }
  31. }

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

  1. <div class="post">
  2. <?php
  3.  
  4. foreach ($posts as $post) {
  5. echo "<h1>", $post->title, "</h1>";
  6. }
  7.  
  8. ?>
  9. </div>

在视图中使用模型(Using models in the view layer)

应用模型在视图层也是可用的。Phalcon\Loader 将在运行时实例化模型:

  1. <div class="categories">
  2. <?php
  3.  
  4. foreach (Categories::find("status = 1") as $category) {
  5. echo "<span class='category'>", $category->name, "</span>";
  6. }
  7.  
  8. ?>
  9. </div>

尽管你可以执行模型处理操作,如在视图层 insert() 或 update(),但这是不推荐,因为在一个错误或异常发生时,它不可能将执行流程转发给另一个控制器。

视图片段(View Sections)

startSection()stopSection() 函数允许您在视图模版中构建视图片段,他们可以在其他任意位置使用。

创建片段(Creating Sections)

您需要定义片段名称。

  1. <?php $this->startSection('category') ?>
  2. <div class="categories">
  3. <?php
  4.  
  5. foreach (Categories::find("status = 1") as $category) {
  6. echo "<span class='category'>", $category->name, "</span>";
  7. }
  8.  
  9. ?>
  10. </div>
  11. <?php $this->stopSection() ?>

获取片段内容(Gets section content)

根据片段名称获取相应片段内容,可以设置默认值,当片段不存在时,返回默认值。

  1. <?php $this->section('category', $this->partial("shared/category", NULL, FALSE)) ?>

缓存视图片段(Caching View Fragments)

有时当你开发动态网站和一些区域不会经常更新,请求的输出是完全相同的。 Phalcon\Mvc\View 提供缓存全部或部分的渲染输出来提高性能。

Phalcon\Mvc\View 配合 Phalcon\Cache 能提供一种更简单的方法缓存输出片段。你可以手动设置缓存处理程序或一个全局处理程序。

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends Controller
  6. {
  7. public function showAction()
  8. {
  9. // Cache the view using the default settings
  10. $this->view->cache(true);
  11. }
  12.  
  13. public function showArticleAction()
  14. {
  15. // Cache this view for 1 hour
  16. $this->view->cache(
  17. array(
  18. "lifetime" => 3600
  19. )
  20. );
  21. }
  22.  
  23. public function resumeAction()
  24. {
  25. // Cache this view for 1 day with the key "resume-cache"
  26. $this->view->cache(
  27. array(
  28. "lifetime" => 86400,
  29. "key" => "resume-cache"
  30. )
  31. );
  32. }
  33.  
  34. public function downloadAction()
  35. {
  36. // Passing a custom service
  37. $this->view->cache(
  38. array(
  39. "service" => "myCache",
  40. "lifetime" => 86400,
  41. "key" => "resume-cache"
  42. )
  43. );
  44. }
  45. }

当我们没有定义缓存的 key 的值时,该组件会自动根据文件路径生成 MD5 值作为 key 的值,它是定义每个关键动作的一个良好实践,这样你可以很容易地识别与每个视图关联的缓存。

当视图组件需要缓存的东西时,就会请求缓存服务的服务容器。这个服务的服务名称约定为”viewCache”:

  1. <?php
  2.  
  3. use Phalcon\Cache\Frontend\Output as OutputFrontend;
  4. use Phalcon\Cache\Backend\Memcache as MemcacheBackend;
  5.  
  6. // Set the views cache service
  7. $di->set('viewCache', function () {
  8.  
  9. // Cache data for one day by default
  10. $frontCache = new OutputFrontend(
  11. array(
  12. "lifetime" => 86400
  13. )
  14. );
  15.  
  16. // Memcached connection settings
  17. $cache = new MemcacheBackend(
  18. $frontCache,
  19. array(
  20. "host" => "localhost",
  21. "port" => "11211"
  22. )
  23. );
  24.  
  25. return $cache;
  26. });
前端 Phalcon\Cache\Frontend\Output 和服务 ‘viewCache’ 必须在服务容器(DI)注册为总是开放的(不共享 not shared)

在视图中使用视图缓存也是有用的,以防止控制器执行过程所产生的数据被显示。

为了实现这一点,我们必须确定每个缓存键是独一无二的。 首先,我们验证缓存不存在或是否过期,再去计算/查询并在视图中显示数据:

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class DownloadController extends Controller
  6. {
  7. public function indexAction()
  8. {
  9. // Check whether the cache with key "downloads" exists or has expired
  10. if ($this->view->getCache()->exists('downloads')) {
  11.  
  12. // Query the latest downloads
  13. $latest = Downloads::find(
  14. array(
  15. 'order' => 'created_at DESC'
  16. )
  17. );
  18.  
  19. $this->view->latest = $latest;
  20. }
  21.  
  22. // Enable the cache with the same key "downloads"
  23. $this->view->cache(
  24. array(
  25. 'key' => 'downloads'
  26. )
  27. );
  28. }
  29. }

PHP alternative site 是实现缓存片段的一个例子。

缓存任意视图片段(Caching Any View Fragments)

在视图文件中,使用 Phalcon\Cache 实现任意位置数据缓存:

  1. <?php
  2.  
  3. $content = $cache->start("categories-cache.html");
  4. if ($content === null) {
  5. ?>
  6. <div class="categories">
  7. <?php
  8.  
  9. foreach (Categories::find("status = 1") as $category) {
  10. echo "<span class='category'>", $category->name, "</span>";
  11. }
  12.  
  13. ?>
  14. </div>
  15. <?php
  16. $cache->save();
  17. } else {
  18. echo $content;
  19. }
  20. ?>

模版引擎(Template Engines)

模板引擎可以帮助设计者不使用复杂的语法创建视图。Phalcon包含一个强大的和快速的模板引擎,它被叫做叫 Volt。

此外, Phalcon\Mvc\View 允许你使用其它的模板引擎而不是简单的PHP或者Volt。

使用不同的模板引擎,通常需要使用外部PHP库并且引入复杂的文本解析来为用户生成最终的输出解析。这通常会增加一些你的应用程序的资源耗费。

如果一个外部模板引擎被使用,Phalcon\Mvc\View 提供完全相同的视图渲染等级,仍然可以尝试在这些模板内访问的更多的API。

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

创建模版引擎(Creating your own Template Engine Adapter)

有很多模板引擎,你可能想整合或建立一个自己的。开始使用一个外部的模板引擎的第一步是创建一个适配器。

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

方法 render() 接受一个到视图文件的绝对路径和视图参数,设置使用 $this->view->setVar()。必要的时候,你可以读入或引入它。

  1. <?php
  2.  
  3. use Phalcon\Mvc\Engine;
  4.  
  5. class MyTemplateAdapter extends Engine
  6. {
  7. /**
  8. * Adapter constructor
  9. *
  10. * @param \Phalcon\Mvc\View $view
  11. * @param \Phalcon\Di $di
  12. */
  13. public function __construct($view, $di)
  14. {
  15. // Initialize here the adapter
  16. parent::__construct($view, $di);
  17. }
  18.  
  19. /**
  20. * Renders a view using the template engine
  21. *
  22. * @param string $path
  23. * @param array $params
  24. */
  25. public function render($path, $params)
  26. {
  27. // Access view
  28. $view = $this->_view;
  29.  
  30. // Access options
  31. $options = $this->_options;
  32.  
  33. // Render the view
  34. // ...
  35. }
  36. }

替换模版引擎(Changing the Template Engine)

你可以想下面一样从控制器更换或者添加更多的模板引擎:

  1. <?php
  2.  
  3. use Phalcon\Mvc\Controller;
  4.  
  5. class PostsController extends Controller
  6. {
  7. public function indexAction()
  8. {
  9. // Set the engine
  10. $this->view->registerEngines(
  11. array(
  12. ".my-html" => "MyTemplateAdapter"
  13. )
  14. );
  15. }
  16.  
  17. public function showAction()
  18. {
  19. // Using more than one template engine
  20. $this->view->registerEngines(
  21. array(
  22. ".my-html" => 'MyTemplateAdapter',
  23. ".phtml" => 'Phalcon\Mvc\View\Engine\Php'
  24. )
  25. );
  26. }
  27. }

你可以完全更换模板引擎或同时使用多个模板引擎。方法 Phalcon\Mvc\View::registerEngines() 接受一个包含定义模板引擎数据的数组。每个引擎的键名是一个区别于其他引擎的拓展名。模板文件和特定的引擎关联必须有这些扩展名。

Phalcon\Mvc\View::registerEngines() 会按照相关顺序定义模板引擎执行。如果 Phalcon\Mvc\View 发现具有相同名称但不同的扩展,它只会使第一个。

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

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. // Setting up the view component
  6. $di->set('view', function () {
  7.  
  8. $view = new View();
  9.  
  10. // A trailing directory separator is required
  11. $view->setViewsDir('../app/views/');
  12.  
  13. $view->registerEngines(
  14. array(
  15. ".my-html" => 'MyTemplateAdapter'
  16. )
  17. );
  18.  
  19. return $view;
  20. }, true);

Phalcon Incubator 有一些适配器可用于数个模板引擎

注入服务到视图(Injecting services in View)

每个视图执行内部包含一个 Phalcon\Di\Injectable 实例, 提供方便地方式访问应用程序的服务容器。

下面的示例演示如何用一个框架约定好的URL服务写一个 jQuery ajax request 。“url” (usually Phalcon\Mvc\Url) 服务被注入在视图由相同名称的属性访问:

  1. <script type="text/javascript">
  2.  
  3. $.ajax({
  4. url: "<?php echo $this->url->get("cities/get"); ?>"
  5. })
  6. .done(function () {
  7. alert("Done!");
  8. });
  9.  
  10. </script>

独立的组件(Stand-Alone Component)

在Phalcon的所有部件都可以作为胶水(glue) 组件单独使用,因为它们彼此松散耦合:

分层渲染(Hierarchical Rendering)

如下所示,可以单独使用 Phalcon\Mvc\View

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. $view = new View();
  6.  
  7. // A trailing directory separator is required
  8. $view->setViewsDir("../app/views/");
  9.  
  10. // Passing variables to the views, these will be created as local variables
  11. $view->setVar("someProducts", $products);
  12. $view->setVar("someFeatureEnabled", true);
  13.  
  14. // Start the output buffering
  15. $view->start();
  16.  
  17. // Render all the view hierarchy related to the view products/list.phtml
  18. $view->render("products", "list");
  19.  
  20. // Finish the output buffering
  21. $view->finish();
  22.  
  23. echo $view->getContent();

使用短的语法也可以:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4.  
  5. $view = new View();
  6.  
  7. echo $view->getRender('products', 'list',
  8. array(
  9. "someProducts" => $products,
  10. "someFeatureEnabled" => true
  11. ),
  12. function ($view) {
  13. // Set any extra options here
  14. $view->setViewsDir("../app/views/");
  15. $view->setRenderLevel(View::LEVEL_LAYOUT);
  16. }
  17. );

简单渲染(Simple Rendering)

如下所示,以单独使用 Phalcon\Mvc\View\Simple

  1. <?php
  2.  
  3. use Phalcon\Mvc\View\Simple as SimpleView;
  4.  
  5. $view = new SimpleView();
  6.  
  7. // A trailing directory separator is required
  8. $view->setViewsDir("../app/views/");
  9.  
  10. // Render a view and return its contents as a string
  11. echo $view->render("templates/welcomeMail");
  12.  
  13. // Render a view passing parameters
  14. echo $view->render(
  15. "templates/welcomeMail",
  16. array(
  17. 'email' => $email,
  18. 'content' => $content
  19. )
  20. );

多视图目录设置(Multiple Views Directory)

如下所示,视图文件将从app/views/view1app/views/view2寻找:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View as View;
  4.  
  5. $view = new View();
  6.  
  7. $view->setBasePath(array("../app/views/"));
  8. $view->setViewsDir(array("./view1/", "./view2/"));

视图事件(View Events)

如果事件管理器(EventsManager)存在,Phalcon\Mvc\ViewPhalcon\Mvc\View 能够发送事件到 EventsManager。事件触发使用的“view”类型。当返回布尔值false,一些事件可以停止运行。以下是被支持的事件:

事件名称 触发点 是否可以停止?
beforeRender 渲染过程开始前触发 Yes
beforeRenderView 渲染一个现有的视图之前触发 Yes
afterRenderView 渲染一个现有的视图之后触发 No
afterRender 渲染过程完成后触发 No
notFoundView 视图不存在时触发 No

下面的例子演示了如何将监听器附加到该组件:

  1. <?php
  2.  
  3. use Phalcon\Mvc\View;
  4. use Phalcon\Events\Manager as EventsManager;
  5.  
  6. $di->set('view', function () {
  7.  
  8. // Create an events manager
  9. $eventsManager = new EventsManager();
  10.  
  11. // Attach a listener for type "view"
  12. $eventsManager->attach("view", function ($event, $view) {
  13. echo $event->getType(), ' - ', $view->getActiveRenderPath(), PHP_EOL;
  14. });
  15.  
  16. $view = new View();
  17. $view->setViewsDir("../app/views/");
  18.  
  19. // Bind the eventsManager to the view component
  20. $view->setEventsManager($eventsManager);
  21.  
  22. return $view;
  23.  
  24. }, true);

下面的示例演示如何创建一个插件 Tidy ,清理/修复的渲染过程中产生的HTML:

  1. <?php
  2.  
  3. class TidyPlugin
  4. {
  5. public function afterRender($event, $view)
  6. {
  7. $tidyConfig = array(
  8. 'clean' => true,
  9. 'output-xhtml' => true,
  10. 'show-body-only' => true,
  11. 'wrap' => 0
  12. );
  13.  
  14. $tidy = tidy_parse_string($view->getContent(), $tidyConfig, 'UTF8');
  15. $tidy->cleanRepair();
  16.  
  17. $view->setContent((string) $tidy);
  18. }
  19. }
  20.  
  21. // Attach the plugin as a listener
  22. $eventsManager->attach("view:afterRender", new TidyPlugin());

原文: http://www.myleftstudio.com/reference/views.html