Symfony 3.x - 对提交的表单数据对象使用实体getId()方法返回对象(不是整数)

I am trying to create a filter form with multiple fields, and one of them is a select/drop-down for selecting from a list of Tournaments.

The idea is to make the form reusable so I'm creating a FilterType form class. The Tournament select field is created by embedding a TournamentChoiceType form class which creates an EntityType field using the Tournament entity.

The issue I'm facing is when the form is submitted and I get the submitted data. The $tournamentChoice is a Tournament object (which is OK), but $tournamentId = $tournamentChoice->getId() is returning a Tournament object too, and it should be an integer (the ID columnn).

The mess seems to happen here:

$filterForm->handleRequest($request);

because when I view/dump the raw POST request all seems normal and the filter[tournament][id] is just an integer parameter passed in, as expected.

Here's the code.

Controller:

$em = $this->getDoctrine()->getManager();
$tournamentSelected = $em->getRepository('MyBundle:Tournament')
        -> findOneById($id);
$tournamentsList = $em->getRepository('MyBundle:Tournament')
        ->findAll();

$formInputData = array();
$formInputData['tournament']['data'] = $tournamentSelected;
$formInputData['tournament']['choices'] = $tournamentsList;
formData = array();

$filterForm = $this->createForm(FilterType::class, $formData, array(
    'data' => $formInputData
));

$filterForm->handleRequest($request);

if ($filterForm->isSubmitted() && $filterForm->isValid()) {
    $formData = $filterForm->getData();

    $tournamentChoice = $formData['tournament'];
    $tournamentId = $tournamentChoice->getId();
    $dateFromChoice = $formData['date_from'];
    $dateToChoice = $formData['date_to'];

    return $this->redirectToRoute(
        'index',
        array('tournament' => $tournamentId)
    );
}

FilterType form class:

class FilterType extends AbstractType
{
    protected $data;

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => null
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $this->data = $options['data'];

        ...

        $builder
            ->add('tournament', TournamentChoiceType::class, array(
                'choices' => $this->data['tournament']['choices'],
                'data' => $this->data['tournament']['data']
            ))
        ;

        ...
    }
}

TournamentChoiceType form class:

class TournamentChoiceType extends AbstractType
{
    protected $data;
    protected $choices;

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\Tournament',
            'choices' => null
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $this->data = $options['data'];
        $this->choices = $options['choices'];

        $builder
            ->add('id', EntityType::class, array(
                'class' => 'MyBundle:Tournament',
                'choices' => $this->choices,
                'choice_label' => 'name',
                'label' => false,
                'data' => $this->data
            ))
        ;
    }
}

Tournament entity class:

class Tournament
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    ...

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    ...
}

Here's how var_dump($filterForm->getData()) looks like, after a submit:

array (size=4)
  'field1' => string 'text' (length=4)
  'field2' => string 'text' (length=4)
  ...
  'tournament' => 
    object(MyBundle\Entity\Tournament)[631]
      private 'id' => 
        object(MyBundle\Entity\Tournament)[522]
          private 'id' => int 11
          private 'name' => string 'tournament1' (length=11)
          private ...
          ...

and here's how var_dump($filterForm->getData()) looks like, after a second submit:

array (size=4)
  'field1' => string 'text' (length=4)
  'field2' => string 'text' (length=4)
  ...
  'tournament' => 
    object(MyBundle\Entity\Tournament)[513]
      private 'id' => 
        &object(MyBundle\Entity\Tournament)[513]
      private 'name' => string 'tournament1' (length=11)
      private ...

What's with the object's ID being an object (and not being just an interger), or referencing an object?

The problem is caused by double data insertion. You have to refactor your code to set the data only once.

Firstly you set it here:

$formInputData['tournament']['data'] = $tournamentSelected;

Secondly if there is any request, then you set it again here:

$filterForm->handleRequest($request);

I'm not certain, but I believe in your controller you need to change this:

from:

$tournamentChoice = $formData['tournament'];

to:

$tournamentChoice = $formData['tournament']['choices'];

Try it. Otherwise you need to post more of your code in the controller. In particular how you create the $formInputData array.

Edit #2. On now seeing the rest of your controller code, I now sees what's going on. You need to get the form data like so:

$formData = $filterForm->get("tournament")->getData();

This gets an array of results, so then you need to do a foreach (or similar). This is because when you created $tournamentList, you did it like this:

$tournamentsList = $em->getRepository('MyBundle:Tournament')->findAll();