How can I show a form with the old values so that you can edit? - forms

in controller I find the id
$oggetto = $this->getDoctrine()
->getRepository('AcmeTryBundle:Try')
->find($id);
after I passed this $values into form(just?)
$form = $this->createForm(new TryType(), $oggetto);
and in FormType? what I put?
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name','text') ?

Your approach is good.
1) Get your $oggetto object in DB
2) Pass it to your FormType $form = $this->createForm(new TryType(), $oggetto);
3) Add the fields you want in your form type
4) Send your form to your view 'form' => $form->createView()
5) In your view, call your form
<form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>
Your fields (you defined in 3) ) will be automaticaly populated by your object data. You can then change them and edit them.
See the doc for more info: http://symfony.com/doc/current/book/forms.html

Your Form seems fine
class TryFormType extends AbstractType {
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name','text') ;
}
public function getName() {
return 'tryform';
}
}
The function getName gives the form a name, which in this case is tryform.
In the controller you can add a return statement like this.
return $this->render('AcmeTryBundle:Default:TryForm.html.twig', array(
'TryForm' => $form->createView()
));
And in twig file access it as follows.
{{ form_widget(TryForm.name) }}
The value will automatically be passed there. You can then edit it

For example in Symfony 4.2.3, you filled and submitted a form and some form values are invalid.
<input type="text" name="name" value="{{ form.vars.value.name }}">
In this way, you will be set old form input as a default value if the value is valid.

Related

Symfony 5.1 $form->getData() Always Null (Basic Form)

