PHP的ORM模型关联(tp6)总结

一对一关联

表:用户表和资料表

  • 用户表:user。主要字段:id, …
  • 资料:profile。主要字段:id, user_id, …

hasOne (一对一关联)

// 用户模型
class User extends Model
{
    public function profile()
    {
        // hasOne('关联模型类名', '外键', '主键');
        // 关联模型(必须):关联模型类名
        // 外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如user_id
        // 主键:当前模型主键,默认会自动获取也可以指定传入
        return $this->hasOne(Profile::class, 'user_id', 'id');
    }
}

belongsTo(相对关联)

// 资料模型
class Profile extends Model 
{
    public function user()
    {
        // belongsTo('关联模型','外键', '关联主键');
        // 关联模型(必须):关联模型类名
        // 外键:当前模型外键,默认的外键名规则是关联模型名+_id
        // 关联主键:关联模型主键,一般会自动获取也可以指定传入
        return $this->belongsTo(User::class, 'user_id', 'id');
    }
}

一对多关联

表:文章和评论。

  • 文章表:article。字段:id,…
  • 评论表:comment。字段:id,article_id,…
// 文章模型
class Article extends Model
{
    public function comments()
    {
        // hasMany('关联模型','外键','主键');
        // 关联模型(必须):关联模型类名
        // 外键:关联模型外键,默认的外键名规则是当前模型名+_id
        // 主键:当前模型主键,一般会自动获取也可以指定传入
        return $this->hasMany(Comment::class, 'article_id', 'id');
        
		// 为关联加条件 comment.is_cancelled=0
		// return $this->hasMany(Comment::class, 'article_id', 'id')->where('is_cancelled', Consts::NO);
    }
}

反之,查评论所属的文章,就要使用belongsTo()这个一对一的方法。

远程关联

