【问题标题】:Doctrine2 and cascade persist - Call to a member function getId() on a non-objectDoctrine2 和级联持续存在 - 在非对象上调用成员函数 getId()
【发布时间】:2013-10-05 23:05:42
【问题描述】:

我正在测试 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-&gt;getCategory()-&gt;getId() 部分。 getCategory() 未设置或其他。

【问题讨论】:

    标签: php symfony doctrine-orm cascade


    【解决方案1】:

    这个教义文档http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html 说:

    Doctrine 只会检查关联的拥有方是否有更改。

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

    仅对关联的反面所做的更改将被忽略。确保更新双向关联的双方(或至少从 Doctrine 的角度来看拥有方)

    双向关联的拥有方是 Doctrine 在确定关联状态时“查看”的一方,因此是否需要更新数据库中的关联

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

    【讨论】:

    • 嗯,我可以看到$job-&gt;setCategory() 解决了所有问题。但是那$category-&gt;addJob()有什么用呢?
    • 如果你想通过一个类别的每一项工作,只是为了对象引用,但对于学说,反面并不重要
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    相关资源
    最近更新 更多