2012-02-08 43 views
15

假設我的數據庫中有兩個表:Rabbits和Carrots。 兔子可以有0或多倍胡蘿蔔,胡蘿蔔屬於一隻兔子。這是兩張表之間的1,n關係。Symfony2 - 在Entity中訪問存儲庫函數

我有兩個實體,兔子和胡蘿蔔。

我在我的模板中傳遞了一串兔子,我想從每隻兔子身上得到具體的胡蘿蔔並顯示它們:比方說,我想要得到10個更昂貴的胡蘿蔔(胡蘿蔔價格將存儲在胡蘿蔔表中)從陣列中的每個$兔子。

喜歡的東西:

{% for rabbit in rabbits %} 
    {% for carrot in rabbit.getMoreExpensiveCarrots %} 

     {{ carrot.price }} 

    {% endfor %} 
{% endfor %} 

我使用存儲庫類,但如果我創建一個兔庫類的函數getMoreExpensiveCarrots($兔),我不能夠從實體訪問該功能一流的那樣,這是我想要的:

$ rabbit-> getMoreExpensiveCarrots()

我認爲一個辦法做到這一點會在兔子實體創建一個getMoreExpensiveCarrots():

// Entity rabbit 
class Rabbit 
{ 
    public function getMoreExpensiveCarrots() 
    { 
     // Access repository functions like getMoreExpensiveCarrots($rabbit) 
     // But how can I do such thing ? Isn't that bad practise ? 
     return $carrots; 
    }   
} 

我想我可以做到這一點:

// Entity rabbit 
    class Rabbit 
    { 
     public function getMoreExpensiveCarrots() 
     { 
      $this->getCarrots(); 

      // Then try here to sort the carrots by their price, using php    

      return $carrots; 
     }   
    } 

這裏是我的控制器:

public function indexAction() 
    { 
     $em = $this->getDoctrine()->getEntityManager(); 

     $rabbits = $em->getRepository('AppNameBundle:Rabbit')->getSomeRabbits(); 

     return $this->render('AppNameBundle:Home:index.html.twig', 
       array(
        "rabbits"=>$rabbits 
     )); 
    } 

什麼是調用從模板中的每個兔子getMoreExpensiveCarrots功能的最佳做法是什麼?

謝謝!

+4

我喜歡這個兔子和胡蘿蔔的東西。<3 – 2014-06-03 00:40:09

回答

8

回到基本。忘記存儲庫和服務,只關注兔子和胡蘿蔔。

class Rabbit 
{ 
/** @ORM\OneToMany(targetEntity="Carrot", mappedBy="rabbit" */ 
protected $carrots; 

public function getCarrots() { return $this->carrots; } 

public function getMoreExpensiveCarrots() 
{ 
    // Get all carrots 
    $carrots = $this->getCarrots()->toArray(); 

    // Sort by price 
    // http://php.net/manual/en/function.usort.php 
    usort(&$carrots,array($this,'compareTwoCarrotsByPrice')); 

    // Now slice off the top 10 carrots (slice - carrots, hah, kindo of funny 
    $carrots = array_slice($carrots, 0, 10); 

    // And return the sorted carrots 
    return $carrots; 
} 
public function compareTwoCarrotsByPrice($carrot1,$carrot2) 
{ 
    if ($carrot1->getPrice() > $carrot2->getPrice()) return -1; 
    if ($carrot1->getPrice() < $carrot2->getPrice()) return 1; 
    return 0; 
} 
} 

從您的查詢中刪除所有胡蘿蔔的東西,只是得到一個兔子的列表。
您的原始模板現在工作完全按照預期:

{% for rabbit in rabbits %} 
    {% for carrot in rabbit.getMoreExpensiveCarrots %} 

     {{ carrot.price }} 

    {% endfor %} 
{% endfor %} 

這裏唯一的缺點是,每個兔子,所有胡蘿蔔一個單獨的查詢將被自動生成的學說。在某些時候,表演會受到阻礙。當你達到那一點時,你可以回到原來的查詢,看看如何更有效地使胡蘿蔔。但讓上面的課程開始工作,因爲我認爲這可能是你的阻礙點。

+0

謝謝!由於$ this-> getCarrots()輸出一個ArrayCollection,我得到一個「usort()期望參數1是數組,對象給出」...我會嘗試調試。 – httpete 2012-02-12 20:04:38

+1

有種驚訝的是usort不能處理實現Iterator的onject。無論如何:$ carrots = $ this-> getCarrots() - > toArray(); – Cerad 2012-02-12 21:07:38