用远程一对多关联的前提
如果模型 A  想远程一对多关联模型 C,前提是中间模型 B 对应的数据库表必须有模型 A 对应的数据表的外键,模型 C 对应的数据库表必须有模型 B 对应数据库表的外键。(套娃)
参考:[ThinkPHP 远程一对多关联](https://blog.csdn.net/weixin_44161401/article/details/131685949)

表:商品表,订单商品表,订单商品评论表

  • 商品表:goods。字段:id,…
  • 订单商品记录表(中间表):order_goods。字段:id,goods_id,…
  • 订单商品评论表(关联表):order_goods_comment。字段:id,order_goods_id,…

远程一对多

class Goods extends Model
{
    // 远程一对多关联获取商品的所有评论
    public function comments()
    {   
        // hasManyThrough('关联模型', '中间模型', '中间表关联主键', '关联表关联主键','当前模型主键','中间模型主键');
        // 1.关联表模型(必须):关联模型类名
        // 2.中间表模型(必须):中间模型类名
        // 3.中间表关联主键:当前模型在中间模型的外键,默认的外键名规则是当前模型名+_id(OrderGoods.goods_id)
        // 4.关联表关联主键:中间模型在关联模型的外键,默认的外键名规则是中间模型名+_id(OrderGoodsComment.order_goods_id)
        // 5.当前模型主键:当前模型主键,一般会自动获取也可以指定传入(Goods.id)
        // 6.中间模型主键:一般会自动获取也可以指定传入(OrderGoods.id)
        return $this->hasManyThrough(OrderGoodsComment::class, OrderGoods::class, 'goods_id', 'order_goods_id', 'id', 'id');
    }
}

执行的SQL:

SELECT * FROM `goods` WHERE  `id` = 1 LIMIT 1
SELECT * FROM `order_goods` WHERE  `goods_id` = 1
SELECT * FROM `order_goods_comment` WHERE  `order_goods_id` = 1

远程一对一

class Goods extends Model
{
    public function comment()
    {
        // hasOneThrough('关联模型', '中间模型', '中间表关联主键', '关联表关联主键','当前模型主键','中间模型主键');
        // 1.关联表模型(必须):关联模型类名
        // 2.中间表模型(必须):中间模型类名
        // 3.中间表关联主键:当前模型在中间模型的外键,默认的外键名规则是当前模型名+_id(OrderGoods.goods_id)
        // 4.关联表关联主键:中间模型在关联模型的外键,默认的外键名规则是中间模型名+_id(OrderGoodsComment.order_goods_id)
        // 5.当前模型主键:当前模型主键,一般会自动获取也可以指定传入(Goods.id)
        // 6.中间模型主键:一般会自动获取也可以指定传入(OrderGoods.id)
        return $this->hasOneThrough(OrderGoodsComment::class, OrderGoods::class, 'goods_id', 'order_goods_id', 'id', 'id');
    }
}

执行的SQL:

SELECT * FROM `goods` WHERE  `id` = 1 LIMIT 1
SELECT * FROM `order_goods` WHERE  `goods_id` = 1
SELECT * FROM `order_goods_comment` WHERE  `order_goods_id` = 1

多对多关联

表:管理员,角色,管理员角色关联表

  • 管理员表:admin。字段:id, …
  • 角色表:admin_role。字段:id, …
  • 关联表(中间表):admin_role_elation。字段:id, onwer_id(管理员ID=admin_id), role_id

** 中间表要继承 Pivot **

class Admin extends Model
{
    public function roles()
    {
        // belongsToMany('关联模型','中间表','外键','关联键');
        // 关联模型(必须):关联模型类名
        // 中间表:默认规则是当前模型名+_+关联模型名 (可以指定模型名)
        // 外键:中间表的当前模型外键,默认的外键名规则是关联模型名+_id
        // 关联键:中间表的当前模型关联键名,默认规则是当前模型名+_id
        return $this->belongsToMany(AdminRole::class, AdminRoleRelation::class, 'role_id', 'owner_id');

        // 为中间表指定条件
        // return $this->belongsToMany(AdminRole::class, AdminRoleRelation::class, 'role_id', 'owner_id')->wherePivot('relation_type', 1);
    }
}

多态关联

表:文章表,书籍表,评论表。

article(文章表)
    id - integer
    title - string
    content - text

book(书籍表)
    id - integer
    title - string

comment(评论表)
    id - integer
    content - text
    commentable_id - integer
    commentable_type - string

多态一对多关联

class Article extends Model
{
    // 多态关联
    public function comments()
    {
        // morphMany('关联模型','多态字段','多态类型');
        // 关联模型(必须):关联的模型类名
        // 多态字段(可选):支持两种方式定义
        //     - 如果是字符串:表示多态字段的前缀,多态字段使用 “多态前缀_type”和“多态前缀_id”。
        //     - 如果是数组:表示使用['多态类型字段名','多态ID字段名']。
        //     - 默认为当前的关联方法名作为字段前缀。
        // 多态类型(可选):当前模型对应的多态类型(字段的值)。默认为当前模型名,可以使用模型名(如Article)或者完整的命名空间模型名(如app\index\model\Article)。

        // 1.多太字段为字符串:commentable_type(关联类型,值默认为当前模型名:Model\\Article), commentable_id(关联表ID,值为:Article.id)
        // return $this->morphMany(Comment::class, 'commentable');

        // 2.多太字段为数组:commentable_type(关联类型,值默认为当前模型名:Model\\Article), commentable_id(关联表ID,值为:Article.id)
        // return $this->morphMany(Comment::class, array('commentable_type', 'commentable_id'));

        // 3.指定多太类型:明确指定类型值为当前类的命名空间
        return $this->morphMany(Comment::class, 'commentable', self::class);
    }
}

多态一对一关联

表:文章表,书籍表,评论表。
** 使用以上表结构,假设文章和书籍都只能有一条评论。 **

class Article extends Model
{
    public function comment()
    {
        // morphOne('关联模型','多态字段','多态类型');
        // 关联模型(必须):关联的模型类名。
        // 多态字段(可选):支持两种方式定义 
        //     - 如果是字符串表示多态字段的前缀,多态字段使用 多态前缀_type和多态前缀_id。
        //     - 如果是数组,表示使用['多态类型字段名','多态ID字段名']。
        //     - 默认为当前的关联方法名作为字段前缀。
        // 多态类型(可选):当前模型对应的多态类型,默认为当前模型名,可以使用模型名(如Member)或者完整的命名空间模型名(如app\index\model\Member)。
        return $this->morphOne(Comment::class, 'commentable');
    }
}

获取所有者模型

class Comment extends Model
{
    // 获取评论对应的多态模型(返回评论所有者)
    public function commentable()
    {
        // morphTo('多态字段',['多态类型'=>'模型类名', ...]);
        // 多态字段(可选):支持两种方式定义
        //     - 如果是字符串表示多态字段的前缀,多态字段使用 多态前缀_type和多态前缀_id,
        //     - 如果是数组,表示使用['多态类型字段名','多态ID字段名'],
        //     - 默认为当前的关联方法名作为字段前缀
        // 多态类型别名(可选):数组方式定义,类型对应的模型类名(可以相对或绝对)。如果类型值就是模型名,可以不传这个数组。
        return $this->morphTo('commentable', array(
            Article::class => 'Article', // 相对命名空间
            Book::class => 'Model\Book', // 绝对命名空间
        ));
    }
}

$comment = Comment::find(1);
$article = $comment->commentable; // 文章模型

通过关联查询

hasWhere

has开头的关联方式可用。

$goods = Goods::hasWhere('comments', function ($query) {
            $query->where('id', 1);
        })->find(1);

执行的SQL:

SELECT `goods`.* FROM `__table_prefix__goods` `goods` INNER JOIN `__table_prefix__order_goods` ON `__table_prefix__order_goods`.`goods_id`=`goods`.`id`  JOIN `__table_prefix__order_goods_comment` ON `__table_prefix__order_goods_comment`.`order_goods_id`=`__table_prefix__order_goods`.`id` WHERE  `__table_prefix__order_goods_comment`.`id` = '1'  AND `goods`.`id` = '1' GROUP BY `__table_prefix__order_goods_comment`.`order_goods_id` LIMIT 1
$goods = Goods::hasWhere('comments', function ($query) {
            $query->where('id', 1);
        })->select();
SELECT `goods`.* FROM `__table_prefix__goods` `goods` INNER JOIN `__table_prefix__order_goods` ON `__table_prefix__order_goods`.`goods_id`=`goods`.`id`  JOIN `__table_prefix__order_goods_comment` ON `__table_prefix__order_goods_comment`.`order_goods_id`=`__table_prefix__order_goods`.`id` WHERE  `__table_prefix__order_goods_comment`.`id` = '1' GROUP BY `__table_prefix__order_goods_comment`.`order_goods_id`
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自主封装的PHP ORM框架,面向对象的PDO数据库操作,API框架,支持Get/Post/Put/Delete多种请求方式。 代码示例: <?php use Models\User; require '../application.php'; require '../loader-api.php'; //适合查询,如:获取用户列表或者单个用户信息 execute_request(HttpRequestMethod::Get, function() { $action = request_action(); //判断是否存在 if ($action == 1) { list($type, $value) = filter_request(array( request_int('type', 1, 2, 3), //1.用户名 2.邮箱 3.手机号 request_string('value'))); $type_field_map = array( 1 => User::$field_username, 2 => User::$field_email, 3 => User::$field_phone ); if ($type == 2 && !is_email($value) || $type == 3 && !is_mobilephone($value)) { die_error(USER_ERROR, $type_field_map[$type]['name'] . '格式无效'); } $user = new User(); $user->set_where_and($type_field_map[$type], SqlOperator::Equals, $value); $result = $user->exists(create_pdo()); echo_result($result ? 1 : 0); //存在返回1,不存在返回0 } //查询单条信息 if ($action == 2) { list($userid) = filter_request(array( request_userid())); //查询单条数据 $user = new User($userid); //set_query_fields可以指定查询字段,下面两种写法均可 //$user->set_query_fields('userid, username, email'); //$user->set_query_fields(array(User::$field_userid, User::$field_username, User::$field_email)); //还可设置where条件进行查询 //$user->set_where_and(User::$field_status, SqlOperator::Equals, 3); //$user->set_where_and(User::$field_truename, SqlOperator::IsNullOrEmpty); //$user->set_where_and(User::$field_age, SqlOperator::In, array(27, 29)); //$user->set_where_and(User::$field_regtime, SqlOperator::LessThan, '-6 month'); //创建数据库连接 $db = create_pdo(); $result = $user->load($db, $user); //也可以用Model类的静态方法 //$result = Model::load_model($db, $user, $user); if (!$result[0]) die_error(PDO_ERROR_CODE, '获取用户信息时数据库错误'); if (!$user) di
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值