7

以前は再帰に頼っていましたが、いくつかの解決策が得られませんでした.Containableがこれらに対してうまく機能することがわかりました.

私は映画レビューのウェブサイトを開発しています。その中で、特定のジャンルに関連する映画のリストを表示する必要があります。

以下のコードがあります。

//example
$genre = "drama";

$options = array(
    'contain' => array(
        'Movie',
        'MoveiGenre.Genre' => array(
            'conditions' => array('MovieGenre.Genre.name = "'.$genre.'"')
        ),
        'MovieGenre.Genre.name'
    ),
    'recursive' => 2,
    'limit' => 10
);
$this->paginate = $options;
$this->set('movies',$this->paginate());

本当の問題はここから始まります。ジャンル「ドラマ」に関係なくても、すべての映画を取得します。どこが間違っていますか?

データベーステーブルについて説明しましょう。

表: 映画

 ----------------------------
 | id | title | description |
 ----------------------------
 | 1  | mov1  | something1  |
 | 2  | mov2  | something2  |
 | 3  | mov3  | something3  |
 ----------------------------

表:ジャンル

 ---------------
 | id | name   |
 ---------------
 | 1  | drama  |
 | 2  | sci-fi |
 | 3  | comedy |
 ---------------

表: movie_genres

 -------------------------------
 | id | movie_id | genre_id    |
 -------------------------------
 | 1  | 1        | 1           |
 | 2  | 1        | 2           |
 | 3  | 2        | 2           |
 -------------------------------

ここでは、1 つの movie_id に複数のgenre_id があることがわかります。のみを取得する必要がありますmov1が、両方の映画を配列で取得しています。

~~編集~~ おっと!! 申し訳ありませんが、私はこのコードを で使用していますMoviesController。3つのテーブルすべてにそれぞれのコントローラーがあります。ですから、どのコントローラーで使用できるか教えてください。

編集:2

class Movie extends AppModel {
    public $displayField = 'title';

    public $actsAs = array('Containable');

    public $hasMany = array(
        'MovieGenre' => array(
            'className' => 'MovieGenre',
            'foreignKey' => 'movie_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'MovieLanguage' => array(
            'className' => 'MovieLanguage',
            'foreignKey' => 'movie_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
    );

}

モデル:ジャンル

class Genre extends AppModel {

    public $displayField = 'name';

    public $hasAndBelongsToMany = array(
        'Movie' => array(
            'className' => 'Movie',
            'joinTable' => 'movie_genres',
            'foreignKey' => 'genre_id',
            'associationForeignKey' => 'movie_id',
            'unique' => 'keepExisting',
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'finderQuery' => '',
            'deleteQuery' => '',
            'insertQuery' => ''
        )
    );

}

モデル: 映画のジャンル

class MovieGenre extends AppModel {

    public $belongsTo = array(
        'Movie' => array(
            'className' => 'Movie',
            'foreignKey' => 'movie_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'Genre' => array(
            'className' => 'Genre',
            'foreignKey' => 'genre_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );
}
4

1 に答える 1

13

TLDR:ジャンルで検索を行い、その映画を含めるか、joins() を使用します。映画で検索を行い、条件付きでジャンルを含むと、目的の結果が得られません。


説明:

以下は修正された 'contain' コードですが、さらに重要なことは、Genre で 'contain' を実行しても、探している結果が返されないことです。

それが何をするか - あなたの条件に基づいて含まれるジャンルを制限します...したがって、すべての映画を引き出し、一致するジャンルを含みます$genre.


ソリューション (ニーズに応じて):

解決策 1)

  • find()条件付きでジャンルを作成し、その映画を含めます。これにより、一致するジャンルが抽出され、それに関連する映画のみが抽出されます。

解決策 2) - 私がお勧めするもの

  • 「joins()」を使用します。

$conditions = array();
$conditions['joins'] = array(
    array(
        'table' => 'genres_movies', //or movie_genres if you've specified it as the table to use
        'alias' => 'GenresMovie',
        'type' => 'INNER'
        'conditions' => array(
            'GenresMovie.movie_id = Movie.id'
        )
    ),
    array(
        'table' => 'genres',
        'alias' => 'Genre',
        'type' => 'INNER',
        'conditions' => array(
            'Genre.id = GenresMovie.genre_id',
            'Genre.name = "' . $genre . '"'
        )
    )
);
$this->Movie->find('all', $conditions);

編集された(修正されたimo)「含む」例

//edited example
$genre = "drama";

$options = array(
    'contain' => array(
        'Genre' => array(
            'conditions' => array('Genre.name' => $genre)
        )
    ),
    'recursive' => -1,
    'limit' => 10
);
$this->paginate = $options;
$this->set('movies', $this->paginate('Movie'));
  1. 検索を行っているモデルを「含んでいません」(つまり、contain 配列から「Movie」を削除しました)。
  2. 「MovieGenre.Genre」のようなものではなく、モデルのみが含まれています(「.」連結モデルを使用するときはいつでも思いつきません)
  3. Containable を使用するには、再帰を -1 にする必要があります。AppModel でこれを -1 に設定し、再帰の概念を忘れてください。これは悪いことです。
于 2012-10-11T15:12:36.703 に答える