Я впервые работаю с Doctrine2, но я думаю, что этот вопрос достаточно общий, чтобы не зависел от конкретной ORM.
Должны ли объекты в шаблоне Data Mapper знать – и использовать – Mapper ?
У меня есть несколько конкретных примеров, но все они, похоже, сводятся к одному и тому же общему вопросу.
Если я имею дело с данными из внешнего источника – например, у User
есть много Messages
а внешний источник просто предоставляет последние несколько объектов (например, RSS-канал), как можно проверить $user->addMessage($message)
для если он либо не знает о Mapper, либо «ищет» через коллекцию (кажется, это неэффективная вещь).
Конечно, контролер или сценарий транзакций могут проверять наличие дубликатов перед добавлением сообщения пользователю, но это не кажется совершенно правильным и приведет к дублированию кода.
Если у меня есть большая коллекция – снова User
со многими Messages
– как User
объект может предоставить ограничение и разбиение на страницы для коллекции без фактического проксирования вызова Mapper?
Опять же, сценарий Controller или Transaction Script или что-то другое, использующее Entity, может использовать Mapper напрямую для извлечения коллекции Messages
ограниченных подсчетом, диапазоном дат или другими факторами, – но это также приведет к дублированию кода.
Является ли ответ использованием репозиториев и позволяет сущности понять их ? (По крайней мере, для Doctrine2, и любая аналогичная концепция используется другими ORM.) В этот момент Entity по-прежнему относительно отделена от Mapper.
Правило №1: Держите свою модель домена простой и понятной.
Во-первых, преждевременно не оптимизируйте, потому что считаете, что это может быть неэффективно. Создайте свой домен так, чтобы объекты и синтаксис выполнялись правильно. Удерживайте интерфейсы в чистоте: $ user-> addMessage ($ message) является чистым, точным и недвусмысленным. Под капотом вы можете использовать любое количество шаблонов / методов для обеспечения целостности (кеширование, поиск и т. Д.). Вы можете использовать Службы для упорядочивания (сложных) зависимостей объектов, возможно, слишком для этого, но вот базовый образец / идея.
class User { public function addMessage(Message $message) { // One solution, loop through all messages first, throw error if already exists $this->messages[] $message; } public function getMessage() { return $this->messages; } } class MessageService { public function addUserMessage(User $user, Message $message) { // Ensure unique message for user // One solution is loop through $user->getMessages() here and make sure unique // This is more or less the only path to adding a message, so ensure its integrity here before proceeding // There could also be ACL checks placed here as well // You could also create functions that provide checks to determine whether certain criteria are met/unmet before proceeding if ($this->doesUserHaveMessage($user,$message)) { throw Exception... } $user->addMessage($message); } // Note, this may not be the correct place for this function to "live" public function doesUserHaveMessage(User $user, Message $message) { // Do a database lookup here return ($user->hasMessage($message) ? true } } class MessageRepository { public function find(/* criteria */) { // Use caching here return $message; } } class MessageFactory { public function createMessage($data) { // $message = new Message(); // setters return $message; } } // Application code $user = $userRepository->find(/* lookup criteria */); $message = $messageFactory->create(/* data */); // Could wrap in try/catch $messageService->sendUserMessage($user,$message);
Также работал с Doctrine2. Объекты сущности домена – это только те объекты … они не должны иметь никакого представления о том, откуда они пришли, модель домена управляет ими и передает их различным функциям, которые управляют ими и управляют ими.
Оглядываясь назад, я не уверен, что полностью ответил на ваш вопрос. Однако я не думаю, что сами сущности должны иметь доступ к картографам. Создание сервисов / репозиториев / Независимо от того, как работать с объектами и использовать соответствующие методы в этих функциях …
Не переучивайте его с самого начала. Держите ваш домен сосредоточенным на своей цели и рефакторе, когда производительность на самом деле является проблемой.
ИМО, Сущность должна не обращать внимания на то, откуда она взялась, кто ее создал и как заполнить связанные с ней Сущности. В ORM я использую (свой собственный), я могу определить объединения между двумя таблицами и ограничить его результаты, указав (в C #):
SearchCriteria sc = new SearchCriteria(); sc.AddSort("Message.CREATED_DATE","DESC"); sc.MaxRows = 10; results = Mapper.Read(sc, new User(new Message());
Это приведет к соединению, которое ограничено 10 элементами, упорядоченными по дате создания сообщения. Элементы сообщения будут добавлены каждому пользователю. Если я напишу:
results = Mapper.Read(sc, new Message(new User());
объединение отменяется.
Таким образом, объекты Entity полностью не знают о картографе.
Нет.
Вот почему: доверие. Вы не можете доверять данным, чтобы действовать в интересах системы. Вы можете доверять системе только для работы с данными. Это фундаментальная логика программирования.
Скажем, что-то неприятное проскользнуло в данные и предназначалось для XSS. Если блок данных выполняет действия или оценивается, тогда код XSS смешивается с вещами, и он откроет отверстие безопасности.
Пусть не левая рука не знает, что делает правая рука! (в основном потому, что вы не хотите знать)