[v1.0] Taggable Behaviour

Выкладываем свои наработки
mindochin
Сообщения: 50
Зарегистрирован: 2010.12.13, 20:05

Re: [v1.0] Taggable Behaviour

Сообщение mindochin »

во-первых, спасибо за отличные расширения. во-вторых, имею проблемку с ETagListWidget. вызываю так

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

$this->widget('ext.yiiext.behaviors.model.taggable.ETagListWidget', array(
    'model' => 'article',//Yii::app()->controller->id,));
 
а в ответ
Fatal error: Call to a member function getTags() on a non-object in /protected/extensions/yiiext/behaviors/model/taggable/ETagListWidget.php on line 84
при этом в статьях через модель теги работают. в чем загвоздка?

Пысы. пардон, тупанул, надо передавать саму модель а не имя :)
Последний раз редактировалось mindochin 2011.02.08, 12:07, всего редактировалось 1 раз.

Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение Ekstazi »

Посмотрел наконец-то это поведение. Вот что отметил:
1) Разбивка на теги и компонент кеша - код можно оптимизировать.
2) поиск по тегам - sql слишком громоздкий, задача решается через group и having:

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

    
 select idPost from Post2Tag 
where idTag in (4,5) 
group by idPost 
having count(distinct idTag)=1
А так в целом хорошо.

Аватара пользователя
samdark
Администратор
Сообщения: 9403
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение samdark »

Если что — есть тесты и в код можно лезть с целью вышеописанное устранить…

Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение Ekstazi »

Ок

Аватара пользователя
RSol
Сообщения: 325
Зарегистрирован: 2010.05.07, 08:36
Откуда: Северодонецк, Украина
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение RSol »

Отличное расширение. Спасибо.

Возможно я повторюсь, но... функцию updateCount нужно переписать вот так:

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

    protected function updateCount($count) {
        if($this->tagTableCount !== null){
            $conn = $this->getConnection();
            $conn->createCommand(
                sprintf(
                    "UPDATE %s
                    SET %s = %s + %s
                    WHERE %s in (SELECT %s FROM %s WHERE %s = %d)",//было WHERE id in (SELECT %s FROM %s WHERE %s = %d)",
                    $this->tagTable,
                    $this->tagTableCount,
                    $this->tagTableCount,
                    $count,
                    $this->tagTablePk,//небыло этого значения
                    $this->tagBindingTableTagId,
                    $this->getTagBindingTableName(),
                    $this->getModelTableFkName(),
                    $this->getOwner()->primaryKey
                )
            )->execute();
        }
    } 
в исходном варианте считается что таблица имеет первичный ключ "id".

Аватара пользователя
samdark
Администратор
Сообщения: 9403
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение samdark »

Обновил updateCount.

mindochin
Сообщения: 50
Зарегистрирован: 2010.12.13, 20:05

Re: [v1.0] Taggable Behaviour

Сообщение mindochin »

список тегов с количеством статей виджет выводит так -

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

yii <span>1</span>
(строка 94 виджета)
а по идее должно быть как у SamDark на сайте
Пысы, вот нашел как - encodeLabel

jeicd
Сообщения: 2
Зарегистрирован: 2011.05.16, 06:47

Re: [v1.0] Taggable Behaviour

Сообщение jeicd »

Пошарил в доках, на форуме, но так и не нашел ответа. Мне необходимо вывести списком 20 постов и для каждого отобразить теги. Это получается ленивой загрузкой 20 запросов в базу? Кэш это конечно хорошо.. Но другого способа нет вытянуть всё и сразу? Еще на ум приходит, создавать модель "тэги", "связи тэгов" и определять through relations.

Аватара пользователя
Dr.Death
Сообщения: 129
Зарегистрирован: 2011.05.07, 18:24
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение Dr.Death »

А мне нравится когда все связи тегов лежат в одной таблице :) Например: tag_id, tag_group, model_id, model_class

Аватара пользователя
G0rg0t
Сообщения: 21
Зарегистрирован: 2011.12.05, 22:47

Re: [v1.0] Taggable Behaviour

Сообщение G0rg0t »

А как использовать taggable, совместно с CActiveDataProvider и CDbCriteria, чтобы возвращались модели, связанные с тегом?

Аватара пользователя
G0rg0t
Сообщения: 21
Зарегистрирован: 2011.12.05, 22:47

Re: [v1.0] Taggable Behaviour

Сообщение G0rg0t »

Всё. Разобрался сам. Если кому-то полезно будет, то это можно сделать при вызове виджета, который использует данные от CActiveDataProvider во view:

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

$this->widget('bootstrap.widgets.TbListView', array(
                        'dataProvider' => $dataProvider->model->taggedWith($tag)->search(),
                        'itemView' => '_view',
                        'template' => "{items}\n{pager}",
                    ));

Аватара пользователя
G0rg0t
Сообщения: 21
Зарегистрирован: 2011.12.05, 22:47

Re: [v1.0] Taggable Behaviour

Сообщение G0rg0t »

У описанного выше способа обнаружился недостаток: пропадает пагинация, и все найденные результаты выводятся на одной странице. Как это побороть и вернуть пагинацию при поиске по тегу?

