preferred_choices entity field form never run - php

I want to set a form with a "preferred_choices" on top of my select field HTML corresponding to previous submitted datas selected by the user. I want to construct an entity field with a constant list AND a preferred_choices top element if the form is previously submitted.
I never ran correctly this function in symfony2.
Can you help me to construct correctly my field form.
Why my preferred_choices options select nothing when the form is construct ?
I setting this with correct object setted previously in the code.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$defaultCQSsearch = new CqsProSansMarque();
$defaultCQSsearch->setRayLibelle((!array_key_exists('ray_libelle', $options['attr'])) ? null : $options['attr']['ray_libelle']);
$defaultCQSsearch->setFamLibelle((!array_key_exists('fam_libelle', $options['attr'])) ? null : $options['attr']['fam_libelle']);
$defaultCQSsearch->setCaeLibelle((!array_key_exists('cae_libelle', $options['attr'])) ? null : $options['attr']['cae_libelle']);
$builder
->add('ray_libelle', 'entity', array(
'class' => 'ApplicationDriveBundle:CqsProSansMarque',
'data_class' => 'Application\DriveBundle\Entity\CqsProSansMarque',
'property' => 'ray_libelle',
'query_builder' => function(CqsProSansMarqueRepository $er){
return $er->createQueryBuilder('a')
->select('a')
->groupBy('a.ray_libelle');
},
'preferred_choices' => array($defaultCQSsearch),
'label' => 'rayon',
'required' => false,
))

preferred_choices option expects an array of values but you are passing an array of object (i.e. $defaultCQSsearch)

Related

Request error in symfony with boolean in pass to form argument

