#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
andwherePivotIn
при определении взаимосвязи:
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 — это то, что делает трюк! Я проверю