Attractive fatal error in form event subscriber using Symfony 2.3

advertisements

After updating to Symfony 2.3 from 2.1, there is a strange message when I am trying to create a form :

Catchable Fatal Error: Argument 1 passed to msgr\ProfileBundle\Form\EventListener\AddNameFieldSubscriber::preSetData() must be an instance of Symfony\Component\Form\Event\DataEvent, instance of Symfony\Component\Form\FormEvent given in /xxxxxx/aaas/src/msgr/ProfileBundle/Form/EventListener/AddNameFieldSubscriber.php line 29

These are the usual suspects :

ProfileType.php

    <?php

namespace aaas\ProfileBundle\Form;

use Doctrine\ORM\EntityRepository;

use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use aaas\ProfileBundle\Form\EventListener\AddNameFieldSubscriber;

class ProfileType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $subscriber = new AddNameFieldSubscriber($builder->getFormFactory());
        $builder->addEventSubscriber($subscriber);
        $builder
            ->add('firstname')
            ->add('lastname')
            ->add('city')
            ->add('country')
            ->add('mobile')
            ->add('description')
            ->add('avatarFile')
            ->add('website')
            ->add('facebook')
            ->add('twitter')
            ->add('googlePlus')
            ->add('gender', 'choice', array(
                'choices'   => array('M' => 'man', 'F' => 'female'),
                'required'  => true,
                'empty_value' => 'choose your gender',
            ))
            ;
    }

    //public function getParent()
    //{
    //    return 'form';
    //}

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'aaas\ProfileBundle\Entity\Profile'
        ));
    }

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

AddNameFieldSubscriber.php

<?php
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php
namespace aaas\ProfileBundle\Form\EventListener;

use Symfony\Component\Form\FormFactoryInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;

class AddNameFieldSubscriber implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        // Tells the dispatcher that we want to listen on the form.pre_set_data
        // event and that the preSetData method should be called.
        return array(FormEvents::PRE_SET_DATA => 'preSetData');
    }

    public function preSetData(DataEvent $event)
    {
        //$data = $event->getData();
        $form = $event->getForm();

        // During form creation setData() is called with null as an argument
        // by the FormBuilder constructor. We're only concerned with when
        // setData is called with an actual Entity object in it (whether new,
        // or fetched with Doctrine). This if statement let's us skip right
        // over the null condition.
        if (null === $data) {
            return;
        }

        // check if the product object is "new"

        if (!$data->getId()) {
            $form->add($this->factory->createNamed('username','text', array(
                                                   'auto_initialize' => false
                                                    )));
            $form->add($this->factory->createNamed('password','password'));
            $form->add($this->factory->createNamed('email','email'));
            $form->add($this->factory->createNamed('groups', 'entity',null, array(
                                                   'multiple' => false,
                                                   'class' => 'aaasProfileBundle:Group',
                                                   'query_builder' => function(EntityRepository $er) {
                                                                         return $er->createQueryBuilder('g')
                                                                                     ->where('g.id != 1')
                                                                                     ->andwhere('g.id != 2')
                                                                                     ->andwhere('g.id != 3');
                                                      }
                                                  )));
        }

    }
}

Unfortunately, I cannot find the root cause of the problem !


Your class AddNameFieldSubscriber has a method public function preSetData(DataEvent $event) that should instead be typehinting for FormEvent. The Form component changed which Event object was dispatched between 2.1 and 2.3:

<?php
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php
namespace aaas\ProfileBundle\Form\EventListener;

use Symfony\Component\Form\FormFactoryInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;

class AddNameFieldSubscriber implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        // Tells the dispatcher that we want to listen on the form.pre_set_data
        // event and that the preSetData method should be called.
        return array(FormEvents::PRE_SET_DATA => 'preSetData');
    }

    public function preSetData(FormEvent $event)
    {
        //$data = $event->getData();
        $form = $event->getForm();

        // During form creation setData() is called with null as an argument
        // by the FormBuilder constructor. We're only concerned with when
        // setData is called with an actual Entity object in it (whether new,
        // or fetched with Doctrine). This if statement let's us skip right
        // over the null condition.
        if (null === $data) {
            return;
        }

        // check if the product object is "new"

        if (!$data->getId()) {
            $form->add($this->factory->createNamed('username','text'));
            $form->add($this->factory->createNamed('password','password'));
            $form->add($this->factory->createNamed('email','email'));
            $form->add($this->factory->createNamed('groups', 'entity',null, array(
                                                   'multiple' => false,
                                                   'class' => 'aaasProfileBundle:Group',
                                                   'query_builder' => function(EntityRepository $er) {
                                                                         return $er->createQueryBuilder('g')
                                                                                     ->where('g.id != 1')
                                                                                     ->andwhere('g.id != 2')
                                                                                     ->andwhere('g.id != 3');
                                                      }
                                                  )));
        }

    }
}