Вывод таблицы связанной модели как MANY_MANY

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
michaelbag
Сообщения: 12
Зарегистрирован: 2012.06.28, 13:34

Вывод таблицы связанной модели как MANY_MANY

Сообщение michaelbag »

Уважаемые разработчики, помогите с построением правильного и оптимального кода на yii.

Есть модель post (сообщение) и tag (ярлычки), через таблицу tbl_post_tags выполняем привязку:

Код: Выделить всё

public function relations() {
  return array(
    'tags' => array(self::MANY_MANY, 'Tag', 'tbl_post_tags(post_id, tag_id)')
  );
}
При выводе карточки модели post (views/post/view.php) хочу под общими данными post'а вывести в таблице (zii.widgets.grid.CGridView) вывести наименования всех tag'ов.

Код: Выделить всё

...
// Ярлыки сообщения
$this->widget ('zii.widgets.grid.CGridView', array(
    'id'=>'tags-grid',
    'dataProvider'=> ?????????? ,
    'filter'=>$model,
    'columns'=>array(
        'tags.name',
    ),
));
...
Как корректно получить dataProvider?

В модели tag также есть привязка:

Код: Выделить всё

public function relations() {
  return array(
    'posts' => array(self::MANY_MANY, 'Post', 'tbl_post_tags(tag_id, post_id)')
  );
}
Аватара пользователя
resurtm
Сообщения: 299
Зарегистрирован: 2010.12.19, 09:13
Откуда: Казахстан, Алма-Ата
Контактная информация:

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение resurtm »

В AR-модель Tag добавить parametrized scope, который ограничивает выборку по нужному посту Post, а уже затем создавать CActiveDataProvider с этим новым parametrized scope'ом и переданным в него текущим постом. Можно обернуть это дело в Tag::search() с необязательным аргументом-постом Post которым ограничиваем поиск (чуть приятнее).

Выглядеть это будет примерно так (не проверял частности; основная идея):

Код: Выделить всё

<?php

// AR-модель с parametrized scope'ом
class Tag extends CActiveRecord
{
    // при использовании scope'а не забыть в with добавить posts
    // или внутри scope'а добавить в критерий с которым мержим with с posts
    public function postScope($post)
    {
        if($post!==null)
        {
            // работаем только с PK
            if(is_object($post) && get_class($post)=='Post')
                $post=$post->id;
            $this->getDbCriteria()->mergeWith(array(
                'condition'=>'posts.post_id=:post_id',
                'params'=>array(':post_id'=>$post),
                //'with'=>'posts',
            ));
        }
        return $this;
    }
}

// создаём data provider тегов Tag с нужным критерием
$dataProviderForGridView=new CActiveDataProvider(Tag::model()->postScope($currentPost));
 
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение lancecoder »

Код: Выделить всё

if(is_object($post) && get_class($post)=='Post') 
зачем эта проверка? подумайте что случится, если она не сработает
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение lancecoder »

при использовании AR и InnoDB:

$post=Posts::model()->findByPk(10);
$dataProvider=new CActiveDataProvider($post->tags);

не проверял, но должно работать
michaelbag
Сообщения: 12
Зарегистрирован: 2012.06.28, 13:34

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение michaelbag »

lancecoder писал(а):при использовании AR и InnoDB:

$post=Posts::model()->findByPk(10);
$dataProvider=new CActiveDataProvider($post->tags);

не проверял, но должно работать
Считаю, что этот код самый оптимальный, но не работает... :(

Во views/post/view.php добавляю:

Код: Выделить всё

$post=Service::model()->findByPk($model->id);
$dataProvider=new CActiveDataProvider($post->tags);
// В принципе, можно и 
// $dataProvider=new CActiveDataProvider($model->tags);

$this->widget ('zii.widgets.grid.CGridView', array(
    'id'=>'tags-grid',
    'dataProvider'=>$dataProvider,
    'columns'=>array(
        'name',
    ),
));
 
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение lancecoder »

Считаю, что этот код самый оптимальный, но не работает... :(
выложи весь код модели, и экспорт структуры таблицы
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение lancecoder »

'tbl_post_tags(post_id, tag_id)'
тут косяк

у тебя получается что tags строит связь с posts через своюже таблицу
'posts' => array(self::MANY_MANY, 'Post', 'tbl_post_tags(tag_id, post_id)')
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение lancecoder »

тебе надо что то создать типа таблицы tags_posts_relation и тупо там держать связи, я бы так поступил, хотя не вижу всего кода
п.с. и тогда у тебя будут ключами post_id и tag_id, но уже в таблице _relation которая будет держать связи ключей
michaelbag
Сообщения: 12
Зарегистрирован: 2012.06.28, 13:34

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение michaelbag »

lancecoder писал(а):
'tbl_post_tags(post_id, tag_id)'
тут косяк

у тебя получается что tags строит связь с posts через своюже таблицу
'posts' => array(self::MANY_MANY, 'Post', 'tbl_post_tags(tag_id, post_id)')
Таблицы следующие:
tbl_post
tbl_tag
tbl_post_tags - связка
michaelbag
Сообщения: 12
Зарегистрирован: 2012.06.28, 13:34

Re: Вывод таблицы связанной модели как MANY_MANY

Сообщение michaelbag »

Решение следующее...

Менять в модели ничего не надо после генерации. Главное, чтобы все привязки были прописаны?

models/Post.php:

Код: Выделить всё

...
    /**
     * @return array relational rules.
     */
    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'postTags' => array(self::HAS_MANY, 'PostTag', 'post_id'),
        );
    }
...
models/PostTag.php:

Код: Выделить всё

...

    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'tag' => array(self::BELONGS_TO, 'Tag', 'tag_id'),
            'post' => array(self::BELONGS_TO, 'Post', 'post_id'),
        );
    }
...
 
models/Tag.php:

Код: Выделить всё

...

    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'postTags' => array(self::HAS_MANY, 'PostTag', 'tag_id'),
        );
    }
...
 
Во вьюшке views/post/view.php добавляем:

Код: Выделить всё

...
// ====================== Тэги этого поста

$tagProvider = new CActiveDataProvider ('PostTag', array(
    'criteria'=>array(
        'condition'=>'post_id='.$model->id,
        'with'=>array('tag'=>array('select'=>'title, id')),
    ),
    'sort'=>array('defaultOrder'=>'tag.title', 
        'attributes'=>array('tag.title', 'tag.id')
    )
));

$this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'post-grid',
    'dataProvider'=>$tagProvider,
    'columns'=>array(
        'tag.id',
        'tag.title',
    ),
));
...
 
Теперь у нас при просмотре карточки Поста выводят все Тэги, привязанные к этому посту.
Ответить