Код экшна:

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

    public function actionIndex() {
        if (Yii::app()->params['frontTheme'] != false) {
            Yii::app()->theme = Yii::app()->params['frontTheme'];
        }

        $this->layout = '//layouts/column1';

        $criteria = new CDbCriteria(array(
                    'condition' => 'status=' . PortfolioProject::STATUS_PUBLISHED,
                    'order' => 'id ASC',
                ));

        if (isset($_GET['tag'])) {
            $tag = CHtml::encode($_GET['tag']);
        } else {
            $tag = '';
        }

        $dataProvider = new CActiveDataProvider('PortfolioProject', array(
                    'pagination' => array(
                        'pageSize' => Yii::app()->controller->module->projectPerPage,
                    ),
                    'criteria' => $criteria,
                ));

        $this->render('index', array(
            'dataProvider' => $dataProvider,
            'tag' => $tag,
        ));
    }
 

Аватара пользователя
G0rg0t
Сообщения: 21
Зарегистрирован: 2011.12.05, 22:47

Re: [v1.0] Taggable Behaviour

Сообщение G0rg0t »

Похоже, удалось окончательно решить вопрос, путем расширения стандартного CActiveDataProvider:

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

<?php
/**
 * TaggableActiveDataProvider
 * 
 * Класс, расширяющий CActiveDataProvider для корректной работы с моделями,
 * содержащими Taggable Behaviour 
 * http://www.yiiframework.com/extension/taggable/
 *
 * @author Duke
 */
class TaggableActiveDataProvider extends CActiveDataProvider {

    /**
     * Теги 
     * если тегов несколько, можно перечислить их через запятую
     * @var string 
     */
    public $tags = '';

    /**
     * Выбираем данные
     * @return array список элементов данных
     */
    protected function fetchData() {
        $criteria = clone $this->getCriteria();

        if (($pagination = $this->getPagination()) !== false) {
            $pagination->setItemCount($this->getTotalItemCount());
            $pagination->applyLimit($criteria);
        }

        $baseCriteria = $this->model->getDbCriteria(false);

        if (($sort = $this->getSort()) !== false) {
            // set model criteria so that CSort can use its table alias setting
            if ($baseCriteria !== null) {
                $c = clone $baseCriteria;
                $c->mergeWith($criteria);
                $this->model->setDbCriteria($c);
            }
            else
                $this->model->setDbCriteria($criteria);
            $sort->applyOrder($criteria);
        }

        $this->model->setDbCriteria($baseCriteria !== null ? clone $baseCriteria : null);

        if ($this->tags != '') {
            $data = $this->model->taggedWith($this->tags)->findAll($criteria);
        } else {
            $data = $this->model->findAll($criteria);
        }

        $this->model->setDbCriteria($baseCriteria);  // restore original criteria
        return $data;
    }

    /**
     * Вычисляем общее количество элементов данных
     * @return integer общее количество элементов данных
     */
    protected function calculateTotalItemCount() {
        $baseCriteria = $this->model->getDbCriteria(false);
        if ($baseCriteria !== null) {
            $baseCriteria = clone $baseCriteria;
        }

        if ($this->tags != '') {
            $count = $this->model->taggedWith($this->tags)->count($this->getCriteria());
        } else {
            $count = $this->model->count($this->getCriteria());
        }

        $this->model->setDbCriteria($baseCriteria);
        return $count;
    }

}
 
Использовать его можно так:

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

$dataProvider = new TaggableActiveDataProvider('PortfolioProject', array(
                    'pagination' => array(
                        'pageSize' => Yii::app()->controller->module->projectPerPage,
                    ),
                    'criteria' => $criteria,
                    'tags' => $tag,
                ));
 
А дальше работа аналогична CActiveDataProvider. Методов Taggable Behavior самостоятельно вызывать не нужно, это происходит само внутри TaggableActiveDataProvider, при непустом значении прараметра tags.

nikitakls
Сообщения: 47
Зарегистрирован: 2011.01.25, 08:18

Re: [v1.0] Taggable Behaviour

Сообщение nikitakls »

Еще можно сделать следующим образом
в модели немного меняем метод search

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

class Post extends CActiveRecord
{

    public function search($tags = '')
    {
        $criteria=new CDbCriteria;
        $tags = $this->toTagsArray($tags);
        if(!empty($tags))
            $criteria = $this->getFindByTagsCriteria($tags);

        $criteria->compare('id',$this->id,true);
        $criteria->compare('userID',$this->userID,true);
        $criteria->compare('author',$this->author,true);

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


}
 
Далее в Контроллере

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

        $model = new Quote();
        $dataProvider=$model->search(isset($_GET['t'])?$_GET['t']:'');

 

nikitakls
Сообщения: 47
Зарегистрирован: 2011.01.25, 08:18

Re: [v1.0] Taggable Behaviour

Сообщение nikitakls »

Еще небольшое замечание к расширению

Если передать в метод пустую строку

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

$this->toTagsArray('');
То на выходе у нас будет

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

array(
 0 => ''
)

Аватара пользователя
samdark
Администратор
Сообщения: 9403
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: [v1.0] Taggable Behaviour

Сообщение samdark »

На github закидывайте, тут раскопать что-то уже довольно сложно.

Ответить