
Sergey
19.04.2017
13:22:29
ну то есть если у тебя сущность сложная
то лучше заводить отдельную фабрику/билдер которая уже будет знать как собрать сущность
так и запутаться меньше шансов и логику проще проверять и тестить
по сути хэндер это такая штука которая декларирует просто последовательность действий. Сам он ничего не умеет - он менеджер. умеет только делигировать

Google

Roquie
19.04.2017
13:26:39
В данном случае, да. Я там собрал сущность на основе данных из запроса, передал в метод репозитория, он вставил запись. Все верно?
Более интересно, куда вынести обновление данных, если по хорошему, репозиторий для этих целей не подходит.

Sergey
19.04.2017
14:13:39
почему не подходит?
ну то есть у тебя нет сущностей? тогда у тебя должен быть какой-то gateway который скрывает весь sql

Roquie
19.04.2017
14:16:20
почему не подходит?
ну если смотреть со стороны collection like-репозиториев, то там нет сохранения данных

Sergey
19.04.2017
14:16:31
перед апдейтом ты должен был забрать сущность из репозитория
и тогда тебе надо мутить какой-то детектор изменений на стороне репозитория (unit of work)
тогда вместо того что бы "сохранять" ты просто говоришь "закоммитить транзакцию". В идеале когда у тебя хэндлер отработает

Roquie
19.04.2017
14:17:44
я вот про это и говорю, запутался я с детектором изменений и с тем, как в эту парадигму вписать связи

Sergey
19.04.2017
14:18:02
ну у тебя изменения в связях это тоже изменения
их тоже можно трэкать

Google

Roquie
19.04.2017
14:28:26
Давай на примере?
есть у меня 2 сущности, филиалы и операторы.
1) class Office { $id, $name, $operator }
2) class Operator { $id, $name }
Имеем репозиторий офиса:
DoctrineOfficeRepository { func add(Office $office) {} }
Теперь при добавлении, я делаю нечно такое в комманде:
class AddOfficeCommand {
func __construct(array $requestData) {...}
func handle(IOfficeRepository $repo) {
$office = new Office();
$office->setName($this-> requestData['foo']);
$office->assignOperator(new Operator($this->requestData['operator_id']));
$repo->add($office);
}
}
затем, хочу делать апдейт записи и обновить название офиса и привязать другого оператора. Как это сделать используя UoW? Где будет логика запроса в базу?
UoW регистрирует в себе набор изменений, который потом коммитишь, но в нем никак нет логики для обновления записи (сам sql-запрос собранный билдером).

Aleh
19.04.2017
14:31:06
в конце хандла $uow->flush()

Sergey
19.04.2017
14:31:23
> но в нем никак нет логики для обновления записи
там есть вычисление изменений. Зная это ты можешь сформировать sql
$uow->compitudeEntityChangeSet()

Roquie
19.04.2017
14:33:27
черт, я все равно не могу представить весь workflow, как оно друг за дружкой вызывается

Sergey
19.04.2017
14:34:06
или просто почитай про UoW

Roquie
19.04.2017
14:34:28

Aleh
19.04.2017
14:34:55
у тебя есть либо обертка над uow, которую ты вызываешь, когда хочешь изменения все отправить в базу, либо на uow подписывается тот, кто это знает, как из изменений в uow сделать запросы в базу, и ты вызываешь о uow метод, аля посчитай-ка все, что произошло и сообщи кому надо

Roquie
19.04.2017
14:36:42
получается для каждого объекта домена, свой UoW?

Aleh
19.04.2017
14:36:53
нет, в uow все сущности
если в ходе работы изменились две сущности, то очень сомнительно, что надо сохранить изменения только одной
скорее всего это ошибка и(или) костыли

Roquie
19.04.2017
14:43:04
Попробую зайти с другой стороны. По порядку. Я получил массив параметров из запроса. Далее мои действия - собрать из этого entity-объект? (я говорю про апдейт записи, но пока до этого не добрались)

Aleh
19.04.2017
14:44:18
$office = new Office($request->name, $request->foo);
$repo->add($office);
$em->flush();
$office = $repo->findOneById($request->id);
$office->hire($employee);
$em->flush();

Sergey
19.04.2017
14:45:52
при $em->flush() происходит что. Данные из сущности дегидрируются (по сути достаются) и сравниваются с тем что было при fetch.
работает это за счет того что в системе никогда не должно быть более одного инстанса сущности с каким-то ID (Identity Map)
для связей - one-to-one трекать легк

Google

Aleh
19.04.2017
14:46:45

Sergey
19.04.2017
14:46:45
для many-to можно трекать изменения через коллекции

Aleh
19.04.2017
14:47:03
так там просто обходом графа собирается все дерево и сравнивается
а, или обходом там выбирается порядок апдейтов
ну это в любом случае деталь реализации доктрины)

