at least one checkbox selected Symfony2 - forms

I am adding the following field to my form:
->add('interessi_profilo', 'entity', array(
'label' => 'Interessi (Tr)',
'class' => 'MyProfiloBundle:TipoInteresse',
'required' => true,
'multiple' => true,
'expanded' => true,
'property' => 'tipo',
'query_builder' => function(\My\ProfiloBundle\Entity\TipoInteresseRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.id', 'ASC');
},
I would like for the form to be sent only if at least one checkbox is selected and, if possible, have a tooltip that tells the user: at least one option must be selected

Try putting the Count constraint on the field holding the collection:
use Symfony\Component\Validator\Constraints\Count;
class Entity
{
/**
* #Count(min = 1, minMessage = "At least one item must be selected")
*/
private $collection;
// ...
}

Related

SYMFONY FormTypeCollection with various fields

In my project I would like to be able to add a Collection on a Form. I thought about the FormTypeCollection. But the thing is, I need something like that:
A "New" button, at the end of the form and everytime you click on the new, a "mini-form" is added and you have the three input to fill: "name,text,link". I would like it to be stored in the database as artists = [name,text,link] for example. I have no idea how to do that. i don't want to add an Entity Artist because I just need this for display and I don't need it to be stored as an Entity on the database.
My code right now is like that:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('Contenu')
->add('published', CheckboxType::class, ['required' => false, 'label' => 'Publier'])
->add('title', TextType::class, ['required' => true, 'label' => 'Titre'])
->add('marketingEtiquette', TextType::class, ['required' => false, 'label' => 'Etiquette Marketing'])
->add('textLink', TextType::class, ['required' => true, 'label' => 'Texte du lien'])
->add('shoppingLink', TextType::class, ['required' => true, 'label' => 'Lien'])
->add('media', ElFinderType::class, array(
'label' => 'Photo',
'instance' => 'form',
'enable' => true,
'required' => true,
'attr' => array('class' => 'form-control')
)
)
->add('position',ChoiceType::class, array(
'label' => 'Position dans la page',
'choices' => array(
'Bloc Artistes' => 'artists',
'Bloc haut de page' => 'top',
'Bloc bas de page' => 'bottom'
)
))
->add('artists',CollectionType::class,array(
'label' => 'Les artistes',
'allow_add' => true,
))
->end();
}
I don't know how to add 3 fields to the field artists and generate them on the add button click. i don't even know if it's possible actually. I also don't know what should be the type 'artists' in the database.
EDIT:
I would have like to do something similar to that, so I don't need to create an Entity nor a FormType:
->add('artists',CollectionType::class,array(
'entry_type' => TextType::class ,
'entry_options' => [
'artistName' => TextType::class,
'artistText' => TextType::class,
'artistLink' => TextType::class,
],
'label' => 'Les artistes',
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false
))
But it's not working so I guess I can't. Error:
The current field `artists` is not linked to an admin. Please create one for the target entity : ``
EDIT 2:
I created my ArtistFormType:
class ArtistFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('artistName', TextType::class, array(
'label' => 'Nom de l\'artiste'
))
->add('artistText', TextType::class, array(
'label' => 'Texte sous l\'artiste'
))
->add('artistLink', TextType::class, array(
'label' => 'Lien vers l\'artiste'
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => null,
]);
}
}
I called it like that:
->add('artists',CollectionType::class,array(
'entry_type' => ArtistFormType::class,
'label' => 'Les artistes',
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false
))
But I get the same error:
The current field `artists` is not linked to an admin. Please create one for the target entity : ``
EDIT : This solution is limited to Symfony\Component\Form\Extension\Core\Type\CollectionType, it might be different with the one from Sonata Admin.
You can find some information on this in the documentation.
The "easiest" way to do that, is to create another form (ArtistFormType for example) with the fields you wish to add.
Then in your parent form you add the CollectionType :
$formMapper
// ...
->add('artists', CollectionType::class, [
'entry_type' => ArtistFormType::class,
'label' => 'Artists',
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false
])
;
Then if you already have some artists in your entity it will render the ArtistFormType once for each artist.
If you want to add new artists it is a bit trickier and requires some Javascript.
First, render the collection inside an <ul></ul> tag :
<ul class="artists">
{{ form_row(form.artists) }}
</ul>
Following this jsfiddle :
Find the collection and add an "add artist" button to it
<script>
var $addArtistLink = $('Add an artist');
var $newLinkLi = $('<li></li>').append($addArtistLink);
jQuery(document).ready(function() {
// Get the ul that holds the collection of artists
var $collectionHolder = $('ul.artists');
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// ...
}
</script>
Add the "click" event with some dom manipulations to add new artists :
jQuery(document).ready(function() {
// ...
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addArtistLink.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new artist form
addArtistForm($collectionHolder, $newLinkLi);
});
});
function addArtistForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '$$name$$' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add an artist" link li
var $newFormLi = $('<li></li>').append(newForm);
// also add a remove button
$newFormLi.append('x');
$newLinkLi.before($newFormLi);
// handle the removal
$('.remove-artist').click(function(e) {
e.preventDefault();
$(this).parent().remove();
return false;
});
}
Then it should work fine. Of course some changes might be done to fit your project (field names, add the remove button on existing artists, ...).

