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
idand can be set viatagTablePk. - 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.