如何在Laravel中通过多层嵌套关联获取手机号对应的所有用户?
问题描述
用户可拥有多个联系人列表,每个联系人列表包含多个手机号;手机号可属于多个联系人列表,联系人列表也可归属多个用户。需在PhoneNumber模型中实现users()方法,获取所有在其至少一个联系人列表中包含该手机号的用户。
现有模型结构如下:
User 模型
use Illuminate\Database\Eloquent\Relations\MorphMany; class User extends Model { /** * Get contact lists of the user. */ public function lists(): MorphMany { return $this->morphMany(ContactList::class, 'container'); } }
ContactList 模型
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; class ContactList extends Model { /** * Get the container of this contact list (a user or something else). */ public function container(): MorphTo { return $this->morphTo(); } /** * Get phone numbers in that list. */ public function numbers(): BelongsToMany { return $this->belongsToMany(PhoneNumber::class); } }
PhoneNumber 模型
use Illuminate\Database\Eloquent\Relations\BelongsToMany; class PhoneNumber extends Model { /** * Retrieve the contact lists for the number. */ public function lists(): BelongsToMany { return $this->belongsToMany(ContactList::class); } }
解决方案
方法一:嵌套关联查询(高性能)
直接通过whereHas嵌套关联筛选用户,生成单条SQL查询,性能最优:
use Illuminate\Database\Eloquent\Builder; class PhoneNumber extends Model { // 已有的lists()方法... /** * 获取所有关联的用户 * @return Builder */ public function users(): Builder { return User::whereHas('lists.numbers', function (Builder $query) { $query->where('phone_number_id', $this->id); }); } }
使用示例:
$phoneNumber = PhoneNumber::find(1); $users = $phoneNumber->users()->get();
方法二:自定义多对多关联(Eloquent风格)
如果需要返回标准的Eloquent关联实例(支持with、withCount等关联方法),可以通过中间表关联实现:
use Illuminate\Database\Eloquent\Relations\BelongsToMany; class PhoneNumber extends Model { // 已有的lists()方法... /** * 获取所有关联的用户 * @return BelongsToMany */ public function users(): BelongsToMany { // 替换为你实际的中间表名称 $pivotTable = 'contact_list_phone_number'; return $this->belongsToMany(User::class, $pivotTable) ->join('contact_lists', "{$pivotTable}.contact_list_id", '=', 'contact_lists.id') ->where('contact_lists.container_type', User::class) ->select('users.*') ->groupBy('users.id'); } }
使用示例:
$phoneNumber = PhoneNumber::find(1); $users = $phoneNumber->users; // 直接访问关联集合
方法三:关联链取值(直观简洁)
适合数据量较小的场景,通过已有的关联链获取用户并去重:
class PhoneNumber extends Model { // 已有的lists()方法... /** * 获取所有关联的用户 * @return \Illuminate\Support\Collection */ public function users() { return $this->lists() ->where('container_type', User::class) ->get() ->pluck('container') ->unique(); } }
使用示例:
$phoneNumber = PhoneNumber::find(1); $users = $phoneNumber->users();
内容的提问来源于stack exchange,提问作者Rusurano
相关产品推荐
相关产品推荐

