I have a controller action that returns a form to the view. When the form is submitted, the validation of this form needs to be done in a different action than the action returning the form.
This is a sample of the action that returns the form
/**
* #Route("/AjaxAddQuestionForm/{section}")
* #Template
* #ParamConverter("section", class="AppBundle:Section")
*/
public function ajaxAddQuestionFormAction(Request $request, $section)
{
$question = new Question();
$question->setSection($section);
$addQuestionForm = $this->createForm(new AddQuestionType(), $question);
return array(
'section' => $section,
'addAjaxQuestionForm' => $addQuestionForm->createView(),
);
}
And this is the action in which I am currently trying to get the validation to work.
/**
* #Route("/edit/{form}")
* #Template()
* #ParamConverter("form", class="AppBundle:Form")
*/
public function editAction(Request $request, $form)
{
$em = $this->getDoctrine()->getManager();
(...)
$questionForm = new Question();
$addQuestionForm = $this->createForm(new AddQuestionType(), $questionForm);
$addQuestionForm->handleRequest($request);
if ($addQuestionForm->isValid()) {
$em->persist($questionForm);
$em->flush();
return $this->redirectToRoute('app_form_edit', array('form' => $form_id));
}
(...)
The problem is that the validation in the second action is never called. Any idea on how I can get this working?
You should add form action if you want validate form on other url:
In ajaxAddQuestionFormAction:
$addQuestionForm = $this->createForm(new AddQuestionType(), $question,
array(
'action' => $this->generateUrl('edit_form')
));
edit action route:
*#Route("/edit", name="edit_form")
Related
I have the following controller method which creates a new Category entity and persists it to the database:
/**
* #param Request $request
*
* #return array
*
* #Route("/admin/category/new", name="_admin_category_new")
* #Method({"GET", "POST"})
* #Template("Admin/category_new.html.twig")
*/
public function newCategoryAction(Request $request)
{
$category = new Category();
$form = $this->createForm(CategoryType::class, $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($category);
if (!$category->getSlug()) {
$category->setSlug();
}
if ($category->getFile() != null) {
$um = $this->get('stof_doctrine_extensions.uploadable.manager');
$um->markEntityToUpload($category, $category->getFile());
}
$em->flush();
$this->addFlash('success', 'Category successfully created');
$this->redirect($this->generateUrl('_admin_category', array('page' => 1)));
}
return array('form' => $form->createView());
}
Upon successful completion, it's supposed to redirect the user to a different URL. Instead, it just re-displays the current page/form. Any ideas? The route _admin_category does exist, and it is working:
$ bin/console debug:router
...
_admin_category GET ANY ANY /admin/category/{page}
...
And my Category entities are being saved to the DB properly.
You should return redirect response try
return $this->redirectToRoute('_admin_category', ['page' => 1]);
Redirect method creates an object of RedirectResponse class, and it needs to be returned as response. Moreover, you don't have to use redirect + generateUrl you can just use redirectToRoute method which is shortcut for that.
Also I'd suggest wrapping flush with try/catch
For more see docs
I have made a form created after an Ajax request (after the first form (Test1Type) is submitted)
public function indexAction(Request $request): Response
{
$form = $this->createForm(Test1Type::class);
$form->handleRequest($request);
if ($request->isXmlHttpRequest()) {
$form = $this->createForm(Test2Type::class);
return new Response($this->renderView('test/_results.html.twig', [
'form' => $form->createView(),
]));
}
return $this->render('test/index.html.twig', [
'form' => $form->createView(),
]);
}
Then I want to submit, validate and get the datas from this Test2Type in another method
public function confirmAction(Request $request): Response
{
dump($form->getData());
return $this->render('test/confirm.html.twig', [
]);
}
But I don't have acces to my form variable and I will not re-use $form = $this->createForm(Test2Type::class);...
I think this is possible but I really don't have any clues to made this work...
Do you have some ideas ?
It's not possible, you must create $form variable before using it for submittion and validation. To avoid duplicate code on create Test2Type form, you should redirect to confirmAction in indexAction after the form submitted and valid.
public function indexAction(Request $request)
{
$form = $this->createForm(Test1Type::class)->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirectToRoute('confirm.action.route_name');
}
return $this->render('test/index.html.twig', [
'form' => $form->createView(),
]);
}
public function confirmAction(Request $request)
{
$form = $this->createForm(Test2Type::class)->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->render('test/confirm.html.twig', [
'data' => $form->getData()
]);
}
return $this->render('test/_results.html.twig', [
'form' => $form->createView(),
]);
}
You should add another action in your controller for the ajax request with another route!!
This is better readable code and works better with the history button of your browser. (less cache problems) furthermore you can of course simply change the 'action' attribute of the HTML <form> element. Follow this link to read how: http://symfony.com/doc/current/form/action_method.html
I have a search form that works with the method POST, but the method POST doesn't display the requested data in the url.
With method POST the url look like this:
/search_flight
with the method GET no results found, the url look like this:
/search_flight?from=Cape+Town%2C+International+CPT&to=Johannesburg%2C+O.R.+Tambo+International+JNB&departuredate=2016%2F01%2F08&arrivaldate=2016%2F10%2F04&price=57.5%2C1000
I also noticed that with the method GET the data is reset in each input of the form.
routing.yml
searchFlight:
path: /search_flight
defaults: { _controller: FLYBookingsBundle:Post:searchtabflightResult }
requirements:
_method: GET|POST
controller
This method send the requested data to the method searchtabflightResultAction that will handle the query.
public function searchtabflightAction()
{
//$form = $this->createForm(new SearchflightType(),null, array('action' => $this->generateUrl('searchFlight'),'method' => 'GET',));
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
return $this->render('FLYBookingsBundle:Post:searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
.
<form action="{{ path ('searchFlight') }}" method="GET">
{# here I have my forms #}
</form>
.
public function searchtabflightResultAction(Request $request)
{
//$form = $this->createForm(new SearchflightType());
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$airport1 = $form["to"]->getData();
$airport = $form["from"]->getData();
$departureDateObj = $form["departuredate"]->getData();
$arrivalDateObj = $form["arrivaldate"]->getData();
$price = $form["price"]->getData();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($airport1,$airport,$departureDateObj,$arrivalDateObj,$price);
return $this->render('FLYBookingsBundle:Post:searchtabflightResult.html.twig', array(
'entities' => $entities,
'form' => $form->createView(),
));
}
How can I make my search filter works with method get ?
Everything should be done within two actions, the basic concept is:
SearchFlightType has with/wo price option:
class SearchFlightType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('from', FormType\TextType::class)
->add('to', FormType\TextType::class)
->add('departuredate', FormType\TextType::class)
->add('arrivaldate', FormType\TextType::class);
if ($options['price']) {
$builder->add( 'price', FormType\TextType::class );
}
$builder
->add('submit', FormType\SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'price' => false,
));
}
}
Controller.php
class PostController extends Controller
{
/**
* #Route("/index", name="index")
*/
public function indexAction(Request $request)
{
$defaultData = array();
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// action is set to the specific route, so the form will
// redirect it's submission there
'action' => $this->generateUrl('search_flight_result'),
// method is set to desired GET, so the data will be send
//via URL params
'method' => 'GET',
));
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
/**
* #Route("/search_flight_result", name="search_flight_result")
*/
public function searchTabFlightResultAction(Request $request)
{
$defaultData = array();
$entities = null;
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// again GET method for data via URL params
'method' => 'GET',
// option for price form field present
'price' => true,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// get data from form
$data = $form->getData();
// process the data and get result
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($data['from'], $data['to'], ...);
}
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
// present the result
'entities' => $entites,
));
}
}
I have a controller action with a couple of forms. One form is for adding a question entity and the other form is for editing an existing question. This is a part of the action
/**
* #Route("/edit/{form}")
* #Template()
* #ParamConverter("form", class="AppBundle:Form")
*/
public function editAction(Request $request, $form)
{
$questionForm = new Question();
$addQuestionForm = $this->createForm(new AddQuestionType(), $questionForm);
$addQuestionForm->handleRequest($request);
if ($addQuestionForm->isValid()) {
dump('Wrong form');
die();
$em->persist($questionForm);
$em->flush();
return $this->redirectToRoute('app_form_edit', array('form' => $form_id));
}
$editQuestion = new Question();
$editAjaxQuestionForm = $this->createForm(new AddQuestionType(), $editQuestion);
$editAjaxQuestionForm->handleRequest($request);
if ($editAjaxQuestionForm->isValid()) {
dump('Correct form');
die();
$em->persist($editQuestion);
$em->flush();
return $this->redirectToRoute('app_form_edit', array('form' => $form_id));
}
I added the dump() and die() for debugging because the editAjaxQuestionForm was not working properly. Then I noticed that when I submit the editAjaxQuestionForm, the dump('Wrong form') is shown. So the form goes through the wrong validation.
The forms are created after an Ajax call. This is the code
/**
* #Route("/AjaxAddQuestionForm/{section}")
* #Template
* #ParamConverter("section", class="AppBundle:Section")
*/
public function ajaxAddQuestionFormAction(Request $request, $section)
{
$question = new Question();
$question->setSection($section);
$addQuestionForm = $this->createForm(new AddQuestionType(), $question);
return array(
'section' => $section,
'addAjaxQuestionForm' => $addQuestionForm->createView(),
);
}
/**
* #Route("/AjaxEditQuestionForm/{question}")
* #Template
* #ParamConverter("question", class="AppBundle:Question")
*/
public function ajaxEditQuestionFormAction(Request $request, $question)
{
$editQuestionForm = $this->createForm(new AddQuestionType(), $question);
return array(
'question' => $question,
'editAjaxQuestionForm' => $editQuestionForm->createView(),
);
}
I think I've tried everything but I can't figure out what is wrong.
I have a form, which has to be passed by some other validations than unusual (about 4 fields are depending from each other). Thing is, when its failed, I redirect the user back, but then the form loses its values, I dont want it. I know it can be done with session, but there might be a "sanitier" way. Code is usual:
public function printAction()
{
if ($this->getRequest()->getMethod() == "POST")
{
$form->bindRequest($this->getRequest());
if ($form->isValid())
{
.... more validation.... Failed!
return $this->redirect($this->generateUrl("SiteHomePeltexStockStockHistory_print"));
// and this is when I lose the values.... I dont want it
}
}
}
You can use the same action for both GET and POST requests related to a form. If validation fails, just don't redirect and the same form will be redisplayed with entered values and validation error messages:
/**
* #Template
*/
public function addAction(Request $request)
{
$form = /* ... */;
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
// do something and redirect
}
// the form is not valid, so do nothing and the form will be redisplayed
}
return [
'form' => $form->createView(),
];
}
You can passe your parametters to the new page when making the new redirection:
$this->redirect($this->generateUrl('SiteHomePeltexStockStockHistory_print', array('name1' => 'input1', 'name2' => 'input2', 'name3' => $input3, ....)));
or directly pass an array of post values:
$this->redirect($this->generateUrl('SiteHomePeltexStockStockHistory_print', array('values' => $values_array)));
You may want to do something like this
class FooController extends Controller
{
/**
* #Route("/new")
* #Method({"GET"})
*/
public function newAction()
{
// This view would send the form content to /create
return $this->render('YourBundle:form:create.html.twig', array('form' => $form));
}
/**
* #Route("/create")
* #Method({"POST"})
*/
public function createAction(Request $request)
{
// ... Code
if ($form->isValid()) {
if (/* Still valid */) {
// Whatever you do when validation passed
}
}
// Validation failed, just pass the form
return $this->render('YourBundle:form:create.html.twig', array('form' => $form));
}
}