Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 25.08.2020 06:21:46

Как правильно получать данные подзапросов в коллекции

Здравствуйте!

В контроллере получаю массив каких-то данные для отображения списка и далее в 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;
});

Это будет корректным решением или применяются другие подходы?

Не в сети

#2 25.08.2020 10:02:37

Re: Как правильно получать данные подзапросов в коллекции

Конечно же все эти манипуляции нужно делать на бэке.
Посмотрите на ресурсы, в ресурсе необходимо сделать преобразования и вернуть из контроллера ресурс.
https://laravel.com/docs/7.x/eloquent-r … troduction

Не в сети

#3 25.08.2020 10:11:41

Re: Как правильно получать данные подзапросов в коллекции

вернуть из контроллера ресурс.

Но мне же надо не вернуть ресурс, а вернуть view с передачей туда данных

Не в сети

#4 25.08.2020 10:27:12

Re: Как правильно получать данные подзапросов в коллекции

Верните view, и  ['users' => $resource->toArray()], например

Не в сети

#5 25.08.2020 10:58:19

Re: Как правильно получать данные подзапросов в коллекции

Если быть занудой, то хочется наругать за запросы в цикле. Независимо от того, где они происходят. Счетчик коментариев желательно сохранять в таблице и вычислять только тогда, когда количество коментариев изменяется  — наверняка это происходит в сотни/тысячи/миллионы раз реже, чем чтение счётчика.

Если не быть занудой, то рекомендую определиться с форматом данных и вынести добычу этих данных в репозиторий или репозиторий в связке с ресурсом. Контроллер будет только связующим звеном. Потом, когда узнаешь больше про запросы к базе, сможешь изменить добычу так, чтобы всё делалось в один-два запроса и при этом формат данных не изменился и ничего не пришлось бы переписывать в других файлах.


There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Не в сети

#6 25.08.2020 11:04:34

Re: Как правильно получать данные подзапросов в коллекции

Кроме того, в 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.

Не в сети

#7 25.08.2020 11:14:57

Re: Как правильно получать данные подзапросов в коллекции

Если быть занудой,

Мне нравится именно такой подход. Насчет примера с комментариями - это было использовано только для примера. В реальности данные меняются довольно часто и нужно их постоянно проверять. Тут дело в том, что я изначально еще не прочувствовал архитектуру 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)}} - будет ли повторный вызов в БД?

Не в сети

#8 25.08.2020 17:29:50

Re: Как правильно получать данные подзапросов в коллекции

1) Можно передать вьюкопозером в layout и тогда и в хедере, и в дашборде будет доступна переменная

2) Если вызывать через ->comments() то вы получите новый запрос. если без "()" - то будет использоваться уже загруженная связь и запроса в БД не последует

Не в сети

Подвал раздела