douzhangbao2187 2014-09-12 19:47
浏览 48
已采纳

Symfony2表单映射问题

Im having issues with data mapping to an entity after it is submitted

The Entity:

<?php

namespace Site\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\EntityManager;
use JMS\Serializer\Annotation as Serializer;
use JMS\Serializer\Annotation\Groups;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection; 

/**
 * UserAddress
 *
 * @ORM\Table(name="user_address")
 * @ORM\Entity
 * 
 * @Serializer\ExclusionPolicy("all")
 * ---------- SERIALIZER GROUPS -----
 * all -- All entries
 */
class UserAddress
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * 
     * @Serializer\Type("integer")
     * @Serializer\Expose
     * @serializer\SerializedName("ID")
     * @serializer\Groups({"all"})
     */
    public $ID;

    /**
     * @var integer
     *
     * @ORM\Column(name="user_id", type="integer", nullable=false)
     */
    public $UserId;

     /**
     * @var integer
     *
     * @ORM\Column(name="level_id", type="integer", nullable=false)
     * 
     * @Serializer\Type("integer")
     * @Serializer\Expose
     * @serializer\SerializedName("LevelId")
     * @serializer\Groups({"all"})
     */
    public $LevelId;

     /**
     * @var integer
     *
     * @ORM\Column(name="address_type_id", type="integer", nullable=false)
     * 
     * @Serializer\Type("integer")
     * @Serializer\Expose
     * @serializer\SerializedName("AddressTypeId")
     * @serializer\Groups({"all"})
     * 
     * @Assert\NotBlank()
     */
    public $AddressTypeId;

    /**
     * @var string
     *
     * @ORM\Column(name="address_data", type="text", nullable=false)
     * 
     * @Serializer\Type("string")
     * @Serializer\Expose
     * @serializer\SerializedName("Address Data")
     * @serializer\Groups({"all"})
     * 
     * @Assert\NotBlank()
     */
    public $AddressData;

    /**
     * @var integer
     *
     * @ORM\Column(name="public_yn", type="integer", nullable=false)
     * 
     * @Serializer\Type("boolean")
     * @Serializer\Expose
     * @serializer\SerializedName("PublicYN")
     * @serializer\Groups({"all"})
     * 
     * @Assert\NotBlank()
     */
    public $PublicYN;

    /**
     * @var integer
     *
     * @ORM\Column(name="primary_yn", type="integer", nullable=false)
     * 
     * @Serializer\Type("boolean")
     * @Serializer\Expose
     * @serializer\SerializedName("PrimaryYN")
     * @serializer\Groups({"all"})
     * 
     * @Assert\NotBlank()
     */
    public $PrimaryYN;

     /**
    * @ORM\ManyToOne(targetEntity="Site\UserBundle\Entity\UserMain", inversedBy="UserAddress")
    * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
    */
    public $User;  

    /**
     * @ORM\ManyToOne(targetEntity="Site\UserBundle\Entity\UserAddressType", inversedBy="UserAddress")
     * @ORM\JoinColumn(name="address_type_id", referencedColumnName="address_type_id")
     * 
     * @Serializer\Type("Site\UserBundle\Entity\UserAddressType")
     * @Serializer\Expose
     * @serializer\SerializedName("UserAddressType")
     * @serializer\Groups({"all"})
     */
     public $UserAddressType;




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

    /**
     * Set UserId
     *
     * @param integer $userId
     * @return UserAddress
     */
    public function setUserId($userId)
    {
        $this->UserId = $userId;

        return $this;
    }

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

    /**
     * Set LevelId
     *
     * @param integer $levelId
     * @return UserAddress
     */
    public function setLevelId($levelId)
    {
        $this->LevelId = $levelId;

        return $this;
    }

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

    /**
     * Set AddressTypeId
     *
     * @param integer $addressTypeId
     * @return UserAddress
     */
    public function setAddressTypeId($addressTypeId)
    {
        $this->AddressTypeId = $addressTypeId;

        return $this;
    }

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

    /**
     * Set AddressData
     *
     * @param string $addressData
     * @return UserAddress
     */
    public function setAddressData($addressData)
    {
        $this->AddressData = $addressData;

        return $this;
    }

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

    /**
     * Set PublicYN
     *
     * @param integer $publicYN
     * @return UserAddress
     */
    public function setPublicYN($publicYN)
    {
        $this->PublicYN = $publicYN;

        return $this;
    }

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

    /**
     * Set PrimaryYN
     *
     * @param integer $primaryYN
     * @return UserAddress
     */
    public function setPrimaryYN($primaryYN)
    {
        $this->PrimaryYN = $primaryYN;

        return $this;
    }

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

    /**
     * Set User
     *
     * @param \Site\UserBundle\Entity\UserMain $user
     * @return UserAddress
     */
    public function setUser(\Site\UserBundle\Entity\UserMain $user = null)
    {
        $this->User = $user;

        return $this;
    }

    /**
     * Get User
     *
     * @return \Site\UserBundle\Entity\UserMain 
     */
    public function getUser()
    {
        return $this->User;
    }

    /**
     * Set UserAddressType
     *
     * @param \Site\UserBundle\Entity\UserAddressType $userAddressType
     * @return UserAddress
     */
    public function setUserAddressType(\Site\UserBundle\Entity\UserAddressType $userAddressType = null)
    {
        $this->UserAddressType = $userAddressType;

        return $this;
    }

    /**
     * Get UserAddressType
     *
     * @return \Site\UserBundle\Entity\UserAddressType 
     */
    public function getUserAddressType()
    {
        return $this->UserAddressType;
    }
}

