如何使用现有的 PHP header 生成 class 函数来填充树枝模板

How to use existing PHP header generation class function to populate a twig template

在现有的应用程序中,有一个使用classes动态生成header的函数。

 use GLOBALNAMESPACE\Core\Header;

然后在body中,我们使用

<header>
  <title>My Page</title>
    <?php Header::setupHeader('[common],[reporthelper]') ?>
</header>

当页面在浏览器中呈现时,这将像这样构建所有 header。

<header>
    <title>My Page</title> 

 <link rel="stylesheet" href="/openemr/public/assets/bootstrap/dist/css/bootstrap.min.css?v=44" type="text/css">
 <link rel="stylesheet" href="/openemr/public/assets/font-awesome/css/font-awesome.min.css?v=44" type="text/css">
 <link rel="stylesheet" href="/openemr/public/assets/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v=44" type="text/css">

 <script type="text/javascript" src="/openemr/public/assets/jquery/dist/jquery.min.js?v=44"</script>

在我的模板文件中,我试过了。

{%  
     include GLOBALNAMESPACE\Core\Header::setupHeader('[common],[reporthelper]')
 %}

这失败了。有没有办法包含 PHP classes?

更新:

按照建议,在 twig 目录中创建了 HeaderExtension class。

Twig\HeaderExtension

文件里面是这段代码:

 namespace Twig;

 use Twig\Extension\AbstractExtension;

class HeaderExtension extends AbstractExtension
{
public function getFunctions() {
    return [
        new TwigFunction(
            'header_setup',
            [OpenEMR\Core\Header::class, 'Header']
        ),
        // add more if needed
    ];
  }
}

在方法中添加

    $loader = new FilesystemLoader('../../templates/financialreports/insurance');
    $twig = new Environment($loader, [
        'cache' => 'C:\tempt',
    ]);

    return $twig->render('summaryinsurancepaid.html.twig', [
    'header' => new HeaderExtension(),
    'name' => 'Fabien Roger']);

现在,没有任何错误消息。然而,没有达到预期的结果。 似乎缺少对 setupHeader() 的调用。 在新的 TwigFunction 中,'header_setup' 被定义为在全局命名空间中调用到 header 的 class。 但是没有任何东西调用 class 方法 setupHeader(),我可以在其中添加数组 setupHeader(['common'],['reporthelper'])。传入数组将返回所需的结果。

在此页面的示例中 https://symfony.com/doc/current/templating/twig_extension.html

他们使用 TwigFilter 而不是 TwigFunction 在运行时引入 class。 我改变了这一行,从这个

 'header' => new HeaderExtension()

到此。

 'header' => new HeaderExtension('header_setup'),

没有错误,但也没有 header。所以,我改变了这个模板。

{{ header }}

为此:

{{ header(setupHeader(['common'],['reporthelper'])) }}

没有错误消息,也没有 header。 更新结束。

根据您的 Header 确实提供的逻辑 - 特别是关于它创建的输出 - 有不同的方法:

通过 twig 函数公开 select Header 方法

namespace App\Twig;

class HeaderExtension extends \Twig\Extension\AbstractExtension {
    public function getFunctions() {
        return [
            new \Twig\TwigFunction(
                'header_setup', 
                [GLOBALNAMESPACE\Core\Header::class, 'setupAssets']
            ),
            // add more if needed
        ];
    }
}

然后在您的模板中将其用作

{{ header_setup('[common],[reporthelper]') }}

通过一个 twig 函数公开 Header 的静态函数

一个轻微的解决方法可能是另一种方法,与以前几乎相同的 TwigFunction,但使用:

