Pull to refresh

CakePHP 1.2 Containable Behavior

Reading time 8 min
Views 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);
?>


Традиционное: это мой ППНХ, не судите строго :)
Tags:
Hubs:
+11
Comments 12
Comments Comments 12

Articles