I got a table in data base ID, json, status and everything works in another table and in this one I can save, read but can not take the data from repository and pass to form. Look:
that's my SliderType Form
class SliderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('status', ChoiceType::class, array(
'data' => $options['status'],
'choices' => array(
"Aktywna" => 1,
"Nieaktywna" => 0
),
'attr' => array(
'class' => 'form-control'
),
))
And here I need to pass from options resolver a status variable which is boolean, so in controller I done it look:
//tworzymy formularz
$form = $this->createForm(SliderType::class, $request, array(
.
.
'status' => $slider->getStatus,
te problem is that another variables works perfect if i add only this i thrown a error:
Cannot read index "status" from object of type "Symfony\Component\HttpFoundation\Request" because it doesn't implement \ArrayAccess.
Any Idea what is wrong here? and the funny thing is that I got another controller with another table (structure the same) and all works fine.
You are giving the HttpRequest of symfony to the data of your form.
This is causing your issue
You should pass the entity which will be hydrated by the form. Give your slider entity to createForm method second argument
$form = $this->createForm(SliderType::class, $slider, array(
'status' => $slider->getStatus));
Than you should tell the form to handle the request and extract data from request to hydrate your entity with your form.
$form->handleRequest($request);
You should read the form documentation

Symfony - Add and persist extra fields

I have a ChoiceType::Type field that display some choices, and i want to add, for each choices, an input to add a price on it. I did it like this :
->add('product_price', ChoiceType::class, array(
'choices' => array(
"Product 1",
"Product 2",
),
)
The JS that add the input for each choices :
var productBoxes = $("[id^=product_]");
// Listen the checkbox to display or hide the prices inputs
productBoxes.each(function (index) {
var priceField = '<label class="control-label required" for="product_price_' + index + '">Capacité</label>' +
'<input type="text" id="product_price_' + index + '" name="product[price][]" class="form-control">';
$(this).click(function () {
if ($(this).is(':checked')) {
$(this).parent().append(priceField);
}
})
})
The javascript works, it append fields next to each choices. Now I want to send my data in an array, like this :
["Product 1" => "value of the attached field"]
But I don't know how to fetch that extra data and save it to the database.
Did someone knows how to do it ?
EDIT 1
I tried to do it with CollectionType, but don't find out how to render each CollectionType element as checkbox. Is there a way to do it this way ?
Thanks for your help !
I think better way is to create custom type and set additional field there.
For example:
You main form type:
$builder->add('product_price', CollectionType::class, array(
'label' => 'Prices',
'entry_type' => ProductPriceType::class
));
And ProductPriceType:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', TextType::class, array())
->add('price', NumericType::class, array());
}
/**
* #param OptionsResolver #resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SomeEntity'
));
}
I think you get product data from base.
In this case you get array that contains 2 values - product and price
In your example, the easiest way would be to add two more fields to your form. Keep them hidden with CSS (display: none), and just show them with JS (toggle class "hidden" when the choice gets un/selected)
->add('product_one_price', NumberType::class, array(
'attr' => array('class' => 'hidden')
))
->add('product_two_price', NumberType::class, array(
'attr' => array('class' => 'hidden')
))
An alternative would be to have nested forms, or to build the form dynamically which may or may not be overkill, depending on what you're actually doing
Maybe I'm wrong but I think you should dig in the ChoiceType class.
When using the basic ChoiceType, Symfony docs says :
The choices option is an array, where the array key is the item's label and the array value is the item's value
If I correctly understand your case, you want something very specific like this kind of choices :
$choices = [
'item_label' => [
'value' => 'item_value',
'price' => 'item_price'
],
'item_label2' => [
'value' => 'item_value2',
'price' => 'item_price2'
],
...
]
I can't tell you precisely which class to override but your best bet will be to take a look at :
ChoiceListFactory class
ChoiceList class (the ChoiceType uses the child class SimpleChoiceList)
ChoiceToValuesTransformer
I have two questions :
What is the data model to store the label and the price ?
What is this list for ? If it's too complicated for you to dig in the Form components, maybe you should split your process in two steps :
One form to define your prices for your product
One form to select the products you are interested in

Symfony2 formbuilder field with subtype -> Internal Server Error (InvalidArgumentException)

I have a Symfony2 form that's called "item". It is defined in ItemType and looks like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class,
array(
'constraints' => array(
new NotBlank()
)
)
),
->add('item_entry', ItemEntryType::class, array(
'required' => true
))
}
now when I try to send a post request with item_entry missing entirely, it throws an internal server error and the log tells me it was an InvalidArgumentException, "Expected argument of type 'Bundle\Entity\Something', NULL given".
ItemEntry has a field with the something entity. But my problem is, shouldn't Symfony2 realize that itemEntry wasn't submitted at all and not try to validate specific fields? What I would expect is an error that item_entry was not submitted instead of this.
Is there a way to handle this?
Thanks in advance!
Try setting 'required' => false on your item_entry form field.
Also you are missing ';' after the last ->add method
Edit:
If it must be 'required' => true, you can handle this case by removing it from the form dynamically in a PRE_SUBMIT event:
$formData = $event->getData();
if(!isset($formData["item_entry"])) {
$form = $event->getForm();
$form->remove("item_entry");
}
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Symfony2 Embed form values

I have my own utility CalculatorType for just calculating values for my document(I am using ODM), not reference for another document or sub arrays|object.
It has simple 2 inputs:
$builder
->add('price', 'text', array(
'label' => false,
'data' => isset($options['data']) ? $options['data']->getPrice() : '0.00'
))
->add('count', 'integer', array(
'label' => false,
'data' => isset($options['data']) ? $options['data']->getCount() : '10000'
));
In parent form I have:
$builder->
... // multiple fields
->add('calculator', 'calculator');
So when I am trying to save my form, I have an error:
Neither the property "calculator" nor one of the methods
To skip setting calculator field, I've added mapped => false to options
->add('calculator', 'calculator', array('mapped' => false));
and added eventlistener to transform calculator data
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$data["price"] = $data["calculator"]["price"];
$data["count"] = $data["calculator"]["count"];
unset($data["calculator"]);
$event->setData($data);
});
Now form submits values but calculator fields not passing to embed form, because of unsetting $data['calculator']
If I comment unset($data["calculator"]); then I have an error
This form should not contain extra fields
So I can't find any way to make this form work. Any ideas?
Found mistake in my form, so there is option for such type of forms: http://symfony.com/doc/current/cookbook/form/inherit_data_option.html

Add attribute to form widget not work

I'm trying to add the selected attribute to my <option> tags
{% for product in form.products %}
{# of course this should only done inside a if,
but for testing purpose, it's okay #}
{{ form_widget(product, { 'attr': {'selected': 'selected'} }) }}
{% endfor %}
However this does not work. Even exactly the same copy&paste from the symfony2 docs here does not work: http://symfony.com/doc/current/book/forms.html#rendering-each-field-by-hand
I'm adding the form element inside a FormType à la:
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
$builder
->add('products', 'entity', array('attr' => array('class' => 'choseable input-xlarge'),
'property_path' => false, 'label' => 'form.products.title', 'class' => 'Test\Bundle\Entity\Product', 'choices' => $products, 'multiple' => true, 'empty_value' => 'form.products.placeholder'));
}
All variables ($products) are ok in the example above.
Is there a problem?
I'm using Symfony 2.1.9-dev.
Can you update the question with form creation code? I'm pretty sure that Symfony is able to make item selected only if it's present in your model. But since you field is marked with property_path => false I don't think you can override this behavior...
An idea:
Fetch all the data used in your entity field type and pass it to form object (either via constructor or options array)
Add field as you're currently doing it
Invoke setData right afterwards to set field data (using data fetched in step #1)
Btw, I am not big fan of setData but situation like this just calls for it :)
Hope that this helps...
There are several issues with your code. I reformatted the code below for better clarity.
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
$builder->add('products', 'entity', array(
'attr' => array('class' => 'choseable input-xlarge'),
'property_path' => false,
'label' => 'form.products.title',
'class' => 'Test\Bundle\Entity\Product',
'choices' => $products,
'multiple' => true,
'empty_value' => 'form.products.placeholder'
));
}
Don't use class inheritance for form types (except of course extending AbstractType). Use getParent() for extending other types instead.
You can't set attributes of <option> tags manually. You would have to render the tags by hand.
For marking choices as selected, you need to pass default data to the field. Usually getProducts() would be called here to get the defaults, but you disabled that by setting property_path to false. So you should set the defaults manually by using the data option. Note that the defaults need to be an array/a collection, since multiple is true.
You are manually passing choices, which is a bad practice. If you just remove this option, the entity field can itself query the choices from the DB and optimize the needed statements for better performance.
Format your code. Really. :P

Categories