new \Twig\TwigFunction('header', function($func, ...$args) {
    return call_user_func_array([GLOBALNAMESPACE\Core\Header::class, $func], $args);
}

然后将允许:

{{ header('setupAssets', '[common],[reporthelper]') }}

这显然是一种更奇怪的语法。你可以更进一步

公开所有 class/instance 函数

new \Twig\TwigFunction('call', function($class, $func, ...$args) {
    return call_user_func_array([$class, $func], $args);
}

然后用作:

{{ call('GLOBALNAMESPACE\Core\Header', 'setupAssets', '[common],[reporthelper]') }}

(如果有人能够编辑模板,这显然会增加安全风险,因为现在您可以在任何地方调用所有静态函数...)

Header 改写成更漂亮的东西

我假设 Header 的一些功能(如果不是全部的话)是非常基本的,并且可以表示为树枝模板本身,例如 ...

{% set targets = targets ?? ['common'] %}{# <-- defaults for every template? #}
{% if 'common' in targets %}
 <link rel="stylesheet" href="/openemr/public/assets/bootstrap/dist/css/bootstrap.min.css?v=44" type="text/css">
 <link rel="stylesheet" href="/openemr/public/assets/font-awesome/css/font-awesome.min.css?v=44" type="text/css">
 <link rel="stylesheet" href="/openemr/public/assets/jquery-datetimepicker/build/jquery.datetimepicker.min.css?v=44" type="text/css">

 <script type="text/javascript" src="/openemr/public/assets/jquery/dist/jquery.min.js?v=44"></script> 
{% endif %}
{% if 'reporthelper' in targets %}
 <script type="text/javascript" src="/openemr/public/assets/reporthelper/..."></script>
{% endif %}

等等。但是,我很确定您正在寻找的功能是否可以通过 webpack encore

获得

更新:如何将 twig 扩展添加到您的 symfony 项目并使用它

假设您不只是使用 symfony 组件(在这种情况下以下内容将不适用),有几种方法可以实现:

1.实际上延长了树枝

通过 adding twig.extension to your service(即您的 twig 扩展)在 symfony 中扩展 twig,因此,在您的服务 yaml 中(注意根据需要将缩进与空格匹配):

services:
    App\Twig\HeaderExtension:
        tags: ['twig.extension']

如果你不想让这个扩展全局可用,你可以使用 symfony 的依赖注入来获取 twig 服务并添加扩展

public function yourRouteAction(
    \Twig\Environment $twig
    /* your other parameters */
) {
    $twig->addExtension(new HeaderExtension());

    // don't *have* to use $twig here, symfony provides the very
    // same twig environment wherever it's referenced. this is not true
    // if you create one on the fly with new Twig...
    return $this->render(...); 

明确一点:添加扩展提供了 twig 中的功能,您根本不必在渲染调用中添加它!

2。修复你的扩展/使用

现在您实际上添加了扩展 作为扩展 而不是每次都必须手动添加的变量,将有一个可用的函数:

{{ header_setup(...) }}

正如我已经写过的,您必须提供一个可调用对象作为 TwigFunction 构造函数的第二个参数。由于上次您更改了您想打电话的内容,所以我更新了我的答案。可调用的结构是:[classname, functionname] 用于静态调用,因此在您的情况下:[Header::class, 'setupAssets']。这意味着,你在 in twig 中的调用是

{{ header_setup(a) }} {{ header_setup(b,c,d) }} {{ header_setup([e,f]) }}

这将转化为

Header::setupAssets(a) // and
Header::setupAssets(b,c,d) // and
Header::setupAssets([e,f])

分别。

这还假定您的 Header::setupAssets() returns 文本,以便将其插入正确的位置。我不太确定 twigs 如何回显东西,但是如果您的 Header 立即回显所有内容而不是像您的代码建议的那样返回它,您可能必须使用输出缓冲来捕获它:

        new \Twig\TwigFunction(
            'header_setup', 
            function(...$args) {
                ob_start();
                call_user_func_array(
                   [GLOBALNAMESPACE\Core\Header::class, 'setupAssets'],
                   $args
                ); // if Header::setupAssets echoes directly, it will be caught
                return ob_get_clean(); // returns caught stuff
            }
        ),