it-swarm.com.de

Wie man eine Twig-Vorlage aus der Datenbank in symfony2 rendert

Ich arbeite an einer Anwendung, die in symfony2 geschrieben wurde, und ich möchte eine E-Mail nach einer Aktion/einem Ereignis senden ... Das Problem ist, dass Benutzer so etwas wie "E-Mail-Vorlagen" definieren können, die in DB wie eine einfache Zeichenfolge gespeichert werden, zum Beispiel: "This ist eine E-Mail von {{user}} "und ich muss den Rumpf für E-Mails von dieser Vorlage darstellen ... In der Symfony-Dokumentation unter diesem Link: http://symfony.com/doc/2.0/ cookbook/email.html # sendende E-Mails Die Methode für das Rendern ist $ this-> renderView und erwartet einen Verweis auf die Datei als "bundle: controller: file.html.twig", aber meine Vorlage ist eine Datenbank als einfache Zeichenfolge. . Wie kann ich es rendern?

27
Karol Fiturski

Hier ist eine Lösung, die mit Symfony 4 (und möglicherweise auch älteren Versionen, obwohl ich sie noch nicht getestet habe) funktioniert und es Ihnen ermöglicht, mit in der Datenbank gespeicherten Vorlagen auf die gleiche Weise zu arbeiten, wie Sie mit Vorlagen im Dateisystem arbeiten würden.

Bei dieser Antwort wird davon ausgegangen, dass Sie Doctrine verwenden. Sie können jedoch relativ leicht angepasst werden, wenn Sie eine andere Datenbankbibliothek verwenden.

Erstellen Sie die Vorlagenentität

Dies ist eine Beispielklasse, die Annotationen verwendet. Sie können jedoch jede Konfigurationsmethode verwenden, die Sie bereits verwenden.

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;
}

Die absoluten Mindestfelder sind filename und source, aber es ist eine sehr gute Idee, last_updated einzufügen, da sonst die Vorteile des Zwischenspeichers verloren gehen.

Erstellen Sie eine DatabaseLoader-Klasse

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]);  
    }
}

Die Klasse ist relativ einfach. getTemplate sucht den Dateinamen der Vorlage in der Datenbank nach, und die übrigen Methoden verwenden getTemplate, um die von Twig benötigte Schnittstelle zu implementieren.

Fügen Sie den DatabaseLoader Ihrer Service-Konfiguration hinzu

config/services.yaml

services:
    App\Twig\Loader\DatabaseLoader:
        tags:
        - { name: twig.loader }

Jetzt können Sie Ihre Datenbankvorlagen genauso verwenden wie Dateisystemvorlagen.

Rendern von einem Controller:

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

Einschließlich einer anderen Twig-Vorlage (die sich in der Datenbank oder im Dateisystem befinden kann):

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

Rendern in einen String (wobei $twig eine Instanz von Twig\Environment ist)

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

In jedem dieser Fälle überprüft Twig zuerst die Datenbank. Wenn getTemplate in Ihrer DatabaseLoader den Wert null zurückgibt, überprüft Twig das Dateisystem. Wenn die Vorlage nicht in der Datenbank oder des Dateisystems verfügbar ist, gibt Twig einen Twig_Error_Loader aus.

5
Clamburger

Twig_Loader_String ist veraltet und wurde ohnehin immer für den internen Gebrauch konzipiert. Die Verwendung dieses Laders wird dringend empfohlen.

Aus dem API-Dokument:

Dieser Lader sollte NIEMALS verwendet werden. Es existiert nur für Twig-interne Zwecke. Wenn Sie diesen Loader mit einem Cache-Mechanismus verwenden, sollten Sie Wissen, dass jedes Mal ein neuer Cache-Schlüssel generiert wird, wenn sich ein Vorlageninhalt "Ändert" (der Cache-Schlüssel ist der Quellcode der Vorlage). Wenn Sie nicht möchten, dass Ihr Cache außer Kontrolle gerät, müssen Sie Die alte Cache-Datei selbst löschen.

