Reputation: 330
A dropdown selection menu in a Form is available by using a EntityType
form type. It is usefull if you add data. But when you try to edit data with the same FormType class, your $request
data are overwritten by your EntityType.
How use the same FormType class when editing the data? (eg. editAction in controller) How pass Request $request
data to FormType fields as "defaults, or selected" for element EntityType::class in FormBuilder? Is there something in $builder->add() method I can use like if(['choice_value'] !=== null ) xx : yy
?
How to get something like html select selected, from Request object and pass it to xxxFormType class and bind to right EntityType::class element there.
<select>
<option value="volvo">Volvo</option>
<option value="vw">VW</option>
<option value="audi" selected>Audi</option>
</select>
I've looked at EntityType Field, How to Dynamically Modify Forms Using Form Events and lots of StackOverflow posts, but can't find proper solution.
Controller:
public function editProdPackageAction(Request $request, ProdPackage $prodPackage)
{
$form = $this->createForm(ProdPackageFormType::class, $prodPackage);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$prodPackage = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($prodPackage);
$em->flush();
$this->addFlash('success', 'MSG#011E');
return $this->redirectToRoute('admin_package_list');
}
return $this->render(':admin/forms/ProdPackage:edit.html.twig',
[
'ppg' => $form->createView(),
]
);
}
Formtype:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'idCatBig',
EntityType::class,
[
'label' => '* category',
'class' => 'AppBundle\Entity\ProdCategoryBig',
'choice_value' => 'id',
'choice_label' => 'shortName',
'multiple' => false,
'expanded' => false,
]
)
->add(
'dateStart',
DateType::class,
[
'label' => '* some date',
'data' => new \DateTime('now'),
'choice_translation_domain' => true,
]
)
->add(
'dateEnd',
DateType::class,
[
'label' => '* till',
'data' => new \DateTime('now'),
]
)
->add(
'packageName',
TextType::class,
[
'label' => '* package',
'attr' => ['placeholder' => 'default Name'],
'data' => 'your default value',
]
)
Upvotes: 2
Views: 4251
Reputation: 10144
You are overriding an object by using the data
option.
https://symfony.com/doc/3.2/reference/forms/types/entity.html#data:
( ! ) The
data
option always overrides the value taken from the domain data (object) when rendering. This means the object value is also overriden when the form edits an already persisted object, causing it to lose its persisted value when the form is submitted.
So the solution is pretty simple: don't use data
. Instead, set default values in your addProdPackageAction
action (or whatever it is called):
public function editProdPackageAction(Request $request)
{
$prodPackage = new ProdPackage();
$prodPackage->setDateEnd(new Datetime('now'));
//example: use Request or other controller methods to modify your entity
if ($this->getUser()->hasRole('ROLE_ADMIN')) {
$prodPackage->setCreatedByAdmin(true);
}
//your form
}
Alternatively, you can use your entity constructor method:
class ProdPackage
{
//your attributes
private $dateEnd;
public function __construct()
{
$this->dateEnd = new Datetime('now');
}
}
Upvotes: 2
Reputation: 330
Found another interesting solution
in formTypeclass at $builder
->add(
'trBegin',
DateTimeType::class,
[
'label' => 'Tourney Begins',
'required' => true,
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'date_format' => 'dd.MM.yyyy',
]
)
and continuing building form add:
$builder->get('trBegin')->addModelTransformer(
new CallbackTransformer(
function ($value) {
if (!$value) {
return new \DateTime('now + 60 minutes');
}
return $value;
},
function ($value) {
return $value;
}
)
);
it sets default date at moment when form is created. This method is very usefull also for EntityType object, where you can pass id of field in form and get selected your current real choice from database (not all list from the begining) very useful when using EntityField also for editing forms
$builder->get('productCategory')
->addModelTransformer(new CallbackTransformer(
function ($id) {
if (!$id) {
return;
}
return $this->em->getRepository('AppBundle:ProductCategory')->find($id);
},
function($category) {
return $category->getId();
}
));
Upvotes: 0
Reputation: 626
This is what I do in my form, I set a "pre set data listener" to check whether or not this is an edit or a create
function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add(
'dateStart',
DateType::class,
[
'label' => '* some date'
//I don't set a data field here because it is an edit
'choice_translation_domain' => true,
]
)
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (!$data || null === $data->getId()) {
//if the entity does not have an ID it means that this is a new entity not an edit. because all edits have been in the database and have an id
$builder->add(
'dateStart',
DateType::class,
['label' => '* some date',
'data' => new \DateTime('now'), //this is a create so I override my previous setting and set a default data
'choice_translation_domain' => true,]
)
}
});
}
I mainly use this trick to change form fields from required to non required between edits and creates for password fields for example,and sometimes if there is something exceedingly complicated. To change data, honestly, setting default data in constructor is cleaner as Stephan suggests
Upvotes: 2