Passing values to forms and sub forms

Passing a value to a form is a 3-step-process:

  1. Create the needed variable in the form type
  2. Pass the value when creating the form in the controller
  3. Use the variable

In code this looks as follows:

class MyFormType extends AbstractType
{
    /**
     * {@inheritdoc}
    */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $locale = $options['current_locale'];
        $builder
            ->add('language', null, [
                'label' => $current_locale,
            ])
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'current_locale' => null,
        ]);
    }
}

Line 22 defines the variable current_locale, which is set to null. This is needed to define the parameter. In line 8 you see how to use this parameter: it is stored in $options['lcurrent_locale], and can be used as any other variable.

When creating the form in the controller, the new parameter can be passed as any other setting in the form (line 6):

class MemberContactDataController extends Controller
{
    public function showAction()
    {
        $form = $this->createForm(MyFormType::class, null, [
            'current_locale' => 'en',
        ]);

Passing variables to sub forms

 Passing a value to a sub form is a bit more tricky. Passing from the controller and the defining the parameter for the sub form is the same as above, but passing the parameter from the parent form to the sub form is a bit different. Here is an example from the vereniging software:

Sub form:

/**
 * Class PhoneNumberFormType
 */
class PhoneNumberFormType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('phoneNumber', null, [
                'label' => false,
                'required' => false,
            ])
            ->add('phoneNumberType', EntityType::class, [
                'class' => PhoneNumberType::class,
                'query_builder' => function (PhoneNumberTypeRepository $repo) use ($options) {
                    return $repo->createOrderByTypeQueryBuilder($options['current_locale']);
                },
                'label' => false,
            ])
            ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => PhoneNumber::class,
            'validation_groups' => false,
            'current_locale' => null,
        ));
    }
}

The parameter is defined in line 34 and use in line 19. This is as the example above.

Controller:

class MemberContactDataController extends Controller
{
    /**
     * This method is called when the member entry has to be edited or when it is submitted after editing.
     *
     * @param MemberEntry $member  User for which the contact data is shown.
     * @param Request     $request
     *
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function editAction(MemberEntry $member, Request $request)
    {
        // When the user is only allowed to edit its own data and he tries to edit other users, throw an exception.
        if (!$this->isGranted('ROLE_EDIT_OTHER_USERS') && ($this->getUser()->getUsername() !== $member->getUsername())) {
            throw $this->createAccessDeniedException('You are not allowed to edit other users data!');
        }

        $originalEmail = $member->getEmail();

        // Copy the current mailing list subscriptions into a new array collection to be able to compare with the new
        // subscription.
        $originalMailingLists = new ArrayCollection($member->getMailingLists()->toArray());

        $form = $this->createForm(MemberEntryContactDataFormType::class, $member, [
            'current_locale' => $request->getLocale(),
        ]);

Passing the value to the parent form in the controller is also the same as in the first example, as you can see in line 27.

Parent form:

/**
 * Class MemberEntryContactDataType
 */
class MemberEntryContactDataFormType extends AbstractType
{
    /**
     * {@inheritdoc}
    */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('phone_numbers', CollectionType::class, [
                'entry_type' => PhoneNumberFormType::class,
                'entry_options' => ['current_locale' => $options['current_locale']],
                'by_reference' => false,
                'allow_add'    => true,
                'allow_delete' => true,
            ])
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Core\DataBundle\Entity\MemberEntry',
            'current_locale' => null,
        ));
    }
}

In line 29, the parameter is defined in the parent form, as we already know. Passing it to the sub form is done in line 24. Since we cannot define a new parameter here (the entry is of the type CollectionType, which we cannot change), we have to use a special parameter which has been added just for this type of application. In line 14, you see the use of the entry_options parameter, in which the parameter for the sub form is define in the following array.