Symfony 2 Embedded Forms

Daniel picture Daniel · Nov 7, 2011 · Viewed 12k times · Source

I am embedding a form type into another form type like so

$builder->add('parent', new \Company\Bundle\Form\UserObjects\AParentType);

However when I try and bind the request to the form

if($request->getMethod() == 'POST') {
      $form->bindRequest($request);
}

I get the error

Catchable Fatal Error: Argument 1 passed to Company\Bundle\Entity\UserObjects\User::setParent() must be an instance of Company\Bundle\Entity\UserObjects\AParent, array given, called in /Volumes/Media/Symfony/vendor/symfony/src/Symfony/Component/Form/Util/PropertyPath.php on line 346 and defined in /Volumes/Media/Symfony/src/Company/Bundle/Entity/UserObjects/User.php line 771

It seems like the form is passing the "AParent" object as an array instead of as an entity. Any ideas?

Edited

User.php

    <?php
    // src/Company/Bundle/Entity/UserObjects/Users.php

    namespace Company\Bundle\Entity\UserObjects;

    use Symfony\Component\Security\Core\User\UserInterface;

    use Doctrine\ORM\Mapping as ORM;

    /**
     * @ORM\Entity(repositoryClass="Company\Bundle\Repository\UserObjects\UserRepository")
     * @ORM\Table(name="user")
     * @ORM\HasLifecycleCallbacks()
     */
    class User implements UserInterface, \Serializable
    {
         /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;

         /**
         * @ORM\Column(type="string")
         */
        protected $username;

         /**
         * @ORM\Column(type="string")
         */
        protected $password;

         /**
         * @ORM\Column(type="string")
         */
        protected $securityQuestion;

         /**
         * @ORM\Column(type="string")
         */
        protected $securityAnswer;

         /**
         * @ORM\Column(type="string")
         */
        protected $salt;


        /**
         * @ORM\OneToOne(targetEntity="AParent", inversedBy="user")
         */
        private $parent;







        public function serialize()  
        {  
            return serialize(array(  
                'username'    => $this->getUsername(),  
                'password'    => $this->getPassword(),  
                'salt'        => $this->getSalt(),  
                'roles'       => $this->getRoles(),
            ));  
        } 

        public function unserialize($serializedData)  
        {  
            $unserializedData     = unserialize($serializedData);  

            $this->setUsername(isset($unserializedData['username']) ? $unserializedData['username'] : null);  
            $this->setPassword(isset($unserializedData['password']) ? $unserializedData['password'] : null);  
            $this->setSalt(isset($unserializedData['salt']) ? $unserializedData['salt'] : null); 
        }  

        public function getRoles()
        {
            return array('ROLE_USER');
        }




        public function eraseCredentials()
        {
            return false;
        }

         public function equals(UserInterface $user)
        {
               if ($user->getUsername() != $this->getUsername()) {
                    return false;
                }
                if ($user->getEmail() != $this->getEmail()) {
                    return false;
                }
                return true;
        }

        /**
         * Get password
         *
         * @return string 
         */
        public function getPassword()
        {
            return $this->password;
        }

        /**
         * Get salt
         *
         * @return string 
         */
        public function getSalt()
        {
            return $this->salt;
        }

        public function getUsername()
        {
            return $this->username;
        }

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

        /**
         * Set username
         *
         * @param string $username
         */
        public function setUsername($username)
        {
            $this->username = $username;
        }

        /**
         * Set password
         *
         * @param string $password
         */
        public function setPassword($password)
        {
            $this->password = $password;
        }

        /**
         * Set securityQuestion
         *
         * @param string $securityQuestion
         */
        public function setSecurityQuestion($securityQuestion)
        {
            $this->securityQuestion = $securityQuestion;
        }

        /**
         * Get securityQuestion
         *
         * @return string 
         */
        public function getSecurityQuestion()
        {
            return $this->securityQuestion;
        }

        /**
         * Set securityAnswer
         *
         * @param string $securityAnswer
         */
        public function setSecurityAnswer($securityAnswer)
        {
            $this->securityAnswer = $securityAnswer;
        }

        /**
         * Get securityAnswer
         *
         * @return string 
         */
        public function getSecurityAnswer()
        {
            return $this->securityAnswer;
        }

        /**
         * Set salt
         *
         * @param string $salt
         */
        public function setSalt($salt)
        {
            $this->salt = $salt;
        }




        /**
         * Set parent
         *
         * @param Company\Bundle\Entity\UserObjects\AParent $parent
         */
        public function setParent(\DABSquared\ProjectGradesBundle\Entity\UserObjects\AParent $parent)
        {
            $this->parent = $parent;
            if($parent != null) {
                $parent->setUser($this);
            }
        }

        /**
         * Get parent
         *
         * @return Company\Bundle\Entity\UserObjects\AParent 
         */
        public function getParent()
        {
            return $this->parent;
        }


        }
        public function __construct()
        {
        }

    }

