Home > Software design >  Rendering twig to html file, avoid duplicate code to add a variable
Rendering twig to html file, avoid duplicate code to add a variable

Time:10-26

Is there a better way to do this as I have duplicate code?

I have an email twig with a link to open the email in the browser.

Currently I'm having to render the template twice.

Once to get the content and save it to a html file in S3. The second time to add the S3 link to the sent email for viewing the email online.

$emailBody = $this->twig->render('EmailRo/incomplete-listing-moderation/accept-incomplete-listing.email.twig', [
    'user' => $admin,
    'avatar' => AmazonS3Service::URL_PREFIX.$admin->getPhoto(),
    's3html' => '',
]);
$s3 = $this->container->get('s3storage');

$fileName = rand(1000, 999999) . time() . '.html';
file_put_contents($fileName, $emailBody);

$file = $this->container->get('request_stack')->getCurrentRequest()->server->get('DOCUMENT_ROOT').'/'.$fileName;

$s3->upload('users/' . $fileName,
    file_get_contents($file),
    mime_content_type($file));
$s3html = AmazonS3Service::URL_PREFIX . 'emails/' . $fileName;

$emailBody = $this->twig->render('EmailRo/incomplete-listing-moderation/accept-incomplete-listing.email.twig', [
    'user' => $admin,
    'avatar' => AmazonS3Service::URL_PREFIX.$admin->getPhoto(),
    's3html' => $s3html,
]);

In the twig I render it like so

{% if s3html %}
<a href="{{ s3html }}" style="text-decoration: none;"><span style="font-family:'Montserrat','Arial','Helvetica', sans-serif !important; font-weight: normal; font-size:13px; line-height: 15px; color: #27AAE1; font-weight: 400;">
Email not displayed correctly? Read the online version in your browser.
</span></a>
{% endif %}

CodePudding user response:

IMO, I think you could be overcomplicating things for little benefit.

There is no big performance hit for rendering the template twice, those are cached in any case. I imagine the concern is mostly so the code is "neater" without unnecessary repetitions, which is fine but not a significant concern.

But if you want to avoid calling render() twice for the same template...

Just have a template that does not include the "read on a browser" bit, and render only that.

For the email version prepend the "read on a browser" link.

$htmlBody = $this->twig->render('EmailRo/incomplete-listing-moderation/accept-incomplete-listing.email.twig', [
    'user' => $admin,
    'avatar' => AmazonS3Service::URL_PREFIX.$admin->getPhoto(),
]);

// all the S3 logic, which returns an URL
$emailUrl = storeEmailHtmlSomewhere($emailBody);

$emailBody = <<< HTML
<a href="$emailUrl" style="text-decoration: none;"><span style="font-family:'Montserrat','Arial','Helvetica', sans-serif !important; font-weight: normal; font-size:13px; line-height: 15px; color: #27AAE1; font-weight: 400;">
Email not displayed correctly? Read the online version in your browser.
</span></a>

HTML;

// do what you need with that email
sendEmail($emailHeader . $emailBody);

Of you could simply store the two parts in different templates, if it comes to it, and concatenate the result when sending the email.


$emailHtmlBody = $this->twig->render('EmailRo/incomplete-listing-moderation/accept-incomplete-listing.email.twig', [
    'user' => $admin,
    'avatar' => AmazonS3Service::URL_PREFIX.$admin->getPhoto(),
]);

// all the S3 logic, which returns an URL
$emailUrl = storeEmailHtmlSomewhere($emailBody);

$emailHtmlHead = $this->twig->render('EmailRo/header-with-link.email.twig', [
    'emailUrl' => $emailUrl
]);

sendEmail($emailHtmlHead . $emailHtmlBody);

CodePudding user response:

You can use 3 templates instead of one: something like base_mail.html.twig with the main mail content, and two thin wrappers like email_s3.html.twig and email.html.twig where you give the base mail raw HTML as a parameter.

This would give something like this in the controller (not tested, sorry for typos):

$emailBase = $this->twig->render('base_mail.html.twig', [
    'user'   => $admin,
    'avatar' => AmazonS3Service::URL_PREFIX.$admin->getPhoto(),
]);

$emailBodyS3 = $this->twig->render('email_s3.html.twig', [
    'base'   => $emailBase,
    's3html' => /* ... */,
]);

// Handle $emailBodyS3 with S3

$emailBody = $this->twig->render('email.html.twig', [
    'base' => $emailBase,
]);

// Send the email with $emailBody

And the thin wrappers would look like this:

email.html.twig

<div>{{ base | raw }}</div>

email_s3.html.twig

<div>
    {{ base | raw }}
    <a href="{{ s3html }}" style="text-decoration: none;"><span style="font-family:'Montserrat','Arial','Helvetica', sans-serif !important; font-weight: normal; font-size:13px; line-height: 15px; color: #27AAE1; font-weight: 400;">
        Email not displayed correctly? Read the online version in your browser.
    </span></a>
</div>
  • Related