I have a dynamic form which display/hide a FileType field depending on another field value (link).
When i'm trying to get the file in my controller, it always gives me NULL
My UserType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('familyStatus', ChoiceType::class, [
'label' => 'Statut de famille',
'label_attr' => [
'class' => 'fg-label'
],
'attr' => [
'class' => 'sc-gqjmRU fQXahQ'
],
'required' => true,
'choices' => [
'Married' => 'M',
'Single' => 'S'
]
]);
$formModifier = function (FormInterface $form, $status = null) {
if ($status === 'M') {
$form->add('familyInfo', FamilyInfoType::class);
}
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$user = $event->getData();
$formModifier($event->getForm(), $user->getFamilyStatus());
}
);
$builder->get('familyStatus')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$status = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $status);
}
);
}
My FamilyInfoType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('partnerName', TextType::class, [
'label' => 'Nom du partenaire',
'label_attr' => [
'class' => 'fg-label'
],
'attr' => [
'class' => 'sc-gqjmRU fQXahQ'
],
'required' => true
])
->add('weddingProof', FileType::class, [
'label' => 'Acte de mariage',
'label_attr' => [
'class' => 'Upload-label'
],
'attr' => [
'class' => 'Upload-input',
'maxsize' =>'4M',
'accept' =>'image/*'
],
'required' => false,
'mapped' => false
]);
}
My UserController:
/**
* #Route("/user", name="add_user", methods={"GET", "POST"})
* #param Request $request
*/
public function addUser(Request $request) {
$response = [];
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($user->getFamilyStatus() === 'M') {
var_dump("ok");
$document = $form->get('familyInfo')->get('weddingProof')->getData();
$partnerName = $form->get('familyInfo')->get('partnerName')->getData();
var_dump($document); // NULL
var_dump($partnerName); // OK the value is displayed
die;
}
}
return $this->render("user/registration.html.twig", ['form' => $form->createView()]);
}
It's working with TextType field but not with FileType. What's wrong with my form.
The issue is with the mapped => false option to the file type. The form is not setting the uploaded file object in the property of your entity because it’s not mapped.
Related
I would like to make a form with "selected" in option to choose a language. By default, I would like to "selected" User's locale option.
(...)
use Symfony\Component\HttpFoundation\Request;
(...)
class VisitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options, Request $request)
{
$locale = $request->getLocale();
if ($locale == 'fr'){
$prefLang = "Français";
}elseif ($locale == 'nl'){
$prefLang = "Nederlands";
}elseif ($locale == 'en') {
$prefLang = "English";
}
$builder->add('langvis', ChoiceType::class, [
'label' => 'form.input.langvis',
'choices' => [
'Français' => 'Français',
'Nederlands' => 'Nederlands',
'English' => 'English'
],
'preferred_choices' => [$prefLang]
])
->add('save', SubmitType::class, [
'label' => 'form.input.send',
'attr' => [
'class' => 'btn btn-primary form-control'
]
])
->getForm();
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Visit::class
]);
}
}
But I have a compile Error:
Declaration of
App\Form\VisitType::buildForm(Symfony\Component\Form\FormBuilderInterface
$builder, array $options, Symfony\Component\HttpFoundation\Request
$request) must be compatible with
Symfony\Component\Form\AbstractType::buildForm(Symfony\Component\Form\FormBuilderInterface
$builder, array $options)
How can I do that?
you cannot pass request on buildForm, try using OptionsResolver
class VisitType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$locale = $options["locale"];
if ($locale == 'fr') {
$prefLang = "Français";
} elseif ($locale == 'nl') {
$prefLang = "Nederlands";
} elseif ($locale == 'en') {
$prefLang = "English";
}
$builder->add('langvis', ChoiceType::class, [
'label' => 'form.input.langvis',
'choices' => [
'Français' => 'Français',
'Nederlands' => 'Nederlands',
'English' => 'English'
],
'preferred_choices' => [$prefLang]
])
->add('save', SubmitType::class, [
'label' => 'form.input.send',
'attr' => [
'class' => 'btn btn-primary form-control'
]
])
->getForm();
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => Visit::class,
'locale' => 'Français'
]);
}
In controller, when you create form pass locale parameter:
$locale = $request->getLocale();
$formType = 'VisitType';
$entity = 'VisitEntity';
$form = $this->createForm($formType, $entity, array('locale' => $locale));
The below Symfony form works fine in development when I only have a few records of each entity in the database. However, once I connect it to an extract of my production database the page times out.
The size of the database tables in this extract are bigger (around 800 records each) but nothing to justify it timing out completely. I'm assuming that the problem is a misunderstanding of how best to populate $batch in
The controller:
public function batchInvoicesAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$members = $em->getRepository('AppBundle:Member')->findActiveMembers();
$batch = new InvoiceBatch();
foreach ($members as $member) {
$invoice = new Invoice();
$invoice->setMemberId($member);
$invoice->setSelected(True);
$invoice->setCreatedate(new \Datetime());
$invoice->setAmount($member->getDefaultinvoiceamount());
$invoice->setCurrency($member->getDefaultinvoicecurrency());
$invoice->setinvoicebatchid($batch);
$batch->addInvoiceId($invoice);
# exit(VarDumper::dump($batch));
}
$form = $this->createForm(InvoiceBatchType::class, $batch);
$form->handleRequest($request);
if ($form->isSubmitted() && ($form->isValid())) {
$batchform = $form->getData();
foreach ($batchform->getInvoiceids() as $invoiceform) {
if ($invoiceform->getSelected() == False) {
$batchform->removeInvoiceId($invoiceform);
} else {
$em->persist($invoiceform);
}
}
$em->persist($batchform);
$em->flush();
return $this->redirectToRoute('view_monthly_invoices');
}
return $this->render('invoices/new.batch.invoice.html.twig', array(
'page_title' => 'Invoices',
'message' => 'Batch loading of invoices',
'form' => $form->createView(),
));
}
The repository function code is:
public function findActiveMembers()
{
return $this->getEntityManager()
->createQuery
(
'SELECT m
FROM AppBundle:Members m
WHERE m.active= :active
ORDER BY m.familyname1, m.familyname2, m.firstname'
)
->setParameter('active' ,true)
->getResult();
}
In case it's of any help:
1. Vardump of the partial $batch:
{#1022 ▼
#id: null
#invoice_ids: ArrayCollection {#1023 ▼
-elements: array:1 [▼
0 => Invoice {#1024 ▼
#id: null
#invoicebatch_id: InvoiceBatch {#1022}
#member_id: Member {#1049 ▶}
#payment_ids: ArrayCollection {#1027 ▶}
#attendc_ids: ArrayCollection {#1025 ▶}
#attende_ids: ArrayCollection {#1044 ▶}
#bankreceipt: null
#aggregate_payment: 0
#selected: true
#amount: "0.00"
#currency: "S"
#invoicedate: null
#createdate: DateTime {#19571 ▶}
#modifydate: null
#billedmonth: null
#description: null
}
]
}
2. My custom formTypes - this may be the problem as I'm still trying to get my head around FormTypes. The page only has one InvoiceBatchType which has an array of Invoice_ids used as CollectionType with InvoiceForBulkType:
class InvoiceBatchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('batchevent', TextType::class, array(
))
->add('invoice_ids', CollectionType::class, array(
'entry_type' => InvoiceForBulkType::class,
))
;
}
/* ... */
}
class InvoiceForBulkType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('selected', CheckboxType::class, array(
'label' => ' ',
'required' => false,
))
->add('member_id', EntityType::class, array(
'class' => 'AppBundle:Member',
'choice_label' => 'FullName',
'label'=>'Member',
'disabled'=>true,
)
)
->add('amount', TextType::class, array(
'label' => 'Amount',
))
->add('currency',ChoiceType::class, array(
'choices' => array('Soles' => 'S', 'Dollars' => 'D'),
'choices_as_values' => true,
))
->add('invoicedate', DateType::class, array(
'widget' => 'single_text',
'data' => new \DateTime('now'),
'format' => 'dd/MMM/yyyy',
'label' => 'Date of invoice',
'attr'=> array(
'class'=>'datepicker',
)
))
->add('description', TextType::class, array(
'required'=>false,
))
;
}
/*...*/
}
I made several search but I still have a problem...
I want to make a dynamic form. I want to hydrate a select in function of an other select.
This is my configureFormFields:
protected function configureFormFields(FormMapper $formMapper)
{
$emIndustry = $this->modelManager
->getEntityManager('*\*\*\*\Entity\Industry')
;
$query = $emIndustry->getRepository(*:Industry')
->getFindAllParentsQueryBuilder()
;
$formMapper
->add('company')
->add('industry', 'sonata_type_model', [
'attr' => [
'onchange' => 'submit()',
],
'query' => $query,
'required' => false,
])
->add('subIndustry', 'sonata_type_model', [
'choices' => [],
'required' => false,
])
;
$builder = $formMapper->getFormBuilder();
$factory = $builder->getFormFactory();
$subject = $this->getSubject();
$modelManager = $this->getModelManager();
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use($formMapper, $subject, $emIndustry, $modelManager, $factory) {
$form = $event->getForm();
if(!is_null($subject->getIndustry())) {
$query = $emIndustry->getRepository('*:Industry')
->getFindChildrenByParentQueryBuilder($subject->getIndustry())
;
$form
->add(
$factory->createNamed('subIndustry', 'sonata_type_model', null, [
'class' => '*\*\*\*\Entity\Industry',
'query' => $query,
'required' => false,
])
)
;
}
});
}
When I change the value of the select Industry, no problem my form is submited. But nothing happend in second select subIndustry because : all attributes of my $subject object is null...
Have you any idea why ? Is there a best way to make a dynamic form ?
Thank's for your help.
AlexL
want to pre select my form in Symfony.
I do it with the Form builder. It works except of the child table is not saving.
My Invoice Type
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('invoiceNumber', 'hidden', array('label' => ''))
->add('date', 'date', array('label' => 'Field', 'data' => new \DateTime("now")))
->add('PaidPrice', 'money', array('label' => 'Bereits bezahlt', 'attr' => array('class' => '')))
->add('invoicepos', 'collection', array(
'type' => new InvoiceposType(),
'allow_add' => true,
'allow_delete' => true,
'cascade_validation' => true,
'by_reference' => true,
))
;
}
My invoicepos Type
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pos', 'text', array('label' => '', 'attr' => array()))
->add('quantity', 'hidden')
->add('price', 'hidden')
->add('tax', 'hidden')
;
}
My Controller to start the Form
public function newAction($id) {
$em->persist($entInvoice);
//$em->flush($entInvoice); //works perfect, but i dont want to save that, just pre select for the form
$form = $this->createCreateForm($entInvoice);
return array(
'entity' => $entInvoice,
'form' => $form->createView(),
);
}
Code when i submit the form
public function createAction(Request $request) {
$entity = new Invoice();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('pspiess_letsplay_invoice_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
The data is there, but with nor relation!
What did i wrong?
Thanks for help.
Found a solution for my problem.
Before i flush i add the child entity...
foreach ($entity->getInvoicepos() as $entInvoice) {
$entity->addInvoicepos($entInvoice);
}
I have a form with choice field of entities from database:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', 'document', array(
'class' => 'Acme\DemoBundle\Document\Category',
'property' => 'name',
'multiple' => true,
'expanded' => true,
'empty_value' => false
));
}
This form will produce the list of checkboxes and will be rendered as:
[ ] Category 1
[ ] Category 2
[ ] Category 3
I want to disable some of the items by value in this list but I don't know where I should intercept choice field items to do that.
Does anybody know an solution?
you can use the 'choice_attr' in $form->add() and pass a function that will decide wether to add a disabled attribute or not depending on the value, key or index of the choice.
...
'choice_attr' => function($key, $val, $index) {
$disabled = false;
// set disabled to true based on the value, key or index of the choice...
return $disabled ? ['disabled' => 'disabled'] : [];
},
...
Just handled it with finishView and PRE_BIND event listener.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', 'document', array(
'class' => 'Acme\DemoBundle\Document\Category',
'property' => 'name',
'multiple' => true,
'expanded' => true,
'empty_value' => false
));
$builder->addEventListener(FormEvents::PRE_BIND, function (FormEvent $event) {
if (!$ids = $this->getNonEmptyCategoryIds()) {
return;
}
$data = $event->getData();
if (!isset($data['categories'])) {
$data['categories'] = $ids;
} else {
$data['categories'] = array_unique(array_merge($data['categories'], $ids));
}
$event->setData($data);
});
}
...
public function finishView(FormView $view, FormInterface $form, array $options)
{
if (!$ids = $this->getNonEmptyCategoryIds()) {
return;
}
foreach ($view->children['categories']->children as $category) {
if (in_array($category->vars['value'], $ids, true)) {
$category->vars['attr']['disabled'] = 'disabled';
$category->vars['checked'] = true;
}
}
}