I am trying to post data through Symfony form's button but it does not validate form.
Here is my controller file:
public function PurchaseProductAction(Request $request)
{
$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
->setMethod('POST')
->add('CompanyName', 'text', array(
'label'=>false
))
->add('Address1', 'text', array(
'label'=>false
))
->add('Continue_to_Step_2', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid())
{
// It does not come here
$data = $form->getData();
$value = $data['CompanyName'];
echo $value;
}
}
Its my twig file:
{% block content %}
Company Name{{ form_row(form.CompanyName) }}
Address Line 1{{ form_row(form.Address1) }}
{{form_widget(form.Continue_to_Step_2)}}
{% endblock %}
Kindly guide me what I am doing wrong due to which my method does not call?
As explained in the Rendering a Form in a Template part of the documentation, you've to include the {{ form_start(form) }} and the {{ form_end(form) }} twig form helpers.
This will generate the appropriate <form> tags according to your form definition.
Also, keep in mind that Support for submit buttons was added in Symfony 2.3. Before that, you had to add buttons to the form's HTML manually.
Update,
form_end should be called with render_rest option set to false if you don't want it to show unrendered fields,
{# don't render unrendered fields #}
{{ form_end(form, {'render_rest': false}) }}
Related
Using Symfony 4 to build a support ticket form:
Created route and functions in page controller
/**
* #Route("/support/ticket")
*/
public function ticket(){
return $this->render('support/ticket/ticket.html.twig');
}
public function new(Request $request)
{
// creates a Ticket and gives it some dummy data for this example
$ticket = new Ticket();
$form = $this->createFormBuilder($ticket)
->add('category', ChoiceType::class, array(
'choices' => array(
'ROMAC eHR' => 1,
'ROMAC Website' => 2,
'ROMAC Guide' => 3,
)
))
->add('comment', TextareaType::class)
->add('save', SubmitType::class, array('label' => 'Submit Ticket'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// $form->getData() holds the submitted values
// but, the original `$task` variable has also been updated
$ticket = $form->getData();
// ... perform some action, such as saving the task to the database
// for example, if Ticket is a Doctrine entity, save it!
// $entityManager = $this->getDoctrine()->getManager();
// $entityManager->persist($task);
// $entityManager->flush();
return $this->redirectToRoute('ticket_success');
}
return $this->render('support/ticket/ticket.html.twig', array(
'form' => $form->createView(),
));
}
And then render the form in the twig template:
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.category) }}
{{ form_row(form.comment) }}
{{ form_end(form) }}
When I load the page I get a Symfony error stating that "Variable form does not exist".
I have followed the documentation https://symfony.com/doc/current/forms.html. Where/how can I find the issue?
I assume you get this error while accessing "/support/ticket"
You have "form" variable missing in this function
public function ticket(){
return $this->render('support/ticket/ticket.html.twig');
}
I will suggest to wrap your code in twig template in a "if" block
{% if form is defined %}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.category) }}
{{ form_row(form.comment) }}
{{ form_end(form) }}
{% endif %}
Or you need to adjust your controller functions accordingly
I have a problem with form.
For start, in my main twig I include the twig i use for the form:
{% include 'MainBundle::manage.html.twig'%}
The controller is mainController
The controller displays everything that appears in main twig.
The action of the form :
public function manageAction(Request $request){
$manageForm = $this->createFormBuilder()
->add('submitFile', FileType::class, array('label' => 'File to Submit'))
->add('send', SubmitType::class)->getForm();
if ($request->getMethod('post') == 'POST') {
// Bind request to the form
$manageForm->bindRequest($request);
// If form is valid
if ($manageForm->isValid()) {
// Get file
$file = $manageForm->get('submitFile');
$file->getData();
}
}
return $this->render('MainBundle::main.html.twig', array(
'manageForm' => $manageForm->createView()
));
}
routing.yml
manage:
path: /manage
defaults:
_controller: MainBundle:Main:manage
requirements:
_method: POST
manage.html.twig
{% extends 'MainBundle::main.html.twig' %}
{% block content %}
<form action="" method="post">
{{ form_widget(manageForm) }}
<input type="submit" />
</form>
{% endblock %}
when i run in the route /main I should have my form display but i have an error
Variable "manageForm" does not exist.
I guess the controller does not take the view...
In your particular case - change to following.
return $this->render('MainBundle::manage.html.twig', array(
'manageForm' => $manageForm->createView()
));
If you extend the main/base twig in other twig, then you need to render this other twig (always).
Parameters which you pass to extended twig will be available in twig you have extended (in this case the main.html.twig), but it doesn't work the other way around.
{% include 'MainBundle::manage.html.twig'%} // why ?
Don't do anything with main - just extend it in manage!!!!
I see other problems with your overall code also.
CONTROLLER:
// the more modern way instead of checking manually for request method
if ($form->isSubmitted()) {
if ($form->isValid()) {
// perform actions...
} else {
// was not valid...return error messages
}
}
FORM
<form action="" method="post"> // this is the oldschool way
{{ form_widget(manageForm) }}
<input type="submit" />
</form>
Better something like... (some of my recent coded examples)
{{ form_start(form, {'attr' : {'method' : 'post', 'enctype' : 'multipart/form-data', 'class' : 'test'}}) }}
{{ form_errors(form.resume) }}
{{ form_widget(form.resume, {'attr' : {'id' : 'file-upload-rec', 'class' : 'file-upload-rec js-file-upload-rec', 'accept' : '.pdf, .doc, .docx'}}) }}
{{ form_label(form.resume, 'select', {'label_attr' : {'class' : 'file-upload js-file-upload'}}) }}
{{ form_row(form._token) }}
{{ form_end(form, {'render_rest': false}) }}
ps. you might also want to read all of https://symfony.com/doc/current/forms.html
You are rendering main.html.twig instead of manage.html.twig. I guess the first one uses an importForm variable which is therefore not passed to the view.
If not, and you really need to render main.html.twig which includes manage.html.twig, then why is manage.html.twig extending main.html.twig? Either include one in another, or extend one from another, not both.
You need to pass the variable while including your template
{% include 'MainBundle::manage.html.twig' with {'manageForm': manageForm} %}
For more information see https://twig.symfony.com/doc/2.x/tags/include.html
Thanks!
I have a form controlling the search bar in the websites navbar:
public function searchFormAction()
{
$form = $this->createFormBuilder()
->setAction($this->generateUrl('search'))
->setMethod('GET')
->add("value", TextType::class, array('label' => false))
->add("Search", SubmitType::class)
->getForm();
return $this->render('components/search-form.html.twig', [
"form" => $form->createView()
]);
}
As you can see, the form has a specific action path to this function:
/**
* #Route("/search", name="search")
*/
public function searchAction(Request $request)
{
return $this -> render ("post/post-search.html.twig", [
"value" => $request->query->get('value')
]);
}
For now this shouldn't do much more than just display the value on the page.
The problem is that the website fails to redirect when the form is used
So when I put foo in the search, and click submit the path looks like this:
localhost:8000/page?form%5Bvalue%5D=foo&form%5BSearch%5D=&form%5B_token%5D=PsouIRAy2QaQ8j2XO_uYrs7PcaR6jyjQN3W3_xRMdgw
Moreover if I go to localhost:8000/search and try to put anything into the search bar, no value is printed.
Here is how the form is rendered:
//search-form.html.twig
<form class="navbar-form navbar-left">
{{ form_start(form) }}
<div class="form-group">
{{ form_row(form.value) }}
</div>
{{ form_row(form.Search) }}
{{ form_end(form) }}
</form>
And placed in the base navbar:
//base.html.twig
//...
{{ render(controller(
'AppBundle:Form:searchForm'
)) }}
//...
Inspecting the element shows that the form tag has no action and method attributes
What could be the issue here and how can I fix it?
Fixed! Made a simple mistake in the twig file.
Placed the form start inside html form tags, that way the submit button would send to an empty form.
I have an issue trying to render a controller which returns a template with formView.
I understood about the sub-request, but I am having difficult time to show any kind of errors.
I think the problem is that after it sees the form is invalid it redirectsToRoute and it looses the POST Request.
If I don't say redirectTo it just renders the view.
base.html.twig
{{ render(controller('AppBundle:Utility:renderSignUpWizard'), {request: app.request}) }}
Utility Controller
/**
* #Route("/registration/wizard/", name="registration.wizard")
*/
public function renderSignUpWizardAction(Request $request)
{
/** #var $user User */
$user = $this->getUser();
$form = $this->createForm(SignUpWizardType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// save changes to user
$this->persistAndSave($user);
// redirect to profile
return $this->redirectToRoute('profile');
}
else if($form->isSubmitted() && !$form->isValid())
{
return $this->redirectToRoute('home');
}
return $this->render('partials/signup-wizard.html.twig', array
(
'form' => $form->createView(),
));
}
If you could show the twig file where you put the form I could have given a clearer answer. Check the twig file you tell your controller to render and add the following:
Simple way to generate your form(doesn't include errors):
{{ form_start(form) }}
{{ form_widget(form) }
{{ form_end(form) }}
Add:
{{ form_errors(form) }}
if you want erors for a specific field:
{{ form_errors(form.name) }}
I have showUsersAction()-method inside the Defaultcontroller which should render a form where it should be possible to select a user from a list, press a submit-button and then redirects to a route /showItems/{userId} where the items of a user are shown.
I know that it would be possible to do that easy with a link, but I want to make use of ChoiceType:
First I copied an example of ChoiceType from the Symfony documentation with a minimal change:
/**
* #Route("/showUsers", name="showUsers")
*/
public function showUsersAction(){
$users = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findAll();
$form = $this->createFormBuilder()
->setMethod('POST')
->add('user', ChoiceType::class, [
'choices' => $users,
'choice_label' => function($user) {
/** #var User $user */
return strtoupper($user->getUsername());//here is the problem
},
'choice_attr' => function($user) {
return ['class' => 'user_'.strtolower($user->getUsername())];
},
])
->getForm();
return $this->render('default/showUsers.html.twig',
array('users' => $users, 'form' => $form->createView()));
}
I am sure $users gives an array with objects of the class User. When I execute the route in the browser I get following error message:
Error: Call to a member function getUsername() on a non-object
in src\AppBundle\Controller\DefaultController.php at line 50
Line 50 is the commented line return strtoupper($user->getUsername());
What is the problem and how can I solve?
And how can I get the selected User after I submitted via a submit button to the same route?
EDIT: (because of possible duplication)
Of course I know that the method getUsername() can not be called, because $user is a non-object, which should not be related to the Symfony documentation. So my question relates to a Symfony special solution which has absolutly nothing to do with 100 of other problems where the Error is the same.
Use entity type instead. Here is a link to documentation. It's a child type of a choice type, with exactly same functionality, and also every option returns an entity object.
Because I had trouble with setting up the entity type field too, I decided to post my solution for the whole action function and the twig file here:
action method:
/**
* #Route("/showUsers", name="showUsers")
*/
public function showUsersAction(Request $request){
// gets array of all users in the database
$users = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findAll();
$form = $this->createFormBuilder()
->setMethod('POST')
->add('users', EntityType::class, array(
'class' => 'AppBundle:User',
'choices' => $users,
// This combination of 'expanded' and 'multiple' implements radio buttons
'expanded' => true,
'multiple' => false,
'choice_label' => function ($user) {
return $user->__toString();
}
))
// Adds a submit button to the form.
// The 'attr' option adds a class to the html rendered form
->add('selected', SubmitType::class, array('label' => 'Show User Items', 'attr' => array('class' => 'button')))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// gets the selected user
$selectedUser = $form["users"]->getData();
// redirects to route 'showItems' with the id of the selected user
return $this->redirectToRoute('showItems', array('userId' => $selectedUser->getId()));
}
// renders 'default/showUsers.html.twig' with the form as an argument
return $this->render('default/showUsers.html.twig', array('form' => $form->createView()));
}
twig file:
{#
// app/Resources/views/default/showUsers.html.twig
Description:
twig file that implements a form in which one of all users can get
selected via radio button to show the items of the user after a click
on the submit button.
#author goulashsoup
#}
{% extends 'base.html.twig' %}
{% block title %}Users{% endblock %}
{% block body %}
<div class="users">
{{ form_start(form) }}
{% for user in form.users %}
{{ form_widget(user) }}
{{ form_label(user) }}
<br>
{% endfor %}
<br>
{{ form_end(form) }}
</div>
{% endblock %}