Как назвать метод?

fixxxer

К.О.
Партнер клуба
А на репозиторий-то откуда ссылка возьмется? У тебя же там не только save, как я понял, дергается, а вообще все подряд.
 

whirlwind

TDD infected, paranoid
Дык потомушож CRUD. Вот Create и есть фабричный метод. Обычно их несколько для удобных случаев. Оно все и пропихивает.
 

whirlwind

TDD infected, paranoid
Ну вот так сходу прям хорошего примера и нет у меня. Ну например вот http://pastebin.com/PkFLgHVG
Но мне кажется, что здесь нет ответа на твой вопрос. Если ты про репо, это надо смотреть тесты где активно именно репы юзаются.
 

whirlwind

TDD infected, paranoid
Ага.

(С наследованием чота жесть. Но понятно, тяжко без рефлексии.)
Прости, не понял насчет наследования. Наследования у меня почти нету, потому что это очень неудобно для тестов. Если ты про методы, которые делегируют другим сущностям, так в этом и весь смысл. Классы взаимодействуют с ближними соседями, а не со всей системой. Я меняю ближних соседей, вместо того, что бы менять систему. Получаются хорошо изолированные несвязанные компоненты.

Вот репо http://pastebin.com/ejdZiS26
Благодаря напичканой логикой ноде, репо в основном реализует управленческие функции. Именно те, которые ему положены по single responsibility. Если бы это была какая то сложная сервисная функция, репо, возможно имел бы метод-делегат третьему сервису. Наличие метода не говорит о том, что этот метод там реализован. Просто экспрессивные интерфейсы.

ЗЫ. А вот кстати еще пример. http://pastebin.com/qVxtqVgS
Это пул, который инкапсулирует два предыдущих репо. Обратите внимание на метод Register. Он принимает ордер, а возвращает ноду, то есть фабричный метод. Этот пул является и entity (сводный корень) и репозиторием одновременно. Сверху еще один пул для сущности под названием инструмент. Ну и как это можно по папочкам линейно разложить? Никак. Либо смешивать роли, либо анемичная модель. Собственно, я уже говорил об этом.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Наличие метода не говорит о том, что этот метод там реализован. Просто экспрессивные интерфейсы.
Нарушение ISP — это у нас теперь «экспрессивные интерфейсы».

Этот пул является и entity (сводный корень) и репозиторием одновременно.
А если молнию расстегнуть, так ещё и в шорты превратится.

Ну и как это можно по папочкам линейно разложить? Никак.
С такой агрессивной реакцией на любую несогласованность с твоим внутренним мирком это, наверное, действительно невозможно.
 

Redjik

Джедай-мастер
Как дать доступ к методам только сервису?
Например хеш для логина пишется в UserEntity через сервис.
Не хочется, чтобы UserEntity имел публичный setHash

Можно сделать правильно - 2 интерфейса, UserPublicInterface (репо его будет возвращать), UserHashInterface (тайпхинтинг в сервисе)
По факту метод остается публиным, но мы его не видим через интефрейс... такая вот эмуляция срезки

Можно сделать по-другому, но за такое руки отрывают - через bindTo и лямбду поменять приватное свойство в сервисе.

ЗЫ. ну и третий вариант уже тут обсуждался, прокинуть Hasher в setHash
 

whirlwind

TDD infected, paranoid
Я использую интерфейсы. Интерфейсы массу проблем решают. Вурдалак правильно сказал про ISP. Только он не вкуривает, что это относится к способу взаимодейстивия между классами, а не к реализации конкретного класса. Один класс может реализовывать несколько интерфейсов. В некоторых случаях проще имплементнуть, что бы адаптировать entity под имеющийся сервис, чем плодить новый или менять имеющийся сервис под каждый частный случай. Hash для коллекций отличный пример. Hash можно прикрутить к любому классу. Для этого не нужно менять сервис, что бы он знал о всех возможных типах, порождающих хэш. Более выгодно имплементировать нужный для сервиса интерфейс в каждом классе, который требует расчета хэша. Тогда сервис будет не UserHashService, а просто HashService. Низкий уровень связанности и при этом доступен всем желающим, если вдруг понадобится в будущем.
 

Sufir

Я не волшебник, я только учусь
Как дать доступ к методам только сервису?
Например хеш для логина пишется в UserEntity через сервис.
Не хочется, чтобы UserEntity имел публичный setHash

Можно сделать правильно - 2 интерфейса, UserPublicInterface (репо его будет возвращать), UserHashInterface (тайпхинтинг в сервисе)
По факту метод остается публиным, но мы его не видим через интефрейс... такая вот эмуляция срезки

Можно сделать по-другому, но за такое руки отрывают - через bindTo и лямбду поменять приватное свойство в сервисе.

ЗЫ. ну и третий вариант уже тут обсуждался, прокинуть Hasher в setHash
Буквально только что об этом думал. Причем это нужно не только для сущностей, но и для коллекций, т.к. вместо $grade->addPupil($pupil) можно сделать $grade->getPupils()->add($pupil). Коллекция извне должна быть read-only, Collection::add должен быть виден только из сервисов или сущности.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Redjik, опять решил набросить, сволочь?

Как дать доступ к методам только сервису?
Тебе это не нужно.

Можно сделать правильно - 2 интерфейса, UserPublicInterface (репо его будет возвращать), UserHashInterface (тайпхинтинг в сервисе)
По факту метод остается публиным, но мы его не видим через интефрейс... такая вот эмуляция срезки
Я правильно понимаю, что ты будешь пихать объект с интерфейсом UserPublicInterface в метод, требующий UserHashInterface? Плохая идея. Вообще тут возникает сразу куча проблем: а к какому слою тогда относится класс User? Если это domain и ты считаешь, что hash — это не часть domain, то у тебя будет микс из слоёв в одном классе; если это инфраструктура, то там будет бизнес-логика, что отвратительно.

