Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Здравствуйте!
В контроллере получаю массив каких-то данные для отображения списка и далее в foreach все это вывожу. Но в foreach помимо вывода атрибутов модели, также хочется выводить данные, которые есть результат нового запроса на основе данных текущей модели.
Приведу пример:
// CONTROLLER
$users = Users::where('active', true)->get();
//BLADE
@foreach($users as $user)
{{$user->name}}
...
{{$user->getCommentsCount()}}
@endforeach
В данном случае getCommentsCount - метод, который вернет количество всех комментариев пользователя, НО в BLADE некорректно использовать выборки + если нужно несколько раз вывести это значение, то придется два раза писать функцию и делать лишний запрос в БД.
Собственно вопрос, где должны происходить эти вычисления для преобразования коллекции?
В контроллере делать что-то вроде этого?
$users = Users::where('active', true)->get();
$users = $users.map(function($user) {
$user->commentsCount = $user->getCommentsCount();
return $user;
});
Это будет корректным решением или применяются другие подходы?
Не в сети
Конечно же все эти манипуляции нужно делать на бэке.
Посмотрите на ресурсы, в ресурсе необходимо сделать преобразования и вернуть из контроллера ресурс.
https://laravel.com/docs/7.x/eloquent-r … troduction
Не в сети
вернуть из контроллера ресурс.
Но мне же надо не вернуть ресурс, а вернуть view с передачей туда данных
Не в сети
Верните view, и ['users' => $resource->toArray()], например
Не в сети
Если быть занудой, то хочется наругать за запросы в цикле. Независимо от того, где они происходят. Счетчик коментариев желательно сохранять в таблице и вычислять только тогда, когда количество коментариев изменяется — наверняка это происходит в сотни/тысячи/миллионы раз реже, чем чтение счётчика.
Если не быть занудой, то рекомендую определиться с форматом данных и вынести добычу этих данных в репозиторий или репозиторий в связке с ресурсом. Контроллер будет только связующим звеном. Потом, когда узнаешь больше про запросы к базе, сможешь изменить добычу так, чтобы всё делалось в один-два запроса и при этом формат данных не изменился и ничего не пришлось бы переписывать в других файлах.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Не в сети
Кроме того, в eloquent есть метод loadCount(). Он добавляет удобства, но не отменяет потребности в "статическом" счётчике вместо постоянного вычисления при каждом, блин, обращении к странице.
https://laravel.com/docs/7.x/eloquent-relationships искать слово "loadCount"
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Не в сети
Если быть занудой,
Мне нравится именно такой подход. Насчет примера с комментариями - это было использовано только для примера. В реальности данные меняются довольно часто и нужно их постоянно проверять. Тут дело в том, что я изначально еще не прочувствовал архитектуру Laravel и поэтому путаюсь, какая часть системы за что отвечает.
Насчет вашего замечания к циклическим запросам. В правы - я перепишу запрос, который одной транзакцией получит все данные со всеми отношениями. Тут вопрос даже в другом - кто будет делать этот запрос (если говорить про масштабируемую архитектуру)? У меня есть общепринятая структура: Сервис -> Репозиторий -> Модель+БД.
Внедрение Сервиса происходит в контроллере (Репозиторий внедряется в сервис через интерфейс) и он получает одним запросом все данных. Во View приходит уже готовый массив - все верно?
На данном этапе у меня все получалось довольно красиво и без проблем.
А вот немного позже я начал путаться в следующем:
1) Если данные, которые передаются во View повторяются и я не хочу дублировать код в контроллере, то что делать? ViewComposer мне очень не нравится, потому что он передает зависимости неявно. Банальный пример - нужно передавать баланс пользователя в хедер, футер и во view layout.dashboard. Чтобы бы вы порекомендовали в таком случае делать? Только неявно передавать через ViewComposer? Или есть другие варианты, но которые не подразумевают написание Balance::get(Auth::id()) - во всех методах, где учавствуют нужные views. Я раньше с удовольствием делал через фасад и вызов метода сервиса прям в Blade - {{Balance::get(Auth::id())}} - все было бы хорошо, если бы не проблема дублирования (Если надо вывести баланс 2 раза - хедер и футер - то будет 2 обращения к БД).
2) И второе - появилась путаница в понятиях Репозитория и Laravel Model. В документации для создания отношений пишут методы прям в модели через hasMany, например. И в Blade я могу писать, что то типа - {{$user->comments}}, которая дергает метод comments(). А если мне надо после вывода всех комментарием внизу еще написать {{count($user->comments)}} - будет ли повторный вызов в БД?
Не в сети
1) Можно передать вьюкопозером в layout и тогда и в хедере, и в дашборде будет доступна переменная
2) Если вызывать через ->comments() то вы получите новый запрос. если без "()" - то будет использоваться уже загруженная связь и запроса в БД не последует
Не в сети