Skip to content

Commit

Permalink
tags beta
Browse files Browse the repository at this point in the history
  • Loading branch information
noumo committed May 22, 2015
1 parent dca2b38 commit 25b661e
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 3 deletions.
133 changes: 133 additions & 0 deletions behaviors/Taggable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php
namespace yii\easyii\behaviors;

use Yii;
use yii\db\ActiveRecord;
use yii\easyii\models\Tag;
use yii\easyii\models\TagAssign;

class Taggable extends \yii\base\Behavior
{
public $tagValues;
private $_tags;

public function events()
{
return [
ActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
];
}

public function getTagAssigns()
{
return $this->owner->hasMany(TagAssign::className(), ['item_id' => $this->owner->primaryKey()[0]])->where(['class' => get_class($this->owner)]);
}

public function getTags()
{
return $this->owner->hasMany(Tag::className(), ['tag_id' => 'tag_id'])->via('tagAssigns');
}

public function canGetProperty($name, $checkVars = true)
{
if ($name === 'tagNames') {
return true;
}
return parent::canGetProperty($name, $checkVars);
}

public function __get($name)
{
return $name == 'tagNames' ? $this->getTagNames() : $this->getTagsArray();
}

public function canSetProperty($name, $checkVars = true)
{
if ($name === 'tagNames') {
return true;
}
return parent::canSetProperty($name, $checkVars);
}

public function __set($name, $value)
{
$this->tagValues = $value;
}

private function getTagNames()
{
return implode(', ', $this->getTagsArray());
}

public function getTagsArray()
{
if($this->_tags === null){
$this->_tags = [];
foreach($this->getTags()->all() as $tag) {
$this->_tags[] = $tag->name;
}
}
return $this->_tags;
}

public function afterSave()
{
$names = $this->filterTagValues($this->tagValues);

if ($this->tagValues === null) {
$this->tagValues = $this->owner->tagNames;
}
if (!$this->owner->isNewRecord) {
$this->beforeDelete();
}

$tagAssigns = [];
$modelClass = get_class($this->owner);
foreach ($names as $name) {
if(!($tag = Tag::findOne(['name' => $name]))) {
$tag = new Tag(['name' => $name]);
}
$tag->frequency++;
if ($tag->save()) {
$updatedTags[] = $tag;
$tagAssigns[] = [$modelClass, $this->owner->primaryKey, $tag->tag_id];
}
}

Yii::$app->db->createCommand()->batchInsert(TagAssign::tableName(), ['class', 'item_id', 'tag_id'], $tagAssigns)->execute();

$this->owner->populateRelation('tags', $updatedTags);
}

public function beforeDelete()
{
$pks = [];

foreach($this->getTags()->all() as $tag){
$pks[] = $tag->primaryKey;
}

if (count($pks)) {
Tag::updateAllCounters(['frequency' => -1], ['in', 'tag_id', $pks]);
}
Tag::deleteAll(['frequency' => 0]);
TagAssign::deleteAll(['class' => get_class($this->owner), 'item_id' => $this->owner->primaryKey]);
}

/**
* Filters tags.
* @param string|string[] $values
* @return string[]
*/
public function filterTagValues($values)
{
return array_unique(preg_split(
'/\s*,\s*/u',
preg_replace('/\s+/u', ' ', is_array($values) ? implode(',', $values) : $values),
-1,
PREG_SPLIT_NO_EMPTY
));
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"creocoder/yii2-nested-sets": "0.9.*",
"bower-asset/fancybox": "*",
"bower-asset/jquery.switcher": "*",
"bower-asset/eonasdan-bootstrap-datetimepicker": "^4.7@dev"
"bower-asset/eonasdan-bootstrap-datetimepicker": "^4.7@dev",
"2amigos/yii2-selectize-widget": "~1.0"
},
"autoload": {
"psr-4": {
Expand Down
23 changes: 23 additions & 0 deletions controllers/TagsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
namespace yii\easyii\controllers;

use Yii;
use yii\easyii\models\Tag;
use yii\helpers\Html;
use yii\web\Response;

class TagsController extends \yii\easyii\components\Controller
{
public function actionList($query)
{
Yii::$app->response->format = Response::FORMAT_JSON;

$items = [];
$query = urldecode(mb_convert_encoding($query, "UTF-8"));
foreach (Tag::find()->where(['like', 'name', $query])->asArray()->all() as $tag) {
$items[] = ['name' => $tag['name']];
}

return $items;
}
}
1 change: 1 addition & 0 deletions messages/ru/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'Text' => 'Текст',
'Date' => 'Дата',
'Slug' => 'Метка',
'Tags' => 'Список тэгов',
'Status' => 'Состояние',
'Image' => 'Изображение',
'File' => 'Файл',
Expand Down
16 changes: 16 additions & 0 deletions migrations/m000000_000000_install.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,22 @@ public function up()
], 'ENGINE=MyISAM DEFAULT CHARSET=utf8');
$this->createIndex('slug', Text::tableName(), 'slug', true);

//Tags
$this->createTable(models\Tag::tableName(), [
'tag_id' => 'pk',
'name' => Schema::TYPE_STRING . '(128) NOT NULL',
'frequency' => Schema::TYPE_INTEGER . "DEFAULT '0'"
], 'ENGINE=MyISAM DEFAULT CHARSET=utf8');
$this->createIndex('name', models\Tag::tableName(), 'name', true);

$this->createTable(models\TagAssign::tableName(), [
'class' => Schema::TYPE_STRING . '(128) NOT NULL',
'item_id' => Schema::TYPE_INTEGER . "NOT NULL",
'tag_id' => Schema::TYPE_INTEGER . "NOT NULL",
], 'ENGINE=MyISAM DEFAULT CHARSET=utf8');
$this->createIndex('class', models\Tag::tableName(), 'class');
$this->createIndex('item_tag', models\Tag::tableName(), ['item_id', 'tag_id']);

//INSERT VERSION
$this->delete(models\Setting::tableName(), ['name' => 'easyii_version']);
$this->insert(models\Setting::tableName(), [
Expand Down
19 changes: 19 additions & 0 deletions models/Tag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
namespace yii\easyii\models;

class Tag extends \yii\easyii\components\ActiveRecord
{
public static function tableName()
{
return 'easyii_tags';
}

public function rules()
{
return [
['name', 'required'],
['frequency', 'integer'],
['name', 'string', 'max' => 64],
];
}
}
10 changes: 10 additions & 0 deletions models/TagAssign.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace yii\easyii\models;

class TagAssign extends \yii\easyii\components\ActiveRecord
{
public static function tableName()
{
return 'easyii_tags_assign';
}
}
4 changes: 4 additions & 0 deletions modules/article/models/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Yii;
use yii\behaviors\SluggableBehavior;
use yii\easyii\behaviors\SeoBehavior;
use yii\easyii\behaviors\Taggable;
use yii\easyii\models\Photo;
use yii\helpers\StringHelper;

Expand All @@ -29,6 +30,7 @@ public function rules()
['slug', 'match', 'pattern' => self::$SLUG_PATTERN, 'message' => Yii::t('easyii', 'Slug can contain only 0-9, a-z and "-" characters (max: 128).')],
['slug', 'default', 'value' => null],
['status', 'default', 'value' => self::STATUS_ON],
['tagNames', 'safe']
];
}

Expand All @@ -41,13 +43,15 @@ public function attributeLabels()
'image' => Yii::t('easyii', 'Image'),
'time' => Yii::t('easyii', 'Date'),
'slug' => Yii::t('easyii', 'Slug'),
'tagNames' => Yii::t('easyii', 'Tags'),
];
}

