Я всегда работал с различными ORM в прошлом и размещал всю свою логику внутри своих моделей независимо от ее природы – запросы SQL, MongoDB и даже выборку удаленных объектов JSON. Но когда необходимо обеспечить свободную связь, чтобы обеспечить высокий уровень проверки, проблемы этой методологии быстро появляются.
Сегодня я читал о разделении моделей на две части: Domain objects
и Data mappers
.
Если я полностью его понял, Domain objects
полностью не знают о используемом хранилище и вместо этого существуют для обработки бизнес-логики. Data mappers
с другой стороны, заботятся о сохранении набора данных в Domain objects
в установленном хранилище данных.
Тем не менее, мне трудно найти хороший, простой для понимания пример онлайн о том, как работать с DomainObjects & DataMappers в реальном мире.
Будет ли это (ниже показанный код) подходящим способом работы с DomainObjects & DataMappers в моем коде для хранения пользователей или я получил все неправильно в моей голове?
$user = new User_DO; $userSave = new User_DM; $userSave->store( $user->add(array('name' => 'John Doe')) ); class User_DO { function add($array) { if(!isset($array['name'])) { throw new Exception("Name must be set"); } return $array; } } class User_DM { function store($array) { MyDatabase::execute("INSERT INTO..."); } }
Идея этого заключается в том, чтобы иметь стандартный объект, который представляет текущее состояние в реальной жизни или, другими словами, в домене. Эта модель домена обычно представляет собой набор данных без логики.
class person_DO { public $id; public $firstname; public $lastname; public $addresses; }
Загрузка экземпляров этой модели домена ( объектов домена ) и персистентности осуществляется с помощью карт данных – например, адрес вышеупомянутого человека может быть расположен в другой таблице посредством отношения 1: n:
TABLE person { id INTEGER PRIMARY KEY, firstname VARCHAR(32), lastname VARCHAR(32) } TABLE addresses { id INTEGER PRIMARY KEY, person_id INTEGER FOREIGN KEY ON person.id, --Reference on person-row street VARCHAR(64), ... }
Person_DO не должен знать об этом, но datamapper делает это, поскольку он должен собирать данные во время загрузки и разделить при сохранении:
class person_DM { /** * @param [integer] $id * @return [person_DO] an instance of a person or null, if no person * with that id was found. */ public function findById ($id) {...} /** * @return [array of person_DO] */ public function fetchAll() {...} /** * persists a person object * @param [person_DO] an instance of a person */ public function saveOrUpdate(person_DO $person) {...} }
Чтобы еще больше разделить разные части, DataMappers обычно используют шлюз DbTable или аналогичный шаблон, позволяющий использовать разные базы данных или подобные действия. Таким образом, у меня может быть несколько баз данных с одинаковыми схемами, но, например, в разных организациях для создания хранилища данных с тем же кодом, только разные объекты базы данных.
В качестве практического примера я бы предложил посмотреть учебник Quickstart Zend Framework, который точно описывает то, что я только что объяснил.
Да, примерный. Хотя я бы настоятельно рекомендовал не изобретать колесо и использовать сложный ORM, такой как Doctrine 2.x, который реализует такой шаблон. Вы можете посмотреть их документацию ( Глава 8: Работа с объектами ), чтобы пробовать интерфейс.
Вот хорошая книга по интересующей вас теме. Вы можете найти информацию о Mappers данных (абстрактные сопоставления данных) в главе «Персистентность»:
Применение UML и шаблонов: введение в объектно-ориентированный анализ и дизайн и унифицированный процесс