Проектирование модели
1) CОЗДАЕМ КЛАСС МОДЕЛИ (БАЗОВАЯ МОДЕЛЬ).
Описываем данные и поведения, через свойства и методы класса
Класс модели не должен знать о хранении данных, и других, к самому классу не относящихся, вещах
Например:
class Person {
public $_email
public $_password;
public $_username;
// getters and setters
…
Довольно спорный момент, зачем в сущности методы?
Этим должен заниматся Service Layer
// Behaviors
public function authenticate(){}
public function logout(){}
public function ban(){}
}
2) CОЗДАЕМ КОД ДЛЯ СОХРАНЕНИЯ ДАННЫХ. (DATA ACCESS LAYER)
Определяем какие данные мы хотим сохранять, как мы хотим их сохранять
Например:
SQL:
CREATE TABLE person {
username VARCHAR PRIMARY KEY,
password VARCHAR,
email VARCHAR
}
Класс:
class Person_Table extends Zend_Db_Table_Abstract
{
protected $_name = 'person';
protected $_primary = 'username';
}
Можно использовать генератор Symfony(Propel, Doctrine)
3) ОПИСЫВАЕМ СВЯЗЬ МЕЖДУ МОДЕЛЬЮ И БАЗОЙ ДАННЫХ (DATA MAPPER/ORM)
Мэппер — прослойка между нашим простым классом (Базовая модель) и хранилищами. Он обеспечивает базовый интерфейс для работы с хранилищами: сохранение, загрузка и удаление. Будь то файлы, база данных или тот же кэш, интерфейс всегда будет один и тот же
Мэппер принимает объект модели
Мэппер может хранить и извлекать данные и из других хранилищ(КЕШ, файловая система)
Например:
class PersonMapper {
public function save( Person $person )
{
$data = array(
‘username’ => $person->username,
‘password’ => $person->password,
‘email’ => $person->email
);
$this->getTable()->save( $data );
}
private function fetch( $username=null ) {}
private function getTable() {}
private function setTable( $table ) {}
}
4) ДОБАВЛЕНИЕ БИЗНЕСС ЛОГИКИ В SERVICE LAYER
SERVICE LAYER – обеспечивает применение логики в верхней части модели
DATA ACCESS LAYER -> DATA MAPPERS -> DOMAIN MODEL -> SERVICE LAYER
Например:
class PersonService {
public function create( array $data )
{
$person = new Persone;
if( !$data = $this->getValidator->isValid( $data ) )
{
throw new InavalidArgument;
}
$person->username = $data['username'];
$person->password = $data['password'];
$person->email = $data['email'];
$this->getMapper()->save( $person );
}
5) ДЕКОРИРУЕМ МЭППЕРЫ
Декораторы нужны, чтобы добавить или изменить функциональность существующих классов
-) Декоратор нам нужен будет для определения, откуда загружать данные из базы данных или из кеша
-) Декоратор нам нужен будет для возрата данных в разных формата
Сначала вызываем CashMapper, а он если нужно вызыват BdMapper ( кеш декорирует базу )
Слайд-шоу:
http://www.slideshare.net/weierophinney/playdoh-modelling-your-objects-1766001
Статья:
http://habrahabr.ru/blogs/refactoring/67036/
Упрощенный вариант
— Абстракция доступа/фильтрации/валидации Article_Service
— Абстракция взаимодействия с БД/«другими источниками» данных Article_Mapper
— Собственно структура данных class Article (на кой черт ей геттеры сеттеры?
если вы работаете с Article_Service ).
Условно один внешний API для других объектов (это Article_Service) и внутренний API для самого объекта (Article_Mapper). В этом свете, наличие каких либо методов у Article вообще противопоказано
обратите внимание на разницу между структурой данных в памяти и моделью
Жесть.
Вы хоть поняли, что юноша выше предложил?
Организовать доступ к полям объекта через __get/__set
Если я работаю с 200-300 объектов, у каждого из которых по 50 свойств, и доступ к полям через __get()
Что у нас произойдет? Сколько у нас будет вызовов?
Ах, да, можно работать не с коллекцией в 200-300 объектов, а с 1м за раз объектом, но тогда вместо 1го запроса к базе у вас будет 300 запросов. Что впрочем не избавит от необходимости обращаться к полям объектов
после каждого запроса