Как стать автором
Поиск
Написать публикацию
Обновить

CakePHP 1.2 Containable Behavior

Время на прочтение8 мин
Количество просмотров1.4K
Новый релиз замечательного фреймворка CakePHP принесет еще одну фичу, которая может сильно упростить жизнь разработчикам — Containable Behavior. Особенно эта фича будет полезна при работе с моделями с большим количеством ассоциаций.Рассмотрим работу этого behavior на примере проекта видеокаталога. Для начала наши модели:
<?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(134))),
             
'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);
?>


Традиционное: это мой ППНХ, не судите строго :)
Теги:
Хабы:
Всего голосов 23: ↑17 и ↓6+11
Комментарии12

Публикации

Ближайшие события