I'm new with Symfony2 (2.4.4).
I want to create a HTML layout which shows always a form on top (searchbar). I send the form via post and would like to redirect to another controller, which should pass the user input and generate an output. I created a new function like this:
public function searchFormAction(Request $request)
{
//$defaultData = array('sstring' => 'Suche');
$form = $this->createFormBuilder()
->add('fnr', 'hidden')
->add('sstring', 'search', array('label' => false))
->add('submit', 'submit', array('label' => 'suchen'))
->getForm();
$form->handleRequest($request);
if($request->isMethod('POST'))
{
return $this->redirect('SchmanEmployeeBundle:Employee:search', array(
'sstring' => $form->get('sstring')->getData();
));
}
return $this->render('SchmanEmployeeBundle:Employee:searchForm.html.twig', array(
'form' => $form->createView()
));
}
I extended my base layout (base.html.twig) and include the form with the render function
{% render(controller('SchmanEmployeeBundle:Employee:searchForm')) %}
This works fine and the form is always present in my layout. The given HTML looks like this:
<form name="form" method="post" action="/app_dev.php/">
<div><input type="search" id="form_sstring" name="form[sstring]" required="required"></div>
<div><button type="submit" id="form_submit" name="form[submit]">suchen</button></div>
Now I have 3 questions:
If I submit the form, I don't want to be redirected to the searchAction Controller. This is because the $request->isMethod is always GET. Why? The form actions is post?
In the Symfony Webtool the form section is also empty. I see all form fields (sstring) and the data is always null. Where's the user input?
First off, your form is set to be POST by default, so you should be good. Second, you don't pass any data to be filled by your form, and I think you should. Third, you don't check if the form is valid, which includes the test if it's submitted. You should do this:
$defaultData = array(); // No need for a class object, array is enough
$form = $this->createFormBuilder($defaultData)
->add('fnr', 'hidden')
->add('sstring', 'search', array('label' => false))
->add('submit', 'submit', array('label' => 'suchen'))
->getForm();
$form->handleRequest($request);
if($form->isValid())
{
// Happens if the form is submitted
return $this->redirect('SchmanEmployeeBundle:Employee:search', array(
'sstring' => $form->get('sstring')->getData(); // TODO: This will probably produce an error, fix it
));
}
return $this->render('SchmanEmployeeBundle:Employee:searchForm.html.twig', array(
'form' => $form->createView()
));
Also, I think you shouldn't worry about the form method because you don't have different implementations for other methods. This is the usual way the forms are handled in Symfony. You should read on forms in detail before proceeding, the article is quite informative.
I guess its because you didnt specified, in your routing configuration, that the method of this function is POST.
Because the form never submitted to your function (your function want GET, but send POST)
Where is the last question?
There is a great code to make your search function, it should work (sorry if you dont use annotation).
One good point, you can now use your searchType everywhere in your project, you should make your form like that instead of formbuilder into your controller. Easier to read and to use.
Controller:
/**
* To search something
*
* #Route("/search", name="search")
* #Template()
*/
public function searchAction()
{
$form = $this->createForm(new searchType());
$request = $this->get('request');
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid())
{
$informations = $form->get('search')->getData();
//make things here
}
}
}
And here is the searchType class:
class searchType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('fnr', 'hidden')
->add('sstring', 'search', array('label' => false))
->add('submit', 'submit', array('label' => 'suchen'));
}
/**
* #return string
*/
public function getName()
{
return 'yournamespace_searchType';
}
}
Related
I was looking for a answer, but i never found something. .
My starting Position:
This classes / files are included
Controller, DataDFu1Controller.php
Form DataAPatientType.php ,DataDFu1Type.php
Entity DataAPatient, DataDFu1
views/DataDfu1/ form.html.twig
The DataDFu1Controller contains (to the overview) the indexAction, newAction and
editAction and so on.
Both Formtypes (DataAPatientType.php ,DataDFu1Type.php) comes in one Form (look Method) this form goes to be rendered later in the form.html.twig file for the newAction and the editAction
For the newAction i did it so:
private function createNewForm(DataAPatient $entity)
{
$form = $this->createForm($this->get('data_livebundle.form.dataapatienttype'), $entity, array(
'action' => $this->generateUrl('dataapatient_new'),
'method' => 'POST',
));
return $form->add('dFu1', new DataDFu1Type());
}
later the form comes rendered. . .
So first i create "DataAPatientType.php" Form and then i add the "DataDFu1Type.php" to the form.
In the view -> form.html.twig it looks like that.
for DataDFu1Type:
{{ form_widget(form.dFu1.fu1Examiner1)}}
for DataAPatientType:
{{ form_label(form.pSnnid, 'SNN-ID (if known)', {'label_attr':{'style':'margin-top:3px'}})}}
So i can get a variable or a function with the suffix 'dfu1' after the form.
Everything works so fine. I hope the condition are understandible till now..
Now my Problem:
I have to create also an editAction which opend of course the same view-> form.html.twig with the filled values from a dataset (entity). In this process i don't understand how i can create the Form Object based also (DataAPatientType, DataDFu1Type) with the corresponding data. -> I'm trying to be more specific
private function createEditForm(DataDFu1 $entity)
{ /*
* This function shoud create the editform which insists
* DataAPatientType.php ,DataDFu1Type.php included the data from
* $entity. I have the opportunity to get the entity for DataDFu1Type
* easy directly with the Primary Key and the data for DataAPatientType
* over a Foreign Key which is safed in the $entity
*
*/
}
So i only dont understand how i can create a Form based on two types (DataAPatientType.php ,DataDFu1Type.php) with the corresponding Data inside, that i can render it like in the newAction.
For one Form i did it everytime like so and it works.. but for two types i tried a lot things which didnt worked. Have somebody a experiance? or a Solution for this Problem?
the syntax of the form.html.twig isnt changeable so the form has to be rendered equivalent like in the newAction
Example for creating a form based only on one Type and not two
private function createEditForm(Event $entity)
{
$form = $this->createForm($this->get('qcycle_eventbundle.form.eventtype'), $entity, array(
'action' => $this->generateUrl('event_edit', array('id' => $entity->getId())),
'method' => 'POST'
));
$form->add('preview', 'button', array('label' => 'Preview', 'attr' => array('data-preview' => 'preview')))
->add('submit', 'submit', array('label' => 'Save Changes'))
->add('sendAndSave', 'submit', array('label' => 'Send Mail & Save'));
return $form;
}
i really hope, that my problem and Question understandable
thanks
mjh
If i understand you have this form:
class DataAPatientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('dFu1', new DataDFu1Type());
$builder->add('pSnnid', 'text');
[...]
}
}
Then in create
$form = $this->createForm(DataAPatientType(), new DataAPatient());
And in edit you can simply do something like
private function createEditForm(DataDFu1 $entity)
{
$form = $this->createForm(DataAPatientType(), entity); //here the form will be "populated" by the entity data
So if you want to set some default value or overwrite an existing value for example, you would use
private function createEditForm(DataDFu1 $entity)
{
entity->setPSnnid('whatever')
$form = $this->createForm(DataAPatientType(), entity); //here the form will be "populated" by the entity data
I have two entities 'status' and 'doctor'. Every doctor can add a status in his profile. When the doctor wants to add a status, he can add status for another doctor because of the choice field .
It's not logic, I want that every doctor add only his status, not for other doctor.
How can I fix it ?
This is the status form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('medecin','entity',array('class'=>'DoctorBundle:medecin','property'=>'prenom','multiple'=>false))
->add('text')
->add('description')
->add('image',new ImageType())
;
}`
Remove the field Doctor (medecin for you) from the Form and then in the controller when you are handling the form response just do this
if ('POST' === $request->getMethod()) {
$statusForm->handleRequest($request);
if ($statusForm->isValid()) {
$status = $statusForm->getData();
$status->setDoctor($this->getUser());
$statusManager->flush($status);
}
}
$this->getUser() if you're logged in with the doctor, if you're not, get him however you are doing it.
Ok, based on your comments I think you have several ways to tackle this:
Remove medecin form field altogether and assign it later. For example:
$status = ....; // Your entity
$currentDoctor = ... // logic for getting myself :)
$status->setMedecin($currentDoctor);
$form = $this->createForm(StatusType(), $status);
$form->handleRequest($request);
if ( $form->isValid() ){
// The rest is the same
}
Bind data attribute of medecin form field. This further complicates things as you need to pass yourself (currentDoctor) into the form type. I would definitely go for #1 above.
Hope this helps...
I have this code in my status controller of create form:
/**
* Creates a form to create a statut entity.
*
* #param statut $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(statut $entity)
{
$form = $this->createForm(new statutType(), $entity, array(
'action' => $this->generateUrl('statut_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
`
i try this code its OK with the choice field but the Doctor-id take the value null, this is the code create form:$id= $entity->setMedecin();
$form = $this->createForm(new statutType(), $entity, array(
'action' => $this->generateUrl('statut_create'),
'method' => 'POST',
));
I'm developing a blog in symfony and i'm stuck with forms that are embed inside the layout. In my case a simple search form.
<div class="b-header-block m-search">
{{ render(controller('YagoQuinoySimpleBlogBundle:Blog:searchArticles')) }}
</div>
To render the form i'm using an embed controller inside the layout twig file.
public function searchArticlesAction(Request $request)
{
$form = $this->createForm(new SearchArticlesType());
$form->handleRequest($request);
if ($form->isValid()) {
// Do stuff here
}
return $this->render('YagoQuinoySimpleBlogBundle:Blog:searchArticles.html.twig', array(
'form' => $form->createView()
));
}
The indexAction is the one that retrieves the form data and filters a list of articles.
public function indexAction(Request $request)
{
$form = $this->createForm(new SearchArticlesType());
$form->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
$criteria = array(
'title' => $data['search']
);
} else {
$criteria = array();
}
$articles = $this->getDoctrine()->getRepository('YagoQuinoySimpleBlogBundle:Article')->findBy($criteria, array(
'createDateTime' => 'DESC'
), 5);
return $this->render('YagoQuinoySimpleBlogBundle:Blog:index.html.twig', array('articles' => $articles));
}
SearchArticlesType is a form class
class SearchArticlesType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('search', 'text', array(
'constraints' => new NotBlank()
))
->add('submit', 'submit', array(
'label' => 'Buscar'
));
}
public function getName()
{
return 'searchArticles';
}
}
The problem comes when i submit this form. The indexAction do his part, validating the form and filtering the articles but when the embed controller tries to validate data (just for displaying info or whatever)
$form->handleRequest($request);
if ($form->isValid()) {
// Do stuff here
}
I feel like i'm missing something.
Thank you for your help!
When you call render(controller('your_route')) you are actually making a sub request which means the parameters bags are emptied so your request isn't "handled" by the form.
If you are using 2.4+ you could get the master request from the request stack using ..
/** #var \Symfony\Component\HttpFoundation\RequestStack $requestStack */
$requestStack = $this->get('request_stack');
$masterRequest = $requestStack->getMasterRequest();
And then you could handle that request in your rendered controller as opposed to the current (sub) request like..
$form->handleRequest($masterRequest);
In your: public function searchArticlesAction(Request $request) you're missing second argument on create form
$searchArticle = new SearchArticle(); // I assume this is how you named the Entity, if not just change the entity name
$form = $this->createForm(new SearchArticlesType(), $article);
I have a form with one default value:
class GearType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('options')
->add('model', 'choice', array('choices' => $this->getModelChoices(), 'data' => 2));
}
one of the requirements is form can be pre-populated by re-sellers by passing parameters in URL. It is also nice feature for potential customers to copy and paste link to email, communicators, etc.
I did it this way:
/**
* #Route("/car/gear")
* #Template()
*/
public function gearAction(Request $request)
{
$form = $this->createForm(new GearType());
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
return 'is valid';
}
} else {
$get = $this->getRequest()->query->all();
if (!empty($get)) {
$normalizer = new GetSetMethodNormalizer();
$form->setData($normalizer->denormalize($get, new Gear())); # look here
}
}
return array('form' => $form->createView());
}
unfortunately field 'options' has always default value, instead value passed as a parameter.
I have tried to change line # look here into
$gear = $normalizer->denormalize($get, new Gear());
$form = $this->createForm(new GearType(), $gear);
but no result.
It seems that solution is passing additional parameter to GearType object. I do not like this solution. Does anyone know better way?
Add this snippet, and modifiy between the [ ] as appropriate
$form->bind($request);
if ( [ passed parameters from querystring ] ){ //// New Code
$form->getData()->setOptions( [ processed parameter ]); //// New Code
} //// New Code
if ($form->isValid()) {
return 'is valid';
}
The reason for the field options always having default value may be the actual query. Instead of denormalizing and setting the data directly, modify else fragment to:
} else {
$form = $this->createForm(new GearType(), new Gear(), array(
'validation_groups' => array('not-validating')
));
$form->bind($request);
}
The form will validate only against validations associated with the not-validating group, which will avoid showing the common required alerts if the form is built form GET.
Docs about 'validations-groups': http://symfony.com/doc/current/book/forms.html#validation-groups
The question is similar to: Entity form field and validation in Symfony2?
I want to generate a class-less form inside my service.
The way I do it is:
class StepSummary implements StepInterface
{
public function __construct($container)
{
$this->container = $container;
}
public function getVariables()
{
$form = $this->container->get('form.factory')->createBuilder('text')
->add('accept')
->getForm();
return array('form' => $form->createView());
}
}
In the API, I've found that I need to pass a form type to the FormBuilder - I didn't find any reference to that, so I've put imaginary text string. Now it renders the form but this way:
<input type="text" id="text" name="text" required="required" />
Obviously there is no reference to the accept field.
Controller's createForm() method was quite helpful here:
public function createFormBuilder($data = null, array $options = array())
{
return $this->container->get('form.factory')->createBuilder('form', $data, $options);
}
So the solution is:
$form = $this->container->get('form.factory')->createBuilder('form')
->add('accept')
->getForm();
Look at the chapter in the Symfony2 documentation called Using a Form without a Class.
Basically, you have to use createFormBuilder and instead of a string or an object you just pass an array with the default values.
From the documentation mentioned before:
// make sure you've imported the Request namespace above the class
use Symfony\Component\HttpFoundation\Request
// ...
public function contactAction(Request $request)
{
$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
->add('name', 'text')
->add('email', 'email')
->add('message', 'textarea')
->getForm();
if ($request->getMethod() == 'POST') {
$form->bind($request);
// data is an array with "name", "email", and "message" keys
$data = $form->getData();
}
// ... render the form
}
If you don´t want to tie your form to any particular object, you don´t need to pass any object to the builder, you can do:
$form = $this->container->get('form.factory')->createBuilder()
->add('accept')
->getForm();
If you want to set some defaults for the form, you can tie the form to an array. For example:
$data['accept'] = 'default accept';
$form = $this->container->get('form.factory')->createBuilder($data)
->add('accept')
->getForm();