Всем привет.
Не первый год в веб разработке, несколько последних лет использую Laravel (что греха таить, нравится он мне), прочитал много умных книг и статей. Вроде бы и принципы ООП понятны и все фишки с репозиториями и сервис-контейнером в Laravel'e. И много проектов мной на нем написано, которые были легко масштабируемы, легко внедрял в них новые фичи и менял логику по требованию заказчика. Но все-равно постоянно присутствует чувство какой-то неудовлетворенности)) Кажется, что шаблон самого приложения может быть еще чище и изящнее. В связи с этим два вопроса, чтобы выяснить, а как вы их для себя решаете:
1. Котроллеры. Везде пишут, что контроллер должен содержать минимум кода, не должен знать, как модель получает информацию, и как представление ее отображает. Но как это правильно реализовать в рамках Laravel? Основная трудность в данном пункте – как правильно передавать данные в представление? Т.е. один и тот же метод контроллера может выводить данные, скажем, во view шаблон, а может и в json’e отдавать. Как это правильно реализовать? Я вижу тут 2 способа:
- создать какой-то дополнительный класс (или метод в этом же контроллере), который будет делать нужный запрос к модели. При этом роуты обращаются к разным методам контроллера, в зависимости от того, нужен json или view. Но каждый из этих методов контроллера обращается к этому общему методу, а потом выводит в том, в чем должен.
Но тут, кажется, дублирование происходит.
- метод контролера один, но используется GET переменная «json», скажем. Добавляем блок if, если переменная присутствует, то отдаем json, иначе отдаем view. Но тоже, как-то не кошерно смотрится…
Как быть?
2. Модели. То, что в Laravel называется моделями, не подходит на роль бизнес логики приложения, я прав? В моделях задаются «настройки» работы с конкретной таблицей БД, при этом можно сделать массу удобных штук с отношениями, сделать очень удобные скоупы. Но при этом модель может разрастись еще до того, как мы начнем в нее внедрять какие-то особенные именно для данного проекта методы бизнес логики. Т.е. логику желательно куда-то вынести. Часто видел и сам так делал, что просто выносят в App\Services. Но тоже до конца не понятно, как правильно вынести? Должны ли это быть самостоятельные классы, ничего не знающие про Eloquent (вряд ли это получится)?
Но самое главное, как правильно быть на уровне связи моделей с контроллерами? Контроллер должен обращаться к какому-то классу внутри Сервисов, а тот в свою очередь создавать необходимые объекты других классов из того же Сервиса, которые в свою очередь подтягивают Ларавелевские модели… или как? Какая-то длинная цепочка получается.
Про репозитории читал, и кажется, что это может помочь в данном вопросе, но до конца не пойму как именно? То, что в качестве хранилища может использоваться не только БД, но и что-то иное – это все здорово, конечно, но только я с таким особо не сталкивался, и мне кажется, что это избыточно – заботиться о том, что может случиться в одном случае из ста. Или я не прав, и их можно использовать не только для разделения способов хранения, но и для лучшей организации работы контроллера с моделью? Или это вообще не о том?
В общем буду рад, если поделитесь шаблонами Ваших наработок на Laravel, или дадите ссылку на опыт других разработчиков в данном вопросе.
jazzus, потому что вопрос совершенно в другом. Вы про техническую реализацию, а я про "идеологическую", что делать такие "ифы" в каждом методе - не айс как-то.
Сергей, Поэтому следует делать код контроллеров как можно короче.
Кроме того со временем у вас в апи и веб роутах могут появиться какие-то различия, это всё полезет в те же ифы и тогда уже точно будет целесообразно разделять контроллеры.
Сергей, тогда предлагаю такой вариант. Запрос $response = Product::find($id);
в сервис-класс
$response->toJson заменить на return new ProductResource($product);
сделать отдельные api роуты/контроллеры. В контроллерах запрос из сервиса. Правильно, как vism написал, об этом везде говорят. У меня в приложении и так, и так и по-другому в зависимости от ситуации. Иногда нужно быстро ответ получить (или json или return back()) или передать в vue готовые данные
Все просто, для логики - сервисы. да.
В моделях оставются всякие рилешены, мутаторы, я туда так же сую проверки простые, типо checkIsPaid()
Ничего страшного, что сервис знает о модели.
А данные в сервис пердавать желательно через DTO, также видел некоторые реквесты передают, но не массивом или списком агрументов.
Репозитарий обычно не нужен если используете элокуент. Репозитарий нужен как поддержка разных испочников данных. типо если у вас есть елокуент и докрин или вобще какое-то сторонее апи, то описывается интерфейс репозитария и уже для каждого источника реализуется по разному.
Если у вас только элокуент, то по сути репозитарий будет повторять вашу модель. вобщем шило на мыло. элокуент грубо говоря репозитарий для разных БД
- метод контролера один, но используется GET переменная «json», скажем. Добавляем блок if, если переменная присутствует, то отдаем json, иначе отдаем view. Но тоже, как-то не кошерно смотрится…
Это по тому что это должны быть разные контроллеры, один для вебморды, один для API/app.
Сергей, нет, они будут местами похожи, но не одинаковы, а в большинстве случаев абсолютно разные, т.к. много чего что можно через веб нельзя сделать через API(и наоборот), да и часто работа с ними строится по разному, не говоря уже о том что со временем сайт и апи могут идти в разные стороны по функционалу.
Я бы вам посоветовал не тормозить на одном ларавел, хотите красивый и аккуратный код с правильной структурой и принципами, гляньте в сторону зенд. В нем есть куча готового под все задачи кода, и он очень просто для расширения. Все что можно там имеет интерфейс, то есть нужен ответ в json, сделайте свою реализацию используя интерфейс, но скорее всего там уже есть подобная реализация.
Плюсы зенд., зенд ни чего не навязывает, не вью не модель, самое сложное это осилить конфиг, если смотреть в сторону зенд3, а лучше зенд-экспрессив, он более расширяемый https://olegkrivtsov.github.io/using-zend-framewor...
Книжка по zf3 можно бегло пробежать, вы поймёте плюсы сами https://github.com/zendframework/zend-expressive
Плюс пачка репов уже нужного кода (100+)
Сергей, лара как и прочие легкие фреймворки (легкие в освоении) приучают не думать, там многое уже придумали, надо только курить доку, зенд дает пачку инструментов, выбор инструментов зависит от вас, что мне нравиться, так что там не навязывают то или иное, захотел для работы с бд выбрал встроенные инструменты, или подключил чужие/свои
Извиняюсь за оффтоп, но... :) От он - показательный случай про российский форум.
- Как мне бы научиться ловить рыбу?
- Тебе не нужна рыба, руби дрова.
- Спасибо тебе, о мудрец, ты открыл мне потаённый смысл.
Вопросы, сугубо относящиеся к конкретной теме. А человеку эту тему сменить предлагают. Правильно сказала одна известная нейробиолог и профессор - мир сходит с ума, большинство людей сумасшедшие, без обид. До тех пор, пока логика и прямые причинно-следстаенные связи отсутствуют, можно смело говорить об этом вслух.
havemanyquestions, если не рубить дрова, человек не сделает удочку и будет ловить рыбу руками. И он может быть лучшим в руколовле, но любой кто имеет удочку поймает гораздо больше. Поэтому исуществует древнее правило - хочешь ловить рыбу учись рубить дрова
jazzus Оригинальное замечание. ) Дмитрий,
Я намеренно взял принципиально разные вещи (процессы) из мира людей, равно как zend и laravel принципиально разные вещи ( первое - не есть второе, а второе - не есть первое, возможно; да, не самая лучшая аналогия, но суть высказывания я пояснил) с точки зрения вопрошающего, желая подчеркнуть неэквивалентность. Zend никоим образом не относится к вопросу. Выбор фреймворка - дело сугубо индивидуальное, но он сделан и вопрос - в контексте уже сделанного выбора. И когда человек уже находится в определенном категорийном поле, ему своим ответом, который по сути является ответом для вопроса-гиперонима, предлагают подняться на уровень вверх (вопрос выбора инструмента), не дав ответа на его основной вопрос, что в принципе ломает суть вопрос/ответ для области , где не обсуждаются отвлеченные понятия (когда можно сказать, что дескать нет, вы, батенька, неправильный вопрос задаете), но достаточно точные вещи, когда вопрос поставлен точно, определенными тезисами, которые относятся к определенной сущности (в данном случае фреймворк). Никого обидеть цели не имею, просто обращаю внимание, воспользовавшись случаем, и констатирую факт, который легко объясняется категориями логики.
P.S. Кстати, идея в этой связи. Было бы здорово ввести две категории ответов: конкретный ответ и предложение. Первые - это для практиков, зашел, ответил на вопрос, решил свою задачу. А вторые - это когда хочется узнать мнения по вопросу, когда предлагаемое решение, подход не совместимы с существующим инструментарием, заложенным в контекст. Либо блок ответов и комментариев по вопросам, чтобы желающий ответа, а не дебатов, мог не тратить времени. Просто хабровская аудитория - это (мне так кажется, это не факт) развитые интеллектуально и не самые ординарные люди, поэтому им хочется показать свой кругозор, обсудить вопрос и это здорово. Но суть вопросника в другом. Поэтому разделение вопроса на два блока - это хорошая идея, хоть и является гипотезой, которую нужно проверить на практике.
Дмитрий, это заметно по вашему ответу. Работая много лет с WordPress я подобного наслушался до тошноты. Чего вы не поняли в контексте этого вопроса и комментария havemanyquestions - ваше личное мнение/отношение никого не интересует. Все это - инструменты, с плюсами и минусами. Если вопрос в выборе инструмента - можно подискутировать и высказать свое мнение, его будут ждать. Если вопрос по уже выбранному конкретному инструменту - мнение о его выборе никому уже не интересно, проехали.