ThinkPHP 多态关联

多态关联

多态多态,顾名思义,关联得到的对象类型取决于当前状态。

多态关联允许一个模型在单个关联方法中关联一个以上其它模型。

多态关联是动态的,关联的对象取决于多态字段。

使用多态关联的前提

模型 A 多态关联模型 C,模型 C 对应的数据表必须有两个多态字段,其中一个多态字段存着模型 A 对应的数据表的主键,另一个多态字段存着模型 A 对应的数据表的表名称。

多态关联种类

多态关联分为多态一对多关联和多态一对一关联。

多态一对多关联

以 ThinkPHP 官方手册的例子为例,例如用户可以评论书或文章,但评论表通常都是共用同一张数据表,多态一对多关联关系,就是为了满足类似的使用场景而设计。

以 ThinkPHP 官方手册的例子为例子,下面是关联表的数据表结构:

// 文章表
article
    id - integer // 文章表主键
    title - string // 文章标题
    content - text // 文章内容

// 书籍表
book
    id - integer // 书籍表主键
    title - string // 书籍标题

// 评论表
comment
    id - integer // 评论表主键
    content - text // 评论内容
    commentable_id - integer // 多态 id 字段,当前例子存文章表或书籍表的主键 
    commentable_type - string // 多态类型字段,当前例子存 article 或 book 

一个文章(书籍)有多个评论(一对多),文章表和书籍表共用同一张评论表,这就是多态一对多。如果要使用多态关联,评论表必须设计成这样的结构。

有两个需要注意的字段是 comment 表中的 commentable_id 字段和 commentable_type 字段我们称之为多态字段。其中,commentable_id 用于存放书籍表或者文章表的 id(主键),而 commentable_type 用于存放该评论所属的表的表名称(article 或 book),通过这样的表设计,我们可以清楚的知道当前评论属于哪篇文章或哪本书籍。通常多态字段的设计是有一个公共的前缀(例如这里用的 commentable ),当然,也支持设置完全不同的字段名(例如用 data_id 和 type)。

多态一对多关联定义

文章表模型:

<?php
namespace app\index\model;

use think\Model;

class Article extends Model
{
    /**
     * 获取所有属于文章的评论。
     */
    public function comments()
    {
        // Article 模型多态一对多关联 Comment 模型
        return $this->morphMany('Comment', 'commentable');
        // 完整写法 
        // return $this->morphMany('Comment', 'commentable', 'Article');
    }
}

morphMany 方法的参数如下:

morphMany('关联模型', '多态字段前缀或数组', '多态类型');

关联模型(必须):关联的模型名称,可以使用模型名(如 Comment )或者完整的命名空间模型名(如 app\index\model\Comment )。

多态字段前缀或数组(可选):如果是字符串则表示多态字段的前缀(多态前缀_type 和 多态前缀_id) ,如果是数组,使用 ['多态类型字段名', '多态ID字段名'] 的格式,默认为当前的关联方法名作为字段前缀(当前例子默认为 comments)。

多态类型(可选):当前模型对应的多态类型,默认为当前模型名,可以使用模型名(如 Article 或 Book )或者完整的命名空间模型名(如  app\index\model\Article    app\index\model\Book  )。

书籍表模型:

<?php
namespace app\index\model;

use think\Model;

class Book extends Model
{
    /**
     * 获取所有属于书籍的评论。
     */
    public function comments()
    {
        // Book 模型多态一对多关联 Comment 模型
        return $this->morphMany('Comment', 'commentable');
        // 完整写法 
        // return $this->morphMany('Comment', 'commentable', 'Book');
    }
}

书籍模型的设置方法同文章模型一致,区别在于多态类型不同,但由于多态类型默认会取当前模型名,因此不需要单独设置。

评论表模型

<?php
namespace app\index\model;

use think\Model;

class Comment extends Model
{
    /**
     * 获取评论对应的多态模型。
     */
    public function commentable()
    {
        return $this->morphTo(); // 当前例子获取 Article 模型或 Book 模型
    }
}

morphTo 方法的参数如下:

morphTo('多态字段前缀或数组', ['多态类型别名']);

