学说2 OneToMany协会 - 级联从两侧坚持

时间:2015-03-30 22:35:32

标签: php doctrine-orm

免责声明:n00b到Doctrine,而不是一般的ORM,或数据映射器模式,只是Doctrine。不确定我是否遗漏了某些东西(如果具体是对文档的引用是欢迎的!我已经仔细阅读了)或者还有另一种首选方法。这个问题的一个重要部分是如何做到正确的方式,而不一定是如何做到这一点。

deets:我在两个实体之间有一对多关联:Calendar和Event。一个日历可以有很多事件。相关代码:

日历实体

<?php namespace MyPackage\Src {
    use \Doctrine\Common\Collections\ArrayColleciton;
    class Calendar {

        /**
         * @OneToMany(targetEntity="MyPackage\Src\Event", mappedBy="calendarInstance", cascade={"all"})
         */
        protected $associatedEvents;

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

        public function addEvent( Event $eventObj ){
            $eventObj->setCalendarInstance($this);
            $this->associatedEvents->add($eventObj);
        }

        public function getEvents(){
            return $this->associatedEvents;
        }

        // Assume entityManager() returns... an entity manager instance
        public function save(){
            $this->entityManager()->persist($this);
            $this->entityManager()->flush();
            return $this;
        }
    }
}

活动实体

<?php namespace MyPackage\Src {
    class Event {

        /**
         * @ManyToOne(targetEntity="MyPackage\Src\Calendar", inversedBy="associatedEvents")
         * @JoinColumn(name="calendarID", referencedColumnName="id", nullable=false)
         */
        protected $calendarInstance;

        public function setCalendarInstance( Calendar $calObj ){
            $this->calendarInstance = $calObj;
        }

        // Assume entityManager() returns... an entity manager instance
        public function save(){
            $this->entityManager()->persist($this);
            $this->entityManager()->flush();
            return $this;
        }
    }
}

ORM的语义指出“Doctrine只会检查关联的拥有方是否有变化”(&lt; - 读取文档的证明)。因此,在创建新事件时执行以下操作(假设日历强制执行级联持久性,我已使用“all”设置),然后从日历实例获取ArrayCollection。

<?php
    // Assume this returns a successfully persisted entity...
    $cal = Calendar::getByID(1);
    // Create a new event
    $event = new Event();
    $event->setTitle('Wowza');
    // Associate the event to the calendar
    $cal->addEvent($event);
    $cal->save();
    // Yields expected results (ie. ArrayCollection is kept in-sync)
    echo count($cal->getEvents()); // "1"

然后喵...让我们说出一些有趣的理由我想从事件方创建一个关联,如下所示:

<?php
    // Assume this returns a successfully persisted entity...
    $cal = Calendar::getByID(1);
    // Create a new event
    $event = new Event();
    $event->setTitle('Dewalt Power Tools');
    // Associate VIA EVENT
    $event->setCalendarInstance($cal);
    $event->save();
    // ArrayCollection in the Calendar instance is out of sync
    echo count($cal->getEvents()); // "0"

以这种方式保持事件 工作(它被保存到数据库) - 但是现在当尝试从日历访问相关事件时,实体管理器不同步。此外,可以理解为什么:在setCalendarInstance()类的Event方法中,所有发生的事情都是

$this->calendarInstance = $calendar;

我已经尝试了以下(实际上有效,只是觉得很顽皮)

$this->calendarInstance = $calendar;
if( ! $this->calendarInstance->getEvents()->contains($this) ){
    $this->calendarInstance->getEvents()->add($this);
}

但是,这感觉非常强烈,因为我正在打破正确的封装,这对我很重要。我是愚蠢的,并且可以在Calendar类之外->add()到Calendar实例的返回ArrayCollection吗? (多数民众赞成我的意思,这感觉不对; ArrayCollection是Calendar的受保护属性,我觉得不应该在外部修改。)

----或----

我是否应该强制仅从拥有方(日历)创建关联,并且不允许执行$event->setCalendarInstance()然后保存事件。这再次提出了关于封装的另一点,setCalendarInstance必须是一个公共方法才能使Calendar的addEvents()方法起作用(所以我如何防止一些可怜的灵魂继承我的代码库不正确地执行它) ?

谢谢,有兴趣听听此方法。

**编辑** 更有趣的业务:走创建新事件的路线,传递日历实例,然后坚持新事件 - 这里似乎存在差异:

// Get an existing Calendar that has one Event
$calObj = Calendar::getByID(1);
echo count($calObj->getEvents()); // "1"

// Add from event side
$event = new Event();
$event->setTitle('Pinkys Brain');
$event->setCalendarInstance($calObj);
$event->save();

// I would think this would be "2" now...
echo count($calObj->getEvents()); // Still "1"

但是......这很有效,而且感觉很糟糕。

// Get an existing Calendar that has one Event
$calObj = Calendar::getByID(1);
echo count($calObj->getEvents()); // "1"

// Add from event side
$event = new Event();
$event->setTitle('Pinkys Brain');
$event->setCalendarInstance($calObj);
$event->save();

// Clear the entity manager on the existing $calObj
$calObj->entityManager()->clear();

// Now get a NEW instance of the same calendar
$calObjAgain = Calendar::getByID(1);
echo count($calObjAgain->getEvents()); // "2"

0 个答案:

没有答案