1

I have an object, Object1, that references Object2 in a one-to-many relationship: one Object1 to many Object2.

In my Object1 view, I am trying to include a yii\grid\GridView of the related Object2 items only. Not in addition to the Object1 data. Just a GridView of Object2 items only.

Using code like that below, I believe I have to set both $dataProvider and $searchModel in my controller but I'm not sure how to link Yii::$app->request->queryParams with $id.

My code just returns all Object2 items, regardless of their relationship with Object1, which although makes perfect sense to me, is not what I'm looking for.

I am not even sure that this is the correct approach. Does anyone know of a solution? Thanks in advance.

/* Object1 model */
public function getRelations() {
    return $this->hasMany(Object2::className(), ['relation' => 'id']);
}

/* Object1 view */
<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'id',
        'attr1',
        'attr2',
        'attr3',
        'attr4',
        ['class' => 'yii\grid\ActionColumn'],
    ],
]);

/* Object1 controller */
public function actionView($id){
    $searchModel = new Object2Search();
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('view', [
        'model' => $this->findModel($id),
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}
Mr Goobri
  • 1,449
  • 5
  • 19
  • 42
  • What do you want to show in your gridview? – Jalali Jul 31 '16 at 19:00
  • The attributes of `Objectt2`, whose `relation` attribute is the `id` of the `Object1` currently being viewed in the view. – Mr Goobri Jul 31 '16 at 19:13
  • every object in object1 has multiple object in object2.you can get relations and use foreach for showing them – Jalali Jul 31 '16 at 19:16
  • Yes. Of course I could. But I would like to use the GridView. – Mr Goobri Jul 31 '16 at 19:18
  • you can customize gridview – Jalali Jul 31 '16 at 19:19
  • Yes. There are lots of things I could do, like just write my own widget, but it makes more sense to reuse what's available. I'm sure my problem is not a unique one. It seems a pretty standard use of a GridView. – Mr Goobri Jul 31 '16 at 19:21
  • maybe this link can help you http://stackoverflow.com/questions/35048452/yii2-has-many-gridview-and-detailview – Jalali Jul 31 '16 at 19:23

1 Answers1

1

Instead of rendering GridView in detail view I can suggest alternative approach.

Create a separate regular GridView widgets for both Object1 and Object2 items.

Extend ActionColumn of Object1 GridView with additional link to related items. I already explained it here, but I also include code here for better understanding:

[
    'class' => 'yii\grid\ActionColumn',
    'template' => '{objects2} {view} {update} {delete}',
    'buttons' => [
        'objects2' => function ($url, $model, $key) {
            /* @var $model common\models\Object1 */
            return Html::a(
                '<span class="glyphicon glyphicon-arrow-down"></span>',
                ['objects2/index', 'object1_id' => $model->id],
                [
                    'title' => 'Objects 2',
                    'aria-label' => 'Objects 2',
                    'data-pjax' => '0',
                ]
            );
        },        
    ],
],

Modify index action of Object2Controller to accept additional parameter (Object 1 id):

/**
 * @param integer $object1_id
 * @return string
 * @throws \yii\web\NotFoundHttpException
 */
public function actionIndex($object1_id)
{
    $searchModel = new Object2Search;
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('index', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}

search() method of Object2Search should also handle additional parameter:

/**
 * @param array $params
 * @return ActiveDataProvider
 */
public function search($params)
{
    $query = Object2::find()->where(['object1_id' => $params['object1_id']]);

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

    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }

    // Additional filters

    return $dataProvider;
}

Make sure to not include object1_id in rules() and additional filters.

As for display of Object2 items, simply exclude object1_id column and you are done.

Obviously this can be customized more, it's just a basic example.

The main advantage of this approach is code for models of different type is separated and easier to maintain.

As for using it in detail view, modify search() method of Object2Search model to apply initial filter by object1_id as I described above, but in this case pass id parameter from query params (which comes from view action):

$query = Object2::find()->where(['object1_id' => $params['id']]);

Use partials for GridView for better views organization.

Community
  • 1
  • 1
arogachev
  • 33,150
  • 7
  • 114
  • 117
  • This does not answer my question. – Mr Goobri Aug 01 '16 at 07:45
  • Thank you for your answer but am I correct, that this will show all Object1data, with related data shown when the icon is clicked? This is not the question I asked. – Mr Goobri Aug 01 '16 at 08:53
  • @MrGoobri Read additional remark after explanation of this alternative. You just need to apply initial filter by object 1 id. – arogachev Aug 01 '16 at 09:40
  • You are correct, the small code snippet you provide at the bottom does work for this instance, yes, but consequentially it will then break the `Object2` index view, where I see all `Object2` instances? – Mr Goobri Aug 01 '16 at 10:18
  • @MrGoobri How it will break the index view? – arogachev Aug 01 '16 at 10:19
  • Sorry - if my `Object2` index view were to contain a list of all `Object2`, it will throw an exception as it won't recognise `$params['id']`: `Undefined index: id`. I could put an `if` in there to catch this but this would now be the `id` of `Object2` not `Object1`. Am I correct? – Mr Goobri Aug 01 '16 at 10:23
  • 1
    I think I am wrong. Sorry. And you are right. Thank you for your help. :) – Mr Goobri Aug 01 '16 at 10:25