用多对多关联的前提
如果模型 A 多对多关联模型 C,必须存在一张中间表 B 记录着双方的主键,因为就是靠着这张中间表 B 记录着模型 A 与模型 C 的关系。
举例,数据表结构如下
// 商品表
goodsgoods_id - integer // 商品主键goods_name - varchar // 商品名称// 分类表
categorycategory_id - integer // 分类主键name - varchar // 分类名称// 商品分类关系表
goods_category_relid - integer // 主键goods_id - integer // 商品表主键的外键category_id - integer // 分类表主键的外键
如果按以前的数据表设计,商品表与分类表不是这样设计的,而是 goods 表有一个 category_id 字段,该字段保存 category 表的 category_id,这样每个商品都对应着一个分类,比如荔枝的分类是水果,但这样的设计缺点也是显而易见的,一个商品只能有一个分类,比如荔枝的分类只能是水果,但如果把数据库设计成上面这样的结构,荔枝的分类就可以有多个,比如除了水果,还能是特价产品,或者是其它分类等等。
多对多关联定义
商品表模型:
<?phpnamespace app\api\model;class Goods extends Base
{protected $pk = 'goods_id';protected $hidden = ['create_time', 'update_time'];// 获取商品的分类public function category(){// Goods 模型多对多关联 Category 模型return $this->belongsToMany('Category', 'GoodsCategoryRel');// 完整写法// return $this->belongsToMany('Category', 'GoodsCategoryRel', 'category_id', 'goods_id');}}
belongsToMany
方法的参数如下:
belongsToMany('关联模型', '中间模型', '外键1', '外键2');
- 关联模型(必须):模型名或者模型类名
- 中间模型:默认规则是当前模型名+
_
+关联模型名 (可以指定模型名) - 外键1:关联模型在中间表的外键,默认的外键名规则是关联模型名+
_id
- 外键2:当前模型在中间表的外键,默认规则是当前模型名+
_id
中间表模型
<?phpnamespace app\api\model;class GoodsCategoryRel extends Base
{protected $hidden = ['create_time', 'update_time'];
}
分类表模型
<?phpnamespace app\api\model;class Category extends Base
{// 因为不是默认主键所以要重新定义protected $pk = 'category_id';protected $hidden = ['create_time', 'update_time'];}
实例演示
shop_goods 表
shop_category 表
shop_goods_category_rel 表
演示1
获取 goods_id 为 1 的商品详情以及它的分类
Goods 控制器
<?phpnamespace app\api\controller;use app\api\model\Goods as GoodsModel;class Goods extends Base
{// 获取 goods_id 等于 1 的商品详情public function detail(){$goods_id = 1;$detail = GoodsModel::getDetail($goods_id);halt($detail);}
}
Goods 模型
<?phpnamespace app\api\model;class Goods extends Base
{// 因为不是默认主键名称,所以要重新定义protected $pk = 'goods_id';protected $hidden = ['create_time', 'update_time'];// 获取商品详情public static function getDetail($goods_id){ // 关联预载入查询// 第二个参数是所用到的关联方法的方法名return self::get($goods_id, 'category');}// 多对多关联获取商品的所有分类public function category(){return $this->belongsToMany('Category', 'GoodsCategoryRel');// 完整写法// return $this->belongsToMany('Category', 'GoodsCategoryRel', 'category_id', 'goods_id');}
}
Goods 控制器 detail 方法输出
array(7) {["goods_id"] => int(10001)["goods_name"] => string(12) "桂味荔枝"["stock_total"] => int(0)["status"] => int(10)["sort"] => int(0)["is_delete"] => int(0)["category"] => object(think\Collection)#50 (1) {["items":protected] => array(2) {[0] => object(app\api\model\Category)#41 (2) {["data"] => array(8) {["category_id"] => int(6)["name"] => string(12) "新鲜水果"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454738)["update_time"] => int(1688454738)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#51 (2) {["data"] => array(5) {["id"] => int(1001)["goods_id"] => int(10001)["category_id"] => int(6)["create_time"] => int(1688696518)["update_time"] => int(1688696518)}["relation"] => array(0) {}}}}[1] => object(app\api\model\Category)#47 (2) {["data"] => array(8) {["category_id"] => int(10)["name"] => string(12) "特价产品"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454870)["update_time"] => int(1688454870)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#52 (2) {["data"] => array(5) {["id"] => int(1002)["goods_id"] => int(10001)["category_id"] => int(10)["create_time"] => int(1688795635)["update_time"] => int(1688795635)}["relation"] => array(0) {}}}}}}
}
关联方法名 category 作为键名,关联查询结果集对象 Collection 作为键值。
获取当前商品的分类,访问 category(关联方法名) 属性即可,如下
<?phpnamespace app\api\controller;use app\api\model\Goods as GoodsModel;class Goods extends Base
{public function detail(){$goods_id = 10001;$detail = GoodsModel::get($goods_id);$categories = $detail->category;halt($categories);}
}
输出
object(think\Collection)#47 (1) {["items":protected] => array(2) {[0] => object(app\api\model\Category)#41 (2) {["data"] => array(8) {["category_id"] => int(6)["name"] => string(12) "新鲜水果"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454738)["update_time"] => int(1688454738)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#50 (2) {["data"] => array(5) {["id"] => int(1001)["goods_id"] => int(10001)["category_id"] => int(6)["create_time"] => int(1688696518)["update_time"] => int(1688696518)}["relation"] => array(0) {}}}}[1] => object(app\api\model\Category)#46 (2) {["data"] => array(8) {["category_id"] => int(10)["name"] => string(12) "特价产品"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454870)["update_time"] => int(1688454870)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#51 (2) {["data"] => array(5) {["id"] => int(1002)["goods_id"] => int(10001)["category_id"] => int(10)["create_time"] => int(1688795635)["update_time"] => int(1688795635)}["relation"] => array(0) {}}}}}
}
演示2
获取所有的商品详情以及它的分类
Goods 控制器
<?phpnamespace app\api\controller;use app\api\model\Goods as GoodsModel;class Goods extends Base
{// 获取所有商品public function getList(){$goodsList = GoodsModel::getList();halt($goodsList);}
}
Goods 模型
<?phpnamespace app\api\model;class Goods extends Base
{protected $pk = 'goods_id';protected $hidden = ['create_time', 'update_time'];// 获取所有商品列表public static function getList(){// 关联预载入// 参数为所用到的关联方法return self::with(['category'])->select();}// 多对多获取商品分类public function category(){return $this->belongsToMany('Category', 'GoodsCategoryRel');// 完整写法// return $this->belongsToMany('Category', 'GoodsCategoryRel', 'category_id', 'goods_id');}
}
输出
object(think\Collection)#40 (1) {["items":protected] => array(1) {[0] => object(app\api\model\Goods)#42 (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) {["category"] => object(think\Collection)#50 (1) {["items":protected] => array(2) {[0] => object(app\api\model\Category)#41 (2) {["data"] => array(8) {["category_id"] => int(6)["name"] => string(12) "新鲜水果"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454738)["update_time"] => int(1688454738)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#51 (2) {["data"] => array(5) {["id"] => int(1001)["goods_id"] => int(10001)["category_id"] => int(6)["create_time"] => int(1688696518)["update_time"] => int(1688696518)}["relation"] => array(0) {}}}}[1] => object(app\api\model\Category)#47 (2) {["data"] => array(8) {["category_id"] => int(10)["name"] => string(12) "特价产品"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454870)["update_time"] => int(1688454870)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#52 (2) {["data"] => array(5) {["id"] => int(1002)["goods_id"] => int(10001)["category_id"] => int(10)["create_time"] => int(1688795635)["update_time"] => int(1688795635)}["relation"] => array(0) {}}}}}}}}}
}
每个商品模型的 relation (关联数组)属性保存着关联模型,关联方法名 category 作为键名,结果集对象作为键值,结果集对象的 items 属性(数组)保存着关联查询结果。
获取每个商品的分类,访问 category(关联方法名) 属性即可,如下
<?phpnamespace app\api\controller;use app\api\model\Goods as GoodsModel;class Goods extends Base
{public function getList(){$goodsList = GoodsModel::getList();foreach($goodsList as $value){dump($value->category);}}}
Goods 模型 getList 方法输出
object(think\Collection)#50 (1) {["items":protected] => array(2) {[0] => object(app\api\model\Category)#41 (2) {["data"] => array(8) {["category_id"] => int(6)["name"] => string(12) "新鲜水果"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454738)["update_time"] => int(1688454738)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#51 (2) {["data"] => array(5) {["id"] => int(1001)["goods_id"] => int(10001)["category_id"] => int(6)["create_time"] => int(1688696518)["update_time"] => int(1688696518)}["relation"] => array(0) {}}}}[1] => object(app\api\model\Category)#47 (2) {["data"] => array(8) {["category_id"] => int(10)["name"] => string(12) "特价产品"["parent_id"] => int(1)["image_id"] => int(0)["status"] => int(1)["sort"] => int(0)["create_time"] => int(1688454870)["update_time"] => int(1688454870)}["relation"] => array(1) {["pivot"] => object(think\model\Pivot)#52 (2) {["data"] => array(5) {["id"] => int(1002)["goods_id"] => int(10001)["category_id"] => int(10)["create_time"] => int(1688795635)["update_time"] => int(1688795635)}["relation"] => array(0) {}}}}}
}