多态字段前缀或数组(可选):如果是字符串则表示多态字段的前缀,如果是数组,使用['多态类型字段名', '多态ID字段名'] 的格式,默认为当前的关联方法名作为多态字段前缀(当前例子为 commentable )。

多态类型别名(可选):数组方式定义。

Comment 模型的 commentable 关联会返回 Article 或 Book 模型的对象实例,这取决于评论的多态类型字段值。

morphTo 方法正如我在文章开头说的那样,多态关联允许一个模型在单个关联方法中关联一个以上其它模型。

多态一对一关联

多态一对一关联与多态一对多关联的区别就像一对一关联和一对多关联。以 ThinkPHP 官方手册的例子为例,有一个个人表和一个团队表,而无论是个人还是团队都有一个头像需要保存,而且他们共用同一张头像表,并且无论是个人还是团队都只能拥有一个头像,数据表结构如下

// 会员表
member
    id - integer // 会员表主键
    name - string 
   
// 团队表
team
    id - integer // 团队表主键
    name - string

// 头像表
avatar
    id - integer // 头像表主键
    avatar - string
    avatartable_id - integer // 多态 id 字段,当前例子存会员表主键或团队表主键
    avatartable_type - string // 多态类型字段,当前例子存 member 或 team

一位会员或一个团队都是只有一个头像(一对一),会员表和团队表共用同一张头像表,这就是多态一对一。如果要使用多态关联,头像表必须设计成这样的表结构。