The form is:

namespace Site\UserBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;

class UserAddressType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('UserId','hidden')
            ->add('LevelId', 'integer', array(
                    'label'=>'Sort Rate (Order)'
                ))
            ->add('AddressTypeId', 'entity', array(
                    'class'=>'SiteUserBundle:UserAddressType',
                    'query_builder'=> function(EntityRepository $er){
                            return $er->createQueryBuilder('t')
                            ->orderBy('t.AddressDescription', 'ASC');                        
                        },
                    'property'=>'AddressDescription',
                    'label'=>'Address Type'
                ))
            ->add('AddressData', 'text')
            ->add('PublicYN', 'choice', array(
                    'choices' => array( 'false'=>'Private', 'true'=>'Public'),
                    'required'=>true,
                    'label'=>'Pubicly Visable'
                ))
            ->add('PrimaryYN', 'choice', array(
                    'choices' => array( 'false'=>'Secondary', 'true'=>'Primary'),
                    'required'=>true,
                    'label'=>'Primary Contact',
                ))
            ->add('save', 'submit', array(
                        'label'=>'Add Address',
                        'attr'=>array(
                            'class'=>'btn btn-primary',
                        ),
                  ))
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Site\UserBundle\Entity\UserAddress',
            'csrf_protection'=>false,
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'Create_User_Address';
    }
}

