Не отображается имя пользователя с помощью отношений

Рейтинг: 0Ответов: 1Опубликовано: 27.02.2023

Есть код отображения

@foreach($chats as $chat)
    <a class="flex items-center px-3 py-2 text-sm transition duration-150 ease-in-out border-b border-gray-300 cursor-pointer hover:bg-gray-100 focus:outline-none">
        <img class="object-cover w-10 h-10 rounded-full" src="INGAME_free-file.png" alt="username" />
        <div class="w-full pb-2">
            <div class="flex justify-between">
                <span class="block ml-2 font-semibold text-gray-600">{{ $chat->sender == Auth::user()->id ? $chat->recipient->name : $chat->sender->name }}</span>
                <span class="block ml-2 text-sm text-gray-600">25 minutes</span>
            </div>
            <span class="block ml-2 text-sm text-gray-600">bye</span>
        </div>
    </a>
@endforeach

В моделе чат я делаю 2 отношения

public function sender()
{
    return $this->belongsTo(User::class, 'sender');
}
    
public function recipient()
{
    return $this->belongsTo(User::class, 'recipient_id');
}

И получается так, что функция recipient возвращает имя пользователя, а функция sender нет. Если вывести $chat->sender, то он покажет правильный id пользователя, но достучаться до его имени не получается

Ответы

▲ 1

У вас ошибка в том, что имя метода и имя связующего ключа одинаковые. Переименуйте поле в таблице sender на sender_id и всё заработает. Плюс это правильный подход в плане наименования. Не надо смешить стили написания и так далее. Где-то писать sender где-то Sender, а где-то sender_id.

После того как исправите. Возникает следующая проблема, которую будете замечать и отслеживать сразу как наберётесь больше опыта. Это касается вывода на страницу.

Нельзя в цикле (в данном случае в цикле foreach($chats as $chat)) делать вызов связующего отношения (в данном случае $chat->sender) таким способом как Вы делаете. Так как когда вы делаете данную операцию, то на каждом этапе цикла идёт запрос к базе данных. То есть если у вас в переменной $chats будет 100 элементов, то будет 100 доп запросов к бд. Если зайдут 10 пользователей на сайт одновременно, то будет 1000 запросов в секунду, в результате сервер может упасть.

Решение

В ларавель есть два метода для ленивой загрузки Первый метод load(). Вызывается на коллекции элементов (лучше в контроллере) $chats->load('sender') (можно передавать массив зависимостей $chats->load([...])). В результате когда будет произведён вызов sender то ларавель поймет что надо минимизировать кол-во запросов. То есть данные будут загружены только тогда, когда Вы их запросите при этом минимизировав нагрузку

Второй метод решающий проблему это ->with('sender') работает точно так же за исключением того, что он сразу в коллекцию результатов выполнения запроса подгружает необходимые зависимости. И поэтому вызывается на билдере Chat::where('recipient_id', Auth::user()->id)->with('sender')... После в переменной $chats сразу будет массив с отправителем. И вызов $chat->sender не будет делать запроса в принципе. Подробнее можете почитать в документации, когда лучше использовать один, а когда другой.