Swiftmailer//Twig email not rendering correctly - symfony

I'm experimenting with symfony2 framework and i'm trying to send emails using swiftmailer and twig. The problem is, with my current implementation, the email is sent in html (you can see the tags, everything).
Here is the controller i'm using:
public function formularioAction()
{
$enquiry = new Enquiry();
$form = $this->createForm(new EnquiryType(), $enquiry);
$request = $this->getRequest();
if($request->getMethod() == 'POST'){
$form->bindRequest($request);
if($form->isValid()){
$message = \Swift_Message::newInstance()
->setSubject('Mail from the App')
->setFrom('no-reply#app.com')
->setTo('******#gmail.com')
->setBody($this->render( 'AcmeDemoBundle:Demo:email.html.twig' ));
$this->get('mailer')->send($message);
//end of mail sending
//redirect - it's important to prevent users from reposting the form if
//they refresh the page
return $this->redirect($this->generateUrl( '_formulario'));
}
}
return $this->render('AcmeDemoBundle:Demo:formulario.html.twig', array('form' => $form->createView()));
}
And the twig template the email is using:
{% extends "AcmeDemoBundle::layout.html.twig" %}
{% block title "Email de teste" %}
{% block content%}
<H1>Este é um render de um email de teste!</H1>
{% endblock%}
What am i doing wrong?

You have to specify the Content-type of the body, by calling the setBody() method like this.
$message->setBody($messageBody, 'text/html');
For more information, see: http://swiftmailer.org/docs/messages.html#setting-the-body-content

Related

Symfony render controller

want to display a form in a modal in the header. In order to make the form work I call the controller Homecontroller.
I called the controller with render controller in the branch but I got a blank page.
Thanks for your help.
header.html.Twig
<h1 class="fw-bold"></h1>
<p class="lead fw-bold"></p>
{{include ('fragments/modal_form.html.twig') }}
</main>
</div>
</div>
modal_form.html.twig
{{ render(controller(
'App\\Controller\\HomeController::index',{'form' : form.createForm()} )) }}
</div>
Controller :
* #Route("/", name="home")
*/
public function index(PostsRepository $postsRepository,TagRepository $tagRepository, Request $request ):Response
{
$listTag = $tagRepository->findAll();
$listPost = $postsRepository->findByPostPHp('php');
$posts = $postsRepository->findByExampleField($value = 6);
$partage = New Posts();
$form = $this->createForm(PartagePostType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$partage = $form->getData();
$this->entityManager->persist($partage);
$this->entityManager->flush();
$this->addFlash('success', 'Votre post a bien été partagé');
}
return $this->render('home/index.html.twig', [
'posts' => $posts,
'tag' => $listTag,
'listPost' => $listPost,
'form' => $form->createView(),
]);
}
I dont' really get how you are trying to render you form but it doesn't work that way, in your modal_form.html.twig you should use the {{ form_start() }} and {{ form_end() }} twig helpers. They take in parameters the created view of the form, i.e, the variable "form" in your case (created in your render with the createView() method).
It should look like that:
{{ form_start(form}}
{{ form_row(form.field) }}
<input type="submit" value="submit">
{{ form_end(form) }}
"field" is whatever name you defined in your FormType. Notice how I added raw HTML for the submit button, it is suggested by Symfony you add the send button that way, even though you can add it in your FormType.
You can learn more about form rendering here : How to Customize Form Rendering
And forms in general there : Forms
Last thing, if you want to use multiple forms with this modal, don't forget to change the name of the variable (also don't forget to add this variable in your controller when you render a template with a form in it, obviously)

symfony form handling subcontroller

