2012-02-08 23 views
15

私のデータベースには、ウサギとニンジンの2つのテーブルがあります。 ウサギは0個または複数のニンジンを持ち、ニンジンは1個のウサギに属します。これは、これらの2つのテーブル間の1とnの関係です。Symfony2 - エンティティのリポジトリ機能へのアクセス

私は、2つの実体、ウサギとニンジンを持っています。

私はテンプレートに合格したうさぎの配列を持っており、各ウサギから特定のニンジンを入手したいと思います。私は高価なニンジン10個を取得したいとしましょう(ニンジン価格はニンジンテーブルに保存されます)配列内の各$ウサギから。

何かのように:

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

     {{ carrot.price }} 

    {% endfor %} 
{% endfor %} 

私は、リポジトリのクラスを使用していますが、私はウサギのリポジトリクラス内の関数getMoreExpensiveCarrots($ウサギ)を作成した場合、私は、エンティティからその機能にアクセスすることはできません私が欲しいものであるようなクラス、:

$ウサギ - > getMoreExpensiveCarrots()

私はそれを行う方法は、ウサギのエンティティに)(getMoreExpensiveCarrotsを作成するだろうと考えた:

ここで

// 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関数を呼び出すためのベストプラクティスは何?私は、私はあまりにもがそれを行うことができると思った

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

ありがとうございます!

+4

私はこのウサギとニンジンのものが大好きです。<3 –

答えて

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

+1

アイソレータがIteratorを実装しているオブジェクトを処理できないという驚いた種類のものです。いずれにせよ、$ carrots = $ this-> getCarrots() - > toArray(); – Cerad

+0

ああ男、それは最終的に働いている\ o /ありがとうございます:) – httpete

7

エンティティクラスは、それらが表すオブジェクトについてのみ気にし、エンティティマネージャやリポジトリについてはまったく知識がありません。

可能な解決策は、getMoreExpensiveCarrotsメソッドを含むサービスオブジェクト(RabbitService)を使用することです。このサービスは、エンティティマネージャとリポジトリを知ることができるため、ここでは複雑な操作を実行します。

サービスオブジェクトを使用することで、懸念の分離を維持し、エンティティクラスが意図したとおりの仕事を行うことが保証されます。

ニンジンがArrayCollectionに格納されていることを前提に、2番目のオプションを使用することもできます。メソッド内で必要な並べ替えロジックを実行するだけです。これは、あなたがエンティティに利用可能にされたデータを操作しているのでうまくいくでしょう。

+0

私はエンティティラビットからそのサービスを呼び出すでしょうか? – httpete

+0

コントローラーのように、サービスを別々に呼び出すことができます。 –

+1

私は初心者です。コントローラーから呼び出す必要があるので、このケースではリポジトリーとサービスの違いをよく理解していません。(コントローラーからgetMoreExpensiveCarrotsを呼び出す必要はありません。私のテンプレートの各$ウサギからです 実際に私のコントローラーでは、私は自分のウサギを入手するためにそれを行います: $ rabbits = $ em-> getRepository( 'AppNameBundle:Rabbit') - > getSomeRabbits(); 私はサービスのgetMoreExpensiveCarrotsを呼び出しますか? – httpete

7

私はそれを説明するショットを撮ってみましょう。 Doctrine 2 ORMは少し考え直す必要があります。あなたは現在、ウサギがそれを必要とするたびにそれをニンジンに照会できるようにすべきであるという考えを持っています。あなたはその考え方を変える必要があります。

ドクトリン2については、ウサギを作成するとすぐにウサギにそのニンジンを与えることが考えられます。つまり、クエリ時に実行されます。何らかのプロセスがウサギのデータベースを照会している間は、ニンジンの特定のセットも必要であることがわかっています。

あなたのプロセスがそれを知る必要があるように、最も高価なニンジン10個が必要です。では、@Armsの答えに戻り、loadRabbitsWithExpensiveCarrotsというメソッドを使って自分自身をRabbitManagerサービスにします。戻り値は、すでにニンジンを入れたうさぎの配列になります。

コメントを解決するためにこれを更新しました。 symfonyの2サービスVS

  1. 教義2リポジトリ

リポジトリは、ウサギを扱うときに最もよく使用されている、すなわちウサギリポジトリエンティティの一つのタイプに集中する傾向があります。複数のタイプのエンティティを必要とするより複雑な要件に遭遇し始めると、特定の関数がどのリポジトリにあるかを判断することが難しくなります。アプリケーションプログラム(コントローラ)は、どのリポジトリを持ち込むか、実際に知る必要があるよりも内部についての詳細

Symfony 2サービスは、ウサギとニンジンの体系をすべて隠しています。これはより一般的な概念であり、複数のエンティティを含むより複雑な種類のクエリに対処できます。それはS2の基本的なビルディングブロックであり、あなたは本当にそれに慣れていく必要があります。

現在の要件では、いずれの方法でも動作します。

  1. ニンジンのparam質問それでも

あなたが意味を正確にわかりません。おそらくサンプルクエリを投稿することができますか?ウサギオブジェクトにgetExpensiveCarrots()メソッドを追加することができます。このメソッドは、getCarrots()を呼び出すことから始まります。返されたニンジンは、最初のクエリによってすでに読み込まれています。あなたのメソッドはフィルタリングしてソートします。

私たちは、ウサギが数百または数千のニンジンを付着させている場合に対処しようとしています。だから私たちはパフォーマンスの考慮のためだけにすべてのニンジンを積み込むことを避けようとしています。最初のクエリではニンジンを載せない方が簡単に始めることができます。代わりに、初めてrabbit-> getCarrots()が呼び出されると、Doctrine 2は自動的にクエリを発行し、そのウサギのすべてのニンジンを読み込みます。そして、もう一度あなたのgetExpensiveCarrotsメソッドは、必要に応じてフィルターとソートを行います。

このヘルプが必要です。たぶんあなたをもっと混乱させるでしょう。

+0

助けてくれてありがとう、私は今それがうまくいく方法を理解していますが、それでも、私は文字通りそれを動作させることはできません;)ウサギのリポジトリloadRabbitsWithExpensiveCarrots($ rabbits = $ em-> getRepository( 'AppNameBundle:Rabbit') - > loadRabbitsWithExpensiveCarrots();)と全く同じことをするサービスを使用していますか? 私はパラメタで注文されたウサギを検索するためのクエリを作成することはできませんし、同時に価格でニンジンを注文します。 – httpete

+0

私はあなたのための答えを追加しました:) http://stackoverflow.com/a/9251217/668157 – httpete

関連する問題