Отношения один ко многим в Doctrine 2 ORM без вставки удаленного ключа - PullRequest
1 голос
/ 07 июля 2011

Привет, участники Stack Overflow!

У меня проблема с некоторыми отношениями Doctrine 2, которые в настоящее время сбивают меня с ног.

Я пытаюсь настроить очень хороший и простойОтношение один ко многим в Doctrine между моей моделью AnalyticsCampaign и моей моделью AnalyticsData.

Ниже приведен мой код и моя проблема.

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();

Данные Google Analytics Campaign

<?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="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

<?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;
    }


}

Проблема, с которой я сталкиваюсь, заключается в том, что она действительно добавляет данные дочерней таблицы без проблем, однако она не заполняет поле моей рекламной кампании, которое находится внутри AnalyticsData.

Когда я вручную пытаюсь установить этот идентификатор вместо того, чтобы делать это, он дает мне следующее:

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',
)                

Кто-нибудь видел это раньше, если да, то, что, черт возьми, я делаю неправильно ??

Большое спасибо, я отдам 1 000 000 интернетов человеку, который может помочь!

1 Ответ

3 голосов
/ 08 июля 2011

Проблема заключалась в том, что мне нужно было вставить AnalyticsData в AnalyticsCampaign, а затем AnaltyicsCampaign в AnalyticsData.

Я думал о Doctrine, по-видимому, совершенно неправильно.Мне нужно было думать об этом с точки зрения объектов.Поэтому, когда я пытался вставить CampaignId, он терпел неудачу, потому что Doctrine пришлось устанавливать отношения с объектами, а не с идентификаторами.

Поэтому мой код в итоге выглядел так:

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

Так какcampaign-> data - это ArrayObject, он не будет принимать только объект, поэтому сначала нужно поместить его в массив (очевидно, это означает, что вы можете вставить столько дочерних объектов, сколько захотите).

было ли это!

Вся заслуга Беберлею в #doctrine на freenode IRC.

...