Yii: CGridView - две строки из родительской таблицы

Yii: 1.1.15

До сих пор я много делал с CGridView - теперь я застрял на простой вещи: в CGridView я хочу показать данные из двух разных строк из родительской таблицы:

таблица/модель: люди (родительская таблица)

id    name
1     Bush
2     Heineken
3     Miller
4     Gonzales

стол/модель: друзья (ребенок-стол)

id    friend1_id friend2_id
1     1          3
2     2          4

В модели Frinds.php у меня есть отношение:

public function relations() {
    return array(
        'people' => array(self::BELONGS_TO, 'People', 'friend1_id')
}

В моем CGridview я хочу видеть - и я не знаю, как:

id  friend1   friend2
1   Bush      Miller
2   Heineken  Gonzales

person Didgejo    schedule 15.03.2015    source источник


Ответы (1)


Насколько я понимаю, у вас есть таблица «Люди», в которой вы храните всех пользователей, и таблица «Друзья», в которой вы храните строку для каждой дружбы между двумя пользователями.

Теперь я предполагаю, что ваша сетка дает результаты для модели друзей, верно?

Вам следует:

1) Правильно определите два отношения внутри модели друзей:

public function relations() {
    return array(
        'friend1' => array(self::BELONGS_TO, 'People', 'friend1_id'),
        'friend2' => array(self::BELONGS_TO, 'People', 'friend2_id'),
    );
}

2) Теперь добавьте в модель друзей два новых свойства:

class Friends extends CActiveRecord {

  public $friend1Name;
  public $friend2Name;

...

3) Теперь в вашей сетке вы можете использовать такие столбцы:

'columns' => array(
    'friend1Name'=>array(
        'name'=>'friend1Name',
        'value'=>'$data->friend1->name',
    ),
    'friend2Name'=>array(
        'name'=>'friend2Name',
        'value'=>'$data->friend2->name',
    ),

4) Два свойства, которые вы добавили, теперь не имеют ярлыка, вы можете настроить его с помощью атрибутовLabels:

public function attributeLabels() {
    return array(
      'friend1Name' => 'Friend 1 name',
      'friend2Name' => 'Friend 2 name',

5) Кроме того, вы можете добиться еще двух вещей, если настроите метод search() модели друзей:

  • Поскольку вы лениво загружаете модели, Yii будет делать sql-запрос к базе данных, чтобы получить каждого друга, если вы показываете 10 результатов на странице, это будет 20 запросов, чтобы превратить это в только один, вы можете использовать $criteria-> with() и поместите туда отношения friend1 и friend2 с внутренним соединением joinType.

  • Во-вторых, вы можете добиться сортировки результатов, когда щелкаете столбцы сетки, для этого вы можете добавить конфигурацию сортировки в CActiveDataProvider, возвращаемую методом search(), и сопоставить friend1Name и friend2Name для сортировки по соответствующим полям в отношениях.

Обновление: дополнительные пункты:

public function search() {

    //... compare conditions here

    /* 6) Run only one SQL query by joining tables instead of one query per every Person */
    $criteria->with=array(
        'friend1'=>array(
            'joinType'=>'INNER JOIN',
        ),
        'friend2'=>array(
            'joinType'=>'INNER JOIN',
        ),
    );

    /* Tip: You can use with() and not use the joinType but by using it we are forcing a INNER JOIN that makes sense in this case */

    return new CActiveDataProvider($this, array(
        'criteria'=>$criteria,

        /* 7) Apply sorting for the columns from the related tables */
        'sort'=>array(
          'attributes'=>array(
              '*',
              'friend1Name'=>array(
                  'asc'=>'friend1.name',
                  'desc'=>'friend1.name desc',
              ),
              'friend2Name'=>array(
                  'asc'=>'friend2.name',
                  'desc'=>'friend2.name desc',
              ),
          ),
        ),
    ));

}

/* 8) Auto-fill friend1Name and friend2Name with the names from the related tables */
protected function afterFind () {

    $this->friend1Name=$this->friend1->name;
    $this->friend2Name=$this->friend2->name;

    // Tip: Now you can use in your grid directly friend1Name instead of $data->friend1->name

    parent::afterFind();
}
person Alexandru Trandafir Catalin    schedule 16.03.2015
comment
Спасибо за это идеальное легкое для понимания руководство. Есть ли у вас простое предложение для (5): как получить значения в общедоступном $friend1Name и как сортировать? Можете ли вы добавить это в свой код? - person Didgejo; 17.03.2015
comment
Я обновил свой ответ блоком кода с пунктами 6, 7 и 8. - person Alexandru Trandafir Catalin; 18.03.2015