I have a working contactform, which allows the user to send a e-mail to me and additionally gets a confirmation mail.
I would like to add a confirmation message to the page, so the user is sure the message was sent.
default.html.twig
<div>
{% include 'includes/overview.html.twig' %}
{% include 'includes/service.html.twig' %}
{% include 'includes/offer.html.twig' %}
{% include 'includes/aboutus.html.twig' %}
{% include 'Advanced/contactForm.html.twig' %}
</div>
contactForm.html.twig
<div class="col-lg-6 col-md-6 contactfrom nopadding">
{# request has to go further to the contactCormController -> {'request' : app.request} #}
{{ render(controller('AppBundle\\Controller\\ContactFormController::contactForm', {'request' : app.request})) }}
</div>
ContactController.php
public function contactForm(Request $request, \Swift_Mailer $mailer)
{
$contactForm = new ContactForm();
$form = $this->createForm(ContactFormType::class, $contactForm);
$form->handleRequest($request);
if ($form->isSubmitted()){ //&& $form->isValid()
$message = (new \Swift_Message)
->setFrom($contactForm->getEmail())
->setTo('mail')
->setSubject("Kontaktformular - ". $contactForm->getFirstname() ." ". $contactForm->getLastname())
->setBody($contactForm->getMessage())
;
if ($contactForm->getHonigtopfRoboter() == "") {
try {
// Sending message to the Host
// Sending confirmation message to the user
$mailer->send($message);
$this->confirmationMail($mailer, $contactForm->getEmail());
// empty ContactForm
unset($contactForm);
unset($form);
$contactForm = new ContactForm();
$form = $this->createForm(ContactFormType::class, $contactForm);
// add succes flashmessage
// $this->addFlash('success', 'message');
}
catch (\Swift_TransportException $Ste){
//TODO: Exception Handling
//echo $Ste->getMessage();
// add error flashmessage
// $this->addFlash('danger', 'message');
}
}
else{
}
}
$contactFormEntity = $form->getData();
return $this->render('form/contactForm.html.twig',
['contactform' => $form->createView()
]);
}
The most common solution I found was to use "flash message", sadly flash messages only work, if you redirect to a new page. Due to the fact, that my contact form stays on the same page it does not work.
My form is embedded and rendered in a sub-html.twig page, so I have the problem to get the information to my ContentController.php and further to the page.
I am really stuck and don't really know the best workflow for this scenario. How do i handle the submit and:
Success -> empty contact form -> success message on page
Error -> leave contact form -> error message on page
Thanks for your help.
If your form is valid, you should redirect the user after the form submission
public function contactForm(Request $request, \Swift_Mailer $mailer)
{
$form = ...
if ($form->isSubmitted() && $form->isValid()) {
$message = ...
$mailer->send($message);
$this->addFlash('success', 'Wohoo, we got it!');
return $this->redirectToRoute('app_contact_form');
}
return $this->render('form/contactForm.html.twig', ['contactform' => $form->createView()]);
}
Doing this, you don't need to empty the form like you do and then re-create it. And as the user is redirected, he will see the flash message.
Also, always check if the form is valid !

Can't send a variable to twig in order to send an email

I want to send an confirmation email, but I can't send the variable of my form to my email
Here's my code
if($form->isValid() && $form->isSubmitted()) {
$NewsLetters = $form->getData();
if(!$NewsLetters->getNom()) {
$NewsLetters->setNom("Anonyme");
}
$em->persist($NewsLetters);
$em->flush();
$nom = $NewsLetters->getNom();
$message = (new \Swift_Message('Confirmation d\'inscription à la newsletter'))
->setFrom('ez#zezezezeeze.fr')
->setTo($NewsLetters->getEmail())
->setBody(
$this->renderView('emails/confirmationEmail.html.twig'),
array('nom' => $nom, //HERE
),
'text/html'
);
$this->get('mailer')->send($message);
But twig give me this error
Variable "nom" does not exist in emails\confirmationEmail.html.twig at line 4.
<html>
<body>
Vous avez été inscrit avec succès à la Newsletter : {{ nom }}
{#{{ newsletterWebsite }} {{ newsletterStylo }} {{ newsletterCrayon }}#}
</body>
</html>
Normally it's work
Thanks for your help !
Seems a problem of wrong indentation: the array with params should be passed as second argument of the renderView method as follow:
$message = (new \Swift_Message('Confirmation d\'inscription à la newsletter'))
->setFrom('ez#zezezezeeze.fr')
->setTo($NewsLetters->getEmail())
->setBody(
$this->renderView(
'emails/confirmationEmail.html.twig',
array('nom' => $nom),
), // close renderView
'text/html'
); // close setBody
Hope this help

symfony trying to export a csv file from a link

I have this function in the controller, that returns a form with a select box. When the values are selected, I retrieve them with
$manifestations = $form['manifestations']->getData();
then put them in a repository function that queries the database $invites = $repository->searchInviteByManif($manifestations);
public function indexAction() {
$entity = new Invite();
$form = $this->createForm(new ManifSearchType(), $entity);
$request = $this->get('request');
$invites = null;
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
$message = '';
$manifestations = $form['manifestations']->getData();
$repository = $this->getDoctrine()
->getManager()
->getRepository('PrifProtocoleBundle:Invite');
$invites = $repository->searchInviteByManif($manifestations);
$response1 = $this->render('PrifProtocoleBundle:Invite:index.html.twig', array(
'form' => $form->createView(),
'entities' => $invites,
'message' => $message,
));
return $response1;
}
return array(
'form' => $form->createView(),
'entities' => $invites,
);
}
This function then returns a view index.html.twig with a table and all the fields found in the db.
What I want is to export all the queried data $invites in a CSV file, by clicking on a link directly from the HTML table.
So I've put an href="" link in the Twig file,
{% if message is defined %}
<div class="pdf">
<img height="40px" width="40px" src={{ asset('bundles/prifprotocole/images/excel.jpg') }}>
{% for entity in entities %}
<tr class="{{ cycle(['odd', 'even'], loop.index0) }}">
<td>{% if entity.etat == 1 %} Actif {% else %} Inactif {% endif %}</td>
<td>{{ entity.titreGrade }} {{ entity.prenom }} {{ entity.nom }}</td>
<td>{{ entity.fonction }}</td>
This is how I use to export the CSV file without the link :
$response2 = $this->render('PrifProtocoleBundle:Invite:export.csv.twig', array(
'entities' => $invites));
$response2->headers->set('Content-Type', 'text/csv');
$csvfile = $response2->headers->set('Content-Disposition', 'attachment; filename="export.csv"');
return $csvfile;
export.csv.twig file
{% for entity in entities %}
Id {{ entity.id }};
Etat {{ entity.etat }};
Titregrade {{ entity.titreGrade }};
Prenom {{ entity.prenom }};
Nom {{ entity.nom }};
Fonction {{ entity.fonction }};
{% endfor %}
Can someone give me a detailed solution on how to perform this? Much thanks!
You should simply pass the filter criterias, here the $manifestations array as a route parameter, by serializing it first.
Then, you should put a controller like downloadCsvAction() handling this route, querying the $invites from the database, and rendering your export.csv.twig template.
Another option, if you cannot serialize the data in URI, is to create a form with hidden fields containing the data. Then you replace the download link with the submit button of this hidden form.
Guillaume's answer is great if you don't mind fetching your data twice. Once when you display your page, and then when you download the CSV. Another way to do this is to cache the answer. I will give an example using memcache (which is what I use).
First, make sure that memcache is active in your php.ini.
Then before rendering your first page (after fetching the data), cache it:
$key = "csv.$userId";
$memcache = new \Memcache();
$memcache->connect($yourServerHost, $yourServerPort);
$memcache->set($key, json_encode($invites), MEMCACHE_COMPRESSED, 86400); // 24h
The trick is to find a good key, to add your report to the cache, and then be able to retrieve it. It has to be unique. Here, I assume that you have a user that is logged in, and I use the user ID to create a key. If that is not the case, you could create yourself a token, and pass it when rendering the page (along with $invites). This way, you can add the token to the URL to generate the CSV.
Then, in your second action, where you download the CSV, you just fetch the cached data:
$memcache = new \Memcache();
$memcache->connect($yourServerHost, $yourServerPort);
$json = $memcache->get($key);
$invites = json_decode($json , true);
That's it. You should probably create yourself a service for Memcache, so you don't have to create an object, and connect everytime.

How to get params in twig file

how can i use $_GET params in TWIG file like using PHP and alerting with JS.
URI-> ?comment=added...
in TWIG,
if($_GET['comment'] == "added"){
...echo '<script>alert("in TWIG file!");</script>';
}
hope it will help you
{% if app.request.get('comment') == "added" %}
<script>alert("in TWIG file!");</script>
{% endif %}
Depending on what you're really trying to achieve, the "Symfony way" of showing confirmation messages would be to use "Flash Messages":
YourController.php:
public function updateAction()
{
$form = $this->createForm(...);
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
// do some sort of processing
$this->get('session')->getFlashBag()->add(
'notice',
'Your changes were saved!'
);
return $this->redirect($this->generateUrl(...));
}
return $this->render(...);
}
Your TwigTemplate.twig:
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="flash-notice">
{{ flashMessage }}
</div>
{% endfor %}
This way you have multiple advantages:
Redirecting after action prevents form reloading.
Message cannot be triggered from outside.
Flash messages are only fetched once.
See the official documentation on this topic.
The "correct" solution would be use your controller to provide a function to Twig rather than switching on the querystring. This will be more robust and provide better security:
Controller:
function someAction()
{
$params = array('added' => false);
if( /* form logic post */ )
{
//some logic to define 'added'
$params['added'] = true;
}
$this->render('template_name', $params);
}
view:
{% if added %}
<script>alert('added');</script>
{% endif %}
The reasoning is that this is more secure (I can't trigger the alert by just browsing to the url), it maintains all business logic in the controller and you're also able to handle any errors - e.g. if you browse to foo.php?comment=added and there is an error wherein your comment isn't added, the user will still receive the alert.

Resources