用远程一对多关联的前提
如果模型 A 想远程一对多关联模型 C,前提是中间模型 B 对应的数据库表必须有模型 A 对应的数据表的外键,模型 C 对应的数据库表必须有模型 B 对应数据库表的外键。(套娃)
举例,商品获取商品评论
数据表结构如下
// 商品表
goods
goods_id - integer // 商品主键
goods_name - varchar // 商品名称
// 订单商品记录表
order_goods
order_goods_id - integer // 订单商品主键
goods_id - integer // 商品主键
goods_name varchar // 商品名称
// 订单商品评论表
order_goods_comment
order_goods_comment_id - integer // 订单商品评论表
order_goods_id - integer // 订单商品主键
comment - varchar // 订单商品评论
订单商品评论表有订单商品记录表的主键,订单商品记录表有商品表的主键,这样,商品就可以远程一对多获取商品的评论。(有点像我们所说的套娃)
远程一对多关联定义
商品表 goods 模型:
<?php
namespace app\api\model;
class Goods extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'goods_id';
protected $hidden = ['create_time', 'update_time'];
// 获取商品详情以及商品的评论
// 第二个参数是所用到的关联方法的方法名
public static function getDetail($goods_id)
{
return self::get($goods_id, 'comments');
}
// 远程一对多关联获取商品的所有评论
public function comments()
{
return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods');
// 完整写法
// return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods', 'goods_id', 'order_goods_id', 'goods_id');
}
}
hasManyThrough
方法的参数如下:
hasManyThrough('关联模型', '中间模型', '外键1', '外键2', '主键');
- 关联模型(必须):模型名或者模型类名
- 中间模型(必须):模型名或者模型类名
- 外键1:当前模型在中间模型的外键,默认的外键名规则是当前模型名+
_id
- 外键2:中间模型在关联模型的外键,默认的外键名规则是中间模型名+
_id
- 主键:当前模型主键,一般会自动获取也可以指定传入
订单商品表(中间表) order_goods 模型
<?php
namespace app\api\model;
class OrderGoods extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_id';
}
订单商品评论表 order_goods_comment 模型
<?php
namespace app\api\model;
class OrderGoodsComment extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_comment_id';
}
实例演示
演示1
获取 goods_id 为 10001 的商品详情以及它的评论
商品 Goods 控制器
<?php
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
class Goods extends Base
{
// 获取 goods_id = 10001 的商品详情以及商品评论
public function detail()
{
$goods_id = 10001;
$detail = GoodsModel::getDetail($goods_id);
echo '<pre>';
var_dump($detail);
echo '</pre>';
}
}
商品表 goods 模型
<?php
namespace app\api\model;
class Goods extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'goods_id';
protected $hidden = ['create_time', 'update_time'];
public static function getDetail($goods_id)
{
// 获取商品详情以及商品评论
// 第二个参数是所用到的关联方法的方法名
return self::get($goods_id, 'comments');
}
// 远程一对多获取商品的所有评论
public function comments()
{
return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods');
// 完整写法
// return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods', 'goods_id', 'order_goods_id', 'goods_id');
}
}
订单商品表(中间表) order_goods 模型
<?php
namespace app\api\model;
class OrderGoods extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_id';
}
订单商品评论表 order_goods_comment 模型
<?php
namespace app\api\model;
class OrderGoodsComment extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_comment_id';
}
Goods 控制器 detail 方法输出
object(app\api\model\Goods)#41 (2) {
["data"]=>
array(8) {
["goods_id"]=>
int(10001)
["goods_name"]=>
string(12) "桂味荔枝"
["stock_total"]=>
int(0)
["status"]=>
int(10)
["sort"]=>
int(0)
["is_delete"]=>
int(0)
["create_time"]=>
int(1688696518)
["update_time"]=>
int(1688696518)
}
["relation"]=>
array(1) {
["comments"]=>
object(think\model\Collection)#47 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\OrderGoodsComment)#50 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(1)
["order_goods_id"]=>
int(1)
["comment"]=>
string(24) "桂味荔枝非常好吃"
["user_id"]=>
int(1)
["create_time"]=>
int(1689670979)
["update_time"]=>
int(1689670979)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\OrderGoodsComment)#51 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(2)
["order_goods_id"]=>
int(2)
["comment"]=>
string(36) "桂味荔枝很甜,一点都不酸"
["user_id"]=>
int(2)
["create_time"]=>
int(1689732500)
["update_time"]=>
int(1689732500)
}
["relation"]=>
array(0) {
}
}
}
}
}
}
当条查询输出的是 Goods 模型实例,Goods 模型实例的 relation 属性(关联数组)保存着关联模型,在该关联数组中,关联方法名 comments 作为键名,结果集对象作为键值,结果集对象的 items 属性(索引数组)保存着关联查询结果。
所用的 SQL 如下
SELECT * FROM `shop_goods` WHERE `goods_id` = 10001 LIMIT 1
SELECT * FROM `shop_order_goods` WHERE `goods_id` = 10001
SELECT * FROM `shop_order_goods_comment` WHERE `order_goods_id` IN (1,2)
获取当前商品的所有评论,访问 comments(关联方法名) 属性即可,如下
<?php
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
class Goods extends Base
{
// 显示商品评论
public function detail()
{
$goods_id = 1;
$detail = GoodsModel::getDetail($goods_id);
echo '<pre>';
var_dump($detail->comments);
echo '</pre>';
}
}
输出结果集对象,结果集对象的 items 属性(数组)保存着当前商品的所有评论,如下
object(think\model\Collection)#47 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\OrderGoodsComment)#50 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(1)
["order_goods_id"]=>
int(1)
["comment"]=>
string(24) "桂味荔枝非常好吃"
["user_id"]=>
int(1)
["create_time"]=>
int(1689670979)
["update_time"]=>
int(1689670979)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\OrderGoodsComment)#51 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(2)
["order_goods_id"]=>
int(2)
["comment"]=>
string(36) "桂味荔枝很甜,一点都不酸"
["user_id"]=>
int(2)
["create_time"]=>
int(1689732500)
["update_time"]=>
int(1689732500)
}
["relation"]=>
array(0) {
}
}
}
}
演示2
获取所有的商品详情以及它的评论
Goods 控制器
<?php
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
class Goods extends Base
{
// 获取所有商品
public function list()
{
$goodsList = GoodsModel::getList();
echo '<pre>';
var_dump($goodsList);
echo '</pre>';
}
}
Goods 模型
<?php
namespace app\api\model;
class Goods extends Base
{
protected $pk = 'goods_id';
protected $hidden = ['create_time', 'update_time'];
public static function getList(array $param)
{
// 获取全部商品的详情与评论
// 第二个参数是所用到的关联方法的方法名
return self::with('comments')->select();
}
// 获取商品的所有评论
public function comments()
{
return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods');
// 完整写法
// return $this->hasManyThrough('OrderGoodsComment', 'OrderGoods', 'goods_id', 'order_goods_id', 'goods_id');
}
}
订单商品表(中间表) order_goods 模型
<?php
namespace app\api\model;
class OrderGoods extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_id';
}
订单商品评论表 order_goods_comment 模型
<?php
namespace app\api\model;
class OrderGoodsComment extends Base
{
// 不是默认主键名称记得定义 pk 属性
protected $pk = 'order_goods_comment_id';
}
Goods 控制器 list 方法输出
object(think\model\Collection)#42 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\Goods)#41 (2) {
["data"]=>
array(8) {
["goods_id"]=>
int(10001)
["goods_name"]=>
string(12) "桂味荔枝"
["stock_total"]=>
int(0)
["status"]=>
int(10)
["sort"]=>
int(0)
["is_delete"]=>
int(0)
["create_time"]=>
int(1688696518)
["update_time"]=>
int(1688696518)
}
["relation"]=>
array(1) {
["comments"]=>
object(think\model\Collection)#49 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\OrderGoodsComment)#52 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(1)
["order_goods_id"]=>
int(1)
["comment"]=>
string(24) "桂味荔枝非常好吃"
["user_id"]=>
int(1)
["create_time"]=>
int(1689670979)
["update_time"]=>
int(1689670979)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\OrderGoodsComment)#53 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(2)
["order_goods_id"]=>
int(2)
["comment"]=>
string(36) "桂味荔枝很甜,一点都不酸"
["user_id"]=>
int(2)
["create_time"]=>
int(1689732500)
["update_time"]=>
int(1689732500)
}
["relation"]=>
array(0) {
}
}
}
}
}
}
[1]=>
object(app\api\model\Goods)#43 (2) {
["data"]=>
array(8) {
["goods_id"]=>
int(10002)
["goods_name"]=>
string(15) "妃子笑荔枝"
["stock_total"]=>
int(0)
["status"]=>
int(10)
["sort"]=>
int(0)
["is_delete"]=>
int(0)
["create_time"]=>
int(1690166322)
["update_time"]=>
int(1690166322)
}
["relation"]=>
array(1) {
["comments"]=>
object(think\model\Collection)#57 (1) {
["items":protected]=>
array(1) {
[0]=>
object(app\api\model\OrderGoodsComment)#54 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(3)
["order_goods_id"]=>
int(3)
["comment"]=>
string(27) "妃子笑荔枝酸甜可口"
["user_id"]=>
int(1)
["create_time"]=>
int(1690166563)
["update_time"]=>
int(1690166563)
}
["relation"]=>
array(0) {
}
}
}
}
}
}
}
}
多条查询输出的是 Collection(结果集) 对象,Collection 对象的 item 属性保存着每个 Goods 模型实例, 每个 Goods 模型实例的 relation 属性(关联数组)属性保存着关联模型,关联方法名 comments 作为键名,因为关联方法 comments 是对多关联,所以结果集对象作为键值,结果集对象的 items 属性(索引数组)保存着关联查询结果。
所用到的 SQL 如下
SELECT * FROM `shop_goods`
SELECT * FROM `shop_order_goods` WHERE `goods_id` IN (10001,10002)
SELECT * FROM `shop_order_goods_comment` WHERE `order_goods_id` IN (1,2,3)
获取每个商品的评论,访问 comments(关联方法名) 属性即可,如下
<?php
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
class Goods extends Base
{
public function list()
{
$goodsList = GoodsModel::getList();
foreach ($goodsList as $value) {
echo '<pre>';
var_dump($value->comments);
echo '</pre>';
}
}
}
Goods 控制器 list 方法输出
object(think\model\Collection)#49 (1) {
["items":protected]=>
array(2) {
[0]=>
object(app\api\model\OrderGoodsComment)#52 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(1)
["order_goods_id"]=>
int(1)
["comment"]=>
string(24) "桂味荔枝非常好吃"
["user_id"]=>
int(1)
["create_time"]=>
int(1689670979)
["update_time"]=>
int(1689670979)
}
["relation"]=>
array(0) {
}
}
[1]=>
object(app\api\model\OrderGoodsComment)#53 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(2)
["order_goods_id"]=>
int(2)
["comment"]=>
string(36) "桂味荔枝很甜,一点都不酸"
["user_id"]=>
int(2)
["create_time"]=>
int(1689732500)
["update_time"]=>
int(1689732500)
}
["relation"]=>
array(0) {
}
}
}
}
object(think\model\Collection)#57 (1) {
["items":protected]=>
array(1) {
[0]=>
object(app\api\model\OrderGoodsComment)#54 (2) {
["data"]=>
array(6) {
["order_goods_comment_id"]=>
int(3)
["order_goods_id"]=>
int(3)
["comment"]=>
string(27) "妃子笑荔枝酸甜可口"
["user_id"]=>
int(1)
["create_time"]=>
int(1690166563)
["update_time"]=>
int(1690166563)
}
["relation"]=>
array(0) {
}
}
}
}