Symfony 2异常:使用表单事件时,在非对象上调用成员函数

时间:2013-12-04 21:31:51

标签: forms events exception symfony doctrine-orm

我正在尝试创建一个动态加载与“项目”相关的所有“网站”的表单,似乎this会有用,所以我试了一下:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class EngineeringType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('project','entity',array(
                'class' => 'tBundle:Project',
                'label' => 'Project'
            ;
    $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function(FormEvent $event) {
                $form = $event->getForm();
                $data = $event->getData();

                $sites = $data->getProject()->getSites();

                $form->add('site', 'entity', array('choices' => $sites));
            }
        );
    }

当我尝试访问表单时出现问题,我得到:

FatalErrorException: Error: Call to a member function getSites() on a non-object in ... tBundle\Form\EngineeringType.php line 41

以下是我的实体:

namespace tBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Engineering
 *
 * @ORM\Table(name="engineerings")
 * @ORM\Entity
 */
class Engineering
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */

    private $id;

    /**
      * @ORM\ManyToOne(targetEntity="tBundle\Entity\Project")
      * @ORM\JoinColumn(name="project_id", referencedColumnName="id",nullable=false)
      */
    private $project;

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

    /**
     * Set project
     *
     * @param string $project
     * @return Engineering
     */
    public function setProject(\tBundle\Entity\Project $project)
    {
        $this->project = $project;

        return $this;
    }

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

项目:

命名空间tBundle \ Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Project
 *
 * @ORM\Table(name="projects")
 * @ORM\Entity
 */
class Project
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


     /**
     * @ORM\ManyToMany(targetEntity="tBundle\Entity\Site")
     * @ORM\JoinTable(name="project_sites",
     *      joinColumns={@ORM\JoinColumn(name="site_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="project_id", referencedColumnName="id")}
     *      )
     */
    private $sites;

        public function __construct()
    {
        $this->sites = new ArrayCollection();
    }

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

    /**
     * Set name
     *
     * @param string $name
     * @return Project
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Get Sites
     *
     * @return array 
     */
    public function getSites()
    {
        return $this->sites;
    }

    /* Returns Project's Name */
    public function __toString() 
    {
        return $this->name;
    }

我做错了什么?

修改

控制器:

/**
    * Creates a form to create a Engineering entity.
    *
    * @param Engineering $entity The entity
    *
    * @return \Symfony\Component\Form\Form The form
    */
    private function createCreateForm(Engineering $entity)
    {
        $form = $this->createForm(new EngineeringType(), $entity, array(
            'action' => $this->generateUrl('engineering_create'),
            'method' => 'POST',
        ));

        $form->add('submit', 'submit', array('label' => 'Create'));

        return $form;
    }


 /**
    * Creates a form to edit a Engineering entity.
    *
    * @param Engineering $entity The entity
    *
    * @return \Symfony\Component\Form\Form The form
    */
    private function createEditForm(Engineering $entity)
    {
        $form = $this->createForm(new EngineeringType(), $entity, array(
            'action' => $this->generateUrl('engineering_update', array('id' => $entity->getId())),
            'method' => 'POST',
        ));

        $form->add('submit', 'submit', array('label' => 'Update'));

        return $form;
    }

2 个答案:

答案 0 :(得分:1)

PRE_SET_DATA事件实际上被触发了两次。第一次没有任何数据。手册中曾经有一个模糊的解释原因,但我再也找不到了。

所以只是:

        function(FormEvent $event) {
            $form = $event->getForm();
            $data = $event->getData();
            if ($data)
            {

                $sites = $data->getProject()->getSites();

                $form->add('site', 'entity', array('choices' => $sites));
            }
        }

=============================================== ======

更新了答案,展示了如何处理不存在的$ project:

            if ($data)
            {
                $project = $data->getProject();
                $sites = $project ? $project->getSites() : array();

                $form->add('site', 'entity', array('choices' => $sites));
            }

答案 1 :(得分:0)

有一个简单的解决方案,为什么不使用"属性"表单构建器上的属性?

$builder
        ->add('project','entity',array(
            'class' => 'tBundle:Project',
            'label' => 'Project',
            'property' => 'sites');

如果这还不够,甚至可以使用查询构建器:

$builder->add('users', 'entity', array(
    'class' => 'AcmeHelloBundle:User',
    'query_builder' => function(EntityRepository $er) {
        return $er->createQueryBuilder('u')
            ->orderBy('u.username', 'ASC');
    },
));

如果这还不够,你可以在这里找到更多描述: Symfony documentation

编辑:

所以你的问题是,使用第一个解决方案,它将成为一个数组,因此请使用我的第二个选项,并在查询构建器中指定将反映您需求的内容。 或者使用它,就像课程不是项目而是网站。