2017-08-31 65 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',我不确定这是否会影响任何内容。 –