Fork me on GitHub

Taggable Behavior

Позволяет модели работать с тегами.

Установка и настройка

Создать таблицу для хранения тегов и кросс-таблицу для связи тегов с моделью. Для конфигурации ниже можно воспользоваться SQL из файла schema.sql.

Определить в модели ActiveRecord метод behaviors():

function behaviors() {
    return array(
        'tags' => array(
            'class' => 'ext.yiiext.behaviors.model.taggable.ETaggableBehavior',
            // Имя таблицы для хранения тегов
            'tagTable' => 'Tag',
            // Имя кросс-таблицы, связывающей тег с моделью.
            // По умолчанию выставляется как Имя_таблицы_моделиTag
            'tagBindingTable' => 'PostTag',
            // Имя внешнего ключа модели в кроcc-таблице.
            // По умолчанию равно имя_таблицы_моделиId
            'modelTableFk' => 'post_id',
            // Имя первичного ключа тега
            'tagTablePk' => 'id',
            // Имя поля названия тега
            'tagTableName' => 'name',
            // Имя поля счетчика тега
            // Если устанвовлено в null (по умолчанию), то не сохраняется в базе
            'tagTableCount' => 'count',
            // ID тега в таблице-связке
            'tagBindingTableTagId' => 'tagId',
            // ID компонента, реализующего кеширование. Если false кеширование не происходит.
            // По умолчанию ID равен false.
            'cacheID' => 'cache',
 
 
            // Создавать несуществующие теги автоматически.
            // При значении false сохранение выкидывает исключение если добавляемый тег не существует.
            'createTagsAutomatically' => true,
 
            // Критерий по умолчанию для выборки тегов
            'scope' => array(
                'condition' => ' t.user_id = :user_id ',
                'params' => array( ':user_id' => Yii::app()->user->id ),
            ),
 
            // Значения, которые необходимо вставлять при записи тега
            'insertValues' => array(
                'user_id' => Yii::app()->user->id,
            ),
        )
    );
}

Если надо использовать теги через модель (например, для назначения им своего поведения), используйте класс EARTaggableBehavior

Добавить в секцию import настроек строку подключения директории расшриения taggable

return array(
  // ...
  'import'=>array(
        'application.models.*',
        'application.components.*',
        'ext.yiiext.behaviors.model.taggable.*',
        // ...
        // другие импорты
    ),
    // ...
);

Определить в модели ActiveRecord метод behaviors():

function behaviors() {
    return array(
        'tags_with_model' => array(
            'class' => 'ext.yiiext.behaviors.model.taggable.EARTaggableBehavior',
            // Имя таблицы для хранения тегов
            'tagTable' => 'Tag',
            // Имя модели тега
            'tagModel' => 'Tag',
            // ...
            // остальные нужные параметры указываются также, как и выше
        )
    );
}

Методы

setTags($tags)

Задаёт новые теги для модели затирая старые.

$post = new Post();
$post->setTags('tag1, tag2, tag3')->save();

addTags($tags) или addTag($tags)

Добавляет один или несколько тегов к уже существующим.

$post->addTags('new1, new2')->save();

removeTags($tags) или removeTag($tags)

Удаляет указанные теги (если есть).

$post->removeTags('new1')->save();

removeAllTags()

Удаляет все теги данной модели.

$post->removeAllTags()->save();

getTags()

Отдаёт массив тегов.

$tags = $post->getTags();
foreach($tags as $tag){
  echo $tag;
}

hasTag($tags) или hasTags($tags)

Назаначены ли модели указанные теги.

$post = Post::model()->findByPk(1);
if($post->hasTags("yii, php")){
    //
}

getAllTags()

Отдаёт все имеющиеся для этого класса моделей теги.

$tags = Post::model()->getAllTags();
foreach($tags as $tag){
  echo $tag;
}

getAllTagsWithModelsCount()

Отдаёт все имеющиеся для этого класса модели теги с количеством моделей для каждого.

$tags = Post::model()->getAllTagsWithModelsCount();
foreach($tags as $tag){
  echo $tag['name']." (".$tag['count'].")";
}

taggedWith($tags) или withTags($tags)

Позволяет ограничить запрос AR записями с указанными тегами.

$posts = Post::model()->taggedWith('php, yii')->findAll();
$postCount = Post::model()->taggedWith('php, yii')->count();

resetAllTagsCache() и resetAllTagsWithModelsCountCache()

Используются для сборса кеша getAllTags() и getAllTagsWithModelsCount().

Приятные бонусы

Теги, разделённые запятой можно распечатать следующим образом:

$post->addTags('new1, new2')->save();
echo $post->tags->toString();

Использование нескольких групп тегов

Модели можно присвоить теги из нескольких групп. Например, для модели Software можно задать теги групп OS и Category.

Для этого необходимо создать по две таблицы на каждую группу тегов:

/* Tag table */
CREATE TABLE `Os` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `Os_name` (`name`)
);
 
/* Tag binding table */
CREATE TABLE `PostOs` (
  `post_id` INT(10) UNSIGNED NOT NULL,
  `osId` INT(10) UNSIGNED NOT NULL,
  PRIMARY KEY  (`post_id`,`osId`)
);
 
/* Tag table */
CREATE TABLE `Category` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `Category_name` (`name`)
);
 