This Symfony form question has been asked 100 times (and I've read ALL of the responses), but none are working for me. I have a class (Employer), a form (Preview.html.twig), and a controller (DefaultController.php). No matter what I try, I still get null values for the form fields. The form displays properly and I'm not saving to a database (I just want to dump the variables, then I'll move on to db action). This has consumed weeks of my life and any assistance is sincerely appreciated.
The Default Controller (DefaultController.php)
<?
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Employer;
use App\Form\EmployerType;
class DefaultController extends AbstractController
{ /**
* #Route("/preview", name="preview")
*/
public function preview(Request $request)
{
$employer = new Employer();
$form = $this->createForm(EmployerType::class, $employer, ['csrf_protection' => false]);
$form->handleRequest($request);
//the next two lines were added to force the form to submit, which it wasn't doing prior to
if ($request->isMethod('POST')) {
$form->submit($request->request->get($form->getName()));
if ($form->isSubmitted() && $form->isValid()) {
$employer = $form->getData();
dump($form); /****** ALL ENTRIES FROM THIS DUMP ARE NULL. *****/
exit; /***Added to capture dump ******/
return $this->redirectToRoute('homepage'); /** Works when the exit is removed ***/
}
}
return $this->render('preview.html.twig',
['form'=> $form->createView()]
);
}}
The Employer Class (Employer.php)
namespace App\Entity;
class Employer
{
protected $companyName;
protected $companyAddress;
public function setCompanyName($companyName)
{ $this->companyName = trim($companyName); }
public function getCompanyName()
{ return $this->companyName; }
public function setCompanyAddress($companyAddress)
{ $this->companyAddress = trim($companyAddress); }
public function getCompanyAddress()
{ return $this->companyAddress; }
}
Form Builder (EmployerType.php)
<?php
namespace App\Form;
use App\Entity\Employer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class EmployerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('companyName', TextType::class, ['label' => 'Company Name', 'required' => false])
->add('companyAddress', TextType::class, ['label' => 'Address', 'required' => false])
->add('submit',SubmitType::class, ['label' => 'Submit & Preview'])
->getForm() //I've added and removed this line multiple times. Not sure if its needed.
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Employer::class,
]);
}
}
For Display (Preview.html.twig) ** Displays Form Correctly **
{{ form(form) }}
A few rabbit holes:
The site is running on localhost (Symfony, Apache, MySQL).
The form input is sent via POST.
The Default Controller redirects after the Submit; the "exit" was added to pause my code.
The form is not embedded. I've scaled back the entire project because I thought the embedded form was the issue.
I changed the method to PUT and can see the form values appended to the URL, but $employer = $form->getData() still populates $employer with null values.
I tried to get individual form fields upon submit using $form->get('companyName')->getData(); The data remains null.
I'm out of ideas on how to save the form data to the Employer object.
You must delete getForm() in EmployeType.
In DefaultController, delete the line that contains form->submit(). Here the employee that you initialized is the form which fills it automatically. To retrieve your employee, you no longer need to do $form->getData(). The employee is already full. You can check with dd($employer) instead of $employer = $form->getData()
I gave up and created a fresh instance of Symfony using Composer. Starting over led me to the issue. Something (I'm not yet confident of what) in my custom twig file was causing the problem. I'll update everyone once I figure it out.
Final Findings:
The name attribute for my form inputs were incorrect. The controller was expecting named input in the form of:
formName[formField] //Ex: employer[companyName]
and mine were the standard type generated by Twig (formName_formField)
The addition of:
<p>form.vars: </p>
{{ dump(form.vars) }}
in my Twig file led me to the answer. I modified the input using a custom form theme by first adding the following line to twig.yaml:
form_themes: ['custom_bootstrap.html.twig']
Then, in the custom file, I created a new instance for each type of input I use to override the defaults. For example, for checkboxes my code is:
{% use "form_div_layout.html.twig" %}
{%- block checkbox_widget -%}
<input type="checkbox" id="{{ form.vars.name }}" name="{{ full_name }}"
{%- if disabled %} disabled="disabled"{% endif -%}
{%- if required %} required="required"{% endif -%}
{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %}
{{ block('attributes') }}
/>
{%- endblock checkbox_widget -%}
You should be able to add the name values directly to your twig template without using a custom file. I really hope this helps someone save time.

Form collection of imbricated form without entity never validates

I am currently working on a "Filters" form to add the possibility for the users to apply filters on item lists. The issue I am facing is that once the form is submitted, the controller considers that the form is empty and invalid.
Dumping what's returned by $form->getData() shows the following:
array(1) { ["filters"]=> array(0) { } }
There is neither errors nor warnings in the logs. The GUI returns an error on the field of the filter:
This value is not valid.
However if I modify the Twig widget to change the select's id to anything else, I no longer get the invalid value but the form's data still is an empty array.
Here's the layout of this project:
a FormType containing one select input, and one text input,
another FormType that implements the former in a collection,
The controller, which instantiates and use the form,
a Twig view of the 2nd FormType,
and the final Twig page
FilterSearchType.php
namespace NetDev\CoreBundle\Form\Helpers;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use NetDev\CoreBundle\Form\Helpers\FilterType;
class FilterSearchType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('filters', 'collection', array('type' => new FilterType($options['entity']), 'allow_add' => true,
'allow_delete' => true, 'by_reference' => false))
->add('search', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('filters' => [],
'entity' => null));
}
public function getName() {
return 'search_filter';
}
}
FilterType.php
<?php
namespace NetDev\CoreBundle\Form\Helpers;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
class FilterType extends AbstractType {
public function __construct($entity) {
$this->model = $entity;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
/*getFilters returns something like that:
* ['Column A' => 'column_a', 'Column B' => 'column_b', ...]
*/
->add('column_name', 'choice', array('choices' => $this->model->getFilters(true)))
->add('search_value', 'text')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(['column_name' => '',
'search_value' => '']);
}
public function getName() {
return 'netdev_filter';
}
}
Here is how the form is given to Twig from the controller:
RoutesController.php
class RoutesController extends Controller {
public function indexAction($page = 1, Request $request) {
$em = $this->getDoctrine()->getManager();
$orderBy = $request->query->get('orderBy');
$orderType = $request->query->get('orderType');
$form = $this->createForm(new RouteManagerType($em), null, array('orderBy' => $orderBy,
'orderType' => $orderType));
$filterForm = $this->createForm(new FilterSearchType(), null, array('entity' => new Route()));
if ($request->isMethod('POST') && $filterForm->handleRequest($request)->isValid()) {
// Never reached, $filterForm is always marked as invalid
$formData = $filterForm->getData();
var_dump($formData);
exit();
if (!empty($formData['filters']) && count($formData['filters'])) {
if (empty($formData['action'])) $formData['action'] = 'filter';
$form = $this->createForm(new RouteManagerType($em), null,
array('orderBy' => $orderBy,
'orderType' => $orderType,
'filters' => $formData['filters']));
}
}
Twig widget: filter_search.html.twig
{% block netdev_filter_widget %}
{% spaceless %}
{{ form_errors(form) }}
<div class="form-group">
<div class="input-group">
<select {{ block('widget_attributes') }} class="form-control" id="search_column">
{% for group_label, choice in form.column_name.vars.choices %}
<option value="{{ choice.value }}" {{ block('attributes') }}>{{ choice.label }}</option>
{% endfor %}
</select>
<div class="input-group-addon">contains</div>
<input type="text" class="form-control" id="search_criteria" placeholder="search"/>
</div>
</div>
{% endspaceless %}
{% endblock %}
I've dumped pretty much everything I could and nothing was really interesting. I am not even sure that the Kernel understands / correctly "links" the submit the user has performed and the form the controller created.
Any help on that would be greatly appreciated.
OK, so the issue is that if you do the rendering yourself, you should very well be aware of the fact that the names as rendered in HTML are exactly what the backend expects, otherwise you'll get issues like these.
The best way to tackle that is take the default form rendering as a starting point and don't do any custom HTML until you're absolutely sure you need custom templating. When you do, inspect the default templates to see how the names of the elements are built, and follow the exact same naming, or even better, reuse base templates wherever possible (either by extending blocks and calling parent() and/or using the block function).

Use same form on two different pages (URLs) in Symfony 2

I am using the FOSUserBundle with Symfony 2.5.
I have overridden the default registration form and defined a new URL for it.
fos_user_registration_register:
path: /user/new.html
defaults: { _controller: FOSUserBundle:Registration:register }
and this is the form
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->remove('plainPassword');
$builder->remove('username');
$builder->remove("email");
$builder->add('terms', 'checkbox', array('required' => true,
'mapped' => false,
'constraints' => new True(array('message' => 'Required!'))));
$builder->add("email", "email", array("required" => true, "mapped" => true, "constraints" => new MailBlacklist()));
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'my_user_registration';
}
}
finally I registered it as a service.
When I show the form on the URL /user/new.html and submit it, it works: validation errors are shown and if everything is fine with the data, the user is created.
But when I show exactly the same form on a different URL (the root) and submit the form, no validation is done and the user is not saved. Instead, I get redirected to /user/new.html and see an empty form.
I create the form like this
$form = $this->createForm('my_user_registration')->createView();
Why isn't this working? Is FOSUserBundle checking the referer or something?
My template
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST">
{{ form_widget(form) }}
<div>
<input type="submit" value="Registrieren" />
</div>
</form>
Would be great if someone could help my with this "little" problem :)
Problem was the name of my form. If I use the FOSUserBundle form factory instead of createForm(), it works and the name is the right one

