Логарифмическое облако тегов для Yii Framework

10 Июл
2012


Привет, блог. Недавно для собственных средств потребовалось создать облако тегов. Сразу вспомнил про виджет из демо-блога, но, к сожалению, там использовался линейный алгоритм, результат работы которого оставлял желать лучшего. Было решено написать свое расширение и поделиться им с общественностью.

Установка

Сначало необходимо создать таблицу для хранения тегов, она у нас будет простейшая: id, имя тега, частота.
CREATE TABLE `tags` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `frequency` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


Затем создать модель Tag.php:
<?php

/**
 * @author Troy <troytft@gmail.com>
 */
class Tag extends ActiveRecord
{
    /**
     * Минимальный размер шрифта 
     */
    const MIN_FONT_SIZE = 1;

    /**
     * Максимальный размер шрифта 
     */
    const MAX_FONT_SIZE = 10;

    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }


    public function tableName()
    {
        return '{{tags}}';
    }


    /**
     * Возвращает теги вместе с их весом
     * @param integer $limit число возвращаемых тегов
     * @return array вес с индексом равным имени тега
     */
    public function findTagWeights($limit = 20)
    {
        $tags = array();

        $models = $this->findAll(array(
            'limit' => $limit,
                ));

        $sizeRange = self::MAX_FONT_SIZE - self::MIN_FONT_SIZE;

        $minCount = log(Yii::app()->db->createCommand("SELECT MIN(frequency) FROM " . $this->tableName())->queryScalar() + 1);
        $maxCount = log(Yii::app()->db->createCommand("SELECT MAX(frequency) FROM " . $this->tableName())->queryScalar() + 1);
        $countRange = $maxCount - $minCount;

        foreach ($models as $model)
            $tags[$model->name] = round(self::MIN_FONT_SIZE + (log($model->frequency + 1) - $minCount) * ($sizeRange / $countRange));

        return $tags;
    }


}


Основное «волшебство» происходит в методе findTagWeights()

Ну и создадим простейший виджет для вывода облака, назовем его TagCloud.php:
<?php

/**
 * @author Troy <troytft@gmail.com>
 */
class TagCloud extends CWidget
{

    public $limit = 20;

    public function run()
    {
        $tags = Tag::model()->findTagWeights($this->limit);
        foreach ($tags as $tag => $weight)
            echo CHtml::tag('span', array('style' => "font-size:{$weight}pt"), $tag);
    }


}


Готово, теперь мы можем вывести его в любом месте в шаблоне вызовом
<?php $this->widget('TagCloud', array('limit' => 50)); ?>


Так же код доступен на GitHub
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх