开发者

One to many relationships in Doctrine 2 ORM not inserting remote key

Hi there Stack Overflow members!

I am having a problem with some Doctrine 2 relations that are current running me into the ground.

I am attempting to setup a very nice and simple One to Many relationship in Doctrine between my AnalyticsCampaign model and my AnalyticsData model.

Below is my code and my problem.

foreach($entries as $entry)
{
    // Instance of AnalyticsCampaign model with data in it.
    $campaign = $this->_getCampaignByGoogleId($entry['campaignId']);            
    $daysAgo = time() - $campaign->getUpdated();
    $dateCreated = time() - $campaign->getCreated();
    if($daysAgo>=86400 || $dateCreated < 86400)
    {
        // More or equal to 1 day has passed since last database update
        // Let's insert these fuckers.
        // Insert the new GA data.

        $data = new Model_AnalyticsData();
        $data->fromArray($entry);
        $data->setCampaign($campaign->getId());
        $campaign->data = array($data);
        $this->em->persist($campaign);

    }
}
$this->em->flush();

Analytics Campaign data

<?php


/**
 * AnalyticsCampaign
 *
 * @Table(name="analyticsCampaign")
 * @Entity
 */
class Model_AnalyticsCampaign
{

    const STATUS_ACTIVE = 1;

    const STATUS_INACTIVE = 0;

    /**
     * @var integer $id
     *
     * @Column(name="id", type="integer", nullable=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

    /**
     * @var string $analyticsCampaignId
     *
     * @Column(name="analyticsCampaignId", type="integer", length=25, nullable=false)
     */
    private $analyticsCampaignId;


    /**
     * @Column(type=开发者_JAVA百科"integer")
     */
    private $updated;

    /**
     * @Column(type="integer")
     */
    private $created;

    /**
     * @Column(type="integer")
     */
    private $status;

    /**
     * @OneToMany(targetEntity="Model_AnalyticsData", mappedBy="campaign", cascade={"persist"})
     * @param \Doctrine\Common\Collections\ArrayCollection $data
     */
    private $data;


    public function __construct()
    {
        $this->updated();
        $this->created = time();
        if(empty($this->status))
        {
            $this->status = Model_AnalyticsCampaign::STATUS_INACTIVE;
        }
    }

    public function updated()
    {
        $this->updated = time();
    }

    public function created()
    {
        $this->created = time();
    }

    public function getId()
    {
        return $this->id;
    }


    public function fromArray(array $array)
    {
        $objects = get_object_vars($this);
        foreach($array as $item => $value)
        {
            if(array_key_exists($item, $objects))
            {
                $this->$item = $value;
            }
        }
    }

    public function setUpdated()
    {
        $this->updated();
    }

    public function getUpdated()
    {
        return ((!empty($this->updated)) ? $this->updated : 0);
    }

    public function setCreated()
    {
        $this->created();
    }

    public function getCreated()
    {
        return ((!empty($this->created)) ? $this->created : 0);
    }

    public function setStatus($status)
    {
        $statusFlag = "SELF::STATUS_".strtoupper($status);

        if(!defined($statusFlag))
        {
            throw new \InvalidArgumentException("Status '$status' is not valid", 500);
        }

        $this->status = constant($statusFlag);
    }

    public function getStatus()
    {
        $constants = getActiveStatusConstants();

        if(isset($constants[$this->status]))
        {
            return $constants[$this->status];
        }
    }

    private function getActiveStatusConstants()
    {
        $vars = get_object_vars();

        $potentialStatus = array();
        foreach($vars as $var)
        {
            if(strpos("STATUS_") == 0)
            {
                // Matching all of our status variables.
                $potentialStatus[] = array(
                    constant("SELF::$var") => substr($var, 7, strlen($var))
                );
            }
        }

        return $potentialStatus;
    }
    public function __get($property)
    {
        return $this->$property;
    }

    public function __set($property,$value)
    {
        $this->$property = $value;
    }

}

AnalyticsData Model

<?php

/**
 * AnalyticsData
 *
 * @Table(name="analyticsData")
 * @Entity
 */
class Model_AnalyticsData
{
    public function __construct()
    {
        // constructor is never called by Doctrine
        $this->created = $this->updated = time();
    }



    /**
     * @var integer $id
     *
     * @Column(name="id", type="integer", nullable=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $id;


    /**
     * @var integer $campaignrank
     *
     * @Column(name="campaignRank", type="integer", nullable=true)
     */
    private $campaignRank;

    /**
     * @var decimal $cost
     *
     * @Column(name="cost", type="decimal", nullable=true)
     */
    private $cost;

    /**
     * @var integer $impressions
     *
     * @Column(name="impressions", type="integer", nullable=true)
     */
    private $impressions;

    /**
     * @var integer $clicks
     *
     * @Column(name="clicks", type="integer", nullable=true)
     */
    private $clicks;

    /**
     * @var decimal $costperclick
     *
     * @Column(name="costPerClick", type="decimal", nullable=true)
     */
    private $costPerClick;

    /**
     * @var integer $averagecampaignposition
     *
     * @Column(name="averageCampaignPosition", type="integer", nullable=true)
     */
    private $averageCampaignPosition;

    /**
     * @Column(type="integer")
     */
    private $created;

    /**
     * @Column(type="integer")
     */
    private $updated;

    /**
     *
     * Store a reference to the campaign that this relates to
     * @ManyToOne(targetEntity="Model_AnalyticsCampaign", inversedBy="data")
     * @JoinColumn(name="campaignId", referencedColumnName="id")
     */
    protected $campaign;


    public function fromArray(array $array)
    {
        $objects = get_object_vars($this);
        foreach($array as $item => $value)
        {
            if(array_key_exists($item, $objects))
            {
                $this->$item = $value;
            }
        }
    }

    /**
     * @PreUpdate
     */
    public function updated()
    {
        $this->updated = time();

    }

    public function setCampaign($id)
    {
        $this->campaign = $id;
    }


}

The problem I am having is that it does actually add the child table data without an issue, however it dosen't fill in my campaignId field that's inside AnalyticsData.

When I manually try and set that ID rather than it doing it then it presents me with:

Exception information:

Message: A new entity was found through a relationship that was not configured to cascade persist operations: @. Explicitly persist the new entity or configure cascading persist operations on the relationship.
Stack trace:

#0 /usr/share/php/Doctrine/ORM/UnitOfWork.php(490): Doctrine\ORM\UnitOfWork->computeAssociationChanges(Array, 1)
#1 /usr/share/php/Doctrine/ORM/UnitOfWork.php(505): Doctrine\ORM\UnitOfWork->computeChangeSet(Object(Doctrine\ORM\Mapping\ClassMetadata), Object(Model_AnalyticsData))
#2 /usr/share/php/Doctrine/ORM/UnitOfWork.php(249): Doctrine\ORM\UnitOfWork->computeChangeSets()
#3 /usr/share/php/Doctrine/ORM/EntityManager.php(328): Doctrine\ORM\UnitOfWork->commit()
#4 /home/tom/development/seo.qe.org/application/modules/default/controllers/AnalyticsController.php(64): Doctrine\ORM\EntityManager->flush()
#5 /usr/share/php/Zend/Controller/Action.php(513): AnalyticsController->indexAction()
#6 /usr/share/php/Zend/Controller/Dispatcher/Standard.php(295): Zend_Controller_Action->dispatch('indexAction')
#7 /usr/share/php/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#8 /usr/share/php/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#9 /usr/share/php/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#10 /home/tom/development/seo.qe.org/public/index.php(26): Zend_Application->run()
#11 {main}                

Request Parameters:

array (
  'controller' => 'analytics',
  'action' => 'index',
  'module' => 'default',
)                

Has anyone seen this before, if so, what on earth am I doing wrong??

Thanks very much, I will give 1,000,000 internets to the person that can help!


The problem was because I needed to insert the AnalyticsData into AnalyticsCampaign and then AnaltyicsCampaign into AnalyticsData.

I was thinking about Doctrine apparently entirely the wrong way. I needed to think about it in terms of objects. So when I was trying to insert the CampaignId it was failing because Doctrine has to establish relationships with Objects rather than ID's.

So my code ended up as this:

$data = new Model_AnalyticsData();
$data->fromArray($entry);
$data->setCampaign($campaign);
$campaign->data = array($data);
$this->em->persist($campaign);

So because $campaign->data is an ArrayObject, it won't accept just the object, so you need to put it in an Array first (obviously meaning you could insert as many child entities as you wanted).

So that was it!

All credit goes to Beberlei on #doctrine on freenode IRC.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