【问题标题】:Symfony2 and Doctrine - 'Catchable fatal error' on flushSymfony2 和 Doctrine - 刷新时出现“可捕获的致命错误”
【发布时间】:2013-06-11 20:10:10
【问题描述】:

名称因保密协议而更改。

我正在尝试制作一份调查表。每个调查问题都可以有多个答案/分数,因此它们之间存在自然的 1:* 关系。也就是说,对于面向公众的表格,我需要在分数和它相关的问题之间建立 1:1 的关系,这就是我现在正在做的事情。目前,该调查向公众开放,因此每个已完成的调查与用户无关。

我当前设置的有趣部分如下...

问题:

namespace Acme\MyBundle\Entity;

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

class Question
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

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

    /**
     * @var ArrayCollection scores
     *
     * @ORM\OneToMany(targetEntity="Score", mappedBy="question")
     */
    private $scores;

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

    // other getters and setters

    /**
     * @param $score
     */
    public function setScore($score)
    {
        $this->scores->add($score);
    }

    /**
     * @return mixed
     */
    public function getScore()
    {
        if (get_class($this->scores) === 'ArrayCollection') {
            return $this->scores->current();
        } else {
            return $this->scores;
        }
    }
}

最后两个是辅助方法,因此我可以添加/检索个人分数。类型检查卷积是由于我遇到的错误here

得分:

namespace Acme\MyBundle\Entity;

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

class Score
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var integer $question
     *
     * @ORM\ManyToOne(targetEntity="Question", inversedBy="scores")
     * @ORM\JoinColumn(name="question_id", referencedColumnName="id")
     */
    private $question;

    /**
     * @var float score
     *
     * @ORM\Column(name="score", type="float")
     */
    private $score;

    // getters and setters
}

控制器方法:

public function takeSurveyAction(Request $request)
{
    $em = $this->get('doctrine')->getManager();
    $questions = $em->getRepository('Acme\MyBundle\Entity\Question')->findAll();
    $viewQuestions = array();

    foreach ($questions as $question) {
        $viewQuestions[] = $question;
        $rating = new Score();
        $rating->setQuestion($question->getId());
        $question->setRatings($rating);
    }

    $form = $this->createForm(new SurveyType(), array('questions' => $questions));

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

        if ($form->isValid()) {
            foreach ($questions as $q) {
                $em->persist($q);
            }

            $em->flush();
            $em->clear();

            $url = $this->get('router')->generate('_main');
            $response = new RedirectResponse($url);

            return $response;
        }
    }

    return $this->render('MyBundle:Survey:take.html.twig', array('form' => $form->createView(), 'questions' => $viewQuestions));
}

我的表单类型....

调查类型:

namespace Acme\MyBundle\Form\Type;

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

class SurveyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('questions', 'collection', array('type' => new SurveyListItemType()));
    }

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

SurveyListItemType:

namespace Acme\MyBundle\Form\Type;

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

class SurveyListItemType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('rating', new SurveyScoreType());
    }

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

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

SurveyScoreType:

namespace Acme\MyBundle\Form\Type;

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

class SurveyRatingType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('score', 'choice', array('choices' => array(
                             '0' => '',
                             '0.5' => '',
                             '1' => '',
                             '1.5' => '',
                             '2' => '',
                             '2.5' => '',
                             '3' => '',
                             '3.5' => '',
                             '4' => '',
                             '4.5' => '',
                             '5' => ''
                         ), 'expanded' => true, 'multiple' => false));
    }

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

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

好的,尽管如此,当 Doctrine 的 EntityManager 尝试在我的控制器操作中刷新()时,我收到以下错误:

可捕获的致命错误:传递给 Doctrine\Common\Collections\ArrayCollection::__construct() 的参数 1 必须是数组类型,给定对象,在 /home/kevin/www/project/vendor/doctrine/orm/ 中调用lib/Doctrine/ORM/UnitOfWork.php 在第 547 行并在 /home/kevin/www/project/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php 第 47 行定义

相信这与问题的相关分数有关,因为它们应该是 Question 中的一个数组(集合),但在这种情况下它们是单独的实例。唯一的问题是我不知道如何解决它。

我认为我的表单设置可能过于复杂。我真正需要做的就是将每个 Question.id 附加到每个相关的分数。我只是不确定构建它的表单部分的最佳方法,以便正确保存所有内容。

【问题讨论】:

    标签: symfony doctrine-orm


    【解决方案1】:

    我相信你的错误就在这里

        $rating = new Score();
        //...
        $question->setRatings($rating);
    

    通常,如果您的 Entity 中有一个 ArrayCollection,那么您就有 addChildEntity 和 removeChildEntity 方法,用于在 ArrayCollection 中添加和删除元素。

    setRatings() 将采用一组实体,而不是单个实体。

    假设你有这个方法,试试

    $question->addRating($rating);
    

    【讨论】:

    • 这不是我作为辅助方法添加到 Question 中的吗?还是通过 Doctrine 自动添加的,所以我不必手动将其添加到自己的实体中?
    【解决方案2】:

    我认为您的 setRating 方法有误。

    你有

     $this->score->add($score);
    

    应该是:

      $this->scores->add($score);
    

    【讨论】:

    • 不,这只是我的一个错字,并没有完全破坏我的保密协议。在真实的代码中是正确的。
    【解决方案3】:

    我能够通过简单地处理分数来解决它。因此,通过这种方法,我能够删除 SurveyListItemType,并进行以下更改:

    调查类型:

    namespace Acme\MyBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    
    class SurveyType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('scores', 'collection', array('type' => new SurveyRatingType()));
        }
    
        public function getName()
        {
            return 'survey';
        }
    }
    

    请注意集合类型现在如何映射到 SurveyRatingType。

    SurveyRatingType:

    namespace Acme\MyBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    
    class SurveyRatingType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('score', 'choice', array('choices' => array(
                                 '0' => '',
                                 '0.5' => '',
                                 '1' => '',
                                 '1.5' => '',
                                 '2' => '',
                                 '2.5' => '',
                                 '3' => '',
                                 '3.5' => '',
                                 '4' => '',
                                 '4.5' => '',
                                 '5' => ''
                             ), 'expanded' => true, 'multiple' => false));
        }
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        { 
            $resolver->setDefaults(array('data_class' => 'Acme\MyBundle\Entity\Score'));
        }
    
        public function getName()
        {
            return 'survey_rating_type';
        }
    }
    

    以及我修改后的控制器操作:

    public function takeSurveyAction(Request $request)
    {
        $em = $this->get('doctrine')->getManager();
        $questions = $em->getRepository('Acme\MyBundle\Entity\Question')->findAll();
        $ratings = array();
    
        foreach ($questions as $question) {
            $rating = new SurveyRating();
            $rating->setQuestion($question);
            $ratings[] = $rating;
        }
    
        $form = $this->createForm(new SurveyType(), array('ratings' => $ratings));
    
        if ('POST' === $request->getMethod()) {
            $form->bind($request);
    
            if ($form->isValid()) {
                foreach ($ratings as $r) {
                    $em->persist($r);
                }
    
                $em->flush();
                $em->clear();
    
                $url = $this->get('router')->generate('_main');
                $response = new RedirectResponse($url);
    
                return $response;
            }
        }
    
        return $this->render('MyBundle:Survey:take.html.twig', array('form' => $form->createView(), 'questions' => $questions));
    }
    

    由于三种表单类型,我感觉我做错了。这真的是一种糟糕的代码气味。感谢大家的耐心和帮助。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 2017-02-09
      相关资源
      最近更新 更多