Doctrine2和cascade persist - 在非对象上调用成员函数getId()

时间:2013-10-05 23:05:43

标签: php symfony doctrine-orm cascade

我正在测试Symfony2和Doctrin2中Job实体和Category实体之间的级联持续存在。 这是我的Category实体:

<?php
namespace Ibw\JobeetBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Ibw\JobeetBundle\Entity\Affiliate;
use Ibw\JobeetBundle\Entity\Job;
use Ibw\JobeetBundle\Utils\Jobeet;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="Ibw\JobeetBundle\Repository\CategoryRepository")
 * @ORM\Table(name="categories")
 * @ORM\HasLifecycleCallbacks
 */
class Category 
{

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

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     */
    protected $name;

    /**
     * @ORM\OneToMany(targetEntity="Job", mappedBy="category", cascade={"persist"})
     */
    protected $jobs;

    /**
     * @ORM\ManyToMany(targetEntity="Affiliate", mappedBy="categories")
     */
    protected $affiliates;

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     */
    protected $slug;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->jobs = new ArrayCollection();
        $this->affiliates = new ArrayCollection();
    }

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

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

        return $this;
    }

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

    /**
     * Add jobs
     *
     * @param Job $jobs
     * @return Category
     */
    public function addJob(Job $jobs)
    {
        $this->jobs[] = $jobs;

        return $this;
    }

    /**
     * Remove jobs
     *
     * @param Job $jobs
     */
    public function removeJob(Job $jobs)
    {
        $this->jobs->removeElement($jobs);
    }

    /**
     * Get jobs
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getJobs()
    {
        return $this->jobs;
    }

    /**
     * Add affiliates
     *
     * @param Affiliate $affiliates
     * @return Category
     */
    public function addAffiliate(Affiliate $affiliates)
    {
        $this->affiliates[] = $affiliates;

        return $this;
    }

    /**
     * Remove affiliates
     *
     * @param Affiliate $affiliates
     */
    public function removeAffiliate(Affiliate $affiliates)
    {
        $this->affiliates->removeElement($affiliates);
    }

    /**
     * Get affiliates
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getAffiliates()
    {
        return $this->affiliates;
    }

    /**
     * Set slug
     *
     * @param string $slug
     * @return Category
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

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

    /**
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function setSlugValue()
    {
        $this->setSlug(Jobeet::slugify($this->getName()));
    }
}

这里是级联持续存在的部分:

/**
 * @ORM\OneToMany(targetEntity="Job", mappedBy="category", cascade={"persist"})
 */
protected $jobs;

现在,当我尝试使用此测试进行测试时:

public function testAddJobToCategory()
    {
        $job = new Job();
         $job->setType('flexible-time');
         $job->setCompany('Sensio Labs');
         $job->setLogo('sensio-labs.gif');
         $job->setUrl('http://www.sensiolabs.com/');
         $job->setPosition('Web Developer');
         $job->setLocation('Paris, France');
         $job->setDescription('You\'ve already developed websites with symfony and you want to work with Open-Source technologies. You have a minimum of 3 years experience in web development with PHP or Java and you wish to participate to development of Web 2.0 sites using the best frameworks available.');
         $job->setHowToApply('Send your resume to fabien.potencier [at] sensio.com');
         $job->setIsPublic(true);
         $job->setIsActivated(true);
         $job->setToken('job');
         $job->setEmail('job@example.com');
         $job->setExpiresAt(new \DateTime('+30 days'));

         $category = $this->em->createQueryBuilder('c')
                        ->select('c')
                        ->from('IbwJobeetBundle:Category', 'c')
                        ->where('c.id = 1')
                        ->getQuery()
                        ->getSingleResult();

        $category->addJob($job);
        $this->em->persist($category);
        $this->em->flush();

        $jobFromQuery = $this->em->createQueryBuilder('j')
                    ->select('j')
                    ->from('IbwJobeetBundle:Job', 'j')
                    ->where('j.type = :type')
                    ->setParameter('type', 'flexible-time')
                    ->setMaxResults(1)
                    ->setFirstResult(1)
                    ->getQuery()
                    ->getSingleResult();


        $this->assertEquals(1, $jobFromQuery->getCategory()->getId());
    }

当我运行此测试时,我收到此错误:

  

PHP致命错误:在非对象上调用成员函数getId()

所以我认为它在$jobFromQuery->getCategory()->getId()部分。 getCategory()未设置或其他内容。

1 个答案:

答案 0 :(得分:0)

此学说文档http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html说:

  

Doctrine只会检查协会的拥有方是否有变更。

     

要完全理解这一点,请记住在对象世界中如何维护双向关联。关联的每一侧有2个引用,这两个引用都代表相同的关联,但可以彼此独立地改变。当然,在正确的应用程序中,双向关联的语义由应用程序开发人员正确维护(这是他的职责)。 Doctrine需要知道这两个内存引用中的哪一个应该是持久化的,哪些不是。这就是拥有/反向概念主要用于。

     

忽略仅对关联的反面进行的更改。确保更新双向关联的两面(或至少从Doctrine的角度更新所有方)

     

双向关联的拥有方是在确定关联状态时“侧面”的Doctrine“查看”,因此是否有任何事情可以更新数据库中的关联

在您的代码中,您只需执行$category->addJob($job);,因此您可以在反面设置关联。作为被忽略的文档,您至少应该先$job->setCategory($category)