Недостаточный контроль над relations
Всем привет!
Есть две сущности, одна наследует другую (STI), в этих сущностях используются типизированные свойства и в relation явно указывается на что ссылается Relation
class User {
/** @ORM\Relation\BelongsTo(target="Studio", nullable=true)*/
protected ?Studio $studio = null;
// ...
}
class Studio extends User {
// ...
}
И в этой ситуации наш код перестает работать, т.к. до полной загрузки связанной сущности мы работаем с другим объектом Reference
Окей, думаем как исправить это, можно пойти по пути использования своей PromiseFactory, подключаем и ..., это нам также ничем не поможет, т.к. метод promise выгляит так:
public function promise(ORMInterface $orm, string $role, array $scope)
И мы можем узнать только то, что нам пришла роль user и ee scope также не содержит подсказки с чем имеем дело.
Вообще идея у меня была следующая, зная target можно было бы создать пустую сущность и предзаполнить все поля из scope, что помогло бы получить объект нужного типа. Т.е. фабрика нам позволяет поменять Reference на что-то своё, но полного контроля не дает.
Окей, думаем дальше. У вас есть пакет cycle/proxy-factory , он также не сможет создать правильный объект, т.к. он не знает что он имеет дело с STI, создаст просто User и код сломается.
Я вижу два пути выхода из положения
- Передавать каким либо образом текущий Relation и корректный target в нем, чтобы понимать что ожидается
- Давать возможность в анотации или схеме указывать класс, который мы ожидаем на выходе.
P.S. final class это реально зло! Чтобы немного доработать сущестующий код, мне приходится целые классы тащить за собой, вместо переопределения одного метода.
Насчет final отписали в другом топике. :)
Передавать каким либо образом текущий Relation и корректный target в нем, чтобы понимать что ожидается
Думаю вот это можно сделать, контекст известен откуда и куда. Соответственно если передать из какой связи это идет то уже можно будет из схемы забрать все что нужно.
Мы можем убрать final на отдельных классах, но тогда мы не гарантируем что они будут работать при изменении внутреннего АПИ.
Вот тут достаточно просто можно добавить название связи и откуда она вызывается, это поможет с STI.
https://github.com/cycle/orm/blob/master/src/Relation/Traits/PromiseOneTrait.php#L27
https://ocramius.github.io/blog/when-to-declare-classes-final/
Вот тут достаточно просто можно добавить название связи и откуда она вызывается, это поможет с STI.
https://github.com/cycle/orm/blob/master/src/Relation/Traits/PromiseOneTrait.php#L27
Я полностью изучил как происходит работа с Relations, проблема в том, что даже имея на руках relation объект мы не можем узнать корректный target и пришлось привязываться к $relation->__toString(), который мне выдал что-то похожее на studio(Cycle\ORM\Relation\BelongsTo)->user
Гм. Да, у нас нет метода getTarget(). Исправим!
https://ocramius.github.io/blog/when-to-declare-classes-final/
Ну я понимаю смысл final, и я понимаю что если вы что-либо измените, то да может у меня все сломаться, но мне никто не мешает все классы к себе перетащить от вас, это просто займет больше времени, но от проблемы изменения внутреннего API это не спасет, я переопределил ORM класс, но все связанные с ним классы я буду использовать ваши и они также могут сломать всю работу ORM. Здесь разработчик сам должен осознавать риски и возомжно в этом случае проще его предупредить, чтобы либо завязывался на версию, либо он делает на свой страх и риск.
Гм. Да, у нас нет метода getTarget(). Исправим!
Дело в том, что getTarget() вернет мне User, а не Studio
А вот это уже скорее всего часть генератора схемы. В момент рантайма сзязи знают только о том что им говорит схема. А раз там STI то происходит фаллбек на родителя... гм.
Это больше похоже на недоработку schema-builder. Решить это можно если сделать свой генератор, либо разбить STI на физически разные сущности с общим родителем.
Здесь разработчик сам должен осознавать риски и возомжно в этом случае проще его предупредить, чтобы либо завязывался на версию, либо он делает на свой страх и риск. Если бы все читали предупреждения :(
P.S. https://github.com/cycle/orm/pull/98
У вас есть возможность изолировать проблему? Я пока не очень понимаю почему у вас родитель ссылается на потомка который расширяет родителя...
Я думаю эту проблему достаточно просто решить если описать схему руками и явно указать что Studio это физически другая сущности, хоть и хранится в той же таблице.
Я думаю эту проблему достаточно просто решить если описать схему руками и явно указать что Studio это физически другая сущности, хоть и хранится в той же таблице.
Разве в этом случае будет работать STI?
У вас есть возможность изолировать проблему? Я пока не очень понимаю почему у вас родитель ссылается на потомка который расширяет родителя...
Проблема частично решена, через кучу костылей, поэтому пока что делаюсь инфой
Вот что находится в Relation

Разве в этом случае будет работать STI?
Да, конечно. ОРМ может прекрасно хранить несколько сущностей в одной таблице. Поломается только референс на Studio через ид юзера, но я так понимаю в вашем случае это и ну нужно.
Достаточно описать Studio как отдельную сущность и все должно быть ок. Без костылей. Но schema-builder так пока не умеет, так что либо свой генератор, либо руками описать схему по докам (можно просто скопировать уже скомпиленную и ее поправить).
Разве в этом случае будет работать STI?
Да, конечно. ОРМ может прекрасно хранить несколько сущностей в одной таблице. Поломается только референс на Studio через ид юзера, но я так понимаю в вашем случае это и ну нужно.
Достаточно описать Studio как отдельную сущность и все должно быть ок. Без костылей. Но schema-builder так пока не умеет, так что либо свой генератор, либо руками описать схему по докам (можно просто скопировать уже скомпиленную и ее поправить).
Да в том то и дело, что хотелось бы оставить и _type в бд и по нему кастить нужную сущность. В общем типизированные свойства грядут и пришло то время, когда все захотят их использовать :)
Да в том то и дело, что хотелось бы оставить и _type в бд и по нему кастить нужную сущность. В общем типизированные свойства грядут и пришло то время, когда все захотят их использовать :)
А _type можно в маппере ставить фиксированно, будет ОК. Есть же доступ к extract, и он не финальный.
I think this is still the case, where STI child is referred in a relationship, the schema generator will fallback to the parent class. This is possibly because in the generator sequence, TableInheritance is run after Entities, and those child classes are not in $this->entities when the relationship is being calculated.
It comes down to here:
I was already using my child STI classes with no issues, but apparently all of those places were also STI, so their relationships were resolved much later via TableInheritance. When I tried to use an inherited table class in a regular table class via a relationship, the issue revealed itself.
If you think there is a bug, could you make a test case using https://cycle-orm.dev/docs/issue-test-case ?