Controller Function is: (I'm using fosrestbundle)

public function newAddressAction($userid, Request $request)
    {

        $statusCode = 201;
        $address = new UserAddress();
        $address->setUserId($userid);

        $form = $this->createForm( new UserAddressType(), $address, array(
                'method'=>'GET',
            ));
        $form->handleRequest($request);

        if($form->isValid()){
               $em = $this->getDoctrine()->getManager();
               $em->persist($address);
               $em->flush();
               return new Response('User Added to system');
        }        
        return $this->render('SiteUserBundle:UserAddress:newUserAddress.html.twig', array(
            'form' => $form->createView(),

)); }

The Twig template is very simple. All the data is posted correctly to the server: (Query String Parameters )

Create_User_Address[LevelId]:0
Create_User_Address[AddressTypeId]:5
Create_User_Address[AddressData]:555-555-5555
Create_User_Address[PublicYN]:false
Create_User_Address[PrimaryYN]:false
Create_User_Address[save]:
Create_User_Address[UserId]:3

but i keep getting the following error:

An exception occurred while executing 'INSERT INTO user_address (user_id, level_id, address_type_id, address_data, public_yn, primary_yn) VALUES (?, ?, ?, ?, ?, ?)' with params [null, 0, null, "555-555-5555", "false", "false"]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'user_id' cannot be null

As you can see the UserID and AddressTypeId fields are not mapping from the form to the Entity. I have looked over the code for all 3 pieces over and ove and for the life of me i can't see where the mismatch is happening. I did at one point change the names of those two fields in the Entity but i deleted all the getters and setters and regenerated them as well as clear the dev cache.

My hunch is there is a file somewhere in Symfony2 there is a mapping class that is wrong but i can't find it..

Thanks all

EDIT:

I tried clearing the doctrine cache as stated here: Symfony2 doctrine clear cache .

app/console doctrine:cache:clear-metadata 
app/console doctrine:cache:clear-query  
app/console doctrine:cache:clear-result

this resulted in the same error being generated,so the cache issue may be off the table.

EDIT:

As per Isaac's suggestion i removed ->add('UserId', 'hidden') . The form still posted with the same error message. The field is being generated correctly to the page; <input type="hidden" id="Create_User_Address_UserId" name="Create_User_Address[UserId]" class=" form-control" value="3"> and as you can see from the Query Parameters above being posted back to the server correctly.

EDIT:

I tracked the issue down to the User and UserAddressType variables. If i remove these two variables and their getters and setters the form works perfectly without other modifications of my code. I should note that these two variables are joins to other entities. Some how they seem to be wiping out the data being submitted by the forms.

  • 写回答

2条回答 默认 最新

  • douqiao2471 2014-09-30 00:22
    关注

    As per lsouza suggestion I had to create a data transformer.

    namespace Site\UserBundle\Form\DataTransformer;
    
    use Symfony\Component\Form\DataTransformerInterface;
    use Symfony\Component\Form\Exception\TransformationFailedException;
    use Doctrine\Common\Persistence\ObjectManager;
    
    use Site\UserBundle\Entity\UserAddressType;
    
    class AddressTypeToNumber implements DataTransformerInterface
    {
        /**
         * @var ObjectManager
         */
        private $om;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om)
        {
            $this->om = $om;
        }
    
        /**
         * Transforms an object(val) to a string
         * 
         * @param UserAddressType|null $val
         * @return string
         */
        public function transform($val)
        {
            if (null === $val) {
                return "";
            }
    
            return array();
        }
    
        /**
         * Transfers a string to an object (UserAddressType)
         * 
         * @param string $val
         * @return UserAddressType|null 
         * @throws TransformationFailedException if object is not found
         */
        public function reverseTransform($val)
        {
            if (!$val) {
                return null;
            }
    
            $addId = $this->om
                ->getRepository('SiteUserBundle:UserAddressType')
                ->findOneBy(array('AddressTypeId' => $val));  
    
             if (null === $addId) {
                 throw new TransformationFailedException(sprintf(
                    'An Address Type with the ID of "%s" does not exsist in the system',
                    $val
                 ));
             }
    
            return $addId;
        }
    }
    

    Please note that the Transformer function is currently returning null but this should return a value that can be used by the form.

    Some other notes that may help others are that the form class needs to be changed as well.

    The setDefaultOptions function needs the following added to the $resolver variable:

        ->setRequired(array(
            'em',
        ))
        ->setAllowedTypes(array(
            'em'=>'Doctrine\Common\Persistence\ObjectManager',
        ));
    

    The buildForm function needs to be changed slightly to accept the em option:

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $em = $options['em'];
       $transformer = new AddressTypeToNumber($em);
    

    The field needs to be change to the varrable that holds the relationship in the Entity and not the field that is use in the link:

        ->add(
            $builder->create('UserAddressType', 'entity', array(
                'class' => 'SiteUserBundle:UserAddressType',
                'property' => 'AddressDescription',
                'label' => 'Address Type'
            ))
            ->addModelTransformer($transformer)
        )
    

    Finally in your controller you need to pass an instance of $this->getDoctrine()->getManager() to the form class:

    $form = $this->createForm( new UserAddressType(), $address, array(
        'em' => $this->getDoctrine()->getManager(),
    ));
    

    I hope this helps others.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站