Новый релиз замечательного фреймворка CakePHP принесет еще одну фичу, которая может сильно упростить жизнь разработчикам — Containable Behavior. Особенно эта фича будет полезна при работе с моделями с большим количеством ассоциаций.Рассмотрим работу этого behavior на примере проекта видеокаталога. Для начала наши модели:
Не буду приводить весь список моделей, они выглядят аналогично.
Ключевой момент — подключение самого Containable в модели:
Или его можно подключить на лету в контроллере:
Теперь посмотрим, как мы можем упростить себе жизнь :) Вот обычный способ получения всех фильмов с ассоциациями:
В данном случае мы получим не только фильмы, но и все ассоциированные записи + записи ассоциаций второго уровня, согласитесь, такое нужно очень редко. Теперь, посмотрим, что нам предлагает Containable:
Этими вызовами мы получим только список фильмов с ассоциированными странами.
Level up :)
Мне, в принципе, от страны фильма нужно только название. Так зачем мне все остальное?
Level up!
Кроме страны, для списка фильмов мне мужны еще и постеры… Получаем:
Final Strike :)
Разбивка на страницы для нового метода paginate()
Получение данных для одного фильма. Обратите внимание, при указнии уровня рекурсии равного двум, вытягиваются только те модели, которые мы указали, а именно — файлы и тип видео для варианта фильма:
Традиционное: это мой ППНХ, не судите строго :)
<?php
class Film extends AppModel {
var $name = 'Film';
var $hasMany = array(
'FilmPicture' => array('className' => 'FilmPicture',
'foreignKey' => 'film_id',
),
'FilmVariant' => array('className' => 'FilmVariant',
'foreignKey' => 'film_id',
),
);
var $hasAndBelongsToMany = array(
'Country' => array('className' => 'Country',
'joinTable' => 'countries_films',
'foreignKey' => 'film_id',
'associationForeignKey' => 'country_id',
),
'Genre' => array('className' => 'Genre',
'joinTable' => 'films_genres',
'foreignKey' => 'film_id',
'associationForeignKey' => 'genre_id',
),
'Person' => array('className' => 'Person',
'joinTable' => 'films_persons',
'foreignKey' => 'film_id',
'associationForeignKey' => 'person_id',
),
'Publisher' => array('className' => 'Publisher',
'joinTable' => 'films_publishers',
'foreignKey' => 'film_id',
'associationForeignKey' => 'publisher_id',
),
);
var $belongsTo = array(
'FilmType' => array('className' => 'FilmType',
'foreignKey' => 'film_type_id',
)
);
var $hasOne = array(
'MediaRating' => array('className' => 'MediaRating',
'foreignKey' => 'object_id',
'conditions' => 'MediaRating.type="film"',
)
);
var $actsAs = array('Containable');
}
?>
<?php
class FilmVariant extends AppModel {
var $name = 'FilmVariant';
var $belongsTo = array(
'Film',
'VideoType'
);
var $hasMany = array(
'FilmFile',
'Track'
);
}
?>
Не буду приводить весь список моделей, они выглядят аналогично.
Ключевой момент — подключение самого Containable в модели:
<?php
var $actsAs = array('Containable');
?>
Или его можно подключить на лету в контроллере:
<?php
$this->Film->Behaviors->attach('Containable');
?>
Теперь посмотрим, как мы можем упростить себе жизнь :) Вот обычный способ получения всех фильмов с ассоциациями:
<?php
$this->Film->recursive = 2;
$this->Film->find('all')
?>
В данном случае мы получим не только фильмы, но и все ассоциированные записи + записи ассоциаций второго уровня, согласитесь, такое нужно очень редко. Теперь, посмотрим, что нам предлагает Containable:
<?php
$this->Film->contain('Country');
$this->Film->find('all');
//или можно указать, какие модели нам нжны прямо при вызове find()
$this-> Film->find('all', array('contain' => 'Country'));
?>
Этими вызовами мы получим только список фильмов с ассоциированными странами.
Level up :)
Мне, в принципе, от страны фильма нужно только название. Так зачем мне все остальное?
<?php
$this->Film->contain('Country.title');
$this->Film->find('all');
//или можно указать, какие модели нам нжны прямо при вызове find()
$this-> Film->find('all', array('contain' => 'Country.title'));
?>
Level up!
Кроме страны, для списка фильмов мне мужны еще и постеры… Получаем:
<?php
$this-> Film->find('all',
array('contain' => 'Country.title',
'FilmPicture' =>
array('conditions' => array('type' => 'poster'),
'fields' => array('FilmPicture.file_name', 'FilmPicture.id'))));
?>
Final Strike :)
Разбивка на страницы для нового метода paginate()
<?php
$this->paginate = array('Film' =>
array('contain' =>
array('FilmType',
'Genre',
'FilmPicture' => array('conditions' => array('type' => 'poster')),
'Country',
'Person' => array('conditions' => array('FilmsPerson.profession_id' => array(1, 3, 4))),
'MediaRating'),
'order' => array('Film.modified DESC'),
'conditions' => array('Film.active' => 1),
'limit' => 12));
$this->set('films', $this->paginate());
?>
Получение данных для одного фильма. Обратите внимание, при указнии уровня рекурсии равного двум, вытягиваются только те модели, которые мы указали, а именно — файлы и тип видео для варианта фильма:
<?php
$this->Film->recursive = 2;
$this->Film->contain(array('FilmType',
'Genre',
'FilmPicture',
'Country',
'FilmVariant' => array('FilmFile', 'VideoType'),
'MediaRating'));
$film = $this->Film->read(null, $id);
?>
Традиционное: это мой ППНХ, не судите строго :)