Как обычно выглядит Data Mapper?
У меня есть стол Cat
и класс PHP под названием Cat
, Теперь я хочу сделать CatDataMapper
класс, так что Cat extends CatDataMapper
,
Я хочу, чтобы этот класс Data Mapper предоставлял базовую функциональность для выполнения ORM, а также для создания, редактирования и удаления Cat.
Для этого, может быть, кто-то, кто очень хорошо знает эту модель, мог бы дать мне несколько полезных советов? Я чувствую, что было бы немного слишком просто предоставить некоторые функции, такие как update(), delete(), save().
Я понимаю, что Data Mapper имеет следующую проблему: сначала вы создаете экземпляр Cat, затем инициализируете все переменные, такие как name, furColor, eyeColor, purrSound, meowSound, обслуживающий персонал и т. Д., И после того, как все настроено, вы вызываете save () функция, которая унаследована от CatDataMapper. Это было просто;) Но теперь реальная проблема: вы запрашиваете базу данных о кошках и получаете простой скучный набор результатов с большим количеством данных о кошках.
PDO имеет некоторые возможности ORM для создания экземпляров Cat. Допустим, я использую это, или, допустим, даже у меня есть функция mapDataset(), которая принимает ассоциативный массив. Однако, как только я получил свой объект Cat из набора данных, у меня появляются избыточные данные. В то же время двадцать пользователей могут получить те же данные о кошках из базы данных и отредактировать объект кошки, то есть переименовать кошку, и сохранить () ее, в то время как другой пользователь все еще думает об установке другого furColor. Когда все они сохраняют свои правки, все запутано.
Э-э... хорошо, чтобы этот вопрос был коротким: какая здесь хорошая практика?
5 ответов
Data Mapper - это уровень программного обеспечения, который отделяет объекты в памяти от базы данных. В его обязанности входит передача данных между ними, а также их изоляция друг от друга. При использовании Data Mapper объекты в памяти не должны знать даже, что присутствует база данных; они не нуждаются в коде интерфейса SQL и, конечно, не знают схемы базы данных. (Схема базы данных всегда игнорирует объекты, которые ее используют.) Поскольку это форма Mapper (473), сам Data Mapper даже неизвестен для уровня домена.
Таким образом, Cat не должен расширять CatDataMapper, потому что это создаст отношения is-a и привязывает Cat к слою Persistence. Если вы хотите иметь возможность обрабатывать персистентность из ваших Cats таким образом, посмотрите на ActiveRecord или любой из других архитектурных шаблонов источников данных.
Обычно вы используете DataMapper при использовании доменной модели. Простой DataMapper будет просто отображать таблицу базы данных в эквивалентный класс в памяти на основе поля к полю. Однако, когда возникает необходимость в DataMapper, у вас обычно не будет таких простых отношений. Таблицы не будут отображать 1:1 на ваши объекты. Вместо этого несколько таблиц могут объединяться в один объектный агрегат и наоборот. Следовательно, реализация только методов CRUD, может легко стать довольно сложной задачей.
Кроме того, это один из более сложных шаблонов (охватывает 15 страниц в PoEA), который часто используется в сочетании с шаблоном Repository. Посмотрите в столбце связанных вопросов на правой стороне этой страницы для похожих вопросов.
Что касается вашего вопроса о том, как несколько пользователей редактируют один и тот же Cat, это общая проблема, которая называется Concurrency. Одним из решений этой проблемы будет блокировка строки, в то время как кто-то ее редактирует. Но, как и все, это может привести к другим проблемам.
Если вы полагаетесь на ORM, как Doctrine или Propel, основной принцип заключается в создании статического класса, который будет получать фактические данные из базы данных (например, Propel создаст CatPeer), и тогда результаты, полученные классом Peer, будут " гидратировался "в объекты Cat.
Процесс гидратации - это процесс преобразования "простого скучного" набора результатов MySQL в красивые объекты, имеющие геттеры и сеттеры.
Так что для получения вы бы использовали что-то вроде CatPeer::doSelect()
, Затем для нового объекта вы сначала создаете его экземпляр (или извлекаете и копируете из БД): $cat = new Cat();
Вставка будет такой же простой, как и: $cat->save();
Это было бы эквивалентно вставке (или обновлению, если объект уже существует в БД... ORM должен знать, как сделать различие между новыми и существующими объектами, используя, например, наличие или отсутствие первичного ключ).
Реализовать Data Mapper очень сложно в PHP < 5.3, так как вы не можете читать / писать защищенные / приватные поля. У вас есть несколько вариантов загрузки и сохранения объектов:
- Используйте какой-то обходной путь, например, сериализацию объекта, изменение его строкового представления и возвращение его с помощью unserialize.
- Сделайте все поля общедоступными
- Держите их закрытыми / защищенными и пишите мутаторы / средства доступа для каждого из них
Первый метод может порвать с новым выпуском и является очень грубым взломом, второй считается (очень) плохой практикой.
Третий вариант также считается плохой практикой, так как вы не должны предоставлять геттеры / сеттеры для всех ваших полей, только те, которые нуждаются в этом. Ваша модель "повреждается" с точки зрения чистого DDD (доменного проектирования), поскольку она содержит методы, которые необходимы только из-за механизма постоянства. Это также означает, что теперь вы должны описать другое сопоставление для полей -> методов установки, рядом с полями -> столбцами таблицы.
PHP 5.3 предоставляет возможность доступа / изменения ко всем типам полей, используя отражение:
http://hu2.php.net/manual/en/reflectionproperty.setaccessible.php
Благодаря этому вы можете добиться истинного отображения данных, поскольку необходимость в предоставлении мутаторов для всех полей отпала.
PDO имеет некоторые возможности ORM для создания экземпляров Cat. Допустим, я использую это, или, допустим, даже у меня есть функция mapDataset(), которая принимает ассоциативный массив. Однако, как только я получил свой объект Cat из набора данных, у меня появляются избыточные данные. В то же время двадцать пользователей могут получить те же данные о кошках из базы данных и отредактировать объект кошки, то есть переименовать кошку, и сохранить () ее, в то время как другой пользователь все еще думает о настройке другого furColor. Когда все они сохраняют свои правки, все запутано.
Чтобы отслеживать состояние данных, обычно используются IdentityMap и / или UnitOfWork, которые отслеживают все различные операции с сопоставленными объектами... и после этого цикл операций будет выполнен.
Краткий ответ: у вас есть экземпляр Cat. (Может быть, он расширяет CatDbMapper или Cat3rdpartycatstoreMapper) Вы вызываете:
$cats = $cat_model->getBlueEyedCats();
//then you get an array of Cat objects, in the $cats array
Не знаю, что вы используете, вы можете взглянуть на некоторые php framework для лучшего понимания.