2

I am using Symfony2 framework (in particular, Symfony 2.7). My question is related to form building.

I have an entity named place, that can be associates to many other entities of my project. So, I created a custom form type that can be reused in many parts of my application.

class PlacesType extends AbstractType
{

    private $security_context;

    public function __construct(SecurityContext $security_context)
    {
        $this->security_context = $security_context;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $user = $this->security_context->getToken()->getUser();

        parent::configureOptions($resolver);

        $resolver->setDefaults(array(
            'class' => 'AppBundle\Entity\Places',
            'query_builder' => function (EntityRepository $repository) use ($user)
            {
                return $repository->queryPlacesForUser($user);
            },
        ));

    }

    public function getParent()
    {
        return 'entity' ;
    }

    public function getName()
    {
        return 'places';
    }
}

Fact is, places can be soft-removed (I set a deleted flag inside the class). So, new entities can be associated only to active places, while old entities can maintain their association with a now-deleted place.

For this reason, I want that the queryPlacesForUser function returns only active places, unless the place was already being associated to the parent's form data.
Something like this:

    public function configureOptions(OptionsResolver $resolver)
    {
        // ...

        $currdata = $this->getForm()->getData(); // pseudo-code, this does not work

        $resolver->setDefaults(array(
            'class' => 'AppBundle\Entity\Places',
            'query_builder' => function (EntityRepository $repository) use ($user)
            {
                return $repository->queryPlacesForUser($user, $currdata);
            },
        ));

    }

Unfortunately, I have no clue how to get current data from the options resolver. It is possible to retrieve current data inside the form's buildForm function, however it is not possible to set form options inside of it.

Is there a way I can set form default options using form passed data?

3
  • Would you be willing to inject the needed configuration data at that point in your code where you're using this custom form type? Commented Jun 1, 2016 at 10:21
  • No, I thought about it, but you would lose the benefits of having a shared form type. Commented Jun 1, 2016 at 10:32
  • Honestly, I think that's your only option. And it issn't much different from injecting the form data issn't it? I'll add an answer to show what I mean. Commented Jun 1, 2016 at 10:37

2 Answers 2

3

You don't have access to the form data inside configureOptions. With the added constraint that you only want to pre/reconfigure an extended type, I think, the only option is to extract the needed configuration to the place where this custom form type is used. E.g.:

Usage:

<?php

/**
 * @inheritdoc
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $this->builder->add('place', PlacesType::class, [
        'only_active' => false // <- this is the *external* configuration
    ]);
}

In PlacesType:

<?php

/**
 * @inheritdoc
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'class' => 'AppBundle\Entity\Places',
        'only_active' => true, // <- this is the *default* configuration

        // note the extra closure, this gives you access to the *resolved* options.
        'query_builder' => function (Options $options) { 
            return function (EntityRepository $repository) use ($options) {
                return $repository->queryPlacesForUser(
                    $this->security_context->getToken()->getUser(),
                    $options['only_active']
                );
            };
        },
    ));
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your help. I used your answer (I passed directly the current place within the options), but I still do not like it very much. I had to modify more or less 20 forms where I was using my places form type, and other entities of my project could behave in the same way. I would prefer a more scalable solution.
@Alberto I understand and have hit that specific road block myself a number of times. The problem really only arises from the fact that you want to change the defaults of the extended type based on underlying data. Till today, I haven't found a better solution, though I would really like to see one.
0

you can use an event listener like so :

    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
                    $data = $event->getData();
                    $form = $event->getForm();
    //check your data here and add the fields you want accordingly

$field = $builder->get('fieldToModify');         // get the field
$options = $field->getOptions();            // get the options
$type = $field->getType()->getName();       // get the name of the type
$options['label'] = "Login Name";           // change the label
$builder->add('fieldToModify', $type, $options); // replace the field
        }

1 Comment

Thanks for your answer, but I am not trying to add children to the form, but to set the options of current one.

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.