Active Record в Yii довольно мощный и гибкий. Для своей гибкости, ресурсов,
при не очень большом количестве записей, он потребляет не так много,
но в некоторых случаях AR может не подходить:
В этом уроке мы ни в коем случае не призываем отказываться от AR, а всего-лишь
рассматриваем альтернативный способ построения моделей.
Для примера опишем сущность «фильм» в модели Film
. При этом данные фильма могут
храниться как в БД, так и в XML, кэше, Redis и т.д. В нашем случае, поскольку мы
работаем с БД, один объект модели Film
соответствует одной записи в бд.
class Film extends CModel {
public $id;
public $name;
public $comments; // коллекция комментариев
public function rules() {
return array(
array('name', 'required'),
array('name', 'length', 'max'=>255),
);
}
public function getName(){
return $this->name;
}
public function getId(){
return $this->id;
}
public function setName($newName){
$this->name = $newName;
}
public function getComments(){
return $this->comments;
}
}
Далее создадим фасад FilmManager
, реализующий все основные методы для работы
с моделью, такие как:
Данный класс позволяет прозрачно работать с реализованными
в отдельных классах-фабриках методами для разных
хранилищ данных (БД, XML, Sphinx и др.).
class FilmManager {
public function __construct(){
}
public static function factory($driver = 'DB'){
return new 'Film'.$driver.'Manager';
}
/**
*
* @param int $id
* @return Film
*/
public function getFilmById($id) {
}
}
Создаём фабрики:
class FilmDBManager extends FilmManager {
public function getFilmById($id) {
$db = Yii::app()->db;
$film_table = Film::tableName();
$sql = "SELECT * FROM {$film_table} WHERE id=:ID LIMIT 1";
$command=$db->createCommand($sql);
$command->bindParam(":ID", $id);
$row = $command->queryRow();
$film = new Film;
$film->id = $row['id'];
$film->name_ru = $row['name_ru'];
//получаем комментарии для фильма
$film->comments = CommentsManager::getCommentsForFilm($id);
return $film;
}
}
class FilmXMLManager extends FilmManager {
public function getFilmById($id) {
// берём из xml данные, создаем экземпляр класса Film
return $film;
}
}
Будем работать с фабриками через фасад:
// получаем фильм из БД
$film = FilmManager::factory()->getFilmById($id);
echo $film->getName();
foreach($film->getComments() as $comment){
echo $comment->getText();
echo $comment->getAuthor()->getName();
}
// получаем фильм из XML
$film = FilmManager::factory('XML')->getFilmById($id);
echo $film->getName();
В итоге имеем единый API, позволяющий получать объекты одного и того же типа,
с возможностью быстрого переключения на другое хранилище данных.
В случае, когда метод фабрики возвращает не одну модель, а несколько,
логично возвращать не массивы, а типизированные коллекции.
Создадим свой тип коллекции для хранения фильмов:
class FilmCollection extends CList {
// общее число фильмов
private $totalCount;
// Задаём тип параметра Film.
// При попытке добавления объекта другого типа
// произойдёт ошибка.
public function add(Film $item){
parent::add($item);
}
public function setTotal($count){
$this->totalCount = $count;
}
public function getTotal(){
return $this->totalCount;
}
}
Авторы
: pirrat, Sam Dark (rmcreative.ru)Обсуждение и комментарии
: http://yiiframework.ru/forum/viewtopic.php?f=8&t=456