Symfony embedded formType in another formType for adding datas at the same time in two entities that have a ManyToOne relation

I have a relation ManyToOne between two entities Articles.php and Corrections.php.
Look at this code, Corrections.php where my FK constraint is:
class Corrections
{
/**
* #var \Articles
*
* #ORM\ManyToOne(targetEntity="Articles")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="article_id", referencedColumnName="id")
* })
*/
private $article;
An article could have many correction, but a correction belong to only one article.
So, in my Corrections.php, I have the foreign key named $article refers to article_id in MySQL database.
Now I need to add a correction to an article in a form Type, but not only that.
This is the controller code for:
public function addCorrectionAction() {
$em=$this->getDoctrine()->getManager();
$correction= new Corrections;
$form = $this->createForm(new CorrectionsType(), $correction);
$request = $this->getRequest();
if ($request->isMethod('POST') | ($form->isValid()) ) {
$form->bind($request);
$correction= $form->getData();
$em->persist($correction);
$em->flush();
return $this->redirect($this->generateUrl('indexArticles'));
}
else {
return $this->render('Bundle:Folder:addCorrections.html.twig', array('form' => $form->createView() ));
}
}
No problems here for now. This my buildForm, CorrectionsType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('date')
->add('description')
->add('text')
->add('articles', 'collection', array(
'type' => new ArticlesType(),
'allow_add' => true))
;
}
And the twig view:
<form action="{{ path('addCorrection_process') }}" method="POST">
{{ form_widget(form) }}
<div class="row col-md-3">
<input type="submit" value="Add correction and article" class="btn"/>
</div>
</form>
In fact, I need to create a form which allows a user to add an article and his correction at the same time. Or here, when I display the addCorrection method with the form, the field articles is a select which allow user to add a correction to an existing article.
How can I proceed to have a form which allow user correctly ADD a NEW correction and a NEW article at the time in the same form? I need this form must be consistent with my FK constraint too, i-e when I ADD a NEW correction with a NEW article at the same time, the FK $article (article_id) have the correct value refers to the correction_id.
Check Collection Field Type official documentation page. So basically you create ArticleType and CorrectionType forms and connect the latter by collection field type.

