2017-08-31 121 views
1

我有一個表單來創建文檔。一方面,我可以添加名稱和說明,並在旁邊,我可以選擇一個或多個代理創建的文檔所屬。 每個機構被分配到一個特定的市場(總共有7個市場,所以一個市場可以有幾個代理商,但一個代理商只屬於一個市場!) 我想實現的是一個「prePersist」功能這會自動將正確的市場(取決於所選機構的數量)添加到文檔中。Symfony將數據添加到預先保留的對象上

我的文檔實體有兩個實體(市場和機構)與根據getter和setter方法:

/** 
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Market", inversedBy="uploadProfiles", cascade={"persist"}) 
* @ORM\JoinTable(name="document_uploadprofile_markets", 
* joinColumns={@ORM\JoinColumn(name="uploadprofile_id", referencedColumnName="id")}, 
* inverseJoinColumns={@ORM\JoinColumn(name="market_id", referencedColumnName="id")}) 
**/ 
private $markets; 

     /** 
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", inversedBy="uploadProfiles", cascade={"persist"}) 
     * @ORM\JoinTable(name="document_uploadprofile_agencies", 
     * joinColumns={@ORM\JoinColumn(name="uploadprofile_id", referencedColumnName="id")}, 
     * inverseJoinColumns={@ORM\JoinColumn(name="iata8", referencedColumnName="iata8")}) 
     **/ 
     private $agencies; 
    public function __construct() 
    { 
     $this->agencies = new \Doctrine\Common\Collections\ArrayCollection(); 
    $this->markets = new \Doctrine\Common\Collections\ArrayCollection(); 

} 

     /** 
* Add market 
* 
* @param \AppBundle\Entity\Market $market 
* 
* @return UploadProfile 
*/ 
public function addMarket(\AppBundle\Entity\Market $market) 
{ 
    $this->markets[] = $market; 

    return $this; 
} 

/** 
* Remove market 
* 
* @param \AppBundle\Entity\Market $market 
*/ 
public function removeMarket(\AppBundle\Entity\Market $market) 
{ 
    $this->markets->removeElement($market); 
} 

/** 
* Get markets 
* 
* @return \Doctrine\Common\Collections\Collection 
*/ 
public function getMarkets() 
{ 
    return $this->markets; 
} 
    /** 
    * Add agency 
    * 
    * @param \AppBundle\Entity\Agency $agency 
    * 
    * @return UploadProfile 
    */ 
    public function addAgency(\AppBundle\Entity\Agency $agency) 
    { 
     $this->agencies[] = $agency; 

     return $this; 
    } 

    /** 
    * Remove agency 
    * 
    * @param \AppBundle\Entity\Agency $agency 
    */ 
    public function removeAgency(\AppBundle\Entity\Agency $agency) 
    { 
     $this->agencies->removeElement($agency); 
    } 

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

我知道我可以添加prePersist功能到我的文檔實體,並嘗試代碼,我想要什麼實現,但我不認爲這工作,因爲我需要類似的東西:

foreach($document->getAgencies() as $agency) { 
     $document->setMarket($em->getRepository('AppBundle:Agency')->getMarket($agency)); 
    } 

我甚至不能肯定foreach循環是正確的,因爲(到目前爲止),結果總是空。我已經在這裏問了一個關於這個話題的問題:Symfony use setter for Arraycollection in CreateController

我也試着寫一個自己的倉庫函數來從我的代理實體獲取所有不同的市場,但到目前爲止這也不起作用。

另一個想法是在我的表單類中的POST_SUBMIT事件監聽器,但到目前爲止,我也沒有任何意義。

任何想法?如果需要更多代碼,請告訴我!

編輯 我編輯,並以有我的市場和文件之間的多對多關係改變了我上面的代碼。然後我嘗試的是,prePersist函數添加到我的文檔實體,它實際上工作正常,但仍然有OneToMany關係(它只是總是覆蓋以前的市場,但現在並不重要) 我現在試圖編輯該功能,以便可以將多個市場添加到文檔中。 兩個想法我有,但他們都沒有發揮出來:

if(count($this->getAgencies()) > 0){ 
     foreach($this->getAgencies() as $agency) { 
     $this->addMarket($agency->getMarket()); 
     } 
} 

- >市場總是空

if(count($this->getAgencies()) > 0){ 
     $upId = rtrim($this->getId(),"_up"); 
     $query = $em->createQuery("SELECT DISTINCT (a.market) FROM UserBundle\Entity\User u JOIN u.agencies a WHERE u.id = $userId"); 
     $marketIds = $query->getResult(); 

     $em = $this->getDoctrine()->getManager(); 
     $repository = $this->getDoctrine() 
     ->getRepository('AppBundle:Market'); 
     $markets = $repository->findOneById($marketIds); 
     $this->addMarket($markets); 
    } 
    } 

更新

這裏我的prepersist函數在我的文檔實體中,然後是getMarkets()函數,這在其中一個評論中已經提出。我的名字改爲addMarkets而不是getMarkets

/** 
    * @ORM\PrePersist 
    */ 
    public function prePersist() { 
if(count($this->getAgencies()) > 0){ 
     foreach($this->getAgencies() as $agency) { 
     $this->addMarkets($agency->getMarket()); 
     } 
    } 
    } 

