Yii2:GridView:使用hasMany中的数据搜索外部字段

时间:2018-04-03 15:53:35

标签: php gridview yii2 foreign-keys

我需要能够根据相关的外部属性从GridView进行搜索。

我有两个关系表:

operators (id, name, country)
platforms (id, operator_id, platform)

许多平台都属于一个运营商。

到目前为止我所管理的是当我搜索平台(名称)时,列出具有该平台的运算符,但仍然在GridView中我获得该运算符的所有平台。我只需要匹配的那些显示:

Search for "windows" in Platforms

Name    Country      Platforms
=======================================
Oper1   Egypt        linux1, windows3, windows4
Oper5   Germany      Mac, windows2, Mac-b

我希望平台中根本不会列出不匹配的那些。

这是来自运营商模型的getPlatforms:

public function getPlatforms()
{
    return $this->hasMany(Platforms::className(), ['operator_id' => 'id']);
}

我想我需要在此处限制结果,但如何在此处访问平台搜索文本?

视图中的GridView:

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'tableOptions'=>['class'=>'table table-condensed'],
    'columns' => [
        #['class' => 'yii\grid\SerialColumn'],

        #'id',
        'abbr',
        'name',
        'country',
        [
            'attribute' => 'platforms',
            'format' => 'raw',
            'value' => function ($model) {

                // RETURN A COMMA LIST OF THE PLATFORMS

                return $this->render('_platformsInline', [
                    'model' => $model->platforms,
                ]);
            }
        ],

        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

OperatorsSearch的搜索功能:

public function search($params)
{
    $query = Operators::find();

    $query->joinWith(['platforms']);
    // add conditions that should always apply here

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

    $this->load($params);

    if (!$this->validate()) {
        // uncomment the following line if you do not want to return any records when validation fails
        // $query->where('0=1');
        return $dataProvider;
    }

    // grid filtering conditions
    $query->andFilterWhere([
        'id' => $this->id,
        // 'platforms.platform' => $this->platforms,
    ]);

    $query->andFilterWhere(['like', 'abbr', $this->abbr])
        ->andFilterWhere(['like', 'name', $this->name])
        ->andFilterWhere(['like', 'country', $this->country])
        ->andFilterWhere(['like', 'platforms.platform', $this->platforms]);

    // var_dump($query->createCommand()->rawSql);
    // exit;
    return $dataProvider;
}

修改

所以这里有更深入了解后台发生的事情(在我尝试解决这个问题的时候在这里倾注我的笔记)。

当我使用当前代码渲染()时,这些是(最重要的)查询在数据库中发生:

35 Query    SELECT COUNT(*) FROM `operators` LEFT JOIN `platforms` ON `operators`.`id` = `platforms`.`operator_id` WHERE `platforms`.`platform` LIKE '%windows%'

    This one returns:
    +----------+
    | COUNT(*) |
    +----------+
    |        4 |
    +----------+

35 Query    SELECT `operators`.* FROM `operators` LEFT JOIN `platforms` ON `operators`.`id` = `platforms`.`operator_id` WHERE `platforms`.`platform` LIKE '%windows%' ORDER BY `abbr` LIMIT 20

    (Note the duplicate returned results)
    +----+-------+-----------------+---------+
    | id | abbr  | name            | country |
    +----+-------+-----------------+---------+
    | 39 | HP-KW | Hewlett Packard | Kuwait  |
    | 43 | DL-DZ | Dell            | Algeria |
    | 43 | DL-DZ | Dell            | Algeria |
    | 43 | DL-DZ | Dell            | Algeria |
    +----+-------+-----------------+---------+

35 Query    SELECT * FROM `platforms` WHERE `operator_id` IN (39, 43)

    (And here we take all the platforms based on the match above)
    +-----+-------------+---------------------------+-------------+
    | id  | operator_id | platform                  | plat_status |
    +-----+-------------+---------------------------+-------------+
    |  50 |          39 | Linux2                    |           1 |
    |  65 |          39 | Mac1                      |           1 |
    |  85 |          39 | Mac2                      |           0 |
    | 102 |          39 | Windows1                  |           0 |
    | 124 |          39 | Linux3                    |           0 |
    |  33 |          43 | Linux with gadgets        |           0 |
    |  62 |          43 | Virtual windows plat      |           0 |
    |  77 |          43 | Mac1                      |           0 |
    |  90 |          43 | Mac2                      |           0 |
    |  91 |          43 | MM                        |           0 |
    | 110 |          43 | MM2                       |           0 |
    | 126 |          43 | Windows on VM             |           0 |
    | 127 |          43 | Windows2 on VM            |           0 |
    +-----+-------------+---------------------------+-------------+

我认为我现在正处于一个完全错误的角度。

2 个答案:

答案 0 :(得分:0)

如何使用:

return $this->render('_platformsInline', [
                    'model' => $model->getPlatforms()->andWhere('like','platform', $searchModel->platforms)->all(),
                ]);

通过这种方式,您使用关联的getPlatforms()方法访问ActiveQuery,添加where子句以仅获取满足OperatorsSearch-&gt;平台给出的条件的子句。

https://www.yiiframework.com/doc/api/2.0/yii-db-activequery

答案 1 :(得分:0)

到目前为止我所理解的是您能够正确搜索,但您希望隐藏那些当前未搜索的平台,即使操作员已将该平台分配给他。

Default Operators Lists

Name    Country      Platforms
=======================================
Oper1   Egypt        linux1, windows3, windows4
Oper5   Germany      Mac, windows2, Mac-b

在平台过滤器输入中搜索"windows",输出应如下所示

Name    Country      Platforms
=======================================
Oper1   Egypt        windows3, windows4
Oper5   Germany      windows2,

也许有其他方法可以做到这一点,但其中一种方法是查找$_GETYii::$app->request->get(),因为它具有您搜索的值,您可以用来进行比较。

我假设您在platforms模型中定义了名为OperatorsSearch的自定义属性,并将其添加到safe规则中。

我不确定为什么你需要一个视图来呈现逗号分隔值,但由于它没有被添加,我会发布没有视图的解决方案你可以根据需要调整它,将列配置更改为以下

[
    'attribute' => 'platforms' ,
    'format' => 'raw' ,
    'value' => function ($model) {
     $html='';        

     foreach ( $model->platforms as $platform ) {
        if ( isset ( Yii::$app->request->get ( 'OperatorsSearch' )['my_platforms'] ) && Yii::$app->request->get ( 'OperatorsSearch' )['my_platforms'] !== '' ) {
            $html .= (strpos ( $platform->platform , Yii::$app->request->get ( 'OperatorsSearch' )['my_platforms'] ) === FALSE) ? '' : $platform->platform . ',';
        } else {
            $html .= $platform->platform . ',';
        }
     }
        return $html;
    }
] ,