用多对多关联的前提
如果模型 A 多对多关联模型 C,必须存在一张中间表 B 记录着双方的主键,因为就是靠着这张中间表 B 记录着模型 A 与模型 C 的关系。
举例,数据表结构如下
// 商品表
goods
goods_id - integer // 商品主键
goods_name - varchar // 商品名称
// 分类表
category
category_id - integer // 分类主键
name - varchar // 分类名称
// 商品分类关系表
goods_category_rel
id - integer // 主键
goods_id - integer // 商品表主键的外键
category_id - integer // 分类表主键的外键
如果按以前的数据表设计,商品表与分类表不是这样设计的,而是 goods 表有一个 category_id 字段,该字段保存 category 表的 category_id,这样每个商品都对应着一个分类,比如荔枝的分类是水果,但这样的设计缺点也是显而易见的,一个商品只能有一个分类,比如荔枝的分类只能是水果,但如果把数据库设计成上面这样的结构,荔枝的分类就可以有多个,比如除了水果,还能是特价产品,或者是其它分类等等。
多对多关联定义
商品表模型:
<?php
namespace 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
中间表模型
<?php
namespace app\api\model;
class GoodsCategoryRel extends Base
{
protected $hidden = ['create_time', 'update_time'];
}
分类表模型
<?php
namespace 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 控制器
<?php
namespace 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 模型
<?php
namespace 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(关联方法名) 属性即可,如下
<?php
namespace 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 控制器
<?php
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
class Goods extends Base
{
// 获取所有商品
public function getList()
{
$goodsList = GoodsModel::getList();
halt($goodsList);
}
}
Goods 模型
<?php
namespace 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(关联方法名) 属性即可,如下
<?php
namespace 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) {
}
}
}
}
}
}