avatar 表中的 avatartable_id ​字段和 avatar_type 字段我们称之为多态字段。其中,avatartable_id 用于存放会员表或者团队表的 id(主键),而 avatar_type 用于存放头像所属的表的表名称( member 或 team) ,通过这样的表设计,我们可以清楚的知道当前头像属于哪位会员或哪个团队。通常多态字段的设计是有一个公共的前缀(例如这里用的 avatartable),当然,也支持设置完全不同的字段名(例如用 data_id 和 type

会员模型:

<?php
namespace app\index\model;

use think\Model;

class Member extends Model
{
    /**
     * 获取用户的头像
     */
    public function avatar()
    {
        // Member 模型多态一对一关联 Avatar 模型
        return $this->morphOne('Avatar', 'avatartable');
        // 完整写法
        // return $this->morphOne('Avatar', 'avatartable', 'Member');
    }
}

morphOne方法的参数如下:

morphOne('关联模型', '多态字段前缀或数组', '多态类型');

关联模型(必须):关联的模型名称,可以使用模型名(如 Avatar)或者完整的命名空间模型名(如 app\index\model\Avatar)。

多态字段前缀或数组(可选):如果是字符串则表示多态字段的前缀(多态前缀_type 和 多态前缀_id) ,如果是数组,使用 ['多态类型字段名', '多态ID字段名'] 的格式,默认为当前的关联方法名作为字段前缀(当前例子默认为 avatar)。

多态类型(可选):当前模型对应的多态类型,默认为当前模型名(Member),可以使用模型名(如 Member)或者完整的命名空间模型名(如 app\index\model\Member)。

团队模型:

<?php
namespace app\index\model;

use think\Model;

class Team extends Model
{
    /**
     * 获取团队的头像
     */
    public function avatar()
    {
        // Team 模型多态一对一关联 Avatar 模型
        return $this->morphOne('Avatar', 'avatartable');
        // 完整写法
        // return $this->morphOne('Avatar', 'avatartable', 'Team');
    }
}

团队模型的设置方法同会员模型一致,区别在于多态类型不同,但由于多态类型默认会取当前模型名,因此不需要单独设置。

头像模型:

<?php
namespace app\index\model;

use think\Model;

class Avatar extends Model
{
    /**
     * 获取头像对应的多态模型。
     */
    public function avatartable()
    {
        return $this->morphTo(); // 当前例子获取 Member 模型或 Team 模型
    }
}

morphTo 方法的参数如下:

morphTo('多态字段前缀或数组', ['多态类型别名']);

多态字段前缀或数组(可选):如果是字符串则表示多态字段的前缀,如果是数组,使用['多态类型字段名',  '多态ID字段名'] 的格式,默认为当前的关联方法名作为多态字段前缀(当前例子默认为 avatartable )。

多态类型别名(可选):数组方式定义。

Avatar 模型的 avatartable 关联会返回 Member 或 Team 模型的对象实例,这取决于头像的多态类型字段值。

morphTo 方法正像我在文章开头说的那样,多态关联允许一个模型在单个关联方法中关联一个以上其它模型。

理解了多态一对多关联后,多态一对一关联其实就很容易理解了,区别就是当前模型和动态关联的模型之间的关联属于一对一关系。

总结

多态多态,顾名思义,关联得到的对象类型取决于当前状态。

多态关联允许一个模型在单个关联方法中关联一个以上其它模型。

多态关联是动态的,关联的对象取决于多态字段。

实例演示

shop_article 表

 shop_comment 表



shop_video

演示1

获取 article_id 为 1 的文章详情以及属于它的评论,一篇文章有多个评论,所以使用的是多态一对多 morphMany 方法。

Article 控制器

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Article as ArticleModel;

class Article extends Base
{
    // 获取文章详情以及属于文章自己的评论
    public function detail()
    {
        $article_id = 1;
        $detail = ArticleModel::getDetail($article_id);

        echo '<pre>';

        var_dump($detail);

        echo '</pre>';
    }


}

Article 模型

<?php

namespace app\api\model;

class Article extends Base
{
    // 因为主键不是默认的名称,所以要重新定义主键名称
    protected $pk = 'article_id';

    public static function getDetail($article_id)
    {
        // 预载入关联查询
        // 第二个参数是所用到的关联方法的方法名
        $detail = self::get($article_id, 'comments');

        return $detail;
    }

    // 多态一对多获取文章的所有评论
    public function comments()
    {
        /*
        第二个参数多态字段前缀默认为当前方法名 comments,数据表中的多态字段前缀是             
        comment_table,所以要自己手动输入。
        第三个参数多态字段类型默认为当前模型名 Article,实际上多态字段类型应该是 article,        
        所以也要自己手动输入                
        */
        return $this->morphMany('Comment', 'comment_table', 'article');
    }
}

Comment 模型

<?php
namespace app\api\model;

class Comment extends Base
{
    
}

Article 控制器 的 detail 方法输出如下

object(app\api\model\Article)#41 (2) {
  ["data"]=>
  array(6) {
    ["article_id"]=>
    int(1)
    ["title"]=>
    string(12) "测试标题"
    ["content"]=>
    string(12) "测试内容"
    ["user_id"]=>
    int(1)
    ["create_time"]=>
    int(1689401566)
    ["update_time"]=>
    int(1689401566)
  }
  ["relation"]=>
  array(1) {
    ["comments"]=>
    object(think\model\Collection)#50 (1) {
      ["items":protected]=>
      array(2) {
        [0]=>
        object(app\api\model\Comment)#45 (2) {
          ["data"]=>
          array(6) {
            ["comment_id"]=>
            int(1)
            ["content"]=>
            string(30) "文章写得很好,点个赞"
            ["comment_table_id"]=>
            int(1)
            ["comment_table_type"]=>
            string(7) "article"
            ["create_time"]=>
            int(1689401637)
            ["update_time"]=>
            int(1689401637)
          }
          ["relation"]=>
          array(0) {
          }
        }
        [1]=>
        object(app\api\model\Comment)#46 (2) {
          ["data"]=>
          array(6) {
            ["comment_id"]=>
            int(2)
            ["content"]=>
            string(36) "文章写得很好,下次别写了"
            ["comment_table_id"]=>
            int(1)
            ["comment_table_type"]=>
            string(7) "article"
            ["create_time"]=>
            int(1689403338)
            ["update_time"]=>
            int(1689403338)
          }
          ["relation"]=>
          array(0) {
          }
        }
      }
    }
  }
}

单条查询输出的是文章(Article )模型实例,文章模型实例的 relation 属性(关联数组)保存着关联模型,在该关联数组中,关联方法名 comments 作为键名,结果集对象作为键值,结果集对象的 items 属性(索引数组)保存着关联查询结果。