Same field multiple times Symfony 4 form

I have an Entity Report, which is holds many Answers.
class Report
{
/**
* #ORM\OneToMany(targetEntity="App\Entity\Answer", mappedBy="report")
*/
private $answers;
...
}
class Answer
{
/**
* #ORM\ManyToOne(targetEntity="Report", inversedBy="answers")
*/
private $report;
...
}
I add the questions manually in my ReportType (I know this is not the best aproach but the questions will never change and I'm only interested in the answers.)
class ReportAnswersType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('answers', ChoiceType::class, array(
'label' => 'Room state',
'multiple' => false, 'expanded' => false,
'choices' => array('OK' => 'OK', 'NG' => 'NG', 'NP' => 'NP',),
))
->add('answers', IntegerType::class, array(
'label' => 'Temperature',
))
->add('answers', ChoiceType::class, array(
'label' => 'Is it good?',
'multiple' => false, 'expanded' => false,
'choices' => array('YES' => 'YES', 'NO' => 'NO',),
))
...
}
->add('save', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Report::class,
));
}
What I would like this to do is to generate a Form with 3 questions and insert each of the answers in the database.
But the rendered form only shows the last question (because with each ->add('answers', ...) I replace the last one added).
I tried different solutions to solve this:
Following the documentation on How to Embed a Collection of Forms, which, consists in adding each answer (with a label of the question) to the Report in the Controller and then rendering the ReportType. The problem about this is that each of my questions have different type (Choice, Text, Integer...) and I don't know how to customize them individually.
And I also tried to do this in my ReportType but it only shows the last question added.
I appreciate any help, thanks!
I managed to get it working. In the end I followed the instructions on How to Embed a Collection of Forms.
To make it work I added the fields question and questionType to my Answer entity. And on the AnswerType.php I check everytime what type of question it is, and then I create the type of the answer based on that. It looks like this:
$builder->addEventListener(FormEvents::POST_SET_DATA, function ($event) {
$builder = $event->getForm();
$answer = $event->getData();
$questionType = $answer->getQuestionType();
$question = $answer->getQuestion();
if ($questionType == 1){
$builder->add('answer', ChoiceType::class, array(
'label' => $question,
'multiple' => false, 'expanded' => false,
'choices' => array('OK' => 'OK', 'NG' => 'NG', 'NP' => 'NP',),
));
}
else if($questionType == 2){
$builder->add('answer', ChoiceType::class, array(
'label' => $question,
'multiple' => false, 'expanded' => false,
'choices' => array('SI' => 'SI', 'NO' => 'NO',),
));
}
else ...
}
You can use the Entity–Attribute–Value model to solve this problem. I would suggest using sidus/eav-model-bundle. This would be a great deal of work but you would learn alot. Using EAV model, you can have N number of questions and answers.
I can not think of solving this using simple form types.

Not to validate the form in Symfony 2

Here is my form, I build in the controller:
$defaulData = ....
$formBuilder = $this->createFormBuilder($defaultData);
$entity_options = array(
'class' => 'MyBundle:Param',
'property' => 'description',
'query_builder' => function(EntityRepository $er) {
return $er->getParamsFromCategorieQueryBuilder(MyController::$category_for_list);
},
'label' => 'Donnée à afficher'
);
$formBuilder
->add('entity_types', 'entity', $entity_options);
The form is a list of Param objects, it displays good but for some reason, when I submit the form, I have an error on entity_types field saying that the value cannot be blank though there is one Param selected (even by default).
So I was wondering if I could disable validation.
When whould I put this validation_groups to false ? if it is in $entity_options, I tried it already and it does not work.
ty
You should modify you options like this (both require and groups are needed):
$entity_options = array(
'class' => 'MyBundle:Param',
'property' => 'description',
'query_builder' => function(EntityRepository $er) {
return $er->getParamsFromCategorieQueryBuilder(MyController::$category_for_list);
},
'required' => false,
'validation_groups' => false,
'label' => 'Donnée à afficher'
);
If the error is instead on the Form class itself, you should change in:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false,
));
}
The way to prevent validation for good is this one :
$formBuilder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$event->stopPropagation();
}, 900);
It prevents from calling the validation event.
The solution that giosh94mhz gave me what not good because even with validation_group = false some validation are still done.

