Как организовать работу со связанными моделями в Eloquent при создании REST api?
Подскажите пожалуйста, как организовать работу?
Если я правильно понял из исходников и документации - у нас есть несколько видов связей
BelongsTo - Услуга находится в категории
HasOne/HasMany - Категория содержит одну/несколько услуг
BelongsToMany - Пользователь "находится в" нескольких ролях, связь через 3-ю таблицу
HasOneThrough/HasManyThrough - Роль содержит одну/несколько пользователей, связь через 3-ю таблицу
MorphOne/MorphMany - то же, что и HasOneThrough/HasManyThrough, только еще с условием, то есть сработает только для определенного значения в колонке
MorphToMany - взаимодействие четырех таблиц. Если MorphMany имелось в виду несколько один-ко многим в одной таблице, то это несколько MorphMany со списком в четвертой таблице. Лютая дичь
Pivot - Системная. Когда пробегаемся по списку пользователей, полученных из роли через связь, Пивот это таблица-связка
MorphTo - Системная. При работе с Morph связывает таблицу, чтобы MorphOne/MorphMany работали
Кроме того, что тут намудрено лютая туча этих связей, как оказалось в коде - они еще и не все умеют сохранять, как будто их делали только для считывания и фильтрации.
Например belongsTo() - умеет associate()/dissociate() - по сути проставить айдишник на свое место, потом надо вызывать save(). Это вроде правильно. hasOne/hasMany() - умеет только saveOne()/saveMany() - то есть она не устанавливает связь, а сразу пишет в базу, проставляя айдишники походу, но прикол в том, что если родительской модели нету, то и айдишники не проставятся, приехали, то есть она не меняет модель, она сразу пишет, потом вопросы с транзакциями, когда хочешь сделать рекурсивное сохранение belongsToMany() - умеет sync() и attach(), аттач - в связанной таблице добавить запись даже если есть, detach() - удалить записи по списку, sync() - удалить лишнее и добавить которых не было. Причем делает это сразу в базе данных. А значит её тоже нужно вызывать в сервисе, понятия типа "построить модель со связями по ДТО" здесь нету походу.
остальные связи и вовсе не умеют, мне кажется, сохранять, а только считывать - там есть какие-то наброски по сохранению, но они не проставляют внешних ключей, а тупо срабатывают как будто я на самой модели вызвал save().
Я сначала хотел переписать метод push() который рекурсивно сохраняет модель и её связи, но поскольку связи работают черт его разбери как - это почти не имеет смысла.
===
Я почему спрашиваю... Если я пытаюсь сделать RestController которому какую модель не дай - он умеет CRUD + еще немножко, то мне нужно формирование модели с которой я работаю, а потом её сохранение в транзакции. Тут же получается всё заточено под то, что каждой модели нужно писать 5 экшенов контроллера и в каждом экшене вызывать собственную логику сохранения, которая написана чуть ли не на `for`ах.
Я правильно понял, или есть элегантный способ с этим взлетать?
Взглянув на код Relations\Pivot пришел к выводу что тут просто наброски. С багами
parseIds() почему-то сначала делает из Eloquent\Collection -> array, а потом array -> Support\Collection теряя при этом айдишники, и потом пытается сделать array_diff() по ключам, которые уже не ключи а номера индексов.
Если вы пытаетесь сделать "RestController", то мб вам, все таки, нужна cms? В каком таком юс кейсе вам нужно как минимум ТРИ полностью одинаковых контроллера? У вас в проекте есть аж ТРИ сущности, которым нужен просто CRUD?
Не пытайтесь ничего придумать. Все уже придумано за вас. Придумывать сможете, когда ближе к сеньеру пододвинетесь, а не
"хотел переписать метод push() который рекурсивно сохраняет модель и её связи", потому что это ахуительно гибкое и очевидное для других разработчиков решение, от которого так легко уйти и которое будет так стабильно работать,
не
"parseIds() почему-то сначала делает из Eloquent\Collection -> array, а потом array -> Support\Collection теряя при этом айдишники, и потом пытается сделать array_diff() по ключам, которые уже не ключи а номера индексов.", потому что в коде фреймворка, который полностью покрыт тестами, вы нашли баг, из-за которого половина проектов вообще бы не работали, и потому что по вашему перевод Collection -> array занимает какие-то ресурсы,
не
"которая написана чуть ли не на `for`ах.", потому что "`for`'ы" - это уже "чуть ли", и.е. крайности,
не
"что если родительской модели нету, то и айдишники не проставятся, приехали", потому что, очевидно, фреймворк должен УГАДАТЬ какой вы там хотите айдишник и проставить его, просто потому что вам лень сделать ->save() на перенте,
не
"понятия типа "построить модель со связями по ДТО" здесь нету походу.", потому что, очевидно, это такая простая задача, которую, очевидно, должен выполнять фреймворк, а точно не гигантские инструменты типа graphql,
и, гвоздь программы - "МНЕ КАЖЕТСЯ":
"остальные связи и вовсе не умеют, мне кажется, сохранять, а только считывать "
Ну, раз вам так кажется, зачем вам laravel? Да напишите вы уже фреймворк, хоспаде, что вам там, богу программирования, делать то? Час работы.
Я на тебя выкатывал претензии или с фига ли ты рамсишь на меня? Я могу прожевать и стерпеть, ничего не сказать, но опыт показывает что после этого такие как ты окончательно слетают с катушек и уже вролне унижающим тоном утапливают тех кто сомневается в дерьме и грязи. Не будем в это скатываться, согласен со мной?
Давай сначала. Я задал вопрос потому что не понимаю, как это использовать. А вместо рекомендаций как надо я получаю разбор своего вопроса и замечаний по словам, где написано, что я неправильно сказал, но не написано, что я не так делаю. При этом используются зарубежные слова юзкейсы и в общем то хорошо что только оно, просто ты в другой компании общаещься там так привыкли, это нормально для меня.
Насчет одинаковых контроллеров меня испугало то что когда я пишу контроллеры с помощью которых я планирую делать админ панель, поиски и сортировки в ней, то я подумал это и есть рест апи. В данном случае набор исходных данных отличается только полями модели, для записи, и набором имеющихся скоупов для выборки. Вот поэтому я решил что сущности одинаковые, а не потому что я лучший герой всех легенд, как вам почемуто показалось. Мне интересно например зачем в реквестах задавать список полей, если этот список мы и задаем в модели когда выставляем свойства по умолчанию? Я бы хотел поговорить об этом в личной беседе, если после твоей тирады судя по моему опыту обычно говорят что ничего мне не должны и исчезают лишь бы не помогать выродкам типа меня. То что я выродок это наверное по умолчанию предполагается
Теперь о самих связях. Мне не понятен порядок действий и распределения ответственности если мне нужно создавать любую из связей через некую сущность. Например мне нужно добавить цену на услуги для пользователя. Это много ко многим и участвуют услуга, цена и пользователь. Я вот сейчас ичтощенный написал просто класс с названием от балды который на входе ждет обьект и массив с ценами и с помощью логики и поиска в существующих добавляет или удаляет цены. В общем и целом щаливка одной связи заняла 8 методов и около трех сотен строк с учетом пробелов и переносов. Рядом с этим лежит переписанный класс который с пуш рекурсивно заливает по связям и добавление связанных моделей тоже переписанные методы которые в сумме чтото вроде 400 строк, но работают для любой таблицы стоит мне только проставить идентификатор в свойство с помощью сеттера. Но изаза особенностей покрытого тестами фреймворка эта штука половину не сохраняет, в пивотах игрорирует сеттеры, а связи через третью таблицу заливает с помощью контрсвязи. Реализуя логику заливки одной связи на 300 строк принимая во внимание количество связей у меня строк тысяч 20 выйдет на мои 32 таблицы. Либо я чтото не так делаю, либо я чтото не так понимаю. В первую очередь что то что придумано до нас как то неожиданно работает и мне предлагают ни в коем случае об этом не задумываться.
Жду твоего комментария, мне важно знать что мастер фреймворка может о нем рассказать. Спасибо
Григорий Васильков, "Не будем в это скатываться, согласен со мной?" - куда уж дальше скатыватся? Ты приходишь на площадку с вопросами, заявляешь какой laravel говно, не имея никакого понятия даже о том, как оно СЕЙЧАС работает, и, уж тем более, как оно ДОЛЖНО работать.
Нет, laravel во многом говно, но твои "аргументы" - это совсем не то. Я ответил по полочкам.
" рамсишь на меня" - ясно понятно, back to 90's.
" А вместо рекомендаций как надо я получаю разбор своего вопроса и замечаний по словам" - а я вместо вопроса увидел список причин, почему тебе не нравится laravel. Я написал что ты не так делаешь раз 10, в комментарии вверху.
"При этом используются зарубежные слова юзкейсы" - чего? Кто тебя заставляет использовать зарубежные слова? Я использовал их, ты то тут при чем?
"админ панель" - так возьми готовую админ панель. Nova, Voyager, еще десять каких-то админок. Они все под это заточены.
"ничего мне не должны" - именно, потому что любая беседа должна быть интересна для ОБЕИХ собеседников. Тут же речь о простом "используй, как в документации", так как у тебя явно недостаточно опыта что бы сделать что-то лучше. Хочешь больше инфы, чем в доке? Смотри laracasts.com.
" То что я выродок" - забавно, что в своем комментарии я, вроде, уважительно обращался на "вы", и об оскорблениях речи не идет.
"штука половину не сохраняет" - мб потому что твой код не работает? Нее, как такое может быть? Должно быть это фреймворк, который в продакшене используется годами, не работает. Ага.
"тысяч 20" - тысяч 20? Строк? На релейшены? "Либо я чтото не так делаю" - вот ответ.
"как то неожиданно работает" - это уже другой вопрос. Работает оно так, как в документации, никак иначе. Идеальное ли оно - конечно нет, но оно ТОЧНО работает и ТОЧНО лучше того, что написал бы ты. Поэтому ответ "ни в коем случае об этом не задумыватся" - более чем уместен.
Но никого не заставляю. Можешь писать свои 300 строк и использовать, посмотрим как пойдет. Мб если все так хорошо, пулл реквестик кинешь в laravel/framework. Но чую я, что нет.
Я ожидаю твоих комментариев как это работает и снова получаю опус о том что я из 90х, что я не так говорю, не так спрашиваю, оправдания про полочки и тд. здесь нет ответа. Либо ты не хотел его давать, и выкручиваешь мне яйца, либо ты не знаешь ответа. С такими только в 90х и разговаривать. Не то сказал - достали ствол и пришили. Все авторитетами меряешься, то не так это не так.
Я ему про задачу, он мне про то что я плохой, оценка твоя меня меня не заботит, не потому что мне плевать, а потому что в этом нет пользы
Еще раз уточняю. Я не пытаюсь говорить с теми кто сюда зайдет, как мне кажется это ты у себя сделал. Я не пытаюсь показать им что тот дурак этот не дурак. Я хочу чтобы нам удалось описать здесь как пользоваться той документацией что там есть. Пример - заливка по связи в третью таблицу работает через метод sync(), туда нужно закинуть айди с чем вяжем и массив который зальется в таблицу связку.
Это нужно подготовить. Но форичах в контроллере это можно сделать но экшены будут большие, хотя все будет работать. Я спрашиваю - как понимать принцип работы этого. Сразу в модели делать? Или готовить массивами, а потом заливать?
Где задавать валидаторы? С одной стороны они делают магические модели, где минимум наследования, с другой стороны говорят что нужно наследовать Request и в нем писать правила валидации. То есть они как бы и за наследование и против него. Есть способ с этим работать, причем без хардкода в контроллеры форичей готовящих массивы.
Это как-то делается в геттерах, сеттерах, а еще ж есть вещи которые быстрее выполнить для нескольких обьектов, чем для каждого. Это где делать, понимая что в результате запроса прилетает уже готовая модель, и её менять потом не то чтобы плохо, но неприятно и грозит сюрпризами
Твои ответы как бесполезный шум. "Наверное я что-то не так делаю"? Ответ: да. Как делать? Читай ларакаст. И потом - "я тебе ответил". Ты не ответил и не помог, ты продемонстрировал открытость и свободу свою, свою необязанность никому и ничего, продемонстрировал ум и умение делать бизнес - никому ничего не дать, но показать что ты владеешь тайными знаниями. Ничем и никому не помог, но теперь все знают что вот ты то мастер здесь. Мастер то мастер, только мастер тот кто на детальки может разложить не-мастеру. А в твоем случае мастер получается тот, кто умеет сказать "сходи в библиотеку". Это не мастер, это обыватель.