使用到的 SQL

SELECT * FROM `shop_article` WHERE `article_id` = 1 LIMIT 1 

SELECT * FROM `shop_comment` WHERE `comment_table_id` = 1 AND `comment_table_type` = 'article' 

获取文章的评论,访问关联方法名即可,

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Article as ArticleModel;

class Article extends Base
{

    public function detail()
    {
        $article_id = 1;
        
        $detail = ArticleModel::getDetail($article_id);

        echo '<pre>';

        var_dump($detail->comments);

        echo '</pre>';
    }


}

输出如下

object(think\model\Collection)#50 (1) {
  ["items":protected]=>
  array(2) {
    [0]=>
    object(app\api\model\Comment)#45 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(1)
        ["content"]=>
        string(30) "文章写得很好,点个赞"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689401637)
        ["update_time"]=>
        int(1689401637)
      }
      ["relation"]=>
      array(0) {
      }
    }
    [1]=>
    object(app\api\model\Comment)#46 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(2)
        ["content"]=>
        string(36) "文章写得很好,下次别写了"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689403338)
        ["update_time"]=>
        int(1689403338)
      }
      ["relation"]=>
      array(0) {
      }
    }
  }
}

输出结果集对象,结果集对象的 items 属性(数组)保存着当前文章的所有评论,如下

演示二

获取所有的文章以及属于它自己的评论

Article 控制器

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Article as ArticleModel;

class Article extends Base
{

    // 获取所有文章以及属于文章自己的评论
    public function list()
    {
        $list = ArticleModel::getList();
        
        echo '<pre>';

        var_dump($list);

        echo '</pre>';

    }


}

Article 模型

<?php

namespace app\api\model;

class Article extends Base
{

    protected $pk = 'article_id';

    // 获取全部文章以及属于文章的评论
    public static function getList()
    {
        // 关联预载入
        // 参数为所用到的关联方法名称
        return self::with('comments')->select();
    }

    // 多态一对多获取文章的所有评论
    public function comments()
    {
        return $this->morphMany('Comment', 'comment_table', 'article');
    }
}

Article 控制器的 list 方法输出

object(think\model\Collection)#43 (1) {
  ["items":protected]=>
  array(2) {
    [0]=>
    object(app\api\model\Article)#41 (2) {
      ["data"]=>
      array(6) {
        ["article_id"]=>
        int(1)
        ["title"]=>
        string(12) "测试标题"
        ["content"]=>
        string(12) "测试内容"
        ["user_id"]=>
        int(1)
        ["create_time"]=>
        int(1689401566)
        ["update_time"]=>
        int(1689401566)
      }
      ["relation"]=>
      array(1) {
        ["comments"]=>
        object(think\model\Collection)#51 (1) {
          ["items":protected]=>
          array(2) {
            [0]=>
            object(app\api\model\Comment)#46 (2) {
              ["data"]=>
              array(6) {
                ["comment_id"]=>
                int(1)
                ["content"]=>
                string(30) "文章写得很好,点个赞"
                ["comment_table_id"]=>
                int(1)
                ["comment_table_type"]=>
                string(7) "article"
                ["create_time"]=>
                int(1689401637)
                ["update_time"]=>
                int(1689401637)
              }
              ["relation"]=>
              array(0) {
              }
            }
            [1]=>
            object(app\api\model\Comment)#47 (2) {
              ["data"]=>
              array(6) {
                ["comment_id"]=>
                int(2)
                ["content"]=>
                string(36) "文章写得很好,下次别写了"
                ["comment_table_id"]=>
                int(1)
                ["comment_table_type"]=>
                string(7) "article"
                ["create_time"]=>
                int(1689403338)
                ["update_time"]=>
                int(1689403338)
              }
              ["relation"]=>
              array(0) {
              }
            }
          }
        }
      }
    }
    [1]=>
    object(app\api\model\Article)#42 (2) {
      ["data"]=>
      array(6) {
        ["article_id"]=>
        int(2)
        ["title"]=>
        string(13) "测试标题1"
        ["content"]=>
        string(13) "测试内容1"
        ["user_id"]=>
        int(1)
        ["create_time"]=>
        int(1689498967)
        ["update_time"]=>
        int(1689498967)
      }
      ["relation"]=>
      array(1) {
        ["comments"]=>
        object(think\model\Collection)#52 (1) {
          ["items":protected]=>
          array(0) {
          }
        }
      }
    }
  }
}

