devanych / view-renderer
简单的PHP视图渲染器
Requires
- php: ^7.4|^8.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.5
- vimeo/psalm: ^4.3
This package is auto-updated.
Last update: 2024-09-22 00:31:57 UTC
README
一个轻量级且易于使用的PHP库,专为渲染原生PHP视图而设计。
亮点
- 方便的平面块系统。
- 为所有视图设置全局参数。
- 支持使用现有PHP函数。
- 通过添加自定义函数轻松扩展。
- 具有无限嵌套的灵活布局功能。
俄语详细描述的指南可在此处获取。
安装
此包需要PHP版本7.4或更高。
composer require devanych/view-renderer
用法
渲染的最简单示例
use Devanych\View\Renderer; $renderer = new Renderer('/path/to/root/directory/of/views'); $content = $renderer->render('path/to/view/file', [ 'variableName' => 'the value of a variable of any type', ]); echo $content;
render()
方法将其第一个参数作为视图文件的路径,该路径必须在创建对象时传递给构造函数的目录中是相对的。第二个参数传递一个数组参数(name => value
),这些参数将在视图内部转换为变量。
$renderer->render('post/show', [ 'post' => $posts->get($id), ]);
在视图中
<h1><?=$post->getName();?></h1>
视图文件可以有或没有扩展名,如果未指定文件扩展名,则默认使用 .php
。可以通过将其传递给构造函数作为第二个参数来更改默认扩展名。
$renderer = new Renderer('/path/to/root/directory/of/views', 'tpl');
在布局和视图中,渲染器实例在 $this
中可用。
<title><?=$this->renderBlock('title');?></title>
块
block()
、beginBlock()
和 endBlock()
方法允许你在视图中创建内容块。块的内容被保存以在视图的任何地方使用,以及在任何父布局中。方法 renderBlock()
渲染块中存储的内容。
布局代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title><?=$this->renderBlock('title');?></title> <?=$this->renderBlock('meta');?> </head> <body class="app"> <?=$this->renderBlock('content');?> </body> </html>
视图代码
<?php declare(strict_types=1); /** @var Devanych\View\Renderer $this */ $this->layout('layouts/main'); $this->block('title', 'Page Title'); ?> <p>Page Content</p> <?php $this->beginBlock('meta');?> <meta name="description" content="Page Description"> <?php $this->endBlock();?>
渲染结果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Page Title</title> <meta name="description" content="Page Description"> </head> <body class="app"> <p>Page Content</p> </body> </html>
块不能嵌套,但你可以在一个块内部渲染另一个块。
<!-- Allowed --> <?php $this->beginBlock('parent');?> <!-- ... --> <?=$this->renderBlock('children');?> <!-- ... --> <?php $this->endBlock();?> <!-- Disallowed --> <?php $this->beginBlock('parent');?> <!-- ... --> <?php $this->beginBlock('children');?> <!-- ... --> <?php $this->endBlock();?> <!-- ... --> <?php $this->endBlock();?>
请注意,content
是一个保留的块名称。它渲染视图和子布局的内容。如果你尝试创建名为 content
的块,将抛出 \RuntimeException
异常。
当使用不存在块的名称调用 renderBlock()
方法时,renderBlock()
方法返回一个空字符串,因此不需要额外的方法来检查块的存在。在 renderBlock()
中,可以传递默认值,如果指定的名称的块不存在,则替换该值。
<!-- Output the block content, if it exists --> <?php if ($name = $this->renderBlock('name')): ?> <h1><?=$name;?></h1> <?php endif;?> <!-- Output the default content if the block doesn't exist --> <?=$this->renderBlock('title', 'Default Title');?> <!-- or using a different block --> <?=$this->renderBlock('title', $this->renderBlock('default-title'));?>
布局
布局是特殊类型的表示,非常适合用于渲染重复部分(页眉、页脚、侧边栏等)。此包允许您构建具有无限嵌套的布局链。通过 layout()
方法在视图或子布局的文件中设置布局继承。
父布局代码(layouts/main
)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title><?=$this->renderBlock('title');?></title> </head> <body class="app"> <?=$this->renderBlock('content');?> </body> </html>
子布局代码(layouts/columns
)
<?php declare(strict_types=1); /** @var Devanych\View\Renderer $this */ $this->layout('layouts/main'); ?> <main class="main"> <?=$this->renderBlock('content');?> </main> <aside class="sidebar"> <!-- Sidebar Code --> </aside>
视图代码(site/page
)
<?php declare(strict_types=1); /** @var Devanych\View\Renderer $this */ $this->layout('layouts/columns'); $this->block('title', 'Page Title'); ?> <p>Page Content</p>
渲染视图
$renderer->render('site/page', [/* params */]);
渲染结果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Page Title</title> </head> <body class="app"> <main class="main"> <p>Page Content</p> </main> <aside class="sidebar"> <!-- Sidebar Code --> </aside> </body> </html>
如果您只需要从父布局中渲染子布局文件,您可以使用 render()
方法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title><?=$this->renderBlock('title');?></title> </head> <body class="app"> <?=$this->render('layouts/_header.php')?> <?=$this->renderBlock('content');?> <?=$this->render('layouts/_footer.php', [ 'parameter' => 'value' ])?> </body> </html>
渲染结果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Page Title</title> </head> <body class="app"> <header>Header</header> <p>Page Content</p> <footer>Footer</footer> </body> </html>
扩展
扩展功能允许您添加自己的函数并在布局和视图中使用它们。要添加一个函数,您需要创建一个实现Devanych\View\Extension\ExtensionInterface接口的自定义类。该接口仅包含一个方法,该方法返回一个数组,其键为添加的函数名称,而值可以是任何可能的callable
类型变体。
interface ExtensionInterface { /** * Returns an array of functions as `function name` => `function callback`. * * @return array<string, callable> */ public function getFunctions(): array; }
此包包含一个扩展Devanych\View\Extension\AssetExtension,该扩展简化了资产(脚本、样式、字体等)的连接,并给文件添加了时间戳。要添加扩展,请使用addExtension()
方法。
$extension = new AssetExtension('/path/to/assets', 'https://examle.com/assets', true); $renderer->addExtension($extension); // Result: 'https://examle.com/assets/css/style.css?v=1601742615' $renderer->asset('css/style.css');
全局参数
使用addGlobal()
方法,您可以添加将在所有视图和布局中可用的全局参数。
// The `$variableName` variable will now be available inside files. $renderer->addGlobal( 'variableName', 'the value of a variable of any type');
再次添加具有相同名称的变量将导致抛出\RuntimeException
异常,但您可以通过在渲染视图时传递具有相同名称的参数或直接在视图中分配值来更改特定视图的全局变量值。
// For all views and layouts, the value is `$author` will equal `Boby` $renderer->addGlobal( 'author', 'Boby'); // Only for the `blog/page` view, the value is `$author` will be equal to `John` $renderer->render('blog/page', [ 'author' => 'John', ]); // or assign a value in the view $author = 'John';
转义
为了防止输出潜在危险HTML代码,渲染器包含esc()
方法,该方法转义特殊字符,将它们转换为相应的HTML实体。
// Result: '<script>alert(123);</script>' $renderer->esc('<script>alert(123);</script>'); // Equivalently to: `htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true)`
此方法仅用于方便,但您也可以使用原始的htmlspecialchars()
函数,因为所有现有的PHP函数都在视图和布局中可用。