I'm trying to render twig template as variable, using symfony. I have a 'sendAction' Controller, which uses the mailgun API to send emails to one or more mailing lists. Here is my code for the Controller:
public function sendAction(Request $request, Newsletter $newsletter, MailgunManager $mailgunManager) {
$form = $this->createForm(SendForm::class);
$form->handleRequest($request);
$formData = array();
if ($form->isSubmitted() && $form->isValid()) {
$formData = $form->getData();
$mailingLists = $formData['mailingLists'];
foreach ($mailingLists as $list) {
$mailgunManager->sendMail($list->getAddress(), $newsletter->getSubject(), 'test', $newsletter->getHtmlContent());
return $this->render('webapp/newsletter/sent.html.twig');
}
}
return $this->render('webapp/newsletter/send.html.twig', array(
'newsletter' => $newsletter,
'form' => $form->createView()
));
}
}
And here's my sendMail (mailgun) function:
public function sendMail($mailingList, $subject, $textBody, $htmlBody) {
$mgClient = new Mailgun($this::APIKEY);
# Make the call to the client.
$mgClient->sendMessage($this::DOMAIN, array(
'from' => $this::SENDER,
'to' => $mailingList,
'subject' => $subject,
'text' => $textBody,
'html' => $htmlBody
));
}
I want my ' $newsletter->getHtmlContent()' to render template called 'newsletter.twig.html'. can anyone help me or point me in the right direction as to what I can do or Where I can find Tutorials or notes on what I am trying to do. the symfony documentation is quite vague.
You can use getContent() chained to your render function.
return $this->render('webapp/newsletter/send.html.twig', array(
'newsletter' => $newsletter,
'form' => $form->createView()
))->getContent();
Simply inject an instance of Symfony\Bundle\FrameworkBundle\Templating\EngineInterface into your action, and you’ll be able to use Twig directly:
public function sendAction(Request $request, EngineInterface $tplEngine, Newsletter $newsletter, MailgunManager $mailgunManager)
{
// ... other code
$html = $tplEngine->render('webapp/newsletter/send.html.twig', [
'newsletter' => $newsletter,
'form' => $form->createView()
]);
}
Note that $this->render() (in the controller action) will return an instance of Symfony\Component\HttpFoundation\Response, while $tplEngine->render() returns a HTML string.
Related
so I have a controller that essentially submits an edit of a category for approval by sending an email to the admin. This was fine before I decided to add in an actions table to store action history (e.g. category: edit).
The problem that's arose is that, by using entityManager to add data to the actions table, it's automatically updating the category entity due to the Event Watcher.
I tried a google and couldn't find anything on setting entityManager to one entity only.
This is my current controller:
<?php
namespace App\Controller\Category\Edit;
use App\Entity\Action;
use App\Entity\Category;
use App\Entity\User;
use App\Form\Category\EditCategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class EditController extends Controller
{
public function edit($id, Request $request, \Swift_Mailer $mailer)
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
$category = $this->getDoctrine()->getRepository(Category::class)->find($id);
$categoryGuru = $category->getGuru();
$guruName = $categoryGuru->getUsername();
$category->setGuru($categoryGuru);
$form = $this->createForm(EditCategoryType::class, $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$formData = $form->getData();
$name = $formData->getName();
$description = $formData->getDescription();
$newGuruId = $form['guru']->getData();
$newGuru = $this->getDoctrine()->getRepository(User::class)->find($newGuruId);
$actionId = $this->setAction();
$approveUrl = $category->getId();
$approveUrl .= '/'. $actionId;
$approveUrl .= '/'. $name;
$approveUrl .= '/'. $description;
$approveUrl .= '/'. $newGuru->getId();
$message = (new \Swift_Message('Category Edit Request - '. $category->getName()))
->setFrom('some#email.com')
->setTo('another#email.co.uk')
->setBody(
$this->renderView(
'emails/category/edit-request.html.twig',
array(
'category' => $category->getName(),
'category_new_name' => $name,
'description' => $category->getDescription(),
'category_new_description' => $description,
'guru' => $guruName,
'category_new_guru' => $newGuru->getUsername(),
'category_new_guru_id' => $newGuru->getId(),
'category_id' => $category->getId(),
'category_author' => $this->getUser()->getUsername(),
'approve_url' => $approveUrl,
'action_id' => $actionId
)
),
'text/html'
);
$mailer->send($message);
$this->addFlash('success', 'Category Edit Submitted for Review.');
return $this->redirectToRoute('category_list');
}
return $this->render(
'category/edit.html.twig',
array('form' => $form->createView(), 'category' => $category, 'guru' => $categoryGuru)
);
}
# this was originally a part of the above controller
# tried separating to see if it would work - didn't
public function setAction()
{
$action = new Action();
$entityManager = $this->getDoctrine()->getManager();
# set action data
$action->setDate(new \DateTime());
$action->setUserId($this->getUser()->getId());
$action->setDescription($this->getUser()->getUsername(). ' has edited a category');
$action->setStatus('pending');
$action->setType('Category: edit');
$entityManager->persist($action);
$entityManager->flush();
return $action->getId();
}
}
The answer I came to was, don't. Use the Repository class:
CategoryRepository.php
public function addAction($userId, $description, $status, $type)
{
$entityManager = $this->getEntityManager();
$connection = $entityManager->getConnection();
$date = date('Y-m-d H:i:s', strtotime('now'));
$connection->insert(
'action',
array(
'type' => $type,
'user_id' => $userId,
'date' => $date,
'description' => $description,
'status' => $status
)
);
return $entityManager->getConnection()->lastInsertId();
}
then call it in the controller - no longer classing entityManager issues.
I'm trying to save my ManyToMany relations between users and categories. Actually I'm trying to save my category with given users, but this doesn't work.
Form
$builder->add('name')
->add('users', EntityType::class, array(
'label' => 'Benutzer',
'class' => 'AppBundle\Entity\User',
'multiple' => true,
'expanded' => true,
'required' => false,
'choice_label' => function (User $user) {
return $user->getUsername();
}
))
->add('submit', SubmitType::class, array(
'label' => 'Speichern'
));
Form Handler
public function onSuccess(Request $request)
{
// Get category from form
$category = $this->getForm()->getData();
// Redirect to parent category when setted
if ($this->parent) {
$category->setParent($this->parent);
$response = new RedirectResponse($this->router->generate('categories.view', [
'category' => $this->parent->getId()
]));
} else {
// Build new redirect response
$response = new RedirectResponse($this->router->generate('categories.view', [
'category' => $category->getId()
]));
}
try {
// Save category in database
$this->em->merge($category);
$this->em->flush();
} catch (ORMException $ex) {
throw $ex;
}
return $response;
}
Maybe you have to unserialize the Entity $category first?
$detachedCategory = unserialize($category);
$this->em->merge($detachedCategory);
$this->em->flush();
I found this link regarding that:
How to manage deserialized entities with entity manager?
Not sure if that's the answer, but you might want to do more research.
I am building simple car renting app in Symfony for a programming class at my university.
On URL /search I show a form to user. Right now when the form is submitted user his /search again but different template is rendered
This is form code:
class SearchQueryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pickupCity', TextType::class)
->add('returnCity', TextType::class)
->add('pickupDateTime', DateTimeType::class, array(
'years' => range(2016,2017),
'error_bubbling' => true,
))
->add('returnDateTime', DateTimeType::class, array(
'years' => range(2016,2017),
'error_bubbling' => true,
))
->add('save', SubmitType::class, array(
'label' => 'Find Car',
'attr' => array(
'class' => 'btn-secondary btn-lg'
)))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SearchQuery',
));
}
}
And controller for this route:
class SearchController extends Controller
{
public function searchAction(Request $request)
{
$query = new SearchQuery();
$form = $this->createForm(SearchQueryType::class, $query);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/* Some logic here */
return $this->render('AppBundle:default:results.html.twig', array(
'form' => $form->createView()
));
}
return $this->render('AppBundle:default:search.html.twig', array(
'form' => $form->createView()
));
}
}
However when the form is submitted I want to redirect to URL /results?SUBMITTED-PARMS-HERE, so user can send this link to someone and receive the same results. On /results again I wand to render form, this time filled with search params submitted and below render available car.
I don't know if its the best way to handle this problem, current solution works but link can't be send to someone else.
EDIT:
I change the code to fallowing:
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$session = $this->get('session');
$session->set('pickupCity', $data->getPickupCity());
$session->set('returnCity', $data->getReturnCity());
$session->set('pickupDateTime', $data->getPickupDateTime());
$session->set('returnDateTime', $data->getReturnDateTime());
return $this->redirectToRoute('results', array(
'pickupCity' => $data->getPickupCity(),
'returnCity' => $data->getReturnCity(),
'pickupDate' => $data->getPickupDateTime()->format('d-m-Y-H-i'),
'returnDate' => $data->getReturnDateTime()->format('d-m-Y-H-i'),
), 301);
}
So as a result I receive URL ./results/Paris/Berlin/10-02-2016-10-00/17-02-2016-10-00
And in routing.yml:
results:
path: /results/{pickupCity}/{returnCity}/{pickupDate}/{returnDate}
defaults: { _controller: AppBundle:Search:result}
methods: [POST]
Because I only want to receive POST request on this route and now when I submit form I get error page saying:
No route found for "GET /results/Paris/Berling/01-07-2016-00-00/01-11-2016-00-00": Method Not Allowed (Allow: POST)
Any idea how to fix it?
EDIT 2:
Never mind, my reasoning was bad.
Not sure, but maybe using this example.
$this->redirect($this->generateUrl('default', array('pickupCity' => $pickupCity, 'returnCity' => $returnCity, 'pickupDateTime' => $pickupDateTimepickupDateTime)));
With your own parameter, which you can get where you put your comment
/* Some logic here */
You can use getQueryString() function.
Sample:
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirect('results?'.$request->getQueryString());
}
I have complete this: SF2 Handle File Uploads with Doctrin
Now I try to do multiple upload, but can't find newer tutorial for this. All what I found is like 2+ years old, and doesn't work.
Could someone help me with this problem?
I tried change $path, $file to array, and add foreach($this->file as $files) to upload() function, but .... error ....
Here is my code:
Entity: http://pastie.org/private/1qvkhcdhojm1n1orfzuja
Controller: http://pastie.org/private/ppcoezaoicdufg5dsa9dw
Twig: http://pastie.org/private/eclba9e84kzfbh96ecgya
PS: I need Something like this in path(in database): "image1.jpeg,image2.jpeg,image3.jpeg,..."
Sorry, but I'm so dumb with this, just learning..
Thank you
here is some pseudo example code showing how i access to the multiple uploaded files and persist an entity for each uploaded file
$form = $this->createForm('doc',null);
$request = $this->getRequest();
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
$data=$form->getData();
try {
$i=1;
// upload each file
foreach ($data['file'] as $item) {
$document = new Document();
$document->setFile($item);
// upload file
$document->upload();
$document->setUploadedBy($user->getUserName());
// set thumbnail path
$em->persist($document);
// generate images and set paths
$imageService->optiPathSingle($document);
$i++;
}
return $this->redirect($this->generateUrl('gleisdreieck_core_index'));
} catch (\Exception $e) {
$form->addError(new FormError($e->getMessage()));
}
}
return array(
"form"=>$form->createView(),
"tags"=>$tags
);
} else{
return array(
"form"=>$form->createView(),
"tags"=>$tags
);
}
used formbuilder:
class DocumentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('file', 'file', array(
'label' => 'Attachments',
'required' => true,
'attr' => array (
'accept' => 'image/*',
'multiple' => 'multiple'
)
))
->add('save', 'submit');
}
I have 2 entities:
class Exercise
{
//entity
}
and
class Question
{
//entity
}
Their relationship is ManyToMany.
The question is: How I can filter (on the exercise form) the Question entities?
I have this form for Exercise:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('questions', null, array(
'property' => 'name',
'multiple' => true,
'expanded' => false,
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('u')
->where('u.level = :level')
->setParameter('level',$options['level'])
->orderBy('u.dateR', 'ASC');},
))
//other fields
->add('Save','submit')
;
}
I know that I can filter with the query_builder but, how I can pass the var $search?
Should I create another form?
Any help would be appreciated.
Best regards
EDIT: I have found the solution that I want. I put 2 forms on the Controller Action, one form for the entity and one form for filter.
//ExerciseController.php
public function FormAction($level=null)
{
$request = $this->getRequest();
$exercise = new Exercise();
//Exercise form
$form = $this->createForm(new ExerciseType(), $exercise,array('level' => $level));
//create filter form
$filterForm = $this->createFormBuilder(null)
->add('level', 'choice', array('choices' => array('1' => '1','2' => '2','3' => '3')))
->add('filter','submit')
->getForm();
//Manage forms
if($request->getMethod() == 'POST'){
$form->bind($request);
$filterForm->bind($request);
//If exercise form is received, save it.
if ($form->isValid() && $form->get('Save')->isClicked()) {
$em = $this->getDoctrine()->getManager();
$em->persist($exercise);
$em->flush();
return $this->redirect($this->generateUrl('mybundle_exercise_id', array('id' => $exercise->getId())));
}
//If filter form is received, filter and call again the main form.
if ($filterForm->isValid()) {
$filterData = $formFiltro->getData();
$form = $this->createForm(new ExerciseType(), $exercise,array('level' => $filterData['level']));
return $this->render('MyBundle:Exercise:crear.html.twig', array(
'ejercicio' => $ejercicio,
'form' => $form->createView(),
'formFiltro' => $formFiltro->createView(),
));
}
}
return $this->render('juanluisromanCslmBundle:Ejercicio:form.html.twig', array(
'exercise' => $exercise,
'form' => $form->createView(),
'formFiltro' => $filterForm->createView(),
));
}
Templating the forms
On the form.html.twig
{{ form_start(filterForm) }}
{{ form_errors(filterForm) }}
{{ form_end(filterForm) }}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_end(form) }}
It works for me and it is that i was looking for.
What you probably want to do here, is to make use of the form builder:
$search = [...]
$form = $this->createForm(new AbstractType(), $bindedEntityOrNull, array(
'search' => $search,
));
here you can provide any list of arguments to the builder method of your AbstractType.
public function buildForm(FormBuilderInterface $builder, array $options)
as you may have guessed at this point you may access the options array throu the $option variable.
As a side note remember to provide a fallback inside the default option array. In your AbstractType you can do something like this:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'search' => 'some_valid_default_value_if_search_is_not_provided'
));
}
hope it helps, regards.