Не хочется, чтобы UserEntity имел публичный setHash
Не нужно вообще ничего называть setFoo(), мы никогда не говорим «Вася решил установить себе новое имя Петя». Вася решил сменить имя. Нейминг с сеттерами — это путь в сторону anemic.

По поводу исключения hash из domain у меня большие сомнения, а вот salt можно исключить просто из маппинга ORM и доставать только на уровне инфраструктуры.
 

Redjik

Джедай-мастер
Ты не понял немного, предположим нам нужна хеш строка, ну там для активации ака, или для одноразовой авторизации...
Генерим мы строку сервисом, ну тот же SecureRandom из Symfony...
И как все это разрулить то?

Я вижу способо через сревис
UserService::__construct($repo,$hasher)
UserService::generateRandomHash(User $user)

При этом хотелось бы исключить присваивание хеша напрямую Юзеру

ЗЫ. я сам уже придумал как обойти задачу как минимум 3мя способами. Но хочется получить именно решение по условию, которое я описал... Ибо такое поведение конечно не совсем для хеша подходит, но вполне проявляется в других местах
 

Sufir

Я не волшебник, я только учусь
Зачем? Зачем тогда этот хеш вообще сдался User'у?
Суть в том, что всё равно требуются какие-то свойства и методы доступные внутри пакета (в слое домена) и недоступные пользователю извне (в слое приложения). Как пример с коллекцией указанный мной выше. Пользователь не должен иметь возможности сделать $grade->getPupils()->add($pupil), у него есть $grade->addPupil($pupil) (а внутри Grade::addPupil() уже вызывается в том числе и Collection::add()). Вопрос, сдался коллекции метод add() или нет? Если нет, то как добавлять элементы в коллекцию?

Так же и у сущностей могут быть какие-то свойства и методы, скажем так, "служебные", через которые мы могли бы манипулировать сущностью внутри пакета, но не могли бы извне.

Ну, вот такое ещё в голову приходит - подсущности сущности... Для сохранения в базу у $pupil нужно свойство grade_id, в то время как с точки зрения домена никаких gradeId у Pupil конечно нет. Впрочем, не слишком удачный пример вероятно, первое что в голову приходит. Но суть, думаю ясна.
 

whirlwind

TDD infected, paranoid
Суть в том, что всё равно требуются какие-то свойства и методы доступные внутри пакета (в слое домена) и недоступные пользователю извне (в слое приложения). Как пример с коллекцией указанный мной выше. Пользователь не должен иметь возможности сделать $grade->getPupils()->add($pupil), у него есть $grade->addPupil($pupil) (а внутри Grade::addPupil() уже вызывается в том числе и Collection::add()). Вопрос, сдался коллекции метод add() или нет? Если нет, то как добавлять элементы в коллекцию?

Так же и у сущностей могут быть какие-то свойства и методы, скажем так, "служебные", через которые мы могли бы манипулировать сущностью внутри пакета, но не могли бы извне.

Ну, вот такое ещё в голову приходит - подсущности сущности... Для сохранения в базу у $pupil нужно свойство grade_id, в то время как с точки зрения домена никаких gradeId у Pupil конечно нет. Впрочем, не слишком удачный пример вероятно, первое что в голову приходит. Но суть, думаю ясна.
Еще раз. Зачем ты открываешь всему свету внутренности сущности? Ты своей рукой как пользуешься, пальцами управляешь через репозиторий: дайте мне мизинец, согнуть мизинец, разогнуть? Нафига снаружи эти детали? Ты берешь предмет в руку. Это все что тебе нужно. $grade->addPupil(). Завтра ты что нибудь добавишь или захочешь поменять реализацию, ты будешь всех пользователей твоей коллекции переписывать. Вопрос - нафига? Вот подобное $this->something->anything->another должно вызывать подозрения сразу. Тоже говорил про это пару страниц назад.

Делаешь два интерфейса. User и к примеру EditableUser extends User. С репами то же самое. Для публичного использования отдаешь через публичные методы User. Для служебного оперируешь EditableUser (например поставщик данных). При этом саму модель можно сделать независимой от поставщиков данных. Поставщики данных как драйверы как угодно можно реализовать. Потребители модели об этом знать не будут и не должны. Будет такая схема

бизнес-процесс -> модель <- поставщики данных
 

Redjik

Джедай-мастер
whirlwind, ну дак это же как раз я и предложил...
твою позицию я понимаю... у тебя смешение инфраструктуры и домена идет... возможно оправдано, ибо я пока только так и работал ... и схема и правда рабочая

Вурдалак, ты толи троллишь, толи сам себе противоречишь. На 99 процентов вопросов - у тебя один ответ (ладно два), сервисы нельзя инжектить в домен и у тебя неправильная бизнес модель.

Вот ребята бизнес задача, объясните мнне тугому, как ее решить, без махания руками. Я сам вижу кучу решений, но мне интересно вас послушать ибо не могу до конца вас понять:

— Необходимо авторизовывать юзера по одноразовой протухающей через определенное время ссылке.

Специально не буду продолжать показывать какие-то свои примеры и размышления. Просто на интерфейсах покажите решения этой задачи.
Было бы неплохо, чтобы генерация ссылки просиходила через какой-нибудь сервис-рандомизатор, но это уже реализация, а значит вместо конструктива рискую получить "у тебя неправильная бизнес модель".
 
Сверху