Symfony2 form type customization

I need help with this since I just can't figure it out by myself even after reading and examining all resources I found on the internet.
I have an Image entity. It has 3 mapped properties.
id
location
thumb_location
And I have custom ImageSelectType form type which extends AbstractType:
buildForm function looks like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$em = $options['em'];
$qb = $em->createQueryBuilder();
$result = $qb->select('i')
->from('BloggerBlogBundle:Image', 'i')
->leftJoin('i.articles', 'a')
->where('a is NULL')
;
$builder
->add('images', 'entity', array(
'class' => 'BloggerBlogBundle:Image',
'query_builder' => $result,
'required' => true,
'multiple' => false,
'expanded' => true,
)
)
->setAttribute('widget', 'imageSelect')
;
}
So it takes all images that aren't used by any article and populates form with them. With these options, I get radiobuttons, like this:
<div id="image_images">
<input type="radio" id="image_images_67" name="image[images]" required="required" value="67"><label for="image_images_67" class="required">c5252b4ffc9c50540218e25be1353b33aaa4ee05.png</label>
<input type="radio" id="image_images_68" name="image[images]" required="required" value="68"><label for="image_images_68" class="required">fcfc7d7d05d63b1f55dff8cbff0bedeb3c917dfc.jpeg</label>
</div>
What I want now is all radiobuttons to have custom html5 data attribute data-thumb="thumbnail/location.png" which would be the thumb_location property value of image object represented by that radiobutton.
I hope I was clear enough. If any more info is needed I will provide it.
I've read so much about this but I think I'm imagining things more complex then they actually are. At one point I just wanted to say 'Oh, forget it, I'll just render this manually' and use:
{% for choice in form.vars.choices %}
<input type="radio" data-thumb="{{choice.thumb_location}}" />
{% endfor %}
But I really want to use good practices that this amazing framework provides....Sometimes just don't seem as obvious to me as they should.
Ah, I thought this was relating to this object as the FormType is. So in this case I see the possibility to set a variable withe the buildView method.
/**
* {#inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['thumb'] = $options['thumb'];
}
You can set this option whether in the ->add(x, x, array('thumb_location' => 'location'))
(or in the setDefaultOptions method).
But now I am not sure to be honest. Because you would need to set in the view like this:
<input data-thumb="{{ thumb }}" type="radio" id="blog_article_image_17" name="blog_article[image]" required="required" value="17">
And this means you make <input data... by hand again.
Not sure if this is possible in your case but I think it would be nice to define a second FormType for the radio input field:
public function buildForm(FormBuilderInterface $builder, array $options)
{
...this is your current form builder....
->add('radio', MyRadioType());
}
Not sure if I understand the question, you want to set the data-thumb directly within the form builder, right?
So the form builder contains mains features (http://api.symfony.com/2.0/Symfony/Component/Form/FormBuilder.html) including the setAttribute(string $name, string $value) method.
You could do something like:
setAttribute('data-thumb', $yourvalue);
To apply these attributes in your input field, you need to set attributes in your twig template:
<input type="radio" {{ block('widget_attributes') }} />