You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:07:44