Как я могу получить доступ к данным из сводной таблицы в Laravel?

#php #laravel

#php #laravel

Вопрос:

Возможно, я неправильно реализую. Может быть, я делаю то, что не должен делать, но концептуально я думаю, что все в порядке.

У меня есть две модели, одна есть Users , другая есть Communities , и поскольку это отношение «многие ко многим», мне нужна промежуточная таблица, Laravel называет их сводной таблицей. В соответствии с рекомендациями Laravel он называется communities_users

Обычно сводные таблицы содержат только идентификаторы основных таблиц. Но мне нужно немного больше данных. Проверьте это изображение, миграции выполняются в соответствии с этой диаграммой:

введите описание изображения здесь

Здесь у меня есть role в сводной таблице. Допустим, пользователь принадлежит к двум сообществам, один как президент сообщества, другой как участник.

Конечно president , у него будет больше возможностей, чем member , например, он может принять pending человека, чтобы стать member человеком, или он может повысить участника до deputy статуса или около того…

Теперь допустим, я хочу получить имена людей с deputy ролью в данном сообществе. Я могу легко сделать это с помощью построителя запросов, объединив три таблицы и применив where('communities_users.role', 'deputy') ,

Теперь, что, если я хочу использовать ORM и получить всю User модель?

Я хотел бы иметь функцию в сообществе, чтобы она давала мне users заданное role , может быть:

 public function users($role) {
    ...
}
 

Поэтому я могу делать такие вещи, как:

 $community = Community::find($id);
foreach ($community->users('deputy') as user) {
    ...
    echo user->name; // or whatever
    ...
}
 

Возможно ли это? Как?

Ответ №1:

Скрытие в разделе «Многие ко многим» документов Eloquent relationship:

Фильтрация связей через промежуточные столбцы таблицы

Вы также можете фильтровать возвращаемые результаты belongsToMany , используя методы wherePivot and wherePivotIn при определении взаимосвязи:

 return $this->belongsToMany('AppRole')->wherePivot('approved', 1);

return $this->belongsToMany('AppRole')->wherePivotIn('priority', [1, 2]);
 

Предполагая, что в вашей модели сообществ уже установлены belongsToMany отношения для пользователей, вы должны быть в состоянии сделать что-то вроде:

 $deputies = $community->users()
    ->wherePivot('role', 'deputy') // or equivalent value
    ->get();
 

Комментарии:

1. скрыто… буквально. Большое спасибо. weherePivot — это именно то, что мне нужно

2. Должны ли мы определять сводную таблицу для обеих User Community моделей и?

3. @IstiaqueAhmed Нет, вам не обязательно. Вы можете добавить его в любую модель, через которую хотите выполнить запрос. Например, если вы никогда не хотите получать сообщества пользователей, вам не нужно добавлять belongsToMany() в User . Если вы хотите получить связь обоими способами, вы можете добавить ее в оба. Решать вам!

Ответ №2:

Как вы сказали, в сводной таблице будут присутствовать только ключи модели:

По умолчанию в сводном объекте будут присутствовать только ключи модели. Если ваша сводная таблица содержит дополнительные атрибуты, вы должны указать их при определении отношения:

 return $this->belongsToMany('AppRole')->withPivot('column1', 'column2');
 

Итак, чтобы использовать дополнительные поля при запросе связанных записей, вам нужно сообщить Laravel, что вы храните больше столбцов в своей промежуточной / сводной таблице:

 // Community.php

public function users()
{
    return $this->belongsToMany(User::class)
                ->withPivot('role'); // <---
}
 

Теперь вы можете получить желаемый результат:

 $community = Community::find($id);
$deputies = $community->users()->wherePivot('role', '=', 'deputy')->get();

foreach ($deputies as $deputy)
{
    echo $deputy->name;
}
 

Прочитайте этот раздел документации.


Наблюдение

Вы сказали:

… в соответствии с рекомендациями Laravel он называется communities_users

Сначала я подумал, что это нормально, поскольку ваши модели, похоже, имеют имена во множественном числе (я говорю о названии модели, а не имени таблицы). но тогда в вашем желаемом выводе вы Community ссылались на модель. Итак, я процитирую это из раздела «Многие ко многим» документации:

Многие ко многим

Для определения этой связи необходимы три таблицы базы данных: users , roles , и role_user . role_user Таблица является производной от алфавитного порядка связанных имен моделей и содержит столбцы user_id и role_id .

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

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

Комментарии:

1. Я всегда могу использовать явное имя, что я в основном и делаю, в belongsToMany() есть параметр для явного присвоения имени таблице, которую вы хотите использовать. Эта вещь о множественном числе / единственном числе несколько запутана, особенно когда вы используете неанглоязычные имена таблиц.

2. Конечно, @luisfer, вы действительно можете настраивать имена таблиц. Я только что сказал, чтобы уточнить соглашение Laravel по умолчанию. Хорошего дня.

Ответ №3:

Сначала вы должны определить взаимосвязь между моделями, подобными этой :

вы сказали, что у вас есть модель пользователей, а затем в Users:

 public function communities(){
    return $this->belongsToMany(Communities::class, 'communities_users','user_id', 'community_id');
}
 

и в вашей модели сообществ :

 public function users(){
    return $this->belongsToMany(Users::class, 'communities_users','community_id','user_id')
     ->withPivot("role");
}
 

Теперь вы можете получить доступ к пользователям любого типа ролей в ваших контроллерах следующим образом :

 $community = Community::find($id);
$deputies = $community->users()
->wherePivot('role', 'deputy') // by passing different role
->get();

foreach ($deputies as $deputy)
{
    echo $deputy->name; // print names
}
 

Комментарии:

1. Большое спасибо! У меня было два отношения, и все работало нормально, wherePivot — это то, что делает трюк! Я проверю