首页 > 解决方案 > ActiveRecord 和 GridView 行为中的 Yii2 多态关系

问题描述

我试图在 Yii2 ActiveRecord 中实现多态关系,但我遇到了这个问题。
所以,我有以下数据库结构:

票务表

+----+-------+
| id | type  |
+----+-------+
|  1 |     1 |
|  1 |     2 |
|  1 |     3 |
+----+-------+

TicketOne 表

+----+--------------+---------------------+
| id |   relation   |   anotherRelation   |
+----+--------------+---------------------+
|  1 | ticketOneRel | ticketOneAnotherRel |
|    |              |                     |
+----+--------------+---------------------+

TicketTwo 表

+----+--------------+---------------------+
| id |   relation   |   anotherRelation   |
+----+--------------+---------------------+
|  1 | ticketTwoRel | ticketTwoAnotherRel |
|    |              |                     |
+----+--------------+---------------------+

在 Ticket Active Record 模型中,我实现了这些方法:

public function getTicket()
    {
        switch ($this->type){
            case self::TYPE_CLIENT:
                return $this->getTiektOne();
            case self::TYPE_STAFF:
                return $this->getTicketTwo();
            default:
                throw new \RuntimeException('Appeal type is wrong!');
        }
    }


public function getTicketOne()
{
    return $this->hasOne(TicketOne::className(), ['EXT_ID' => 'FID_APPEAL']);
}

public function getTicketTwo()
{
    return $this->hasOne(TicketTwo::className(), ['EXT_ID' => 'FID_APPEAL']);
}

两个子 Ticket 模型都有返回相应字段getRelation()getAnotherRelation()方法。

为了显示所有票,我使用了 GridView 小部件。在 TiecktSearch 模型中,我创建了 $dataProvider:

$query = Ticket::find()
    ->with('ticket')
    ->with('ticket.relation')
    ->with('ticket.anotherRelation');

$dataProvider = new ActiveDataProvider([
    'query' => $query,
]);

因此,当我过滤 GridView 以显示一种票证类型时,它可以正常工作。但是,如果我使用未过滤的 GridView,奇怪的事情就会开始发生。
例如:如果第一个 GridView 行的类型为 TicketOne,则所有类型为“One”的工单都显示良好。但是 TicketTwo 类型的票会中断。
问题是当我进入ticket.relationGridView 列时,它的行为就像这种关系从 TypeOne 票证中获取数据:在“关系”GridView 字段中,它显示ticketOneRel它真正应该是什么时候ticketTwoRel

标签: yii2

解决方案


我认为你的方法是不可能的。您要求 Yii 在 Gridview 中对每行进行不同的左连接,但这不是它的工作方式。Yii 正在尝试构建一个查询来提供所有数据。

相反,您可以创建一个独立的函数,每行执行一个独立的查询

public function getTicket(){
   If ($this->type == self::TYPE_CLIENT)
      $model = new TicketOne::find();
   else
       $model = new TicketTwo::find();

   $model->select(...
   return $model->getOne();

如果您只重新调整 Gridview 中的一或两列,这应该没问题。但是,如果您有很多列,这会大大降低您的网站速度。


推荐阅读