Вот решение, которое работает с Symfony 4 (и, возможно, также с более старыми версиями, хотя я его не тестировал) и позволяет вам работать с шаблонами, хранящимися в базе данных, так же, как вы работали бы с шаблонами в файловой системе.
В этом ответе предполагается, что вы используете Doctrine, но его относительно легко адаптировать, если вы используете другую библиотеку базы данных.
Создайте сущность Template
Это примеркласс, который использует аннотации, но вы можете использовать любой метод конфигурации, который вы уже используете.
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;
}
Поля минимального заполненияfilename
и source
, но стоит включить last_updated
, иначе вы потеряете преимущества кэширования.
Создайте класс DatabaseLoader
src/Twig/Loader/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]);
}
}
Класс относительно прост.getTemplate
ищет имя файла шаблона в базе данных, а остальные методы используют getTemplate
для реализации интерфейса, который необходим Twig.
Добавьте DatabaseLoader в конфигурацию вашей службы
config / services.yaml
services:
App\Twig\Loader\DatabaseLoader:
tags:
- { name: twig.loader }
Теперь вы можете использовать шаблоны базы данных так же, как шаблоны файловой системы.
Рендеринг с контроллера:
return $this->render('home.html.twig');
В том числе из другого шаблона Twig (который может находиться в базе данных или файловой системе):
{{ include('welcome.html.twig') }}
Отображение в строку (где $twig
является экземпляром Twig\Environment
)
$html = $twig->render('email.html.twig')
В каждом из этих случаев Twig будет проверятьбаза данных в первую очередь.Если getTemplate
в вашем DatabaseLoader
вернет ноль, Twig проверит файловую систему.Если шаблон недоступен в базе данных или файловой системы, Twig выдаст Twig_Error_Loader
.