+0

哦,男人,它終於工作\ o /非常感謝你:) – httpete 2012-02-12 21:44:44

7

您的實體類應該只關心它們所代表的對象,並且完全不瞭解實體管理器或存儲庫。

此處可能的解決方案是使用包含getMoreExpensiveCarrots方法的服務對象(RabbitService)。該服務允許瞭解實體管理器和存儲庫,因此您可以在這裏執行任何複雜的操作。

通過使用服務對象,您可以保持關注點分離,並確保您的實體類完成他們所要完成的工作,僅此而已。

假設胡蘿蔔存儲在ArrayCollection中,您也可以使用第二個選項。您只需在該方法中執行所需的任何排序邏輯即可。這樣做會很好,因爲您將使用提供給實體的數據。

+0

然後我會從我的實體兔子那裏打這個服務? – httpete 2012-02-08 02:41:55

+0

您可以單獨調用該服務,如從控制器中調用。 – 2012-02-08 02:51:03

+1

對不起,我是一個初學者,我不太明白在這種情況下倉庫和服務之間的區別,因爲我必須從控制器調用它:(我不想從我的控制器調用getMoreExpensiveCarrots,但是從我的模板中的每個$ rabbit。 其實在我的控制器中,這就是我做我的兔子: $ rabbits = $ em-> getRepository('AppNameBundle:Rabbit') - > getSomeRabbits(); 現在應該如何我打電話給服務的getMoreExpensiveCarrots? – httpete 2012-02-08 03:08:41

7

讓我來解釋一下吧。 Doctrine 2 ORM確實需要一點反思。您目前的心態是,一隻兔子在需要時能夠查詢它的胡蘿蔔。你需要改變這種心態。

對於Doctrine 2來說,想法是一旦創建兔子就給兔子胡蘿蔔。換句話說,它在查詢時完成。假設是,無論查詢數據庫的哪個過程都知道你還想要一組特定的胡蘿蔔。

在這種情況下,你需要10個最昂貴的胡蘿蔔,所以你的過程需要知道這一點。所以,現在你回到@Arms的回答,並使用一種名爲loadRabbitsWithExpensiveCarrots的方法爲自己創建一個RabbitManager服務。返回值將是一串已經填滿了胡蘿蔔的兔子。

更新了此內容以解決評論。

  1. 學說2庫VS的Symfony 2服務

阿庫往往集中於一種類型的實體即兔庫的時只處理兔,最好使用。當你開始遇到需要多種類型的實體的更復雜的需求時,它可能開始變得難以確定給定函數應該在哪個存儲庫中。你的應用程序(控制器)將不得不知道要引入哪個Repository並且可能更多關於內部的信息比它真正需要知道的更多。

Symfony 2服務隱藏了關於如何組織兔子和胡蘿蔔的所有細節。這是一個更一般的概念,可以處理涉及多個實體的更復雜類型的查詢。這是S2的一個基本組成部分,你確實需要適應它。

對於您當前的要求,任一方法都可以使用。

  1. 胡蘿蔔PARAM問題

仍然不知道你的意思是什麼。也許你可以發佈一個示例查詢?請記住,你當然可以添加一個getExpensiveCarrots()方法到你的兔子對象。該方法將開始調用getCarrots()。返回的胡蘿蔔已經被最初的查詢加載了。你的方法會過濾和排序。

請記住,我們正試圖處理兔子可能有數百或數千個胡蘿蔔附着在其上的情況。所以我們試圖避免爲了性能考慮而加載所有的胡蘿蔔。在初始查詢中根本不加載胡蘿蔔可能會更容易。相反,第一次調用rabbit-> getCarrots()時,Doctrine 2將自動發出一個查詢併爲該兔子加載所有的胡蘿蔔。然後,您的getExpensiveCarrots方法會再次根據需要進行篩選和排序。

希望得到這個幫助。可能只是更困惑你。

+0

好吧,感謝您的幫助,我現在更好地瞭解它如何工作。但是,我仍然無法設法使它工作;)使功能在兔子倉庫loadRabbitsWithExpensiveCarrots($ rabbits = $ em-> getRepository('AppNameBundle:Rabbit') - > loadRabbitsWithExpensiveCarrots();)並使用服務來完成同樣的事情? 另外我不能使查詢檢索我的兔子由參數排序,並在同一時間訂購價格胡蘿蔔。 – httpete 2012-02-12 15:41:07

+0

我給你加了個答案:) http://stackoverflow.com/a/9251217/668157 – httpete 2012-02-12 18:04:28