Yii2 使用左连接将 SqlDataProvider 转换为 ActiveDataProvider

Yii2 convert SqlDataProvider to ActiveDataProvider with left join

我有两个表:调用,Phones

两个模型:调用,Phone

和以下代码:

$q = 'select 
      c.calling, sp.name as srcname, sp.org as srcorg, 
      c.called, dp.name as dstname, dp.org as dstorg 
      from Calls c 
      left join Phones sp on c.calling = sp.num 
      left join Phones dp on c.called = dp.num ORDER BY c.time '
$sql = Yii:$app->db->createCommand($q)
$count = $sql->queryScalar();
$dataProvider = new SqlDataProvider([
   'sql' => $q,
   'pagination' => [
      'pageSize' => 25,
    ],
   'totalCount' => $count,
]);

如何将其转换为 ActiveDataProvider 查询?

$dataProvder = new ActiveDataProvider([
'query' => Call::find()->...,
'pagination' => [
      'pageSize' => 25,
    ],
]);

我有一些意见可以回答你的问题。

模型而不是原始查询

使用 Gii 为您的两个 table 创建模型。该扩展是内置的,您可以在调试模式下通过调用 http://yourproject.com/gii 来简单地打开它。

当您创建模型时,它也会建立您与其他人的关系 table。您可以根据 model-documentation and ActiveRecord-documentation of Yii2. The later will also show you how to specify relations here.

轻松自定义这些

在您的情况下,Call-模型将有两个 hasOne-关系:

  • sourcePhone引用发起调用phone的机型
  • destinationPhone参考接收机型phone

用于列出调用的数据提供者和网格视图

启动现在很容易了。比方说你想列出所有的电话,你可以这样做:

<?= GridView::widget([
    'dataProvider'=>new ActiveDataProvider(['query'=>Call::find()]),
    'columns'=>[
        'id',
        [
            'label'=>Yii::t('app', 'Source phone'),
            'value'=>function ($model, $key, $index, $column) {
                return $model->sourcePhone->name;
            },
        ],
        [
            'label'=>Yii::t('app', 'Destination phone'),
            'value'=>function ($model, $key, $index, $column) {
                return $model->destinationPhone->name;
            },
        ],
        //more columns as of your requirements...
    ],
]) ?>

你现在不仅用ActiveDataProvider,你还用Yii2常用的方式来展示这样的数据(关系等)。可以像上面一样在数据提供程序上自定义分页和内容。

如何将 join 部分与 ActiveQuery

一起使用

这个很简单。 table 的实际加入将在您调用关系(延迟加载)时自动发生。在上面的示例中,这将发生在此处:

return $model->destinationPhone->name

这导致另一个查询填充与相应 Phone-实例的关系。如果您希望这与实际的调用查询一起发生,只需扩展您提供给 ActiveDataProvdier 的查询:

'dataProvider'=>new ActiveDataProvider([
    'query'=>Call::find()->joinWith(['sourcePhone', 'destinationPhone']),
]),

joinWith 方法告诉查询获取调用对象以及您在参数中指定的两个关系。请务必阅读 documentation of this method. I also have written an answer to a problem I had myself,其中进一步解释了它。

如果您想访问相关对象的列,只需像调用对象的属性一样访问相关对象,然后再访问属性本身。在上面的示例中,您可以看到我如何访问相关 phone-模型的 name-属性。

如果您需要有关某些部分的更多信息,请告诉我。