3

I am having an issue setting default values for checkboxes displayed for a many t many relationship.

I have a User entity and Options entity with a many-to-many relationship, mapped b a user_option table.

In a user form, I display the list of options in a checkbox.

The options entity contains a default field that indicated if the checkbox is set or unset for a new user. If the user has selected, then the user selection must be displayed.

class User {

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=64, nullable=true)
     */
    protected $name;

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Bundle\Entity\Option", inversedBy="users")
     * @ORM\JoinTable(name="user_options")
     */
    protected $userOptions;
}

class CommunicationOption {

   /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50)
     */
    protected $name;

    /**
     * @var boolean
     *
     * @ORM\Column(name="default_state", type="boolean")
     */

}

The form load the options

public function buildForm(FormBuilderInterface $builderInterface, array $options)
{
    $builderInterface
        ->add('userOptions', 'entity', array(
            'class' => 'Bundle\Entity\Option',
            'expanded' => true,
            'multiple' => true,
            'required' => false,
            'query_builder' => function (EntityRepository $repository) {
                return $repository->getFindAllQueryBuilder();
            },
            'by_reference' => true,
        ))
    ;
}

This displays all options. However, all checkboxes are unchecked. If a user saves data in the user_options table, then the checkbox is correctly displayed.

    {% for element in form.userOptions %}
       {{ form_widget(element, {'attr': {'class': 'col-xs-1' }}) }}
       {{ element.vars.label|raw }}
    {% endfor %}

I require that for new entries, the default field is considered. Setting the value in the constructor did not change the checkbox value, and in any case will set the default for all fields to true, which is not what I want.

I am using Symfony 2.6

2
  • Hi, what symfony version are you using ? Commented Feb 5, 2016 at 5:41
  • 2.6 - I updated my question. Thank you. Commented Feb 5, 2016 at 12:20

3 Answers 3

2

Using symfony 2.6

You could try to use ChoiceType instead of EntityType which inherits from it.

EntityType is just a way to populate choices with an automatic findAll() form the entity manager of a specified class via the option class or with a more advanced query_builder option.

In your case first create a Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList:

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class SomeController extends Controller
{
    public function someAction(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $options = em->getRepository('\AppBundle\Entity\CommunicationOption')
            ->findAll();

        // from here we are making a custom choice loader
        $choices = array(); // will hold the indexed labels the user will choose
        $mappedUserOptions = array(); // will hold each $option as $label => $option

        // we want each $choice as $index => $label, where $value is the index in $choices
        foreach($options $as $option) {
            $choices[] = $option->getName(); // 0 => 'Some Option Name'
            $mappedOptions[$option->getName()] = $option; // 'Some Option Name' => CommunicationOption $option
        }

        // now I skip the part when you create a form builder for the user then :
        $builder = // ... create your user form
        $form = $builder->add('userOptions', 'choice', array(
            'choice_list' => new ChoiceList(
                array_fill(0, count($choices), true), // the checkbox input value will be normalised to string "on", false would be normalised to false
                $choices, // labels for the user to choose
            ),
            'expanded' => true,
            'multiple' => true,
            'required' => false,
            'by_reference' => true, // not needed, it is the default
        ))
        ->getForm();

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            // get an array of selected labels
            $userOptions = $form->get('userOptions')->getData(); // array('Some User Option', 'Some Other Option')
            // remap the options to to data
            $selectedUserOptions = array(); // CommunicationOption[]
            foreach ($userOptions as $choice) {
                $selectedUserOptions[] = $mappedOptions[$choice];
            }
            $user = $form->get('user')->getData();

            $user->setOptions($selectedUserOptions);

            // ... persists and flush
            // you could redirect somewhere else
        }
    
        // return a response
    }
}

However I recommend upgrading to symfony 2.7 or even better 2.8.

Using symfony 2.7+

(pending PR see link)

// Just copy-pasted your example before edit :
$builderInterface
    ->add('userOptions', 'entity', array(
        'class' => 'Bundle\Entity\Option',
        'expanded' => true,
        'multiple' => true,
        'required' => false,
        'query_builder' => null, // omit it will load all entity by default
        'by_reference' => true, // not needed
        // Using new option introduced in 2.7 see the [doc](http://symfony.com/doc/2.7/reference/forms/types/choice.html#choice-value)
        'choice_value' => 'on', // this only should make the trick 
    ))
;
           
Sign up to request clarification or add additional context in comments.

Comments

1

I work with symfony3. That's how it works

->add('aptitudes', EntityType::class, array( //change this line
      'class' => 'BackendBundle:Aptitudes', //change this line
      'expanded' => true,
      'multiple' => true,
      'required' => false,
      'query_builder' => null, 
      'by_reference' => true, 
))

Comments

0

older Thread i know. But this one is the best ranked in google, so i wanted to update my solution. I think it's very handy and you don't need that much code as the accepted answer

->add(
        'roles',
        ChoiceType::class,
        [
            'label'   => 'Rolles *',
            'choices' => $this->userService->getRolesForChoiceType(), // change it
            'data'    => [ 1, 3 ] // change it to your default choices
            'help'    => 'some help text'
        ]
    )

This code comes from Symfony 4.4

Hope that safe somebody some more google queries

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.