mediagone / twig-powerpack
为您的Twig模板提供代码质量助手。
Requires (Dev)
- phpunit/phpunit: ^9.0
README
⚠️ 此项目处于实验阶段。
此包为您的Twig模板提供代码质量功能
以及新功能
|json_decode过滤器
安装
此包需要 PHP 7.4+ 和 Twig 2+。
将其作为Composer依赖项添加
$ composer require mediagone/twig-powerpack
如果您使用Symfony,请在 services.yaml 中启用扩展
services: Mediagone\Twig\PowerPack\TwigPowerPackExtension: tags: [twig.extension]
简介
Twig模板引擎在类型方面严重不足...
功能
1) 上下文变量类型检查
模板通常需要特定的外部数据,但没有内置的方式检查提供变量的类型。使用 expect 标签可以在您的Twig文件中声明所需的变量,使它们也变得 自文档化。如果数据无效,将抛出异常。
原始类型
支持的标量类型包括: bool, float, int 和 string。
{% extends 'layout.twig' %}
{% expect 'string' as TITLE %}
{% expect 'bool' as ENABLED %}
{% expect 'float' as AMOUNT %}
{% expect 'int' as COUNT %}
注意:TITLE, ENABLED, AMOUNT 和 COUNT 代表所需变量的名称。
对象
由于它们不保证任何数据结构,匿名对象 (stdClass) 不受支持。然而,强烈建议使用命名类来在模板中公开数据。因此,也可以提供 完全限定类名 (FQCN)
{% expect 'App\\UI\\ViewModels\\Foo' as FOO %}
{{ FOO.bar }}
可为空
有时,您可能想确保一个变量已定义,同时通过使用 nullable 关键字使其可选
{% expect nullable 'App\\UI\\ViewModels\\Foo' as FOO %}
{% if FOO != null %}
...
{% endif %}
数组
您还可以使用 array of 关键字检查变量是否是给定类型的数组
{% expect array of 'App\\UI\\ViewModels\\Foo' as ARRAY %}
{% for foo in ARRAY %}
...
{% endfor %}
数组也可以是可为空的
{% expect nullable array of 'App\\UI\\ViewModels\\Foo' as ARRAY %}
{% if ARRAY != null %}
...
{% endif %}
或包含可为空的元素
{% expect array of nullable 'App\\UI\\ViewModels\\Foo' as ARRAY %}
{% for foo in ARRAY %}
{% if foo != null %}
...
{% endif %}
{% endfor %}
甚至可为空的元素数组!
{% expect nullable array of nullable 'App\\UI\\ViewModels\\Foo' as ARRAY %}
注意:检查数组项的类型可能会引起轻微的性能开销,但除非您有数千个元素,否则应该是可以忽略不计的。
2) 从任何模板注册全局数据
您有时可能需要在模板中声明特定的数据,用于全局范围。例如,如果您的模板动态地将CSS类添加到HTML body中,或者如果它们需要仅在需要时包含可选的CSS或JavaScript资源。
字符串数据
可以使用 {% register <data> in <registry> %} 标签从模板的任何地方注册简短字符串数据
// Page.twig
{% extends 'Layout.twig' %}
{% register 'has-menu' in 'bodyClasses' %}
{% register 'responsive' in 'bodyClasses' %}
{% register '/css/few-styles.css' in 'styles' %}
{% register '/css/some-styles.css' in 'styles' %}
{% register '/js/custom-scripts.js' in 'scripts' %}
...
并通过 registry() 函数在其他地方检索
// Layout.twig <html> <head> ... {% for css in registry('styles') %} <link rel="stylesheet" href="{{ css }}" /> {% endfor %} <!-- <link rel="stylesheet" href="/css/few-styles.css" /> --> <!-- <link rel="stylesheet" href="/css/some-styles.css" /> --> </head> <body class="{{ registry('bodyClasses')|join(' ') }}"> <!-- <body class="has-menu responsive"> --> ... {% for js in registry('scripts') %} <script src="{{ js }}"></script> {% endfor %} <!-- <script src="/js/custom-scripts.js"></script> --> </body> </html>
可选注册子句
为了方便,当数据表示 具有扩展名的路径 时,可以自动推断注册名称,因此使用 in <registry> 是可选的。以下行是等效的
{% register '/styles.css' in 'css' %}
{% register '/styles.css' %}
主体数据
由于您可能需要更长或动态生成的数据,该标签还支持块语法,允许提供内容主体。在这种情况下,您 不能 在打开标签中定义数据,并且 注册子句是强制性的: {% register in <registry> %} <body data> {% endregister %}
例如,如果您想从模板中声明内联脚本
// Page.twig
{% extends 'Layout.twig' %}
{% set name = 'world' %}
{% register in 'inlineJs' %}
alert('Hello {{ name }}');
{% endregister %}
并在HTML页面的末尾包含它
// Layout.twig <html> <body> ... <script> {% for js in registry('inlineJs') %} {{ js|raw }} {% endfor %} <!-- alert('Hello world'); --> </script> </body> </html>
唯一性
数据可以被声明为唯一的,所以如果多个模板注册相同的值,它只会被包含一次。这在大多数情况下都是必要的,只需在标签中添加once关键字即可。
{% register once '/styles.css' %}
// Subsequent identical statements will be ignored
{% register once '/styles.css' %}
它也适用于体数据。
{% register once '/styles.css' %}
{% register once in 'css' %}/styles.css{% register %} // ignored
然而,唯一性只在同一个注册范围内生效,因此以下两个语句都将被考虑。
{% register once '/styles.css' in 'css' %}
{% register once '/styles.css' in 'styles' %}
优先级
由于您无法总是预测数据将被注册的顺序,有时您需要确保某些数据首先注册,例如在其他脚本库中需要的情况。然后,在您的标签末尾添加priority关键字,后跟优先级数字(数值越小越优先*)。
没有优先级的标签总是排在优先级标签之后。
注意:具有相同优先级(或未定义)的数据的顺序没有保证。
{% register '/last.js' %}
{% register '/second.js' priority 2 %}
{% register '/first.js' priority 1 %}
<!-- <script src="/first.js"></script> -->
<!-- <script src="/second.js"></script> -->
<!-- <script src="/last.js"></script> -->
3) 在模板中实例化类
尽管在可能的情况下最好在控制器中执行,但您可能需要在模板中直接创建类实例。new(string $fqcn, ...$args)函数允许您调用给定类的构造函数。
{% include('Partials/Menu.twig') with {Menu: new('App\\UI\\Partials\\Menu',
'Main menu',
[
{Label: 'Item 1', Href: '/url/to/item1'},
{Label: 'Item 2', Href: '/url/to/item2'},
],
)} %}
以下是一个视图模型类
namespace App\UI\Partials; final class Menu { private string $name; private array $items; public function __construct(string $name, array $items) { $this->name = $name; $this->items = array_map(static fn($item) => new MenuItem($item), $items); } }
许可证
《Twig PowerPack》遵循MIT许可证。请参阅LICENSE文件。