Roquie
19.04.2017
14:51:34
гм, если $em->flush() выносить за пределы репозитория, то ведь хрен потом подменишь на InMemoryRepository какой-нить

Aleh
19.04.2017
14:53:00
почему?
а, в смысле что надо еще em отключить будет?

Roquie
19.04.2017
14:53:26
угу

Aleh
19.04.2017
14:53:51
ну да

Roquie
19.04.2017
14:55:43
Видел, как делают репозитории и flush пихают внутрь. Так, вроде, ведь правильнее - код не зависит от доктрины.

Aleh
19.04.2017
14:57:57
слабо представляю, как это поможет

Aleh
19.04.2017
14:58:04
не на find же flush делать :)

Roquie
19.04.2017
15:00:29
ну нет, только на add/remove
$office = $repo->findOneById($request->id);
$office->hire($employee);
окей, привязали $employee, затем как мне тут поможет UoW?
$uow->registerUpdate($office);
$uow->commit();
?

Aleh
19.04.2017
15:04:01
я вместо uow там писал em
если ты нашел сущность, то репозиторий сам скажет uow "следить" за ней, если ты создал новую, то репозиторий при add опять же скажет uow, что вот тебе объект, который новая сущность, не забудь добавить ее при следующем коммите, если удалил из репозитория, то репозиторий опять же скажет uow, вот этот объект, за которым ты следишь уже, его надо будет удалить
в итоге тебе где-то в контроллере или чем-то похожем в конце твоих транзакций надо делать коммит

Roquie
19.04.2017
15:12:42
Мы используя репозитории можем абстрагироваться InMemory хранилищем для всех операций, кроме апдейта. Как и где мы теперь абстрагируемся от апдейта, чтобы заменить его тоже на InMemory?

Google

Aleh
19.04.2017
15:13:15

Roquie
19.04.2017
15:13:59
Т.е. вот так, уже все абстрагировано?
$data = $entityManager->getRepository('ATest')->findOne(1); // ATest is my entitity class
$data->name = "ORM Tested"; // just change the name
$entityManager->persist($data);
$entityManager->flush();

Aleh
19.04.2017
15:14:01
ну точнее добавление и удаление ничем не отличаются от обновления

Roquie
19.04.2017
15:14:18
merge?

Aleh
19.04.2017
15:14:24
он вообще не нужен нигде кроме репозитория

Roquie
19.04.2017
15:14:39

Aleh
19.04.2017
15:15:00
ты persist делаешь только в методе add репозитория и все

Roquie
19.04.2017
15:16:39
я еще больше запутался, как тогда данные обновятся

Admin
ERROR: S client not available

Aleh
19.04.2017
15:17:20
на flush entity manager спросит у uow "а что у тебя обновилось?" как описывал Сергей
и обновит

Roquie
19.04.2017
15:18:02
т.е. где-то в findOne есть вотчер UoW?

Sergey
19.04.2017
15:18:22

Aleh
19.04.2017
15:18:22
да, где-то в find*/add/remove есть $uow->watch/markAsAdded/markAsRemoved

Roquie
19.04.2017
15:18:53

Sergey
19.04.2017
15:18:53
ну то есть не нужно делать detach

Aleh
19.04.2017
15:19:14

Google

Aleh
19.04.2017
15:19:21
ну или чем-то таком

Sergey
19.04.2017
15:19:25
там persist
а не merge

Aleh
19.04.2017
15:19:36
так я про persist говорил)

Sergey
19.04.2017
15:19:46
а ну это да)

Roquie
19.04.2017
15:20:24
-

Sergey
19.04.2017
15:20:29
find - достает референс на объект
persist - добавляет объект в сторадж
flush - сохраняет весь граф объектов крутящихся в in memory хранилище в базу или на диск или куда там тебе надо
flush обозначает границу бизнес транзакции, границу юзкейса
по хорошему flush должен делать декоратор над шиной команд

Roquie
19.04.2017
15:21:19
окей хорошо, куда обернуть вот это:
$data = $entityManager->getRepository('ATest')->findOne(1); // ATest is my entitity class
$data->name = "ORM Tested"; // just change the name
$entityManager->flush();
Если я не хочу зависеть от доктрины, а заюзать например Eloquent?

Sergey
19.04.2017
15:21:42

Aleh
19.04.2017
15:21:42
то тебе нужна другая реализация flush :)

Sergey
19.04.2017
15:21:56
Eloquent = Active Record

Roquie
19.04.2017
15:22:09

Aleh
19.04.2017
15:22:10

Sergey
19.04.2017
15:22:11
то есть у тебя есть data model (не сущность) и у нее есть save
ты моешь вжахнуть UoW который просто будет обходить граф объектов и оркестрировать save-ами
но не более