6 function &getInstance(&$db) {
8 if (!isset($instance)) {
9 $instance = new TagService($db);
14 function TagService(&$db) {
16 $this->tablename = $GLOBALS['tableprefix'] .'tags';
19 function isNotSystemTag($var) {
20 return !(utf8_substr($var, 0, 7) == 'system:');
23 function attachTags($bookmarkid, $tags, $fromApi = false, $extension = NULL, $replace = true, $fromImport = false) {
24 // Make sure that categories is an array of trimmed strings, and that if the categories are
25 // coming in from an API call to add a bookmark, that underscores are converted into strings.
26 if (!is_array($tags)) {
29 if (substr($tags, -1) == ',') {
30 $tags = substr($tags, 0, -1);
33 $tags = explode(' ', $tags);
35 $tags = explode(',', $tags);
42 $tags_count = count($tags);
43 for ($i = 0; $i < $tags_count; $i++) {
44 $tags[$i] = trim(strtolower($tags[$i]));
46 include_once dirname(__FILE__) .'/../functions.inc.php';
47 $tags[$i] = convertTag($tags[$i], 'in');
51 if ($tags_count > 0) {
53 $tags = array_filter($tags, array($this, "isNotSystemTag"));
55 // Eliminate any duplicate categories
56 $temp = array_unique($tags);
57 $tags = array_values($temp);
60 $tags[] = 'system:unfiled';
63 // Media and file types
64 if (!is_null($extension)) {
65 include_once dirname(__FILE__) .'/../functions.inc.php';
66 if ($keys = multi_array_search($extension, $GLOBALS['filetypes'])) {
67 $tags[] = 'system:filetype:'. $extension;
68 $tags[] = 'system:media:'. array_shift($keys);
74 $tags[] = 'system:imported';
77 $this->db->sql_transaction('begin');
80 if (!$this->deleteTagsForBookmark($bookmarkid)){
81 $this->db->sql_transaction('rollback');
82 message_die(GENERAL_ERROR, 'Could not attach tags (deleting old ones failed)', '', __LINE__, __FILE__, $sql, $this->db);
87 // Add the categories to the DB.
88 for ($i = 0; $i < count($tags); $i++) {
89 if ($tags[$i] != '') {
91 'bId' => intval($bookmarkid),
95 if (!$this->hasTag($bookmarkid, $tags[$i])) {
96 $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values);
97 if (!($dbresult =& $this->db->sql_query($sql))) {
98 $this->db->sql_transaction('rollback');
99 message_die(GENERAL_ERROR, 'Could not attach tags', '', __LINE__, __FILE__, $sql, $this->db);
105 $this->db->sql_transaction('commit');
109 function deleteTag($tag) {
110 $userservice =& ServiceFactory::getServiceInstance('UserService');
111 $logged_on_user = $userservice->getCurrentUserId();
113 $query = 'DELETE FROM '. $this->getTableName() .' USING '. $GLOBALS['tableprefix'] .'tags, '. $GLOBALS['tableprefix'] .'bookmarks WHERE '. $GLOBALS['tableprefix'] .'tags.bId = '. $GLOBALS['tableprefix'] .'bookmarks.bId AND '. $GLOBALS['tableprefix'] .'bookmarks.uId = '. $logged_on_user .' AND '. $GLOBALS['tableprefix'] .'tags.tag = "'. $this->db->sql_escape($tag) .'"';
115 if (!($dbresult =& $this->db->sql_query($query))) {
116 message_die(GENERAL_ERROR, 'Could not delete tags', '', __LINE__, __FILE__, $query, $this->db);
123 function deleteTagsForBookmark($bookmarkid) {
124 if (!is_int($bookmarkid)) {
125 message_die(GENERAL_ERROR, 'Could not delete tags (invalid bookmarkid)', '', __LINE__, __FILE__, $query);
129 $query = 'DELETE FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid);
131 if (!($dbresult =& $this->db->sql_query($query))) {
132 message_die(GENERAL_ERROR, 'Could not delete tags', '', __LINE__, __FILE__, $query, $this->db);
139 function &getTagsForBookmark($bookmarkid) {
140 if (!is_int($bookmarkid)) {
141 message_die(GENERAL_ERROR, 'Could not get tags (invalid bookmarkid)', '', __LINE__, __FILE__, $query);
145 $query = 'SELECT tag FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND LEFT(tag, 7) <> "system:" ORDER BY tag';
147 if (!($dbresult =& $this->db->sql_query($query))) {
148 message_die(GENERAL_ERROR, 'Could not get tags', '', __LINE__, __FILE__, $query, $this->db);
153 while ($row =& $this->db->sql_fetchrow($dbresult)) {
154 $tags[] = $row['tag'];
160 function &getTags($userid = NULL) {
161 $userservice =& ServiceFactory::getServiceInstance('UserService');
162 $logged_on_user = $userservice->getCurrentUserId();
164 $query = 'SELECT T.tag, COUNT(B.bId) AS bCount FROM '. $GLOBALS['tableprefix'] .'bookmarks AS B INNER JOIN '. $userservice->getTableName() .' AS U ON B.uId = U.'. $userservice->getFieldName('primary') .' INNER JOIN '. $GLOBALS['tableprefix'] .'tags AS T ON B.bId = T.bId';
166 $conditions = array();
167 if (!is_null($userid)) {
168 $conditions['U.'. $userservice->getFieldName('primary')] = intval($userid);
169 if ($logged_on_user != $userid)
170 $conditions['B.bStatus'] = 0;
172 $conditions['B.bStatus'] = 0;
175 $query .= ' WHERE '. $this->db->sql_build_array('SELECT', $conditions) .' AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC, tag';
177 if (!($dbresult =& $this->db->sql_query($query))) {
178 message_die(GENERAL_ERROR, 'Could not get tags', '', __LINE__, __FILE__, $query, $this->db);
181 return $this->db->sql_fetchrowset($dbresult);
185 // Returns the tags related to the specified tags; i.e. attached to the same bookmarks
186 function &getRelatedTags($tags, $for_user = NULL, $logged_on_user = NULL, $limit = 10) {
187 $conditions = array();
188 // Only count the tags that are visible to the current user.
189 if ($for_user != $logged_on_user || is_null($for_user))
190 $conditions['B.bStatus'] = 0;
192 if (!is_null($for_user))
193 $conditions['B.uId'] = $for_user;
195 // Set up the tags, if need be.
196 if (is_numeric($tags))
198 if (!is_array($tags) and !is_null($tags))
199 $tags = explode('+', trim($tags));
201 $tagcount = count($tags);
202 for ($i = 0; $i < $tagcount; $i++) {
203 $tags[$i] = trim($tags[$i]);
206 // Set up the SQL query.
207 $query_1 = 'SELECT DISTINCTROW T0.tag, COUNT(B.bId) AS bCount FROM '. $GLOBALS['tableprefix'] .'bookmarks AS B, '. $this->getTableName() .' AS T0';
209 $query_3 = ' WHERE B.bId = T0.bId ';
210 if (count($conditions) > 0)
211 $query_4 = ' AND '. $this->db->sql_build_array('SELECT', $conditions);
214 // Handle the parts of the query that depend on any tags that are present.
215 for ($i = 1; $i <= $tagcount; $i++) {
216 $query_2 .= ', '. $this->getTableName() .' AS T'. $i;
217 $query_4 .= ' AND T'. $i .'.bId = B.bId AND T'. $i .'.tag = "'. $this->db->sql_escape($tags[$i - 1]) .'" AND T0.tag <> "'. $this->db->sql_escape($tags[$i - 1]) .'"';
219 $query_5 = ' AND LEFT(T0.tag, 7) <> "system:" GROUP BY T0.tag ORDER BY bCount DESC, T0.tag';
220 $query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5;
222 if (! ($dbresult =& $this->db->sql_query_limit($query, $limit)) ){
223 message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db);
226 return $this->db->sql_fetchrowset($dbresult);
229 // Returns the most popular tags used for a particular bookmark hash
230 function &getRelatedTagsByHash($hash, $limit = 20) {
231 $userservice = & ServiceFactory :: getServiceInstance('UserService');
232 $sId = $userservice->getCurrentUserId();
234 if ($userservice->isLoggedOn()) {
235 $arrWatch = $userservice->getWatchList($sId);
236 // From public bookmarks or user's own
237 $privacy = ' AND ((B.bStatus = 0) OR (B.uId = '. $sId .')';
238 // From shared bookmarks in watchlist
239 foreach ($arrWatch as $w) {
240 $privacy .= ' OR (B.uId = '. $w .' AND B.bStatus = 1)';
245 $privacy = ' AND B.bStatus = 0 ';
248 $query = 'SELECT T.tag, COUNT(T.tag) AS bCount FROM sc_bookmarks AS B LEFT JOIN sc_tags AS T ON B.bId = T.bId WHERE B.bHash = "'. $hash .'" '. $privacy .'AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC';
250 if (!($dbresult =& $this->db->sql_query_limit($query, $limit))) {
251 message_die(GENERAL_ERROR, 'Could not get related tags for this hash', '', __LINE__, __FILE__, $query, $this->db);
254 return $this->db->sql_fetchrowset($dbresult);
257 function &getPopularTags($user = NULL, $limit = 30, $logged_on_user = NULL, $days = NULL) {
258 // Only count the tags that are visible to the current user.
259 if (($user != $logged_on_user) || is_null($user) || ($user === false))
260 $privacy = ' AND B.bStatus = 0';
264 if (is_null($days) || !is_int($days))
267 $span = ' AND B.bDatetime > "'. date('Y-m-d H:i:s', time() - (86400 * $days)) .'"';
269 $query = 'SELECT T.tag, COUNT(T.bId) AS bCount FROM '. $this->getTableName() .' AS T, '. $GLOBALS['tableprefix'] .'bookmarks AS B WHERE ';
270 if (is_null($user) || ($user === false)) {
271 $query .= 'B.bId = T.bId AND B.bStatus = 0';
273 $query .= 'B.uId = '. $this->db->sql_escape($user) .' AND B.bId = T.bId'. $privacy;
275 $query .= $span .' AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC, tag';
277 if (!($dbresult =& $this->db->sql_query_limit($query, $limit))) {
278 message_die(GENERAL_ERROR, 'Could not get popular tags', '', __LINE__, __FILE__, $query, $this->db);
282 return $this->db->sql_fetchrowset($dbresult);
285 function hasTag($bookmarkid, $tag) {
286 $query = 'SELECT COUNT(*) AS tCount FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND tag ="'. $this->db->sql_escape($tag) .'"';
288 if (! ($dbresult =& $this->db->sql_query($query)) ) {
289 message_die(GENERAL_ERROR, 'Could not find tag', '', __LINE__, __FILE__, $query, $this->db);
293 if ($row =& $this->db->sql_fetchrow($dbresult)) {
294 if ($row['tCount'] > 0) {
301 function renameTag($userid, $old, $new, $fromApi = false) {
302 $bookmarkservice =& ServiceFactory::getServiceInstance('BookmarkService');
304 if (is_null($userid) || is_null($old) || is_null($new))
307 // Find bookmarks with old tag
308 $bookmarksInfo =& $bookmarkservice->getBookmarks(0, NULL, $userid, $old);
309 $bookmarks =& $bookmarksInfo['bookmarks'];
312 $this->deleteTag($old);
315 foreach(array_keys($bookmarks) as $key) {
316 $row =& $bookmarks[$key];
317 $this->attachTags($row['bId'], $new, $fromApi, NULL, false);
323 function &tagCloud($tags = NULL, $steps = 5, $sizemin = 90, $sizemax = 225, $sortOrder = NULL) {
325 if (is_null($tags) || count($tags) < 1) {
329 $min = $tags[count($tags) - 1]['bCount'];
330 $max = $tags[0]['bCount'];
332 for ($i = 1; $i <= $steps; $i++) {
333 $delta = ($max - $min) / (2 * $steps - $i);
334 $limit[$i] = $i * $delta + $min;
336 $sizestep = ($sizemax - $sizemin) / $steps;
337 foreach ($tags as $row) {
339 for ($i = 1; $i <= $steps; $i++) {
340 if (!$next && $row['bCount'] <= $limit[$i]) {
341 $size = $sizestep * ($i - 1) + $sizemin;
345 $tempArray = array('size' => $size .'%');
346 $row = array_merge($row, $tempArray);
350 if ($sortOrder == 'alphabet_asc') {
351 usort($output, create_function('$a,$b','return strcmp(utf8_strtolower($a["tag"]), utf8_strtolower($b["tag"]));'));
358 function getTableName() { return $this->tablename; }
359 function setTableName($value) { $this->tablename = $value; }