多条查询返回由多个文章模型组成的结果集对象,每个文章模型对象的 relation 属性(关联数组)保存着关联查询得到的结果集对象,其中键名是所用到的关联方法名,键值是结果集对象,结果集对象的 items 属性(数组)保存着关联查询结果。

使用的 SQL

SELECT * FROM `shop_article` 

SELECT * FROM `shop_comment` WHERE `comment_table_id` IN (1,2) AND `comment_table_type` = 'article'

获取每篇文章的评论

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Article as ArticleModel;

class Article extends Base
{

    public function list()
    {
        $list = ArticleModel::getList();
        
        foreach ($list as $article) {

            echo '<pre>';

            var_dump($article['comments']);

            echo '</pre>';
        }

    }

}

访问关联方法名即可,输出如下

object(think\model\Collection)#51 (1) {
  ["items":protected]=>
  array(2) {
    [0]=>
    object(app\api\model\Comment)#46 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(1)
        ["content"]=>
        string(30) "文章写得很好,点个赞"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689401637)
        ["update_time"]=>
        int(1689401637)
      }
      ["relation"]=>
      array(0) {
      }
    }
    [1]=>
    object(app\api\model\Comment)#47 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(2)
        ["content"]=>
        string(36) "文章写得很好,下次别写了"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689403338)
        ["update_time"]=>
        int(1689403338)
      }
      ["relation"]=>
      array(0) {
      }
    }
  }
}
object(think\model\Collection)#52 (1) {
  ["items":protected]=>
  array(0) {
  }
}

演示三

 获取 comment_id 为 1 的评论详情以及关联它的多态类型,使用的是 morphTo 方法。

comment 控制器

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Comment as CommentModel;

class Comment extends Base
{
    public function detail()
    {   
        $comment_id = 1;
        $detail = CommentModel::getDetail($comment_id);

        echo '<pre>';

        var_dump($detail);

        echo '</pre>';
    }

}

comment 模型

<?php

namespace app\api\model;

class Comment extends Base
{

    protected $pk = 'comment_id'; 

    public static function getDetail($comment_id)
    {
        return self::get($comment_id, 'commentTable');
    }

    // 获取评论对应的多态模型
    public function commentTable()
    {
        // 多态字段前缀默认为当前方法名,因为当前方法名为小驼峰命名法,tp5 会自动转化成下划线法命名         
        // 即 comment_table 
        return $this->morphTo();
        // 完整写法
        // return $this->morphTo('comment_table');
    }
    

}

comment 控制器的 detail 方法输出

object(app\api\model\Comment)#40 (2) {
  ["data"]=>
  array(6) {
    ["comment_id"]=>
    int(1)
    ["content"]=>
    string(30) "文章写得很好,点个赞"
    ["comment_table_id"]=>
    int(1)
    ["comment_table_type"]=>
    string(7) "article"
    ["create_time"]=>
    int(1689401637)
    ["update_time"]=>
    int(1689401637)
  }
  ["relation"]=>
  array(1) {
    ["comment_table"]=>
    object(app\api\model\Article)#45 (2) {
      ["data"]=>
      array(6) {
        ["article_id"]=>
        int(1)
        ["title"]=>
        string(12) "测试标题"
        ["content"]=>
        string(12) "测试内容"
        ["user_id"]=>
        int(1)
        ["create_time"]=>
        int(1689401566)
        ["update_time"]=>
        int(1689401566)
      }
      ["relation"]=>
      array(0) {
      }
    }
  }
}

Comment 模型实例的 relation 属性(数组)保存关联查询结果 ,其中关联方法名 comment_table 作为键名,关联查询结果作为键值(对一关联查询返回模型实例,对多关联查询返回结果集对象)。

