I’m trying to create several identical forms, but it turns out that the forms are the same, or rather their values are the same, thus only the value of the first form changes
foreach ($projectStages as $projectStage) {
$formStage = $this->createFormBuilder($projectStage)
->add('status', ChoiceType::class,
[
'choices' => [
'active' => true,
'not active' => false,
]
])
->add('save', SubmitType::class, array('label' => 'Set active ' . $projectStage->getTitle()));
$forms[$projectStage->getId()] = $formStage->getForm();
$forms[$projectStage->getId()]->handleRequest($request);
if ($forms[$projectStage->getId()]->isSubmitted()) {
$em->flush();
return $this->redirect('/update-project/' . $id);
}
$forms[$projectStage->getId()] = $forms[$projectStage->getId()]->createView();
}
in twig i did this
{% for formStage in formStages %}
{{ form_start(formStage) }}
{{ form_widget(formStage.status) }}
{{ form_end(formStage) }}
{% endfor %}
what is displayed in
HTML
Related
I'm a beginner with PHP and Symfony.
I'm trying to show each values of ring (which is entity) from database and trying to add checkbox at the end of the each ring.
My twig template only shows the checkbox in the first ring.
How do I show all the rings?
This is my controller:
public function testPage(Request $request) {
$ring = $this->ringRepository->customFindAll();
$jewel = $this->ringJewelRepository->customFindAll();
$custom = $this->customRingRepository->customFindAll();
$form = $this->createFormBuilder($ring)
->add('active', CheckboxType::class, [
'label'=>'Selection',
'required'=>false
])
->getForm();
$form->handleRequest($request);
return [
'rings'=>$ring,
'jewels'=>$jewel,
'custom' => $custom,
'form'=>$form->createView()
];
}
This is my Twig template:
{% for ring in rings %}
<div>
<div class="text-center">
<p>Ring Name: {{ ring.ring_name }}</p>
<p>Ring Type: {{ ring.ring_type }}</p>
{{ form_start(form) }}
{{ form_widget(form.active) }}
{{ form_end(form) }}
</div>
<div class="text-center">
Update Ring
</div>
</div>
{% endfor %}
Considering your use-case I think you might be looking for an EntityType, with the 'multiple' option set to true. The syntax would be as below. Make sure to import your Ring class as well.
->add('active', EntityType::class, [
'class' => Ring::class,
'multiple' => true,
'label' => 'Selection',
'required' => false,
'query_builder' => static fn (RingRepository $ringRepository) => $ringRepository->customFindAll(),
]);
You can read more about the EntityType in the symfony docs.
I create a form for a collection type of data in a separated from my controller
its my controller
/**
* #Security("has_role('ROLE_USER')")
* #Route("/phonebook/add", name="add")
*/
public function addPerson()
{
$person = new PhoneBookP();
$form = $this->createForm(PersoanlBookType::class, $person);
return $this->render(
'default/add.html.twig',
array('form' => $form->createView())
);
}
and its my form
->add('emails', CollectionType::class, array(
'entry_type' => EmailType::class,
'allow_add' => true,
'prototype' => true,
'allow_delete' => true,
'attr' => [
'class' => "emails-collection",
],
))
and my twig is
{% block body %}
{{ form(form) }}
{% endblock %}
it has no error and work in any common field (like NumberType,..) but not render CollectionType in my output. I using Symfony 4. whats my wrong?
in your rendering form you need to do this:
$person = new PhoneBookP();
//addEmail() is the arraycollection in your PhoneBookP Entity
//to be able to load the form, you need to add one from your arraycollection
$person->addEmail(new Email());
$form = $this->createForm(PersoanlBookType::class, $person);
The tags form_start and form_end only render the <form>-tags. To render the rest of the form elements call the form-twig-helper inside the <form>-tags too:
{{ form_start(form) }}
{{form(form)}}
<button type="submit">Register!</button>
{{ form_end(form) }}
I'm using materialize for the front end and I have an issue with the rendering of checkbox, to make the materialize checkbox works I've to put the label after the input but I build the form with symfony so this puts the label before the input. Here is how I build my form :
$builder
->add('libelle')
->add('ordre')
->add('categorie')
->add('type', ChoiceType::class, array(
'choices' => array(
'Commande' => 'commande',
'Produit' => 'produit',
'Face' => 'face',
'Job' => 'job'
)
))
->add('fin', CheckboxType::class, array(
'label' => 'Fin action'
));
And I render the form like this :
{{ form_start(edit_form, {'attr': {'class': 'full'}}) }}
{{ form_widget(edit_form) }}
{{ form_end(edit_form) }}
Is there a way with the form builder or twig to render the label after the input ?
You can output label and field separately in Twig:
{{ form_label(field_name) }}
{{ form_widget(field_name) }}
So I'm facing this weird behavior when listing a series of checkboxes with twig
see the new page, it displays everything right, and saying that i'm saving this laboratory
img1
ok, I saved the laboratory, now went to the edit page
img2
the marked checkboxes displays at first, ruining the alphabetic order that was at the new page.
I need that the edit page become exactly like the new page, but I don't know how to organize these checkboxes on twig.
block that renders the checkboxes:
{% block _appbundle_laboratory_laboratoryExams_row %}
<div class="form-group">
{{ form_label(form) }}
<div class="col-md-10 col-md-offset-2">
<div class="app-checkbox-collection">
<p>{{ 'laboratory.field_laboratory' | trans }}</p>
{% dump(form) %}
{% for child in form %}
{% if child.exam.vars.data.type == constant('AppBundle\\Entity\\ExamLaboratory::TYPE')%}
{{ form_widget(child.permission, {
'attr' : {
'class' : 'exam-checkbox'
},
'label' : child.exam.vars.data.name
}) }}
{% endif %}
{% endfor %}
<p>{{ 'laboratory.field_image' | trans }}</p>
{% for child in form %}
{% if child.exam.vars.data.type == constant('AppBundle\\Entity\\ExamImage::TYPE')%}
{{ form_widget(child.permission, {
'attr' : {
'class' : 'exam-checkbox'
},
'label' : child.exam.vars.data.name
}) }}
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
I don't ask at portuguese stackoverflow because no one answers symfony questions there, few users probably
EDIT:
Here is the buildForms:
Laboratory
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, array(
'label' => 'laboratory.name',
'attr' => array('class' => 'focus')
))
->add('leader', null, array(
'label' => 'laboratory.leader'
))
->add('city', null, array(
'label' => 'laboratory.city',
'placeholder' => 'action.select_one'
))
->add('laboratoryExams', 'collection', array(
'label' => 'laboratory.laboratoryExams',
'type' => new LaboratoryExamType(),
'allow_delete' => true,
'by_reference' => false,
))
;
}
LaboratoryExam
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('permission', null, array(
'label' => 'laboratoryexam.permission',
))
->add('exam', null, array(
'label' => 'laboratoryexam.exam',
))
;
}
You can set the order of checkboxes while building the form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('permission', 'entity', [
'class' => 'Acme\AppBundle\Entity\Parameter',
'multiple' => true,
'expanded' => true,
'query_builder'=> function(EntityRepository $repository) {
return $repository->createQueryBuilder('exam')->orderBy('exam.title', 'ASC');
},
]);
}
I would say it has nothing to do with twig.
That would be set on the form type object where the form with checkboxes is constructed.
It seems the data is populated programmatically on form creation with already selected choices being first.
If it isn't the case or you got some problem, please edit your question with formtype code and code where you get the data for the checkboxes.
thanks for the answers, i found a solution by resorting the ArrayCollection in the form.
$iterator = $form->get('laboratoryExams')->getData()->getIterator();
$iterator->uasort(function ($a, $b) {
return ($a->getExam()->getName() < $b->getExam()->getName()) ? -1 : 1;
});
$form->get('laboratoryExams')->setData(new ArrayCollection(iterator_to_array($iterator)));
IMO this should be done by default, I believe that no one would like to have the check-boxes disordered that way
I made form wizard with CraueFormFlowBundle and it works until last step where $flow->isValid() fails and it constantly renders last step instead of going to desired end of form wizard action.
Here is the code necessary to understand where I made mistake:
Controller:
public function indexAction(Activity $activity)
{
$currency = $this->getDoctrine()->getRepository('MycompanyUtilBundle:UtilCurrency')->find(1);
$booking = new Booking();
$booking->setActivity($activity)
->setCurrency($currency)
->setReferenceCode(uniqid())
->setUserAccount($this->getDoctrine()->getRepository('MycompanySettingsBundle:UserAccount')->find(1));
$flow = $this->get('mycompany.form.flow.Booking');
$flow->bind($booking);
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
$form = $flow->createForm();
} else {
return new JsonResponse(['Status' => 'Form is valid']);
}
}
return $this->render(
'#MycompanyDemoBundle/Default/booking.flow.html.twig',
[
'form' => $form->createView(),
'flow' => $flow,
'activity' => $activity->getTitle(),
'formData' => $booking,
'error' => $form->getErrors(true, true),
]
);
}
services.yml:
mycompany.form.Booking:
class: mycompany\BookingBundle\Form\BookingType
tags:
- { name: form.type, alias: mycompany_bookingbundle_booking_form }
mycompany.form.flow.Booking:
class: mycompany\BookingBundle\Form\BookingFlow
parent: craue.form.flow
scope: request
calls:
- [ setFormType, [ #mycompany.form.Booking ] ]
BookingType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
switch ($options['flow_step']) {
case 1:
$builder
->add(
'activity',
'entity',
[
'class' => 'Mycompany\ActivityBundle\Entity\Activity',
'property' => 'title',
]
)
->add(
'scheduledDeparture',
'entity',
[
'class' => 'Mycompany\ActivityBundle\Entity\ActivityScheduledDeparture',
'property' => 'departureDateTimeString',
'empty_value' => 'Select departure time',
]
)
->add(
'payer',
new CrmContactType()
);
break;
case 2:
$builder
->add(
'numberOfAdults',
'choice',
[
'choices' => range(1, 5),
'empty_value' => 'Select number of adult travellers'
]
)
->add(
'numberOfChildren',
'choice',
[
'choices' => range(1, 5),
'empty_value' => 'Select number of child travellers'
]
);
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
[
'data_class' => 'Mycompany\BookingBundle\Entity\Booking',
]
);
}
BookingFlow:
protected function loadStepsConfig()
{
return
[
[
'label' => 'Select tour',
'type' => $this->formType,
],
[
'label' => 'Select travellers',
'type' => $this->formType,
],
[
'label' => 'Confirmation',
],
];
}
and at the end twig file:
{% stylesheets '#CraueFormFlowBundle/Resources/assets/css/buttons.css' %}
<link type="text/css" rel="stylesheet" href="{{ asset_url }}"/>
{% endstylesheets %}
<div>
Steps:
{% include '#CraueFormFlow/FormFlow/stepList.html.twig' %}
</div>
{{ form_start(form) }}
{{ form_errors(form) }}
{{ activity }}
{{ form_rest(form) }}
{% include '#CraueFormFlow/FormFlow/buttons.html.twig' %}
{{ form_end(form) }}
<div>
Errors:
{{ dump(error) }}
</div>
<div>
Form:
{{ dump(form) }}
</div>
There is no extra validation at all, only that field cannot be empty. I get to the last step, and when I click Finish button I thought Symfony will generate JSON with "Form is valid" value, but all I got is last step over and over again.
When I debugged that section, clicking on finish gives false to $flow->isValid($form) although every previous step was true and I cannot get to returning JSON response here.
I'm also dumping form and form->getErrors values in twig but nothing resembles that I'm having some error. If I try to persist that data it is successfully persisted.
I didn't find solution for this on git page of bundle.
Do you guys here maybe know where should I look for the solution?
Lines for the solution was this:
app/config/config.yml
csrf_protection:
enabled: true
Now when I figured that, it makes sense why it needs csrf_token to work with current workflow given on CraueFormFlowBundle example