8 August 2008

Опять облако тегов. Только теперь не вывод — а ввод!

Lumber room
В основном в нете везде есть примеры вывода облака тегов. Я бы хотел показать как я храню сами теги в базе и как вообще происходит работа с тегами.

Как я уже говорил, у нас есть таблица где хранятся сами теги

CREATE TABLE `users_tags` (
`id` int(11) unsigned NOT NULL auto_increment,
`text` varchar(255) character set utf8 NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `txt` (`text`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


Тамблица связи тегов

CREATE TABLE `users_fun_photos_tags_data` (
`photo_id` int(11) unsigned NOT NULL,
`tag_id` int(11) unsigned default NULL,
KEY `tag_id` (`tag_id`),
KEY `photo_id` (`photo_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


И таблица где хранятся записи о фотографиях

CREATE TABLE `users_fun_photos` (
`id` int(11) unsigned NOT NULL auto_increment,
`title` varchar(255) default NULL,
`tags` varchar(255) default NULL, /* Здесь теги хранятся в виде строки вида тег1, тег2, тег3 */
`cat_id` int(11) unsigned NOT NULL default '1',
`file` varchar(30) default NULL,
`dir` varchar(3) default NULL,
`user_id` int(11) unsigned default '1',
`date` datetime NOT NULL default '0000-00-00 00:00:00',
`date_last_comment` datetime default NULL,
`comments` int(11) unsigned NOT NULL default '0',
`views` int(11) NOT NULL default '0',
`points` int(11) default '0',
PRIMARY KEY (`id`),
KEY `views` (`views`),
KEY `user_id` (`user_id`),
KEY `comments` (`comments`),
KEY `cat_id` (`cat_id`),
KEY `title` (`title`),
KEY `tags` (`tags`),
KEY `date` (`date`),
KEY `date_last_comment` (`date_last_comment`),
KEY `points` (`points`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


Обратите внимание на COLLATE=utf8_general_ci — это значит что сравнение для текстовых полей будет регистронезависимым.

Теперь сам код. Идете туда где у вас загружается картинка на сервер.

/* Получаем то что юзер ввел в поле <input type=«text» value=«php,mysql,html,css» name=«tags»> */
$photo_tags = $cms->ValidatePostVar('tags');


/* Далее (у меня) идет код добавление информации в базу о загруженной картинке — здвеь нас интересует только поле tags в которое теги добавляются строкой как их ввел юзер (проверку на разрешенные символы и т.д. это уже сами сделаете */
sql_query(«INSERT INTO „.$prefix.“_users_fun_photos (id, title, tags, cat_id, file, user_id, date, comments, views) VALUES (NULL, '».$photo_title."', '".$photo_tags."', 1, '".$obj->GetNewFileName()."', '".$cms->user_id."', NOW(), 0, 0)", $dbi);


/* Получаем ID записи о загруженной картинке */
$generated_id = mysql_insert_id();


/* И вызываем функцию обработки введенных юзером тегов, с нужными параметрами */
$fun->TagsDataInsert($photo_tags, $generated_id);


А вот сама магическая функция:

function TagsDataInsert($photo_tags, $photo_id)
{
global $prefix, $dbi, $section_folder, $cms;

/* Удаляем старую связь тегов к картинке — используется у меня при редактировании данных о картинке, то есть для обработки сохранения изменений в тегах для редактируемой картинки используется тоже эта функция */
sql_query(«DELETE FROM „.$prefix.“_users_fun_photos_tags_data WHERE photo_id='».$photo_id."'", $dbi);

# Если пользоветель ввел теги — едем дальше
if ($photo_tags)
{
/* Создаем массив введенных тегов */
$tags_array = explode(',', $photo_tags);
/* Удаляем пробелы */
array_walk($tags_array, array($this, 'trim_value'));
/* Проходимся по массиву, и вносим теги в таблицу тегов — в случае если такой тег уже существует — просто обновляем текстовое поле */
foreach ($tags_array as $value)
{
sql_query(«INSERT INTO „.$prefix.“_users_tags (id, text) VALUES (NULL, '».adsl($value)."') ON DUPLICATE KEY UPDATE text='".adsl($value)."'", $dbi);
/* Функция mysql_insert_id хороша тем что она возращает id не только вновь созданного ключа, но и обнавленного */
$generated_tag_id = mysql_insert_id();
/* Пишем данные в таблицу связей */
sql_query(«INSERT INTO „.$prefix.“_users_fun_photos_tags_data (photo_id, tag_id) VALUES ('».$photo_id."','".$generated_tag_id."')", $dbi);
}
}
}


Давайте добавим теги из поля
<input type=«text» value=«php,mysql,html,css» name=«tags»>


В итоге в таблице user_tags будут у нас сами теги и их id



В таблице связи users_fun_photos_tags_data будут данные



Ну и в таблице users_fun_photos в поле tags теги у нас в виде строки php,mysql,html,css



Ну а теперь о том почему в таблице users_fun_photos в поле tags мы храним данные в виде строки —
php,mysql,html,css


1 — Кто то скажет что это не правильно — и в какой то степени будет прав, но — мне просто легче выводить потом теги при показе картинки вот так, без заморочки с объединением таблиц:

if (!empty($photo_tags)) $photo_tags = explode(',', $photo_tags);
$smarty->assign('photo_tags', $photo_tags);

<div class=«tags» style=«color:#777777;»>Теги → {foreach from=$photo_tags item=item}<a title="{$item}" href=«index.php?section=Fun&file=search&tag={$item}»>{$item}</a>, {/foreach}</div>


2. Как видно из пункта 1 — — поиск записей с тегом будет осуществляться не по tag_id а по тексту тега. Для чего? Просто в скрипте поиска картинок по тегам есть возможность искать не только по tag_id когда мы нажимаем на тег в облаке тегов — но и по тексту тега когда юзер вводит искомый тег в поле input

/* Здесь мы просто берем данные а том был введен id тега или просто текст */
$tag = urldecode($cms->ValidateGetVar('tag'));
$get_tag_id = (int)$cms->ValidateGetVar('tag_id');

/* Здесь проверка на то что было введено — и в конечном итоге получаем id тега если введен id а не текст, и наоборот */
if ($tag && !$get_tag_id)
{
$res = sql_query(«SELECT id FROM „.$prefix.“_users_tags where text='».adsl($tag)."'", $dbi);
list($get_tag_id) = sql_fetch_row($res);
}
else if (!$tag && $get_tag_id)
{
$res = sql_query(«SELECT text FROM „.$prefix.“_users_tags where id='».$get_tag_id."'", $dbi);
list($tag) = sql_fetch_row($res);
}

/* В конечном итоге все равно вывод картинки с искомым тегом будет производиться по tag_id */
$res = sql_query(«SELECT SQL_CALC_FOUND_ROWS a.user_id, a.user_nick, b.id, b.title, b.tags, b.cat_id, b.file, b.dir, DATE_FORMAT(b.date, '%d.%m.%Y? %H:%i:%s'), b.comments, b.views, b.points FROM „.$prefix.“_users a, „.$prefix.“_users_fun_photos b, „.$prefix.“_users_fun_photos_tags_data c where b.id=c.photo_id and a.user_id=b.user_id and c.tag_id='».$get_tag_id."' order by b.id DESC limit ".$offset.", ".$on_page."", $dbi);


Вобщем насчет пункта 2 и хранения данных в виде строки в поле tags можно поспорить :)
Tags:phpmysqlоблако теговтеги
Hubs: Lumber room
+1
410 19
Comments 10
Top of the last 24 hours