使用的 SQL

SELECT * FROM `shop_comment` WHERE `comment_id` = 1 LIMIT 1 

SELECT * FROM `shop_article` WHERE `article_id` = 1 LIMIT 1 

获取评论关联的多态类型,访问关联方法名即可

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Comment as CommentModel;

class Comment extends Base
{
    public function detail()
    {   
        $comment_id = 1;

        $detail = CommentModel::getDetail($comment_id);

        echo '<pre>';

        var_dump($detail->commentTable);

        echo '</pre>';

    }

}

输出如下

object(app\api\model\Article)#41 (2) {
  ["data"]=>
  array(6) {
    ["article_id"]=>
    int(1)
    ["title"]=>
    string(12) "测试标题"
    ["content"]=>
    string(12) "测试内容"
    ["user_id"]=>
    int(1)
    ["create_time"]=>
    int(1689401566)
    ["update_time"]=>
    int(1689401566)
  }
  ["relation"]=>
  array(0) {
  }
}

演示四

获取所有评论以及评论对应的多态类型

comment 控制器

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Comment as CommentModel;

class Comment extends Base
{
    public function list()
    {
        $list = CommentModel::getList();

        echo '<pre>';

        var_dump($list);

        echo '</pre>';
    }

}

comment 模型

<?php

namespace app\api\model;

class Comment extends Base
{

    protected $pk = 'comment_id'; 


    // 获取所有评论以及评论对应的多态类型
    public static function getList()
    {
        return self::with('commentTable')->select();
    }


    // 获取评论对应的多态模型
    public function commentTable()
    {
        return $this->morphTo();
    }
    

}

Comment 控制器 list 方法输出

object(think\model\Collection)#44 (1) {
  ["items":protected]=>
  array(3) {
    [0]=>
    object(app\api\model\Comment)#40 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(1)
        ["content"]=>
        string(30) "文章写得很好,点个赞"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689401637)
        ["update_time"]=>
        int(1689401637)
      }
      ["relation"]=>
      array(1) {
        ["comment_table"]=>
        object(app\api\model\Article)#47 (2) {
          ["data"]=>
          array(6) {
            ["article_id"]=>
            int(1)
            ["title"]=>
            string(12) "测试标题"
            ["content"]=>
            string(12) "测试内容"
            ["user_id"]=>
            int(1)
            ["create_time"]=>
            int(1689401566)
            ["update_time"]=>
            int(1689401566)
          }
          ["relation"]=>
          array(0) {
          }
        }
      }
    }
    [1]=>
    object(app\api\model\Comment)#42 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(2)
        ["content"]=>
        string(36) "文章写得很好,下次别写了"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(7) "article"
        ["create_time"]=>
        int(1689403338)
        ["update_time"]=>
        int(1689403338)
      }
      ["relation"]=>
      array(1) {
        ["comment_table"]=>
        object(app\api\model\Article)#47 (2) {
          ["data"]=>
          array(6) {
            ["article_id"]=>
            int(1)
            ["title"]=>
            string(12) "测试标题"
            ["content"]=>
            string(12) "测试内容"
            ["user_id"]=>
            int(1)
            ["create_time"]=>
            int(1689401566)
            ["update_time"]=>
            int(1689401566)
          }
          ["relation"]=>
          array(0) {
          }
        }
      }
    }
    [2]=>
    object(app\api\model\Comment)#43 (2) {
      ["data"]=>
      array(6) {
        ["comment_id"]=>
        int(3)
        ["content"]=>
        string(30) "视频做得很好,点个赞"
        ["comment_table_id"]=>
        int(1)
        ["comment_table_type"]=>
        string(5) "video"
        ["create_time"]=>
        int(1689473711)
        ["update_time"]=>
        int(1689473711)
      }
      ["relation"]=>
      array(1) {
        ["comment_table"]=>
        object(app\api\model\Video)#46 (2) {
          ["data"]=>
          array(5) {
            ["video_id"]=>
            int(1)
            ["title"]=>
            string(12) "视频测试"
            ["user_id"]=>
            int(1)
            ["create_time"]=>
            int(1689473536)
            ["update_time"]=>
            int(1689473536)
          }
          ["relation"]=>
          array(0) {
          }
        }
      }
    }
  }
}

