[抛砖] 关于获取用户列表的实现方法

我的好友关系需求是无序好友,既只要是好友,就是互相都是,没有单方关注等概念。
基于减少冗余的原则,我的好友关系表设计如下

id uid1 uid2 created_at updated_at

但在写代码时发现好像比较麻烦,现在这种精简的结构里,当前用户可能出现在uid1也可能出现在uid2,是分别以这两个字段为基准各筛选一遍,然后把结果集拼接在一起么?

上网搜了一下,没有找到合适的答案,于是我用最笨拙的办法实现了一下。

public function friend()
{
    $userid = Auth::user()->id;
    $friends1 = Friendship_relation::where('uid1','=',$userid)->get();
    $friends2 = Friendship_relation::where('uid2','=',$userid)->get();       
    $users = User::all();
    return view('friend.friend',[
        'friends1' => $friends1,
        'friends2' => $friends2,
        'users' => $users,
    ]);
}

然后在模板里是这么写的

@foreach($friends1 as $friend)
    <tr>
        <td>{{$users[$friend->uid2]->name}}</td>
        <td>{{$users[$friend->uid2]->email}}</td>
        <td>{{$users[$friend->uid2]->created_at}}</td>
    </tr>
@endforeach
@foreach($friends2 as $friend)
    <tr>
        <td>{{$users[$friend->uid1]->name}}</td>
        <td>{{$users[$friend->uid1]->email}}</td>
        <td>{{$users[$friend->uid1]->created_at}}</td>
    </tr>
@endforeach

笨拙吧!我都觉得笨拙的可怕。。。
我本来是想在控制器里就把$friends1和$friends2两个结果集合并起来,但是我尝试了几种方法*都未果。
我的PHP基础是比较薄弱。

不知道有没有朋友能告诉我更科学的写法~~希望大家轻喷重教~~多谢。

我尝试的几种方法:

  • 当成数组合并(array_merge($friends1,$friends2);)报错,显然他们不是数组;
  • 用加号报错不是整形;
  • 用点合并,结果看起来像个数组的样式,但已经是文本格式了:string(6) "[3][1]"
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 8

我已经被砖砸到了……
当时运行了一下发现出数据就以为蒙对了,但仔细一看,在模板中展示数据时出问题了。
$users[$friend->uid2]->name

这行代码并没有按我希望的,展示出users表里id是$friend->uid2所代表值的姓名,而是以$friend->uid2值为数组下标的姓名了。又尝试了几下,发现不知道怎么在这里靠id做用户表姓名的关联查询了……

或者这个也应该在控制器里做好么?

7年前 评论
leo

首先,查朋友列表不需要两条语句,只需要加个or就行了

Friendship_relation::where('uid1','=',$userid)->orWhere('uid2','=',$userid)->get();

然后,给Friendship_relation类增加一个方法getFriend($uid),判断uid1uid2哪个不等于$uid,哪个就是朋友的uid,然后返回User::find(另一个uid)

7年前 评论

@leo 这里果然靠谱!真的有热心高手回复,多谢!我回家试一下。

不过,我现在还面临着另一个棘手的问题,就是我在一楼评论里提到的,我用笨拙的办法还勉强可以把好友id找到,但是卡在了如何关联到用户表查询出对应的用户姓名,在非mvc的结构里我还可以用sql语句关联查询展示,但不知道在laravel的框架内,是否有什么更合理的方式呢?

7年前 评论
xcz196 2年前
leo

@Harry 用我说的方法,就没有你说的问题了呀,直接{{$friend->getFriend($uid)->name}}

7年前 评论

@leo 哦,您说的是直接在Friendship_relation这个Model 里写是吧?我试试去!

7年前 评论

@leo

@leo 现在功能貌似是ok了,但是我感觉有点晕啊……高手是否能帮我讲解一下?
我最终的代码如下,从功能来看功能已经实现了,代码是否还有什么不合理的地方?
模型:Friendship_relation 中增加

public function getFriend($id)
{
    //当前登录用户id
    $userid = Auth::user()->id;

    //好友关系表中含有当前用户的记录集
    $friendData = Friendship_relation::find($id);

    if($friendData->uid1 == $userid){
        return User::find($friendData->uid2);
    } else{
        return User::find($friendData->uid1);
    }
}

控制器:FriendController 中

public function friend()
{
    $userid = Auth::user()->id;

    $friends = Friendship_relation::where('uid1','=',$userid)->orWhere('uid2','=',$userid)->get();

    return view('friend.friend',[
        'friends' => $friends,
    ]);
}

视图文件:

@foreach($friends as $friend)
    <tr>
        <td>{{$friend->getFriend($friend->id)->name}}</td>
        <td>{{$friend->getFriend($friend->id)->email}}</td>
        {{--不明白为什么不能转换日期格式--}}
        {{--{{date('Y-m-d',$friend->getFriend($friend->id)->created_at)}}</td>--}}
        <td>{{$friend->getFriend($friend->id)->created_at}}</td>
    </tr>
@endforeach
7年前 评论

@Harry 你的代码有个问题,就是遍历friends的时候会运行多次getFriend方法,就意味着会运行多条select * from users where id=?,也就是1+N条sql语句的问题 ,优化一下你的代码可以减少到两条sql:
模型 User添加friends方法:

public function friends()
    {
        $ids = Friendship_relation::where('uid1', $this->id)
            ->orWhere('uid2', $this->id)
            ->get()->map(function ($user) {
                return $user->uid1 == $this->id ?
                    $user->uid2 :
                    $user->uid1;
            });

        return static::whereIn('id', $ids);
    }

控制器中:

public function friend()
{
    $friends = Auth::user()->friends()->get();

    return view('friend.friend', compact('friends'));
}
7年前 评论
flc1125

个人经验,参考:

  • 从表设计上,建议是uid1是主角用户,uid2为好友ID,即:若双方互为好友,应有2条数据
  • 表设计与业务应区分,业务上强行双方必须互为好友,但表设计应该是可兼容:互为好友、单方好友的情况。
  • 这样设计的好处是:业务扩展性会更强,其次业务研发也不会过于复杂;当然不足是:数据冗余。
2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!