Symfony 2 嵌入式表单

9
我将一个表单类型嵌入到另一个表单类型中,方法如下:
$builder->add('parent', new \Company\Bundle\Form\UserObjects\AParentType);

然而,当我尝试将请求绑定到表单时。
if($request->getMethod() == 'POST') {
      $form->bindRequest($request);
}

我遇到了错误

可捕获的致命错误:Company\Bundle\Entity\UserObjects\User :: setParent()的第1个参数必须是 Company\Bundle\Entity\UserObjects\AParent 的实例,但却传递了数组,在 /Volumes/Media/Symfony/vendor/symfony/src/Symfony/Component/Form/Util/PropertyPath.php 的第346行调用并在 /Volumes/Media/Symfony/src/Company/Bundle/Entity/UserObjects/User.php 的第771行中定义

看起来表单将“AParent”对象作为数组而不是实体传递。有什么想法吗? 编辑 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';
        }
    }

你的第一个代码片段中,类名后面的括号不是必须的吗? - greg0ire
还有更多的代码会更有帮助。这个并没有告诉我们太多信息。 - Flukey
@greg0ire 我不这么认为,因为表单在页面上构建和显示得很好,但当表单被提交并绑定到用户对象时,就会出现这个错误。 - Daniel
@Jamie,您还想看什么?实际上并没有太多内容,而且我现在也不在电脑旁边,无法提供代码。 - Daniel
你的实体定义和表单类似乎存在关系问题。请检查一下。 - Flukey
@Jamie,我已经添加了所请求的代码。这可能是由于表单无法使用一对一关系进行嵌入吗? - Daniel
1个回答

8
您的 AParentType 表单中尚未设置数据类。您可以按照以下方式进行设置:
public function getDefaultOptions(array $options)
{
    return array(
        'data_class' => 'Project\MyBundle\Entity\AParent',
    );
}

对于Symfony的后续版本,您需要使用以下内容:

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

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

请替换此处:

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

使用以下方法:

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

因为您已经包含了命名空间。
如果是一对一的情况(这就是您的表单模板),您可以这样做:
{{ form_row(form.parent.zipCode) }}

希望这样做可以奏效。你的实体定义看起来很好 :-)

太好了!非常感谢!我简直不敢相信自己居然忘记了那个方法,现在它变得非常清晰易懂了! - Daniel
1
三年后遇到了这个问题,哈!原来的解决方案无效,但使用 setDefaultOptionsOptionsResolverInterface 完美解决了。我已将其添加到您的解决方案中。 - sjagr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接