多条查询返回由多个评论模型实例组成的结果集对象,每个评论模型实例的 relation 属性(关联数组)保存着关联查询得到的关联模型实例,其中键名是所用到的关联方法名,键值是关联查询得到的关联模型实例(因为关联方法 morphTo() 是对一关联,所以键值是关联模型实例,如果关联方法是对多关联,则键值是结果集对象)。

使用的 SQL

SELECT * FROM `shop_comment`

SELECT * FROM `shop_article` WHERE `article_id` = 1

SELECT * FROM `shop_video` WHERE `video_id` = 1 

获取每个评论关联的多态类型,访问关联方法名即可

<?php

declare(strict_types=1);

namespace app\api\controller;

use app\api\model\Comment as CommentModel;

class Comment extends Base
{
    public function list()
    {
        $list = CommentModel::getList();

        foreach ($list as $value) {
            echo '<pre>';
            var_dump($value['commentTable']);
            echo '</pre>';
        }

    }

}

输出如下

object(app\api\model\Article)#41 (2) {
  ["data"]=>
  array(6) {
    ["article_id"]=>
    int(1)
    ["title"]=>
    string(12) "测试标题"
    ["content"]=>
    string(12) "测试内容"
    ["user_id"]=>
    int(1)
    ["create_time"]=>
    int(1689401566)
    ["update_time"]=>
    int(1689401566)
  }
  ["relation"]=>
  array(0) {
  }
}
object(app\api\model\Article)#53 (2) {
  ["data"]=>
  array(6) {
    ["article_id"]=>
    int(1)
    ["title"]=>
    string(12) "测试标题"
    ["content"]=>
    string(12) "测试内容"
    ["user_id"]=>
    int(1)
    ["create_time"]=>
    int(1689401566)
    ["update_time"]=>
    int(1689401566)
  }
  ["relation"]=>
  array(0) {
  }
}
object(app\api\model\Video)#55 (2) {
  ["data"]=>
  array(5) {
    ["video_id"]=>
    int(1)
    ["title"]=>
    string(12) "视频测试"
    ["user_id"]=>
    int(1)
    ["create_time"]=>
    int(1689473536)
    ["update_time"]=>
    int(1689473536)
  }
  ["relation"]=>
  array(0) {
  }
}

如果觉得作者写得好,请帮我点个赞,谢谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThinkPHP进行关联时,可以使用字段相同的方式来建立关联关系。在ThinkPHP中,可以通过使用`_as`和`_on`方法来指定关联条件中的字段相同。 假设有两个模型`UserModel`和`OrderModel`,它们之间存在一对多的关联关系。用户(User)可以拥有多个订单(Order)。在这种情况下,可以通过设置`_on`方法中的字段相同来建立关联关系: ```php namespace app\index\model; use think\Model; class UserModel extends Model { protected $table = 'user'; // 建立一对多关联 public function orders() { return $this->hasMany('OrderModel', 'user_id') ->field('id,order_id,order_name'); } } class OrderModel extends Model { protected $table = 'order'; // 建立多对一关联 public function user() { return $this->belongsTo('UserModel', 'user_id') ->field('id,user_id,user_name'); } } ``` 在上面的例子中,`UserModel`中的`orders`方法定义了与`OrderModel`的一对多关联关系。通过`hasMany`方法,指定了关联模型的名称、关联字段以及需要获取的字段列表。 而在`OrderModel`中的`user`方法定义了与`UserModel`的多对一关联关系。通过`belongsTo`方法,指定了关联模型的名称、关联字段以及需要获取的字段列表。 这样,在执行查询时,ThinkPHP会根据关联条件中的字段相同,建立起对应的关联关系。查询结果可以使用相关方法进行访问和操作,从而方便地进行数据处理和展示。 总结起来,当使用ThinkPHP关联时,可以使用字段相同的方式来建立关联关系,通过`_as`和`_on`方法指定字段相同的关联条件,从而实现数据之间的关联操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值