AParent.php

    <?php
    // src/Company/Bundle/Entity/UserObjects/AParent.php

    namespace Company\Bundle\Entity\UserObjects;

    use Doctrine\ORM\Mapping as ORM;



    /**
     * @ORM\Entity(repositoryClass="Company\Bundle\Repository\UserObjects\AParentRepository")
     * @ORM\Table(name="parents")
     * @ORM\HasLifecycleCallbacks()
     */
    class AParent
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;


        /**
         * @ORM\OneToOne(targetEntity="User", inversedBy="parent")
         */
         private $user;

                    /**
                     * @ORM\Column(type="string")
                     */
                    protected $zipCode;


        public function __construct()
        {

        }

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

        /**
         * Set user
         *
         * @param Company\Bundle\Entity\UserObjects\User $user
         */
        public function setUser(\Company\Bundle\Entity\UserObjects\User $user)
        {
            $this->user = $user;
        }

        /**
         * Get user
         *
         * @return Company\Bundle\Entity\UserObjects\User 
         */
        public function getUser()
        {
            return $this->user;
        }

                    /**
         * Set zipCode
         *
         * @param string $zipCode
         */
        public function setZipCode($zipCode)
        {
            $this->zipCode = $zipCode;
        }

        /**
         * Get zipCode
         *
         * @return string 
         */
        public function getZipCode()
        {
            return $this->zipCode;
        }



    }

UserType.php

    <?php

    namespace Company\Bundle\Form;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilder;

    use Doctrine\ORM\EntityRepository;

    class UserType extends AbstractType
    {
        public function buildForm(FormBuilder $builder, array $options)
        {
            $builder
                ->add('username',null,array('label' => 'Username:'))
                ->add('password',null,array('label' => 'Password:'))
                ->add('securityQuestion',null,array('label' => 'Security Question:'))
                ->add('securityAnswer',null,array('label' => 'Security Answer:'))
                ->add('parent', new \Company\Bundle\Form\UserObjects\AParentType);

        }

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

AParentType.php

    <?php

    namespace Company\Bundle\Form\UserObjects;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilder;

    class AParentType extends AbstractType
    {
        public function buildForm(FormBuilder $builder, array $options)
        {
            $builder
                ->add('zipCode',null,array('label' => 'Zip Code:'));
        }

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

Answer

Flukey picture Flukey · Nov 8, 2011

You haven't set the data class in your AParentType form. You do that like this:

public function getDefaultOptions(array $options)
{
    return array(
        'data_class' => 'Project\MyBundle\Entity\AParent',
    );
}

For later versions of Symfony, you'll need to use this instead:

use Symfony\Component\OptionsResolver\OptionsResolverInterface;
//...

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Project\MyBundle\Entity\AParent',
    ));
}

Replace this:

->add('parent', new \Company\Bundle\Form\UserObjects\AParentType);

With this:

->add('parent', new AParentType());

because you've already included the namespace.

And if it's one-to-one, which it is, in your form template, you do:

{{ form_row(form.parent.zipCode) }}

Hopefully that should work. Your entity definitions look fine :-)