/* Tag binding table */
CREATE TABLE `PostCategory` (
  `post_id` INT(10) UNSIGNED NOT NULL,
  `categoryId` INT(10) UNSIGNED NOT NULL,
  PRIMARY KEY  (`post_id`,`categoryId`)
);

Затем прописать для модели поведения:

return array(
    'categories' => array(
        'class' => 'ext.yiiext.behaviors.model.taggable.ETaggableBehavior',
        'tagTable' => 'Category',
        'tagBindingTable' => 'PostCategory',
        'tagBindingTableTagId' => 'categoryId',
    ),
    'os' => array(
        'class' => 'ext.yiiext.behaviors.model.taggable.ETaggableBehavior',
        'tagTable' => 'Os',
        'tagBindingTable' => 'PostOs',
        'tagBindingTableTagId' => 'osId',
    ),
);

Далее можно писать такой код:

$soft = Software::model()->findByPk(1);
// по умолчанию идут методы подключенного выше поведения,
// поэтому можно не писать $soft->categories->addTag("Antivirus"),
// а использовать краткую форму:
$soft->addTag("Antivirus");
$soft->os->addTag("Windows");
$soft->save();

Использование с CAutoComplete

<?$this->widget('CAutoComplete', array(
    'name' => 'tags',
    'value' => $model->tags->toString(),
    'url'=>'/autocomplete/tags', //путь к URL для дополнения тегов
    'multiple'=>true,
    'mustMatch'=>false,
    'matchCase'=>false,
)) ?>

Сохранение тегов будет выглядеть так:

function actionUpdate(){
    $model = Post::model()->findByPk($_GET['id']);
 
    if(isset($_POST['Post'])){
        $model->attributes=$_POST['Post'];
        $model->setTags($_POST['tags']);
 
        // если у вас более одной группы тегов:
        // $model->tags1->setTags($_POST['tags1']);
        // $model->tags1->setTags($_POST['tags2']);
 
        if($model->save()) $this->redirect(array('index'));
    }
    $this->render('update',array(
        'model'=>$model,
    ));
}

Changelog

1.5

  • updateCount now uses proper PK name (RSol)

1.4

  • Change CacheID defaults to false. If false don't use cache.
  • Fixed phpDoc
  • Fixed cache key generation (Sam Dark)
  • Fixed English docs (Sam Dark)
  • #27: Fixed typos (Sam Dark)

1.3

  • Tag table primary key is no longer hardcoded as id and can be set via tagTablePk.
  • Additional values inserting support (mitallast).
  • Default scope criteria support (mitallast).
  • Better criteria support (mitallast).
  • Files and classnames are renamed to ETaggableBehavior and EARTaggableBehavior.
  • Added criteria support to ETagListWidget.
  • More flexibility for ETagListWidget url.

1.2

  • Fixed getting tags array from string with separator at the end or beginning of line.
  • Fixed getting wrong ids when using withTags() or taggedWith().
  • ETagListWidget.
  • Added getTagsWithModelsCount().
  • getAllTagsWithModelsCount now can accept criteria.
  • Input is being passed through strip_tags now.

1.1

  • DBConnection is now saved in a private variable for better perfomance.
  • Added tagTableName property that allows customizing name field http://code.google.com/p/yiiext/issues/detail?id=12
  • Added tagTableCount property specifying counter field for storing tag count in database http://code.google.com/p/yiiext/issues/detail?id=17
  • New subclass EARTaggableBehaviour for using behavior along with Tags model http://code.google.com/p/yiiext/issues/detail?id=13

1.0.2

  • New manual section: using taggable with CAutoComplete.
  • Renamed __toString to toString since magic was hard to debug in case of failure.
  • Fixed more possible cache keys overlap when using multiple tag sets within one model.

1.0.1

  • New naming conventions.

1.0

  • More PHPDoc documentation.
  • Fixed possible cache keys overlap when using multiple tag sets within one model.

0.9

Warning: this version is not compatible with Yii 1.0.

  • Added resetAllTagsCache() and resetAllTagsWithModelsCountCache().
  • Fixed getAllTags() and getAllTagsWithModelsCount() cache issues.
  • Now tags are saved on save() only if they were changed.
  • Extension is now compatible only with Yii 1.1.
  • Fixed saving empty tags.
  • Fixed caching.

0.8

Warning: this version is not backwards compatible to 0.6.

  • Now you can set tagId field name for binding table.
  • Do not try to delete tag bindings when inserting new record.
  • Added taggedWith() alias withTags().
  • Removed getCountByTags(), findAllByTags(). Use taggedWith().
  • Method chaining: $post->addTags("yii, php")->save();
  • New syntax: $posts = Post::model()->taggedWith(array('php', 'yii'))->findAll();
  • Added parent:: calls in event handlers.
  • Added hasTags() and it's alias hasTag() to check if all tags specified are attached to current model.
  • New syntax: echo $post->tags (or by what name behaviour is attached) will print comma separated tags.
  • getTags now returns array since implode is really easy to do yourself.
  • Removed getTagsArray().
  • addTags(), removeTags(), setTags() are now accept both string and array.
  • Added addTag() as alias of addTags(), removeTag() as alias of removeTags().
  • Some methods are now protected.
  • Added $with to findAllByTags().
  • getAllTags().
  • Unit tests.
  • createTagsAutomatically option allows to throw exception when adding nonexisting tag.

0.6

  • Initial public release.

Provides many useful methods and named scopes to work with model tags.

Documentation

Downloads (Tags)

Resources