public function behaviors()
{
return [
'seoBehavior' => SeoBehavior::className(),
'taggable' => Taggable::className(),
'sluggable' => [
'class' => SluggableBehavior::className(),
'attribute' => 'title',
Expand Down
3 changes: 2 additions & 1 deletion modules/article/views/items/_form.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
use yii\easyii\helpers\Image;
use yii\easyii\widgets\DateTimePicker;
use yii\easyii\widgets\TagsInput;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\widgets\ActiveForm;
Expand Down Expand Up @@ -37,7 +38,7 @@
]) ?>

<?= $form->field($model, 'time')->widget(DateTimePicker::className()); ?>

<?= $form->field($model, 'tagNames')->widget(TagsInput::className()) ?>


<?php if(IS_ROOT) : ?>
Expand Down
8 changes: 7 additions & 1 deletion modules/news/models/News.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Yii;
use yii\behaviors\SluggableBehavior;
use yii\easyii\behaviors\SeoBehavior;
use yii\easyii\behaviors\Taggable;
use yii\easyii\models\Photo;
use yii\helpers\StringHelper;

Expand All @@ -29,6 +30,7 @@ public function rules()
['slug', 'match', 'pattern' => self::$SLUG_PATTERN, 'message' => Yii::t('easyii', 'Slug can contain only 0-9, a-z and "-" characters (max: 128).')],
['slug', 'default', 'value' => null],
['status', 'default', 'value' => self::STATUS_ON],
['tagNames', 'safe']
];
}

Expand All @@ -41,18 +43,20 @@ public function attributeLabels()
'image' => Yii::t('easyii', 'Image'),
'time' => Yii::t('easyii', 'Date'),
'slug' => Yii::t('easyii', 'Slug'),
'tagNames' => Yii::t('easyii', 'Tags'),
];
}

public function behaviors()
{
return [
'seoBehavior' => SeoBehavior::className(),
'taggable' => Taggable::className(),
'sluggable' => [
'class' => SluggableBehavior::className(),
'attribute' => 'title',
'ensureUnique' => true
]
],
];
}

Expand All @@ -61,6 +65,8 @@ public function getPhotos()
return $this->hasMany(Photo::className(), ['item_id' => 'news_id'])->where(['class' => self::className()])->sort();
}



public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
Expand Down
2 changes: 2 additions & 0 deletions modules/news/views/a/_form.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
use yii\easyii\widgets\DateTimePicker;
use yii\easyii\helpers\Image;
use yii\easyii\widgets\TagsInput;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\widgets\ActiveForm;
Expand Down Expand Up @@ -34,6 +35,7 @@
]) ?>

<?= $form->field($model, 'time')->widget(DateTimePicker::className()); ?>
<?= $form->field($model, 'tagNames')->widget(TagsInput::className()) ?>

<?php if(IS_ROOT) : ?>
<?= $form->field($model, 'slug') ?>
Expand Down
17 changes: 17 additions & 0 deletions widgets/TagsInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
namespace yii\easyii\widgets;

use dosamigos\selectize\SelectizeTextInput;

class TagsInput extends SelectizeTextInput
{
public $options = ['class' => 'form-control'];
public $loadUrl = ['/admin/tags/list'];
public $clientOptions = [
'plugins' => ['remove_button'],
'valueField' => 'name',
'labelField' => 'name',
'searchField' => ['name'],
'create' => true,
];
}

0 comments on commit 25b661e

Please sign in to comment.