一、前言
- 前段时间有小白问到,Laravel 下的 DB 操作 MySQL 如何实现表的自连接。
- 当然,我也是第一时间翻阅了 Laravel 的源码,成功的通过 DB 门面,实现了单一数据表的"自连接"查询。
- 所以说看源码很重要。
二、说明
- Laravel 的 DB 门面提供了 toSql() 函数,以便调试时输出原生的 SQL 语句。
- 相信通过在下的提示,越来越多的同学可以学会使用 Laravel 的 DB 门面实现更多的高级 SQL 语句。
- 本文以【社交应用】为背景。在用户关注表 'tb_user_follows' 中查询出 两个互相关注的(即好友)用户 的数据。
- 实际上机制的同学是很容易发现,后文使用的思想是非常简单的 SQL 查询。而本人如此赘述的原因,是在于给后面即将推出的 Laravel业务篇 系列的教程做铺垫,希望借此契机,循序渐进地让大家体会到 Laravel 的优雅。
三、实现
- 创建用户表 'tb_users' 和用户关注表 'tb_user_follows' 如下:
tb_users && tb_user_follows
-
用到了几个简单的表字段,很容易理解。用户关注表 'tb_user_follows' 中的 'user_id' 和 'user_follow_id' 字段均是来自用户表 'tb_users' 的主键ID,这里我也是添加了外键约束,让两个表的关联更加明显。
-
说到这里,为了回顾一下 Laravel 的 Artisan 指令,我们使用模型工厂(Factory) 和模型填充器(Seeder),优雅地制造一些测试数据:
php artisan make:model UserModel
php artisan make:factory UserFactory
php artisan make:seeder UserSeeder
- 上述指令分别生成 'UserModel.php'、'UserFactory.php'、'UserSeeder.php'三个文件,稍作修改就变成:
# Dir: @/app/UserModel.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* @author AdamTyn
* @description <用户>数据模型
*/
class UserModel extends Model
{
/**
* 绑定数据表
* @var string
*/
protected $table = 'tb_users';
/**
* 禁用自带的时间字段
* @var bool
*/
public $timestamps = false;
/**
* 使用模型时可以访问的字段
* @var array
*/
protected $fillable = [
'name', // 用户名称
];
/**
* 使用模型时禁止修改的字段
* @var array
*/
protected $guarded = [
'id',
];
}
# Dir: @/database/factories/UserFactory.php
<?php
use Faker\Generator as Faker;
$factory->define(\App\UserModel::class, function (Faker $faker) {
return [
'name' => $faker->name
];
});
# Dir: @/database/seeds/UserSeeder.php
<?php
use Illuminate\Database\Seeder;
/**
* @author AdamTyn
* @description <用户>数据填充器
*/
class UserSeeder extends Seeder
{
public function run()
{
factory(\App\UserModel::class, 10)->create(['created_at' => time()]);
}
}
当然,仅仅添加了用户表 'tb_users' 的数据还不够,再到数据库中,插入用户关注表 'tb_user_follows' 的几条数据:

-
接着添加一条路由规则:
Route::get('friends/{user_id}', '\App\Http\Controllers\SocialController@friends');
-
最后,编写 'SocialController.php'文件如下:
# Dir: @/app/Http/SocialController.php
<?php
namespace App\Http\Controllers;
use DB;
/**
* @author AdamTyn
* @description <用户社交相关>控制器
*/
class SocialController extends Controller
{
/**
* @author AdamTyn
* @description 获取好友列表
* @get('friends/{user_id}')
*
* @param int|string $userId
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
*/
public function friends($userId)
{
if (!is_numeric($userId) || $userId < 1) {
return response()->json(['status_code' => 404, 'data' => null]);
}
# ⑴获取好友列表的ID
$friendIds = DB::query()->sharedLock() # 启用共享锁
->selectRaw('t2.user_id from tb_user_follows as t1,tb_user_follows as t2') # 和平时SQL语句一样
# 实际上是两表联查,并非真的自连接
->whereRaw('t1.user_id = t2.user_follow_id and t1.user_follow_id = t2.user_id and t1.user_id = ' . $userId)
->whereNull('t1.deleted_at')
->whereNull('t2.deleted_at')
->orderByDesc('t2.created_at')
->get();
$bool = $friendIds->isNotEmpty(); # 集合类的方法
# ⑵获取好友列表的详细信息
$friends = $bool ? DB::table('tb_users')->whereIn('id',
$friendIds->pluck('user_id')->toArray() # 集合类的方法
)->whereNull('deleted_at')->get(['id', 'name']) : collect();
return response()->json(['status_code' => 200, 'data' => $friends]);
}
}
- 打开 PostMan,熟练地敲击键盘输入路由地址,不出意外可以成功返回:
HTTP/1.1 200 OK
{
"status_code": 200,
"data": [
{
"id": 2,
"name": "Alexandrine Orn V"
}
]
}
四、结语
- 本教程面向新手,更多教程会在日后给出。
- 随着系统升级,软件更新,以后的配置可能有所变化,在下会第一时间测试并且更新教程;
- 欢迎联系在下,讨论建议都可以,之后会发布其它的教程。
- 后面紧锣密鼓地将会推出 Laravel业务篇 系列的教程,敬请期待。
网友评论