如何在symfony2中从数据库中呈现Twig模板

Kar*_*ski 30 email render symfony twig

我正在研究用symfony2编写的应用程序,我希望在一些动作/事件之后发送电子邮件...问题是,用户可以定义类似"电子邮件模板"的东西,它像db一样存储在db中,例如:"这个是来自{{user}}的一些电子邮件,我需要从该模板呈现电子邮件的正文...在此链接的symfony文档中:http://symfony.com/doc/2.0/cookbook/email.html#sending -emails用于渲染的方法是$ this-> renderView,它希望引用文件为"bundle:controller:file.html.twig",但我的模板是数据库作为简单字符串...我该如何渲染它?

Ata*_*tan 31

Twig_Loader_String已弃用,无论如何总是设计用于内部使用.强烈建议不要使用此加载程序.

从API文档:

永远不要使用这个装载机.它仅存在于Twig内部用途.当使用带有缓存机制的加载器时,您应该知道每次模板内容"更改"时生成新的缓存键(缓存键是模板的源代码).如果您不希望看到缓存失去控制,则需要自己清理旧的缓存文件.

另请查看此问题:https://github.com/symfony/symfony/issues/10865


我知道从String源加载模板的最佳方法是:

从控制器:

$template = $this->get('twig')->createTemplate('Hello {{ name }}');
$template->render(array('name'=>'World'));
Run Code Online (Sandbox Code Playgroud)

如下所述:http://twig.sensiolabs.org/doc/recipes.html#loading-a-template-from-a-string

从树枝模板:

{{ include(template_from_string("Hello {{ name }}", {'name' : 'Peter'})) }}
Run Code Online (Sandbox Code Playgroud)

如下所述:http://twig.sensiolabs.org/doc/functions/template_from_string.html

请注意,'template_from_string' - 函数默认情况下不可用,需要加载.在symfony中,您可以通过添加新服务来完成此操作:

# services.yml
services:
    appbundle.twig.extension.string:
        class: Twig_Extension_StringLoader
        tags:
            - { name: 'twig.extension' }
Run Code Online (Sandbox Code Playgroud)


ada*_*vea 20

这应该工作.将"Hello {{name}}"替换为模板文本,并使用您需要的任何变量填充传递给render函数的数组.

$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
  "Hello {{ name }}",
  array("name" => "World")
);
Run Code Online (Sandbox Code Playgroud)

  • 我已经阅读了Twig_Loader_String(已弃用)的评论,它将填满缓存...... (3认同)
  • 这有效.我注意到默认情况下不启用自定义树枝扩展.所以问题在这里:http://stackoverflow.com/questions/16383522/twig-extension-to-be-available-in-new-twig-environment (2认同)

Phi*_*ber 10

克隆本机twig服务并使用本机twig字符串加载器替换文件系统加载器:

<service id="my.twigstring" class="%twig.class%">
    <argument type="service" id="my.twigstring.loader" />
    <argument>%twig.options%</argument>
</service>        
<service id="my.twigstring.loader" class="Twig_Loader_String"></service>
Run Code Online (Sandbox Code Playgroud)

控制器内的用法示例:

$this->get('my.twigstring')->render('Hello {{ name }}', array('name' => 'Fabien'));
Run Code Online (Sandbox Code Playgroud)


Kri*_*van 8

Twigengine不支持渲染字符串.但是有一个捆绑可用,它添加了一个名为TwigstringBundle的行为.

它添加了$this->get('twigstring')可用于渲染字符串的服务.


Cla*_*ger 8

这是一个适用于Symfony 4的解决方案(也可能是旧版本,虽然我还没有测试过),并允许您使用存储在数据库中的模板,就像使用文件系统中的模板一样.

这个答案假设您正在使用Doctrine,但如果您正在使用另一个数据库库,则相对容易适应.

创建模板实体

这是一个使用注释的示例类,但您可以使用您已经使用的任何配置方法.

SRC /实体/的template.php

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="templates")
 * @ORM\Entity
 */
class Template
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string", nullable=false)
     */
    private $filename;

    /**
     * @var string
     *
     * @ORM\Column(type="text", nullable=false)
     */
    private $source;

    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime", nullable=false)
     */
    private $last_updated;
}
Run Code Online (Sandbox Code Playgroud)

最基本的字段是filenamesource,但是包含它是一个非常好的主意,last_updated否则你将失去缓存的好处.

创建DatabaseLoader类

SRC /枝条/装载机/ DatabaseLoader.php

<?php
namespace App\Twig;

use App\Entity\Template;
use Doctrine\ORM\EntityManagerInterface;
use Twig_Error_Loader;
use Twig_LoaderInterface;
use Twig_Source;

class DatabaseLoader implements Twig_LoaderInterface
{
    protected $repo;

    public function __construct(EntityManagerInterface $em)
    {
        $this->repo = $em->getRepository(Template::class);
    }

    public function getSourceContext($name)
    {
        if (false === $template = $this->getTemplate($name)) {
            throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
        }

        return new Twig_Source($template->getSource(), $name);
    }

    public function exists($name)
    {
        return (bool)$this->getTemplate($name);
    }

    public function getCacheKey($name)
    {
        return $name;
    }

    public function isFresh($name, $time)
    {
        if (false === $template = $this->getTemplate($name)) {
            return false;
        }

        return $template->getLastUpdated()->getTimestamp() <= $time;
    }

    /**
     * @param $name
     * @return Template|null
     */
    protected function getTemplate($name)
    {
        return $this->repo->findOneBy(['filename' => $name]);  
    }
}
Run Code Online (Sandbox Code Playgroud)

这堂课比较简单.getTemplate从数据库中查找模板文件名,其余方法用于getTemplate实现Twig所需的接口.

将DatabaseLoader添加到服务配置中

配置/ services.yaml

services:
    App\Twig\Loader\DatabaseLoader:
        tags:
        - { name: twig.loader }
Run Code Online (Sandbox Code Playgroud)

现在,您可以像使用文件系统模板一样使用数据库模板.

从控制器渲染:

return $this->render('home.html.twig');

包括来自另一个Twig模板(可以在数据库或文件系统中):

{{ include('welcome.html.twig') }}

渲染到字符串(其中$twig是一个实例Twig\Environment)

$html = $twig->render('email.html.twig')

在每种情况下,Twig将首先检查数据库.如果getTemplate在你的DatabaseLoader返回null中,Twig将检查文件系统.如果模板在数据库文件系统中不可用,Twig将抛出一个Twig_Error_Loader.


Que*_*tin 6

最好的方法是使用template_from_string树枝功能.

{{ include(template_from_string("Hello {{ name }}")) }}
{{ include(template_from_string(page.template)) }}
Run Code Online (Sandbox Code Playgroud)

参见文档template_from_string

看看为什么在stof这个github问题上使用或出于那个目的不是一个好主意.Twig_Loader_ChainTwig_Loader_String