Добавление условий в Containable в CakePHP

Раньше я полагался на рекурсив, но для некоторых я не нашел решения, а потом обнаружил, что 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           |
 -------------------------------

Здесь вы можете видеть, что один movie_id имеет несколько genre_id. Я должен получить только mov1 но я получаю оба фильма в массиве.

~~ РЕДАКТИРОВАТЬ ~~ упс! извините забыл упомянуть, я использую этот код в MoviesController, Все 3 таблицы имеют соответствующий контроллер. Поэтому, пожалуйста, предложите мне, в каком контроллере я могу использовать.

EDIT: 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' => ''
        )
    );

}

Модель: MovieGenre

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' => ''
        )
    );
}

1 ответ

Решение

TLDR: выполните поиск по жанру и укажите его фильмы или используйте joins() - поиск по фильмам и содержание жанра с условиями не будут работать для получения желаемых результатов.


Объяснение:

Ниже приведен исправленный код "содержать", но, что более важно, выполнение "содержимого" в жанре не вернет искомых результатов.

Что он делает - ограничивает содержащиеся жанры в зависимости от вашего состояния... поэтому он будет тянуть ВСЕ фильмы и содержать жанры, которые соответствуют $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);

Ваш отредактированный (исправленный ИМО) пример "содержит"

//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. вы не "содержите" модель, по которой вы выполняете поиск (т.е. я удалил "Movie" из вашего массива размещения).
  2. вы содержите только модели, а не такие вещи, как "MovieGenre.Genre" (я не могу представить, когда вы будете использовать сцепленные модели ".")
  3. для использования Containable для рекурсивного использования должно быть -1 - вы должны установить его в -1 в AppModel и забыть о рекурсивном - это плохо
Другие вопросы по тегам