Symfony - Form - preferred choice for radio button

How to set a preferred choice in a form for radio button ?
What I need is to have a specific radio checked (the last of my 4 radio button) when I load the web page...
But I read that "preferred choice" is used just for a choice list not for radio or checkbox...
http://symfony.com/doc/current/reference/forms/types/choice.html#preferred-choices
I tried that:
->add('Offre', 'entity', array(
'class' => 'AVCMediasBundle:Offre',
'query_builder' => function (EntityRepository $repository) use ($parametre_langue) {
return $repository->createQueryBuilder('q')
->where('q.id = 4')
->orderBy('q.prix', 'DESC');
},
'property' => 'titre' . $parametre_langue,
'expanded' => true,
'multiple' => false,
'label' => false,
'preferred_choices' => array('1'),
'attr' => array(
'class' => 'langue_selector'
)
));
Thanks
My solution was to passed my choice directly in the entity when I load my form
$preferedOffer = $em->getRepository('AVCMediasBundle:Offre')->findOneById('4');
$DetailTransaction->setOffre($preferedOffer);

Symfony2 form populating entitiy based on other entity

I'm using Symfony2 form component to create and modify forms. I'm currently loading all model entities as choices, but I need to get only the Models related to the selected (posted) value from manufacturer.
How can I achieve this?
class VehicleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('manufacturer', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false
));
$builder->add('model', 'entity', array(
'label' => 'Model',
'class' => 'BalslevCarBundle:Models',
'property' => 'model',
'empty_value' => 'All',
'required' => false
));
}
public function getName()
{
return 'search';
}
}
First of all, you have to create "dynamically" your choices based onto user selection.
There are two ways, strictly coupled with your application behaviour, that leads (in both cases) at the same "core" code; the difference is only the way you call it.
So, let's explain the two possibilities:
Select manufacturer "statically" and don't change it over the time of request: use data retrieved from your business logic
Select manufacturer "dinamically" and can change them over the time of request: replace your form at every request; new form will be provided by business logic
So, the HEART of your question is: how can I retrieve only associated entities?
Answer
Into your VehicleType.php (where entity, in this case, is VehicleType ?)
private $manufacturerId;
public function __construct($manufacturerId)
{
$this->manufacturerId = $manufacturerId;
}
public function BuildForm(FormBuilderInterface $builder)
{
$manufacturerId = $this->manufacturerId;
$manufacturerQuery = function(EntityRepository $repo) use ($manufacturerId ){
return $repo->createQueryBuilder('m')
->where('m.id = :id')
->setParameter('id',$manufacturerId );};
$builder->add('manufacturer', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false,
'query_builder' => $manufacturerQuery;
));
$builder->add('model', 'entity', array(
'label' => 'Brand',
'attr' => array('class' => 'input-block-level'),
'class' => 'BalslevCarBundle:Manufacturers',
'property' => 'short_name',
'empty_value' => 'All',
'required' => false,
'query_builder' => $modelQuery;
));
}
As you can see, in this way we use a custom repository to get only entities that are suitable for our needs. Obviously I am writing my DQL query without knowing your DB structure: it's your task and responsibility to adapt it to your real situation.
Moreover, you have to create another query for model (called $modelQuery in my answer) to retrieve correct models based on selected $id