public function addMarkets(\AppBundle\Entity\Market $market) 
    { 
     $markets = array(); 
     foreach($this->agencies as $agency) { 
      $market = $agency->getMarket(); 
      $id  = $market->getId(); 

      // Skip duplicates 
      if (isset($markets['id'])) { 
       continue; 
      } 

      $markets[$id] = $market; 
     } 

     return $markets; 
    } 

另一種方法

所以我編輯了一遍,現在我的功能看起來像

$markets = $this->getMarkets(); 
if(count($this->getAgencies()) > 0){ 
    foreach($this->getAgencies() as $agency) { 
    if(!$this->markets->contains($markets)) { 
     $this->addMarket($agency->getMarket()); 
    } 
    return; 
    dump($markets); 
    } 
} 

我想,這可能努力消除我的重複,但它不..爲什麼?

回答

0

這看起來像是錯誤的做法。市場和代理之間以及代理和文檔之間的一對多關係更有意義。

+0

嗯,這是我有什麼? – sonja

+0

你的意思是說你認爲你的結構就像我的答案一樣? – svgrafov

+0

是的我在代理和市場之間有一對多和多對多的關係。上面顯示的代碼在我的文檔中,所以它是文檔和代理+文檔和市場之間的關係 – sonja

1

這是邏輯上的結構性錯誤。線索在你的問題和代碼中。

會自動將正確的市場(小號

和:

 /** 
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Market") 
     * @ORM\JoinColumn(name="market", referencedColumnName="id") 
     * @var \AppBundle\Entity\Market 
     **/ 
     private $market; 

是不相容的。

如果一個文件可以有許多機構和機構可以有一個市場,那麼你的文件必須允許許多市場。例如:

DocumentA has Agency1 and Agency2. 

Agency1 has MarketParis. 

Agency2 has MarketMarrakesh. 

這必然意味着有文獻展(Agency1的)MarketParis和(Agency2的)MarketMarrakesh - 許多市場。

你問的問題是一個比設置或獲取更大的話題。如果你只想每份文件有一個市場,那麼你就必須在文件代理機構之間強制實行唯一性。例如:

Your form creates DocumentA. 

The user tries to set Agency1 (MarketParis) and Agency2 (MarketMarrakesh). 
This throws an error because there can be ONLY ONE market. 

或者又如:

Your form creates DocumentA 

The user tries to set Agency1 (MarketParis) and Agency3 (MarketParis). 
This is successful because the uniqueness of the Document's Market is enforced. 

這有很多策略,是不是你的問題更大的話題。

編輯

如果您基數的邏輯是正確的(固定我上述的任何問題),你的學說註釋包括級聯在所有的實體,它看起來是正確的,從上面的代碼仍然存在。我能想到的唯一不能正確工作的就是表單的「by_reference」屬性。在您的表單中將「by_reference」設置爲false,並在您的實體中設置級聯持久設置,應該保留與表單關聯的所有實體。請參閱by_reference文檔:http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference

+0

感謝您的詳細解答! 對不起,我和老闆誤會了。它應該是市場和文件之間多對多的關係,所以它應該有可能爲一個文件建立多個市場! 我更新了我的問題。你可能有這個想法嗎? – sonja

+0

編輯我的評論。在此之後,我有點想法。形式和原則應該級聯堅持相關的實體。 – ASOlivieri

1

如果我明白你說的正確,我認爲Documents根本不應該參考Markets。但僅限參考Agency

A Document將與AgencyManyToMany關係,就是這樣。

然後在Document,你可以這樣做:

public function getMarkets() 
{ 
    $markets = array(); 
    foreach($this->agencies as $agency) { 
     $market = $agency->getMarket(); 
     $id  = $market->getId(); 

     // Skip duplicates 
     if (isset($markets[id]) { 
      continue; 
     } 

     $markets[$id] = $market; 
    } 

    return $markets; 
} 
+0

非常感謝你拉米!實際上,我找到了一種使其工作的方法,但後來我意識到,我不會像您在解決方案中那樣跳過重複項。所以現在我試着用你的功能,但現在我的市場一直是空的。我認爲這是因爲你的函數沒有在prePersist上調用,所以我在我的prePersist函數中調用它,但它仍然不起作用。你有一個想法,爲什麼這可能是?我更新了我的問題並添加了兩個功能,可能有幫助?再次感謝! – sonja

+0

所以我再次編輯它,現在我的功能看起來像 $ markets = $ this-> getMarkets(); ($ this-> markets-> contains($ markets)){if(count($ this-> getAgencies())> 0){foreach($ this-> getAgencies()as $ agency){ { $ this-> addMarket($ agency-> getMarket()); } dump($ markets); } } 我認爲這可能會消除我的重複,但它不會..任何想法爲什麼? – sonja

+0

@sonja在我的例子中,我是「讓」市場沒有添加它們。爲了將它們保存到您的實體中,您需要用'$ this-> markets'替換我的示例中的'$ markets'。如果'$ market'實例是對同一個對象的引用,'ArrayCollection :: contains()'也會生效。最後,你的代碼中有一些'return'和'dump',我不確定這是否會影響任何內容。 –