Lesen Sie auch dieses Problem: https://github.com/symfony/symfony/issues/10865


Der beste Weg, eine Vorlage aus einer String-Quelle zu laden, ist:

Von einem Controller:

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

wie hier beschrieben: http://twig.sensiolabs.org/doc/recipes.html#loading-a-template-from-a-string

Aus einer Zweigvorlage:

{{ include(template_from_string("Hello {{ name }}", {'name' : 'Peter'})) }}

wie hier beschrieben: http://twig.sensiolabs.org/doc/functions/template_from_string.html

Beachten Sie, dass die Funktion 'template_from_string' standardmäßig nicht verfügbar ist und geladen werden muss. In symfony würden Sie dies tun, indem Sie einen neuen Dienst hinzufügen:

# services.yml
services:
    appbundle.twig.extension.string:
        class: Twig_Extension_StringLoader
        tags:
            - { name: 'twig.extension' }
27
Atan

Das sollte funktionieren. Ersetzen Sie "Hello {{name}}" durch Ihren Vorlagentext, und füllen Sie das Array, das an die Renderfunktion übergeben wird, mit den erforderlichen Variablen.

$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
  "Hello {{ name }}",
  array("name" => "World")
);
18
adavea

Klonen Sie den systemeigenen twig-Dienst und ersetzen Sie das Dateisystem-Loader durch das native Twig-String-Loader:

<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>

Anwendungsbeispiel innerhalb eines Controllers:

$this->get('my.twigstring')->render('Hello {{ name }}', array('name' => 'Fabien'));
10
Philipp Rieber

Das Twigengine unterstützt das Rendern von Strings nicht. Es ist jedoch ein Paket verfügbar, das dieses Verhalten mit dem Namen TwigstringBundle hinzufügt.

Es fügt den $this->get('twigstring')-Dienst hinzu, den Sie zum Rendern Ihrer Zeichenfolgen verwenden können.

8

Am besten verwenden Sie die template_from_string-Zweigfunktion.

{{ include(template_from_string("Hello {{ name }}")) }}
{{ include(template_from_string(page.template)) }}

Siehe Dokumentation von template_from_string

Sehen Sie, warum es nicht eine gute Idee ist, Twig_Loader_Chain oder Twig_Loader_String für diesen Zweck in dieser github-Ausgabe von stof zu verwenden.

6
Quentin
1
Juburin

Zu Ihrer Information, Diese Funktion war vorgeschlagen , um hinzugefügt im Kern von Twig ab 1.11.0 zu sein, muss aber vom Entwickler aktiviert werden.

0
yvoyer

Ich musste vor kurzem ein CMS implementieren, das von mehreren Parteien verwendet wurde, wobei jede Partei ihre Vorlagen vollständig anpassen konnte. Um dies zu erreichen, habe ich einen benutzerdefinierten Twig Loader implementiert.

Der schwierigste Teil war die Entwicklung einer Namenskonvention für die Vorlagen, die sich garantiert nicht mit vorhandenen Vorlagen überschneiden, beispielsweise <organisation_slug>!AppBundle:template.html.twig. Falls die Vorlage nicht angepasst wurde, müsste die Vorlage AppBundle:template.html.twig als Fallback-Vorlage geladen werden.

Dies ist jedoch beim Chain Loader (AFAIK) nicht möglich, da dort der Vorlagenname nicht geändert werden kann. Daher musste ich den Standardlader (d. H. Die Ladekette) in meinen Lader einspritzen und damit die Fallback-Vorlage laden.

Eine andere Lösung wäre, den Anforderungsstapel oder die Sitzung an das Vorlagenladeprogramm zu übergeben, wodurch die Organisation automatisch erkannt werden kann. Dies ist jedoch schwierig, da die Sicherheitskomponente vom Template-Subsystem abhängt und zirkuläre Abhängigkeitsprobleme verursacht.

0
MauganRa
0
me987654323