Email 如何在symfony2中从数据库中呈现细枝模板
我正在处理用symfony2编写的应用程序,我想在一些行动/活动之后发送电子邮件。。。问题是,用户可以定义类似于“电子邮件模板”的东西,它存储在db中,类似于简单字符串,例如:“这是来自{{user}}的某封电子邮件”,我需要为该电子邮件呈现正文,该邮件应该使用该模板 在这个链接的symfony文档中:render view的方法是$this->renderView,它需要文件的路径,比如“bundle:controller:file.html.twig”,但我的模板是数据库中的简单字符串Email 如何在symfony2中从数据库中呈现细枝模板,email,symfony,render,twig,Email,Symfony,Render,Twig,我正在处理用symfony2编写的应用程序,我想在一些行动/活动之后发送电子邮件。。。问题是,用户可以定义类似于“电子邮件模板”的东西,它存储在db中,类似于简单字符串,例如:“这是来自{{user}}的某封电子邮件”,我需要为该电子邮件呈现正文,该邮件应该使用该模板 在这个链接的symfony文档中:render view的方法是$this->renderView,它需要文件的路径,比如“bundle:controller:file.html.twig”,但我的模板是数据库中的简单字符串 如何
如何渲染它?从Twig 1.10开始,Twig引擎不支持渲染字符串。但是有一个包可以添加这种行为,称为 它添加了
$this->get('twigstring')
服务,您可以使用该服务渲染字符串
(截至19年9月,Twig的当前版本为2.X,版本3即将发布;因此这只适用于Twig的非常旧的版本)。克隆本机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>
这应该行得通。将“Hello{{name}}”替换为模板文本,并使用所需的任何变量填充传递到呈现函数的数组
$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
"Hello {{ name }}",
array("name" => "World")
);
仅供参考,此功能将在的Twig核心中,但需要由开发人员激活。使用Symfony 2.2,您可以使用
最好的方法是使用
template\u from\u string
twig函数
{{ include(template_from_string("Hello {{ name }}")) }}
{{ include(template_from_string(page.template)) }}
看
查看为什么使用
细枝加载器链或细枝加载器字符串用于此目的不是一个好主意。细枝加载器字符串已被弃用,并且始终是为内部使用而设计的。强烈反对使用此加载程序
从API文档:
不得使用此加载程序。它只存在于细枝内部
目的。当将此加载程序与缓存机制一起使用时,您应该
知道每次模板内容更新时都会生成一个新的缓存密钥
“更改”(缓存键是模板的源代码)。如果
你不想看到你的缓存失控,你需要
请自行清除旧的缓存文件
另请查看此问题:
我所知道的从字符串源加载模板的最佳方法是:
从控制器:
如下所述:
从细枝模板:
如下所述:
请注意,“template_from_string”函数在默认情况下不可用,需要加载。在symfony中,您可以通过添加新服务来实现这一点:
# services.yml
services:
appbundle.twig.extension.string:
class: Twig_Extension_StringLoader
tags:
- { name: 'twig.extension' }
我最近不得不实现一个由多方使用的CMS,其中各方可以完全定制他们的模板。为了实现这一点,我实现了一个定制的细枝加载器
最困难的部分是为保证不与任何现有模板重叠的模板制定命名约定,例如!AppBundle:template.html.twig
。
如果模板未自定义,则必须将模板AppBundle:template.html.twig
作为回退模板加载
但是,这在链装入器(AFAIK)中是不可能的,因为无法修改模板名称。因此,我必须将默认加载程序(即加载程序链)注入到我的加载程序中,并使用它加载回退模板
另一种解决方案是将请求堆栈或会话传递给模板加载器,使其能够自动检测组织,但这很困难,因为安全组件依赖于模板子系统,导致循环依赖性问题。这里有一个与Symfony 4一起使用的解决方案(可能还有更老的版本,尽管我还没有测试过),它允许您使用存储在数据库中的模板,就像使用文件系统中的模板一样
这个答案假设您使用的是条令,但如果您使用的是另一个数据库库,则相对容易适应
创建模板实体
这是一个使用注释的示例类,但是您可以使用已经使用的任何配置方法
src/Entity/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;
}
<?php
namespace App\Twig\Loader;
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]);
}
}
该类相对简单。getTemplate
从数据库中查找模板文件名,其余方法使用getTemplate
实现Twig需要的接口
将DatabaseLoader添加到您的服务配置中
config/services.yaml
services:
App\Twig\Loader\DatabaseLoader:
tags:
- { name: twig.loader }
现在,您可以用与文件系统模板相同的方式使用数据库模板
从控制器渲染:
return$this->render('home.html.twig');
包括来自另一个细枝模板的内容(可以在数据库或文件系统中):
{{include('welcome.html.twig')}
呈现为字符串(其中$twig
是twig\Environment
的一个实例)
$html=$twig->render('email.html.twig')
在每种情况下,Twig都会首先检查数据库。如果DatabaseLoader
中的getTemplate
返回null,Twig会检查文件系统。如果数据库或文件系统中没有模板,Twig会抛出Twig\u错误\u加载程序
这对我有用:
$loader = new \Twig\Loader\ArrayLoader([
'Temp_File.html' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('Temp_File.html', ['name' => 'Fabien']);
$this->renderView()
应该返回一个简单的字符串。您是否尝试过返回“some_string”
,而不是返回$this->renderView()
,看看会发生什么?你应该看看这个捆绑包,它能准确地处理你想要的东西。自2011年以来,情况发生了变化。对于现在遇到这个问题的人,请阅读细枝文档中的相关配方:我同意,一个不使用边捆绑包的简洁解决方案。我认为这是最好的解决方案,也是最好的解决方案
<?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;
}
<?php
namespace App\Twig\Loader;
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]);
}
}
services:
App\Twig\Loader\DatabaseLoader:
tags:
- { name: twig.loader }
$loader = new \Twig\Loader\ArrayLoader([
'Temp_File.html' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('Temp_File.html', ['name' => 'Fabien']);