krak / presenter
展示者设计模式的小型简单实现
Requires
- php: ~5.3
- symfony/config: ~2.0
Requires (Dev)
- doctrine/cache: ~1.0
- phpunit/phpunit: ~4.0
- pimple/pimple: ~3.0
- symfony/event-dispatcher: ~2.0
- symfony/http-foundation: ~2.0
- symfony/http-kernel: ~2.0
README
简单而强大的展示者模式实现。
安装
使用composer安装。
{ "repositories": [ { "type": "vcs", "url": "http://gitlab.bighead.net/bighead/krak-presenter.git" } ], "require": { "krak/presenter": "~2.0", /* only if you use the CachePresenter */ "doctrine/cache": "~1.0", /* include if you use the EventListener\ViewListener */ "symfony/event-dispatcher": "~2.0", "symfony/http-kernel": "~2.0", "symfony/http-foundation": "~2.0", /* include if you use the Provider\ViewPresenterServiceProvider */ "pimple/pimple": "~3.0" } }
设计
krak Presenters分为三个主要组件:展示者、装饰者和视图模型。
展示者和装饰者都实现了展示者
接口
interface Presenter { /** * Present the view and return the content associated with it * @param mixed $view * @return string */ public function present($view); /** * Whether or not the presenter can actually present the data/view * @param mixed $data * @return bool */ public function canPresent($view); }
展示者/装饰者将接受一个视图模型进行展示,然后返回其内容。
因此调用
$content = $presenter->present($view);
将始终返回与视图关联的内容。
展示者
展示者将接受视图模型并“展示”它们,即将其渲染为字符串响应。此库附带两个不同的展示者:视图和模拟。
视图展示者将从视图模型中获取适当的视图文件内容。
模拟展示者主要用于测试,但它只是SplObjectStorage的一个简单包装。
ViewPresenter
<?php use Krak\Presenter\ViewPresenter; use Krak\Presenter\View\View; use Krak\Presenter\View\ViewTrait; use Symfony\Component\Config\FileLocator; class MyView implements View { use ViewTrait; private $view_file = 'my-view'; // or just define the getViewFile function public function getViewFile() { return 'my-view'; } public function getHeader() { return '<h1>Header</h1>'; } } $presenter = new ViewPresenter(FileLocator(__DIR__ . '/views'), 'php', 'v'); echo $presenter->present(new MyView());
// __DIR__ . /views/my-view.php <html> <?=$v->getData()?> </html>
最后的echo语句将输出
<html>
<h1>Header</h1>
</html>
ViewPresenter构造函数接受一个文件定位器、一个扩展(默认为空字符串)以及视图模型的别名(默认为'view')。
扩展
$presenter->setExtension('php'); echo $presenter->getExtension(); // outputs: php
如果有设置扩展,则将在每个视图文件名末尾追加.{ext}
。
别名
$presenter->setViewAlias('v_alias'); echo $presenter->getViewAlias(); // outputs: v_alias // then in some-view file <html> <?=$v_alias->getData()?> </html>
MockPresenter
use Krak\Presenter\MockPresenter; $presenter = new MockPresenter(); $view = new stdClass(); $presenter->mock($view, 'some-data'); echo $presenter->present($view);
输出将是
some-data
装饰者
展示者系统设计在展示者
接口周围,这使得装饰器的使用非常容易。
此库附带两个装饰器:缓存和树。
缓存
缓存展示者只是一个装饰器,它将尝试在渲染视图之前从缓存中获取展示者数据。
use Krak\Presenter\CachePresenter; use Krak\Presenter\View\CacheableView; use Doctrine\Common\Cache\ArrayCache; class MyView implements CacheableView { public function getCacheTuple() { return array('my-view-cache-key', 3600); } } /* $presenter is another instanceof Presenter defined beforehand */ $cache = new ArrayCache(); $cache_presenter = new CachePresenter($presenter, $cache); $data = $cache_presetner->present(new MyView()); var_dump($data === $cache->fetch('my-view-cache-key');
输出将是true,因为缓存展示者将数据添加到了缓存中,下一个对同一视图模型的展示调用将直接从缓存返回数据,而不是将其委托给其内部的展示者。
bool(true)
现在,CachePresenter将只缓存实现CacheableView
接口的视图模型。
树
树展示者是另一个装饰器,允许展示视图的层次结构/树。树展示者仅遍历实现TreeView
接口的视图。关于树视图的一个重要注意事项是如何一次性处理多个项目。
调用$tree_presenter->presenter($view)
将返回树对象的输出,它是树的根。然后它将遍历树,并使用其内部展示者获取每个子视图的所有数据。然后它将展示的内容注入到子视图中,以便父视图可以使用。
use Krak\Presenter\TreePresenter; use Krak\Presenter\View\View; use Krak\Presenter\View\TreeView; use Krak\Presenter\View\TreeViewTrait; use Krak\Presenter\ViewPresenter; class TreeViewChild implements View, TreeView { use ViewTrait; use TreeViewTrait; private $view_file = 'child-view.php'; public function getData() { return 'some-data'; } } class TreeViewParent implements View, TreeView { use TreeViewTrait; private $child1; private $view_file = 'parent-view.php'; public function __construct() { $this->child1 = new TreeViewChild(); } public function getChildren() { return array($this->child1); } public function getChild1() { return $this->child1; } } $view_presenter = new ViewPresenter($locator); $tree_presenter = new TreePresenter($view_presenter); echo $tree_presenter->present(new TreeViewParent());
// child-view.php <span><?=$view->getData()?></span>
// parent-view.php <div> <?=$view->getChild1()->getContent()?> </div>
最后的echo语句将显示
<div>
<span>some-data</span>
</div>
视图模型
视图模型是负责渲染视图的实际对象。使用Krak Presenter库,有四种类型的视图:视图、树视图、缓存视图和匿名视图。
视图
interface View { /** * @return string */ public function getViewFile(); }
非常简单的界面,用于检索要加载的视图文件。该界面由ViewPresenter使用。您可以使用ViewTrait
为您定义这些方法。
TreeView
interface TreeView { /** * @return TreeView[] */ public function getChildren(); /** * Set the rendered content for this view * @var string */ public function setContent($content); /** * get the rendered content for this view * @return string */ public function getContent(); }
该接口设计用于与TreePresenter一起使用,如您所见,它允许遍历TreeView模型构成的树,并允许每个视图保存其内容。您可以使用TreeViewTrait
为您定义这些方法。
CacheableView
interface CacheableView { /** * Returns a tuple of the cache key and ttl * @return array */ public function getCacheTuple(); }
该接口设计用于与CachePresenter一起使用。缓存元组如下所示
array('key', 3600);
其中元组有一个键为'key'和一个TTL为3600。
匿名视图
有时您不需要构建整个类,只是为了渲染带有一些数据的文件,为此,我们有了匿名视图模型。
匿名视图实现了View
接口。您可以这样创建匿名视图
use Krak\Presenter\View\AnonymousView; $v = new AnonymousView('some-view-file', array('key'=>'val')); // or $v = AnonymousView::create('some-view-file'); // data is defaulted to an empty array
然后在some-view-file
<div> <?=$view->key?> </div>
此视图将渲染为
<div>
val
</div>
缓冲区
缓冲区是一个在处理TreeView时非常有用的简单实用工具。缓冲区本质上只是保存字符串内容,但您可以将同一个缓冲区与多个视图共享,它们将向同一个缓冲区追加内容。
例如,假设您想允许每个视图定义一些JavaScript。然后每个视图定义的JavaScript应该输出到页面底部。您可以使用缓冲区轻松完成。
首先,我们假设每个视图都有一个具有相同实例的缓冲区作为公共变量,名为js_buf
。
// root view file <html> <body> <?=$view->getInnerView()->getContent()?> </body> <?=$view->js_buf->getContents()?> </html>
// inner view file <?php $view->js_buf->start()?> <script type="text/javascript"> // some javascript </script> <?php $view->js_buf->end()?> <div> <!-- content --> </div>
视图监听器
如果您使用基于Symfony HttpKernel的项目,您可以注册视图监听器,以便您的控制器可以返回视图并将它们转换为响应。
use Krak\Presenter\EventListener\ViewListener, Krak\Presenter\ViewPresenter; $view_presenter = ... $listener = new ViewListener($view_presenter); /* dispatcher instanceof Symfony\Component\EventDispatcher\EventDispatcher */ $dispatcher->addSubscriber($listener);
然后在您的控制器中,您只需返回一个视图模型,如下所示,它将被转换为响应
public function showAction() { // ... /* instanceof Krak\Presenter\View\View */ return new ViewModel(); }
服务提供者
如果您在项目中使用Pimple,则可以使用ViewPresenterServiceProvider
将视图呈现器注册为服务。
$container->register(new ViewPresenterServiceProvider(), [ 'presenter.ext' => 'php', 'presenter.view_alias' => 'view', 'presenter.paths' => [__DIR__], // instead of paths, you can also just specify the file locator 'presenter.file_locator' => function() { return new Symfony\Component\Config\FileLocator([__DIR__]); } ]); $locator = $container['presenter.file_locator']; $presenter = $container['presenter'];
如果您想使用装饰器,则可以使用Pimple::extend
方法,如下所示
use Krak\Presenter\TreePresenter; $container->extend('presenter', function($presenter, $c) { return new TreePresenter($presenter); });