| [ Index ] |
|
Code source de vtiger CRM 5.0.2 |
1 <?php 2 /** 3 * Gordon Luk's Freetag - Generalized Open Source Tagging and Folksonomy. 4 * Copyright (C) 2004-2005 Gordon D. Luk <gluk AT getluky DOT net> 5 * 6 * Released under both BSD license and Lesser GPL library license. Whenever 7 * there is any discrepancy between the two licenses, the BSD license will 8 * take precedence. See License.txt. 9 * 10 */ 11 /** 12 * Freetag API Implementation 13 * 14 * Freetag is a generic PHP class that can hook-in to existing database 15 * schemas and allows tagging of content within a social website. It's fun, 16 * fast, and easy! Try it today and see what all the folksonomy fuss is 17 * about. 18 * 19 * Contributions and/or donations are welcome. 20 * 21 * Author: Gordon Luk 22 * http://www.getluky.net 23 * 24 * Version: 0.240 25 * Last Updated: 12/26/2005 26 * 27 */ 28 29 class freetag { 30 31 /**#@+ 32 * @access private 33 * @param string 34 */ 35 /**#@-*/ 36 37 /** 38 * @access private 39 * @param ADOConnection The ADODB Database connection instance. 40 */ 41 //var $_db; 42 /** 43 * @access private 44 * @param bool Prints out limited debugging information if true, not fully implemented yet. 45 */ 46 var $_debug = FALSE; 47 /** 48 * @access private 49 * @param string The prefix of freetag database vtiger_tables. 50 */ 51 var $_table_prefix = 'vtiger_'; 52 /** 53 * @access private 54 * @param string The regex-style set of characters that are valid for normalized tags. 55 */ 56 var $_normalized_valid_chars = 'a-zA-Z0-9'; 57 /** 58 * @access private 59 * @param string Whether to normalize tags at all. 60 * value 0 saves the tag in case insensitive mode 61 * value 1 save the tag in lower case 62 */ 63 var $_normalize_tags = 0; 64 /** 65 * @access private 66 * @param string Whether to prevent multiple vtiger_users from tagging the same object. By default, set to block (ala Upcoming.org) 67 */ 68 var $_block_multiuser_tag_on_object =0; 69 /** 70 * @access private 71 * @param bool Whether to use persistent ADODB connections. False by default. 72 */ 73 //var $_PCONNECT = FALSE; 74 /** 75 * @access private 76 * @param int The maximum length of a tag. 77 */ 78 var $_MAX_TAG_LENGTH = 30; 79 /** 80 * @access private 81 * @param string The file path to the installation of ADOdb used. 82 */ 83 //var $_ADODB_DIR = 'adodb/'; 84 85 /** 86 * freetag 87 * 88 * Constructor for the freetag class. 89 * 90 * @param array An associative array of options to pass to the instance of Freetag. 91 * The following options are valid: 92 * - debug: Set to TRUE for debugging information. [default:FALSE] 93 * - db: If you've already got an ADODB ADOConnection, you can pass it directly and Freetag will use that. [default:NULL] 94 * - db_user: Database username 95 * - db_pass: Database password 96 * - db_host: Database hostname [default: localhost] 97 * - db_name: Database name 98 * - vtiger_table_prefix: If you wish to create multiple Freetag databases on the same database, you can put a prefix in front of the vtiger_table names and pass separate prefixes to the constructor. [default: ''] 99 * - normalize_tags: Whether to normalize (lowercase and filter for valid characters) on tags at all. [default: 1] 100 * - normalized_valid_chars: Pass a regex-style set of valid characters that you want your tags normalized against. [default: 'a-zA-Z0-9' for alphanumeric] 101 * - block_multiuser_tag_on_object: Set to 0 in order to allow individual vtiger_users to all tag the same object with the same tag. Default is 1 to only allow one occurence of a tag per object. [default: 1] 102 * - MAX_TAG_LENGTH: maximum length of normalized tags in chars. [default: 30] 103 * - ADODB_DIR: directory in which adodb is installed. Change if you don't want to use the bundled version. [default: adodb/] 104 * - PCONNECT: Whether to use ADODB persistent connections. [default: FALSE] 105 * 106 */ 107 function freetag($options = NULL) { 108 /* 109 $available_options = array('debug', 'db', 'db_user', 'db_pass', 'db_host', 'db_name', 'table_prefix', 'normalize_tags', 'normalized_valid_chars', 'block_multiuser_tag_on_object', 'MAX_TAG_LENGTH', 'ADODB_DIR', 'PCONNECT'); 110 if (is_array($options)) { 111 foreach ($options as $key => $value) { 112 $this->debug_text("Option: $key"); 113 114 if (in_array($key, $available_options) ) { 115 $this->debug_text("Valid Config options: $key"); 116 $property = '_'.$key; 117 $this->$property = $value; 118 $this->debug_text("Setting $property to $value"); 119 } else { 120 $this->debug_text("ERROR: Config option: $key is not a valid option"); 121 } 122 } 123 }*/ 124 /* 125 require_once($this->_ADODB_DIR . "/adodb.inc.php"); 126 if (is_object($this->_db)) { 127 $this->db = &$this->_db; 128 $this->debug_text("DB Instance already exists, using this one."); 129 } else { 130 $this->db = ADONewConnection("mysql"); 131 $this->debug_text("Connecting to db with:" . $this->_db_host . " " . $this->_db_user . " " . $this->_db_pass . " " . $this->_db_name); 132 if ($this->_PCONNECT) { 133 $this->db->PConnect($this->_db_host, $this->_db_user, $this->_db_pass, $this->_db_name); 134 } else { 135 $this->db->Connect($this->_db_host, $this->_db_user, $this->_db_pass, $this->_db_name); 136 } 137 } 138 $this->db->debug = $this->_debug; 139 // Freetag uses ASSOC for ease of maintenance and compatibility with people who choose to modify the schema. 140 // Feel free to convert to NUM if performance is the highest concern. 141 $this->db->SetFetchMode(ADODB_FETCH_ASSOC);*/ 142 } 143 144 /** 145 * get_objects_with_tag 146 * 147 * Use this function to build a page of results that have been tagged with the same tag. 148 * Pass along a tagger_id to collect only a certain user's tagged objects, and pass along 149 * none in order to get back all user-tagged objects. Most of the get_*_tag* functions 150 * operate on the normalized form of tags, because most interfaces for navigating tags 151 * should use normal form. 152 * 153 * @param string - Pass the normalized tag form along to the function. 154 * @param int (Optional) - The numerical offset to begin display at. Defaults to 0. 155 * @param int (Optional) - The number of results per page to show. Defaults to 100. 156 * @param int (Optional) - The unique ID of the 'user' who tagged the object. 157 * 158 * @return An array of Object ID numbers that reference your original objects. 159 */ 160 function get_objects_with_tag($tag, $offset = 0, $limit = 100, $tagger_id = NULL) { 161 if(!isset($tag)) { 162 return false; 163 } 164 global $adb; 165 $tag = $adb->quote($tag, get_magic_quotes_gpc()); 166 167 if(isset($tagger_id) && ($tagger_id > 0)) { 168 $tagger_sql = "AND tagger_id = $tagger_id"; 169 } else { 170 $tagger_sql = ""; 171 } 172 $prefix = $this->_table_prefix; 173 174 $sql = "SELECT DISTINCT object_id 175 FROM $prefix}freetagged_objects INNER JOIN $prefix}freetags ON (tag_id = id) 176 WHERE tag = $tag 177 $tagger_sql 178 ORDER BY object_id ASC 179 LIMIT $offset, $limit 180 "; 181 echo $sql; 182 $rs = $adb->query($sql) or die("Error: $sql"); 183 $retarr = array(); 184 while(!$rs->EOF) { 185 $retarr[] = $rs->fields['object_id']; 186 $rs->MoveNext(); 187 } 188 return $retarr; 189 } 190 191 /** 192 * get_objects_with_tag_all 193 * 194 * Use this function to build a page of results that have been tagged with the same tag. 195 * This function acts the same as get_objects_with_tag, except that it returns an unlimited 196 * number of results. Therefore, it's more useful for internal displays, not for API's. 197 * Pass along a tagger_id to collect only a certain user's tagged objects, and pass along 198 * none in order to get back all user-tagged objects. Most of the get_*_tag* functions 199 * operate on the normalized form of tags, because most interfaces for navigating tags 200 * should use normal form. 201 * 202 * @param string - Pass the normalized tag form along to the function. 203 * @param int (Optional) - The unique ID of the 'user' who tagged the object. 204 * 205 * @return An array of Object ID numbers that reference your original objects. 206 */ 207 function get_objects_with_tag_all($tag, $tagger_id = NULL) { 208 if(!isset($tag)) { 209 return false; 210 } 211 global $adb; 212 $tag = $adb->quote($tag, get_magic_quotes_gpc()); 213 214 if(isset($tagger_id) && ($tagger_id > 0)) { 215 $tagger_sql = "AND tagger_id = $tagger_id"; 216 } else { 217 $tagger_sql = ""; 218 } 219 $prefix = $this->_table_prefix; 220 221 $sql = "SELECT DISTINCT object_id 222 FROM $prefix}freetagged_objects INNER JOIN $prefix}freetags ON (tag_id = id) 223 WHERE tag = $tag 224 $tagger_sql 225 ORDER BY object_id ASC 226 "; 227 //echo $sql; 228 $rs = $adb->query($sql) or die("Error: $sql"); 229 $retarr = array(); 230 while(!$rs->EOF) { 231 $retarr[] = $rs->fields['object_id']; 232 $rs->MoveNext(); 233 } 234 return $retarr; 235 } 236 237 /** 238 * get_objects_with_tag_combo 239 * 240 * Returns an array of object ID's that have all the tags passed in the 241 * tagArray parameter. Use this to provide tag combo services to your vtiger_users. 242 * 243 * @param array - Pass an array of normalized form tags along to the function. 244 * @param int (Optional) - The numerical offset to begin display at. Defaults to 0. 245 * @param int (Optional) - The number of results per page to show. Defaults to 100. 246 * @param int (Optional) - Restrict the result to objects tagged by a particular user. 247 * 248 * @return An array of Object ID numbers that reference your original objects. 249 */ 250 function get_objects_with_tag_combo($tagArray, $offset = 0, $limit = 100, $tagger_id = NULL) { 251 if (!isset($tagArray) || !is_array($tagArray)) { 252 return false; 253 } 254 global $adb; 255 //$db = &$this->db; 256 $retarr = array(); 257 if (count($tagArray) == 0) { 258 return $retarr; 259 } 260 if(isset($tagger_id) && ($tagger_id > 0)) { 261 $tagger_sql = "AND tagger_id = $tagger_id"; 262 } else { 263 $tagger_sql = ""; 264 } 265 266 foreach ($tagArray as $key => $value) { 267 $tagArray[$key] = $adb->qstr($value, get_magic_quotes_gpc()); 268 } 269 270 $tagArray = array_unique($tagArray); 271 $tag_sql = join(",", $tagArray); 272 $numTags = count($tagArray); 273 $prefix = $this->_table_prefix; 274 275 // We must adjust for duplicate normalized tags appearing multiple times in the join by 276 // counting only the distinct tags. It should also work for an individual user. 277 278 $sql = "SELECT $prefix}freetagged_objects.object_id, tag, COUNT(DISTINCT tag) AS uniques 279 FROM $prefix}freetagged_objects 280 INNER JOIN $prefix}freetags ON ($prefix}freetagged_objects.tag_id = $prefix}freetags.id) 281 WHERE $prefix}freetags.tag IN ($tag_sql) 282 $tagger_sql 283 GROUP BY $prefix}freetagged_objects.object_id 284 HAVING uniques = $numTags 285 LIMIT $offset, $limit 286 "; 287 $this->debug_text("Tag combo: " . join("+", $tagArray) . " SQL: $sql"); 288 $rs = $adb->query($sql) or die("Error: $sql"); 289 while(!$rs->EOF) { 290 $retarr[] = $rs->fields['object_id']; 291 $rs->MoveNext(); 292 } 293 return $retarr; 294 } 295 296 /** 297 * get_objects_with_tag_id 298 * 299 * Use this function to build a page of results that have been tagged with the same tag. 300 * This function acts the same as get_objects_with_tag, except that it accepts a numerical 301 * tag_id instead of a text tag. 302 * Pass along a tagger_id to collect only a certain user's tagged objects, and pass along 303 * none in order to get back all user-tagged objects. 304 * 305 * @param int - Pass the ID number of the tag. 306 * @param int (Optional) - The numerical offset to begin display at. Defaults to 0. 307 * @param int (Optional) - The number of results per page to show. Defaults to 100. 308 * @param int (Optional) - The unique ID of the 'user' who tagged the object. 309 * 310 * @return An array of Object ID numbers that reference your original objects. 311 */ 312 function get_objects_with_tag_id($tag_id, $offset = 0, $limit = 100, $tagger_id = NULL) { 313 if(!isset($tag_id)) { 314 return false; 315 } 316 global $adb; 317 318 if(isset($tagger_id) && ($tagger_id > 0)) { 319 $tagger_sql = "AND tagger_id = $tagger_id"; 320 } else { 321 $tagger_sql = ""; 322 } 323 $prefix = $this->_table_prefix; 324 325 $sql = "SELECT DISTINCT object_id 326 FROM $prefix}freetagged_objects INNER JOIN $prefix}freetags ON (tag_id = id) 327 WHERE id = $tag_id 328 $tagger_sql 329 ORDER BY object_id ASC 330 LIMIT $offset, $limit 331 "; 332 $rs = $adb->query($sql) or die("Error: $sql"); 333 $retarr = array(); 334 while(!$rs->EOF) { 335 $retarr[] = $rs->fields['object_id']; 336 $rs->MoveNext(); 337 } 338 return $retarr; 339 } 340 341 342 /** 343 * get_tags_on_object 344 * 345 * You can use this function to show the tags on an object. Since it supports both user-specific 346 * and general modes with the $tagger_id parameter, you can use it twice on a page to make it work 347 * similar to upcoming.org and flickr, where the page displays your own tags differently than 348 * other vtiger_users' tags. 349 * 350 * @param int The unique ID of the object in question. 351 * @param int The offset of tags to return. 352 * @param int The size of the tagset to return. Use a zero size to get all tags. 353 * @param int The unique ID of the person who tagged the object, if user-level tags only are preferred. 354 * 355 * @return array Returns a PHP array with object elements ordered by object ID. Each element is an associative 356 * array with the following elements: 357 * - 'tag' => Normalized-form tag 358 * - 'raw_tag' => The raw-form tag 359 * - 'tagger_id' => The unique ID of the person who tagged the object with this tag. 360 */ 361 function get_tags_on_object($object_id, $offset = 0, $limit = 10, $tagger_id = NULL) { 362 if(!isset($object_id)) { 363 return false; 364 } 365 if(isset($tagger_id) && ($tagger_id > 0)) { 366 $tagger_sql = "AND tagger_id = $tagger_id"; 367 } else { 368 $tagger_sql = ""; 369 } 370 global $adb; 371 372 if($limit <= 0) { 373 $limit_sql = ""; 374 } else { 375 $limit_sql = "LIMIT $offset, $limit"; 376 } 377 $prefix = $this->_table_prefix; 378 379 $sql = "SELECT DISTINCT tag, raw_tag, tagger_id, id 380 FROM $prefix}freetagged_objects INNER JOIN $prefix}freetags ON (tag_id = id) 381 WHERE object_id = $object_id 382 $tagger_sql 383 ORDER BY id ASC 384 $limit_sql 385 "; 386 //echo ' <br><br>get_tags_on_object sql is ' .$sql; 387 $rs = $adb->query($sql) or die("Error: $sql"); 388 $retarr = array(); 389 while(!$rs->EOF) { 390 $retarr[] = array( 391 'tag' => $rs->fields['tag'], 392 'raw_tag' => $rs->fields['raw_tag'], 393 'tagger_id' => $rs->fields['tagger_id'] 394 ); 395 $rs->MoveNext(); 396 } 397 return $retarr; 398 } 399 400 /** 401 * safe_tag 402 * 403 * Pass individual tag phrases along with object and person ID's in order to 404 * set a tag on an object. If the tag in its raw form does not yet exist, 405 * this function will create it. 406 * Fails transparently on duplicates, and checks for dupes based on the 407 * block_multiuser_tag_on_object constructor param. 408 * 409 * @param int The unique ID of the person who tagged the object with this tag. 410 * @param int The unique ID of the object in question. 411 * @param string A raw string from a web form containing tags. 412 * 413 * @return boolean Returns true if successful, false otherwise. Does not operate as a transaction. 414 */ 415 416 function safe_tag($tagger_id, $object_id, $tag, $module) { 417 if(!isset($tagger_id)||!isset($object_id)||!isset($tag)) { 418 die("safe_tag argument missing"); 419 return false; 420 } 421 global $adb; 422 423 $normalized_tag = $adb->quote($this->normalize_tag($tag)); 424 425 $tag = $adb->quote($tag); 426 $prefix = $this->_table_prefix; 427 428 // First, check for duplicate of the normalized form of the tag on this object. 429 // Dynamically switch between allowing duplication between vtiger_users on the constructor param 'block_multiuser_tag_on_object'. 430 // If it's set not to block multiuser tags, then modify the existence 431 // check to look for a tag by this particular user. Otherwise, the following 432 // query will reveal whether that tag exists on that object for ANY user. 433 if ($this->_block_multiuser_tag_on_object == 0) { 434 $tagger_sql = " AND tagger_id = $tagger_id"; 435 } 436 $sql = "SELECT COUNT(*) as count 437 FROM $prefix}freetagged_objects INNER JOIN $prefix}freetags ON (tag_id = id) 438 WHERE 1=1 439 $tagger_sql 440 AND object_id = $object_id 441 AND tag = $normalized_tag 442 "; 443 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 444 if($rs->fields['count'] > 0) { 445 return true; 446 } 447 // Then see if a raw tag in this form exists. 448 $sql = "SELECT id 449 FROM $prefix}freetags 450 WHERE raw_tag = $tag 451 "; 452 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 453 if(!$rs->EOF) { 454 $tag_id = $rs->fields['id']; 455 } else { 456 // Add new tag! 457 $tag_id = $adb->getUniqueId('vtiger_freetags'); 458 $sql = "INSERT INTO $prefix}freetags (id,tag, raw_tag) VALUES ($tag_id,$normalized_tag, $tag)"; 459 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 460 461 } 462 if(!($tag_id > 0)) { 463 return false; 464 } 465 $sql = "INSERT INTO $prefix}freetagged_objects 466 (tag_id, tagger_id, object_id, tagged_on, module) 467 VALUES ($tag_id, $tagger_id, $object_id, NOW(), '$module') 468 "; 469 $rs = $adb->query($sql) or die("Syntax error: $sql"); 470 471 return true; 472 } 473 474 /** 475 * normalize_tag 476 * 477 * This is a utility function used to take a raw tag and convert it to normalized form. 478 * Normalized form is essentially lowercased alphanumeric characters only, 479 * with no spaces or special characters. 480 * 481 * Customize the normalized valid chars with your own set of special characters 482 * in regex format within the option 'normalized_valid_chars'. It acts as a filter 483 * to let a customized set of characters through. 484 * 485 * After the filter is applied, the function also lowercases the characters using strtolower 486 * in the current locale. 487 * 488 * The default for normalized_valid_chars is a-zA-Z0-9, or english alphanumeric. 489 * 490 * @param string An individual tag in raw form that should be normalized. 491 * 492 * @return string Returns the tag in normalized form. 493 */ 494 function normalize_tag($tag) { 495 if ($this->_normalize_tags) { 496 $normalized_valid_chars = $this->_normalized_valid_chars; 497 $normalized_tag = preg_replace("/[^$normalized_valid_chars]/", "", $tag); 498 return strtolower($normalized_tag); 499 } else { 500 return $tag; 501 } 502 503 } 504 505 /** 506 * delete_object_tag 507 * 508 * Removes a tag from an object. This does not delete the tag itself from 509 * the database. Since most applications will only allow a user to delete 510 * their own tags, it supports raw-form tags as its tag parameter, because 511 * that's what is usually shown to a user for their own tags. 512 * 513 * @param int The unique ID of the person who tagged the object with this tag. 514 * @param int The ID of the object in question. 515 * @param string The raw string form of the tag to delete. See above for vtiger_notes. 516 * 517 * @return string Returns the tag in normalized form. 518 */ 519 function delete_object_tag($tagger_id, $object_id, $tag) { 520 if(!isset($tagger_id)||!isset($object_id)||!isset($tag)) { 521 die("delete_object_tag argument missing"); 522 return false; 523 } 524 global $adb; 525 $tag_id = $this->get_raw_tag_id($tag); 526 $prefix = $this->_table_prefix; 527 if($tag_id > 0) { 528 529 $sql = "DELETE FROM $prefix}freetagged_objects 530 WHERE tagger_id = $tagger_id 531 AND object_id = $object_id 532 AND tag_id = $tag_id 533 LIMIT 1 534 "; 535 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 536 return true; 537 } else { 538 return false; 539 } 540 } 541 542 /** 543 * delete_all_object_tags 544 * 545 * Removes all tag from an object. This does not 546 * delete the tag itself from the database. This is most useful for 547 * cleanup, where an item is deleted and all its tags should be wiped out 548 * as well. 549 * 550 * @param int The ID of the object in question. 551 * 552 * @return boolean Returns true if successful, false otherwise. It will return true if the tagged object does not exist. 553 */ 554 function delete_all_object_tags($object_id) { 555 global $adb; 556 $prefix = $this->_table_prefix; 557 if($object_id > 0) { 558 $sql = "DELETE FROM $prefix}freetagged_objects 559 WHERE 560 object_id = $object_id 561 "; 562 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 563 return true; 564 } else { 565 return false; 566 } 567 } 568 569 570 /** 571 * delete_all_object_tags_for_user 572 * 573 * Removes all tag from an object for a particular user. This does not 574 * delete the tag itself from the database. This is most useful for 575 * implementations similar to del.icio.us, where a user is allowed to retag 576 * an object from a text box. That way, it becomes a two step operation of 577 * deleting all the tags, then retagging with whatever's left in the input. 578 * 579 * @param int The unique ID of the person who tagged the object with this tag. 580 * @param int The ID of the object in question. 581 * 582 * @return boolean Returns true if successful, false otherwise. It will return true if the tagged object does not exist. 583 */ 584 585 function delete_all_object_tags_for_user($tagger_id, $object_id) { 586 if(!isset($tagger_id)||!isset($object_id)) { 587 die("delete_all_object_tags_for_user argument missing"); 588 return false; 589 } 590 global $adb; 591 $prefix = $this->_table_prefix; 592 if($object_id > 0) { 593 594 $sql = "DELETE FROM $prefix}freetagged_objects 595 WHERE tagger_id = $tagger_id 596 AND object_id = $object_id 597 "; 598 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 599 return true; 600 } else { 601 return false; 602 } 603 } 604 605 /** 606 * get_tag_id 607 * 608 * Retrieves the unique ID number of a tag based upon its normal form. Actually, 609 * using this function is dangerous, because multiple tags can exist with the same 610 * normal form, so be careful, because this will only return one, assuming that 611 * if you're going by normal form, then the individual tags are interchangeable. 612 * 613 * @param string The normal form of the tag to fetch. 614 * 615 * @return string Returns the tag in normalized form. 616 */ 617 function get_tag_id($tag) { 618 if(!isset($tag)) { 619 die("get_tag_id argument missing"); 620 return false; 621 } 622 global $adb; 623 624 $prefix = $this->_table_prefix; 625 626 $tag = $adb->quote($tag, get_magic_quotes_gpc()); 627 628 $sql = "SELECT id FROM $prefix}freetags 629 WHERE 630 tag = $tag 631 LIMIT 1 632 "; 633 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 634 return $rs->fields['id']; 635 636 } 637 638 /** 639 * get_raw_tag_id 640 * 641 * Retrieves the unique ID number of a tag based upon its raw form. If a single 642 * unique record is needed, then use this function instead of get_tag_id, 643 * because raw_tags are unique. 644 * 645 * @param string The raw string form of the tag to fetch. 646 * 647 * @return string Returns the tag in normalized form. 648 */ 649 650 function get_raw_tag_id($tag) { 651 if(!isset($tag)) { 652 die("get_tag_id argument missing"); 653 return false; 654 } 655 global $adb; 656 $prefix = $this->_table_prefix; 657 658 $tag = $adb->quote($tag, get_magic_quotes_gpc()); 659 660 $sql = "SELECT id FROM $prefix}freetags 661 WHERE 662 raw_tag = $tag 663 LIMIT 1 664 "; 665 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 666 return $rs->fields['id']; 667 668 } 669 670 /** 671 * tag_object 672 * 673 * This function allows you to pass in a string directly from a form, which is then 674 * parsed for quoted phrases and special characters, normalized and converted into tags. 675 * The tag phrases are then individually sent through the safe_tag() method for processing 676 * and the object referenced is set with that tag. 677 * 678 * This method has been refactored to automatically look for existing tags and run 679 * adds/updates/deletes as appropriate. 680 * 681 * @param int The unique ID of the person who tagged the object with this tag. 682 * @param int The ID of the object in question. 683 * @param string The raw string form of the tag to delete. See above for vtiger_notes. 684 * @param int Whether to skip the update portion for objects that haven't been tagged. (Default: 1) 685 * 686 * @return string Returns the tag in normalized form. 687 */ 688 function tag_object($tagger_id, $object_id, $tag_string, $module, $skip_updates = 1) { 689 if($tag_string == '') { 690 // If an empty string was passed, just return true, don't die. 691 // die("Empty tag string passed"); 692 return true; 693 } 694 $tagArray = $this->_parse_tags($tag_string); 695 696 $oldTags = $this->get_tags_on_object($object_id, 0, 0, $tagger_id); 697 698 $preserveTags = array(); 699 700 if (($skip_updates == 0) && (count($oldTags) > 0)) { 701 foreach ($oldTags as $tagItem) { 702 if (!in_array($tagItem['raw_tag'], $tagArray)) { 703 // We need to delete old tags that don't appear in the new parsed string. 704 $this->delete_object_tag($tagger_id, $object_id, $tagItem['raw_tag']); 705 } else { 706 // We need to preserve old tags that appear (to save timestamps) 707 $preserveTags[] = $tagItem['raw_tag']; 708 } 709 } 710 } 711 $newTags = array_diff($tagArray, $preserveTags); 712 713 $this->_tag_object_array($tagger_id, $object_id, $newTags, $module); 714 715 return true; 716 } 717 718 /** 719 * _tag_object_array 720 * 721 * Private method to add tags to an object from an array. 722 * 723 * @param int Unique ID of tagger 724 * @param int Unique ID of object 725 * @param array Array of tags to add. 726 * 727 * @return boolean True if successful, false otherwise. 728 */ 729 function _tag_object_array($tagger_id, $object_id, $tagArray, $module) { 730 foreach($tagArray as $tag) { 731 $tag = trim($tag); 732 if(($tag != '') && (strlen($tag) <= $this->_MAX_TAG_LENGTH)) { 733 if(get_magic_quotes_gpc()) { 734 $tag = addslashes($tag); 735 } 736 $this->safe_tag($tagger_id, $object_id, $tag, $module); 737 } 738 } 739 return true; 740 } 741 742 /** 743 * _parse_tags 744 * 745 * Private method to parse tags out of a string and into an array. 746 * 747 * @param string String to parse. 748 * 749 * @return array Returns an array of the raw "tags" parsed according to the freetag settings. 750 */ 751 752 function _parse_tags($tag_string) { 753 $newwords = array(); 754 if ($tag_string == '') { 755 // If the tag string is empty, return the empty set. 756 return $newwords; 757 } 758 # Perform tag parsing 759 if(get_magic_quotes_gpc()) { 760 $query = stripslashes(trim($tag_string)); 761 } else { 762 $query = trim($tag_string); 763 } 764 $words = preg_split('/(")/', $query,-1,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE); 765 $delim = 0; 766 foreach ($words as $key => $word) 767 { 768 if ($word == '"') { 769 $delim++; 770 continue; 771 } 772 if (($delim % 2 == 1) && $words[$key - 1] == '"') { 773 $newwords[] = $word; 774 } else { 775 $newwords = array_merge($newwords, preg_split('/\s+/', $word, -1, PREG_SPLIT_NO_EMPTY)); 776 } 777 } 778 return $newwords; 779 } 780 781 /** 782 * update_tags 783 * 784 * This method supports a user updating their set of all tags on an object 785 * in a streamlined manner. Very useful for interfaces where all tags on an 786 * object from a user may be edited through a single text box. 787 */ 788 789 /** 790 * get_most_popular_tags 791 * 792 * This function returns the most popular tags in the freetag system, with 793 * offset and limit support for pagination. It also supports restricting to 794 * an individual user. Call it with no parameters for a list of 25 most popular 795 * tags. 796 * 797 * @param int The unique ID of the person to restrict results to. 798 * @param int The offset of the tag to start at. 799 * @param int The number of tags to return in the result set. 800 * 801 * @return array Returns a PHP array with tags ordered by popularity descending. 802 * Each element is an associative array with the following elements: 803 * - 'tag' => Normalized-form tag 804 * - 'count' => The number of objects tagged with this tag. 805 */ 806 807 function get_most_popular_tags($tagger_id = NULL, $offset = 0, $limit = 25) { 808 global $adb; 809 if(isset($tagger_id) && ($tagger_id > 0)) { 810 $tagger_sql = "AND tagger_id = $tagger_id"; 811 } else { 812 $tagger_sql = ""; 813 } 814 $prefix = $this->_table_prefix; 815 816 $sql = "SELECT tag, COUNT(*) as count 817 FROM $prefix}freetags INNER JOIN $prefix}freetagged_objects ON (id = tag_id) 818 WHERE 1 819 $tagger_sql 820 GROUP BY tag 821 ORDER BY count DESC, tag ASC 822 LIMIT $offset, $limit 823 "; 824 825 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 826 $retarr = array(); 827 while(!$rs->EOF) { 828 $retarr[] = array( 829 'tag' => $rs->fields['tag'], 830 'count' => $rs->fields['count'] 831 ); 832 $rs->MoveNext(); 833 } 834 835 return $retarr; 836 837 } 838 839 /** 840 * count_tags 841 * 842 * Returns the total number of tag->object links in the system. 843 * It might be useful for pagination at times, but i'm not sure if I actually use 844 * this anywhere. Restrict to a person's tagging by using the $tagger_id parameter. 845 * 846 * @param int The unique ID of the person to restrict results to. 847 * 848 * @return int Returns the count 849 */ 850 function count_tags($tagger_id = NULL) { 851 global $adb; 852 if(isset($tagger_id) && ($tagger_id > 0)) { 853 $tagger_sql = "AND tagger_id = $tagger_id"; 854 } else { 855 $tagger_sql = ""; 856 } 857 $prefix = $this->_table_prefix; 858 859 $sql = "SELECT COUNT(*) as count 860 FROM $prefix}freetags INNER JOIN $prefix}freetagged_objects ON (id = tag_id) 861 WHERE 1 862 $tagger_sql 863 "; 864 865 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 866 if(!$rs->EOF) { 867 return $rs->fields['count']; 868 } 869 return false; 870 871 } 872 873 /** 874 * get_tag_cloud_html 875 * 876 * This is a pretty straightforward, flexible method that automatically 877 * generates some html that can be dropped in as a tag cloud. 878 * It uses explicit font sizes inside of the style attribute of SPAN 879 * elements to accomplish the differently sized objects. 880 * 881 * It will also link every tag to $tag_page_url, appended with the 882 * normalized form of the tag. You should adapt this value to your own 883 * tag detail page's URL. 884 * 885 * @param int The maximum number of tags to return. (default: 100) 886 * @param int The minimum font size in the cloud. (default: 10) 887 * @param int The maximum number of tags to return. (default: 20) 888 * @param string The "units" for the font size (i.e. 'px', 'pt', 'em') (default: px) 889 * @param string The class to use for all spans in the cloud. (default: cloud_tag) 890 * @param string The tag page URL (default: /tag/) 891 * 892 * @return string Returns an HTML snippet that can be used directly as a tag cloud. 893 */ 894 895 function get_tag_cloud_html($module="",$tagger_id = NULL,$obj_id= NULL,$num_tags = 100, $min_font_size = 10, $max_font_size = 20, $font_units = 'px', $span_class = '', $tag_page_url = '/tag/') { 896 global $theme; 897 $theme_path="themes/".$theme."/"; 898 $image_path=$theme_path."images/"; 899 $tag_list = $this->get_tag_cloud_tags($num_tags, $tagger_id,$module,$obj_id); 900 if(!$tag_list[0]) return; 901 // Get the maximum qty of tagged objects in the set 902 $max_qty = max(array_values($tag_list[0])); 903 // Get the min qty of tagged objects in the set 904 $min_qty = min(array_values($tag_list[0])); 905 906 // For ever additional tagged object from min to max, we add 907 // $step to the font size. 908 $spread = $max_qty - $min_qty; 909 if (0 == $spread) { // Divide by zero 910 $spread = 1; 911 } 912 $step = ($max_font_size - $min_font_size)/($spread); 913 914 // Since the original tag_list is alphabetically ordered, 915 // we can now create the tag cloud by just putting a span 916 // on each element, multiplying the diff between min and qty 917 // by $step. 918 $cloud_html = ''; 919 $cloud_spans = array(); 920 if($module =='') 921 $module = 'All'; 922 if($module != 'All') 923 { 924 foreach($tag_list[0] as $tag => $qty) { 925 $size = $min_font_size + ($qty - $min_qty) * 3; 926 $cloud_span[] = '<span id="tag_'.$tag_list[1][$tag].'" class="' . $span_class . '" onMouseOver=$("tagspan_'.$tag_list[1][$tag].'").style.display="inline"; onMouseOut=$("tagspan_'.$tag_list[1][$tag].'").style.display="none";><a class="tagit" href="index.php?module=Home&action=UnifiedSearch&search_module='.$module.'&query_string='. $tag . '" style="font-size: '. $size . $font_units . '">' . htmlspecialchars(stripslashes($tag)) . '</a><span class="'. $span_class .'" id="tagspan_'.$tag_list[1][$tag].'" style="display:none;cursor:pointer;" onClick="DeleteTag('.$tag_list[1][$tag].');"><img src="'.$image_path.'del_tag.gif"></span></span>'; 927 928 } 929 }else 930 { 931 foreach($tag_list[0] as $tag => $qty) { 932 $size = $min_font_size + ($qty - $min_qty) * 3; 933 $cloud_span[] = '<span class="' . $span_class . '"><a class="tagit" href="index.php?module=Home&action=UnifiedSearch&search_module='.$module.'&query_string='. $tag . '" style="font-size: '. $size . $font_units . '">' . htmlspecialchars(stripslashes($tag)) . '</a></span>'; 934 935 } 936 937 } 938 $cloud_html = join("\n ", $cloud_span); 939 940 return $cloud_html; 941 942 } 943 944 /* 945 * get_tag_cloud_tags 946 * 947 * This is a function built explicitly to set up a page with most popular tags 948 * that contains an alphabetically sorted list of tags, which can then be sized 949 * or colored by popularity. 950 * 951 * Also known more popularly as Tag Clouds! 952 * 953 * Here's the example case: http://upcoming.org/tag/ 954 * 955 * @param int The maximum number of tags to return. 956 * 957 * @return array Returns an array where the keys are normalized tags, and the 958 * values are numeric quantity of objects tagged with that tag. 959 */ 960 961 function get_tag_cloud_tags($max = 100, $tagger_id = NULL,$module = "",$obj_id = NULL) { 962 global $adb; 963 if(isset($tagger_id) && ($tagger_id > 0)) { 964 $tagger_sql = " AND tagger_id = $tagger_id"; 965 } else { 966 $tagger_sql = ""; 967 } 968 969 if($module != "") { 970 $tagger_sql .= " AND module = '$module'"; 971 } else { 972 $tagger_sql .= ""; 973 } 974 975 if(isset($obj_id) && $obj_id > 0) { 976 $tagger_sql .= " AND object_id = $obj_id"; 977 } else { 978 $tagger_sql .= ""; 979 } 980 981 $prefix = $this->_table_prefix; 982 $sql = "SELECT tag,tag_id,COUNT(object_id) AS quantity 983 FROM $prefix}freetags INNER JOIN $prefix}freetagged_objects 984 ON ($prefix}freetags.id = tag_id) 985 WHERE 1=1 986 $tagger_sql 987 GROUP BY tag,tag_id 988 ORDER BY quantity DESC"; 989 //echo $sql; 990 $rs = $adb->limitQuery($sql, 0, $max) or die("Syntax Error: $sql"); 991 $retarr = array(); 992 while(!$rs->EOF) { 993 $retarr[$rs->fields['tag']] = $rs->fields['quantity']; 994 $retarr1[$rs->fields['tag']] = $rs->fields['tag_id']; 995 $rs->MoveNext(); 996 } 997 if($retarr) ksort($retarr); 998 if($retarr1) ksort($retarr1); 999 $return_value[]=$retarr; 1000 $return_value[]=$retarr1; 1001 return $return_value; 1002 1003 } 1004 1005 /** 1006 * similar_tags 1007 * 1008 * Finds tags that are "similar" or related to the given tag. 1009 * It does this by looking at the other tags on objects tagged with the tag specified. 1010 * Confusing? Think of it like e-commerce's "Other vtiger_users who bought this also bought," 1011 * as that's exactly how this works. 1012 * 1013 * Returns an empty array if no tag is passed, or if no related tags are found. 1014 * Hint: You can detect related tags returned with count($retarr > 0) 1015 * 1016 * It's important to note that the quantity passed back along with each tag 1017 * is a measure of the *strength of the relation* between the original tag 1018 * and the related tag. It measures the number of objects tagged with both 1019 * the original tag and its related tag. 1020 * 1021 * Thanks to Myles Grant for contributing this function! 1022 * 1023 * @param string The raw normalized form of the tag to fetch. 1024 * @param int The maximum number of tags to return. 1025 * 1026 * @return array Returns an array where the keys are normalized tags, and the 1027 * values are numeric quantity of objects tagged with BOTH tags, sorted by 1028 * number of occurences of that tag (high to low). 1029 */ 1030 1031 function similar_tags($tag, $max = 100) { 1032 $retarr = array(); 1033 if(!isset($tag)) { 1034 return $retarr; 1035 } 1036 global $adb; 1037 $tag = $adb->quote($tag, get_magic_quotes_gpc()); 1038 1039 // This query was written using a double join for PHP. If you're trying to eke 1040 // additional performance and are running MySQL 4.X, you might want to try a subselect 1041 // and compare perf numbers. 1042 $prefix = $this->_table_prefix; 1043 1044 $sql = "SELECT t1.tag, COUNT( o1.object_id ) AS quantity 1045 FROM $prefix}freetagged_objects o1 1046 INNER JOIN $prefix}freetags t1 ON ( t1.id = o1.tag_id ) 1047 INNER JOIN $prefix}freetagged_objects o2 ON ( o1.object_id = o2.object_id ) 1048 INNER JOIN $prefix}freetags t2 ON ( t2.id = o2.tag_id ) 1049 WHERE t2.tag = $tag AND t1.tag != $tag 1050 GROUP BY o1.tag_id 1051 ORDER BY quantity DESC 1052 LIMIT 0, $max 1053 "; 1054 1055 $rs = $adb->query($sql) or die("Syntax Error: $sql"); 1056 while(!$rs->EOF) { 1057 $retarr[$rs->fields['tag']] = $rs->fields['quantity']; 1058 $rs->MoveNext(); 1059 } 1060 1061 return $retarr; 1062 } 1063 1064 /** 1065 * similar_objects 1066 * 1067 * This method implements a simple ability to find some objects in the database 1068 * that might be similar to an existing object. It determines this by trying 1069 * to match other objects that share the same tags. 1070 * 1071 * The user of the method has to use a threshold (by default, 1) which specifies 1072 * how many tags other objects must have in common to match. If the original object 1073 * has no tags, then it won't match anything. Matched objects are returned in order 1074 * of most similar to least similar. 1075 * 1076 * The more tags set on a database, the better this method works. Since this 1077 * is such an expensive operation, it requires a limit to be set via max_objects. 1078 * 1079 * @param int The unique ID of the object to find similar objects for. 1080 * @param int The Threshold of tags that must be found in common (default: 1) 1081 * @param int The maximum number of similar objects to return (default: 5). 1082 * @param int Optionally pass a tagger id to restrict similarity to a tagger's view. 1083 * 1084 * @return array Returns a PHP array with matched objects ordered by strength of match descending. 1085 * Each element is an associative array with the following elements: 1086 * - 'strength' => A floating-point strength of match from 0-1.0 1087 * - 'object_id' => Unique ID of the matched object 1088 * 1089 */ 1090 function similar_objects($object_id, $threshold = 1, $max_objects = 5, $tagger_id = NULL) { 1091 global $adb; 1092 $retarr = array(); 1093 1094 $object_id = intval($object_id); 1095 $threshold = intval($threshold); 1096 $max_objects = intval($max_objects); 1097 if (!isset($object_id) || !($object_id > 0)) { 1098 return $retarr; 1099 } 1100 if ($threshold <= 0) { 1101 return $retarr; 1102 } 1103 if ($max_objects <= 0) { 1104 return $retarr; 1105 } 1106 1107 // Pass in a zero-limit to get all tags. 1108 $tagItems = $this->get_tags_on_object($object_id, 0, 0); 1109 1110 $tagArray = array(); 1111 foreach ($tagItems as $tagItem) { 1112 $tagArray[] = $adb->quote($tagItem['tag']); 1113 } 1114 $tagArray = array_unique($tagArray); 1115 1116 $numTags = count($tagArray); 1117 if ($numTags == 0) { 1118 return $retarr; // Return empty set of matches 1119 } 1120 1121 $tagList = join(',', $tagArray); 1122 1123 $prefix = $this->_table_prefix; 1124 1125 $sql = "SELECT matches.object_id, COUNT( matches.object_id ) AS num_common_tags 1126 FROM $prefix}freetagged_objects as matches 1127 INNER JOIN $prefix}freetags as tags ON ( tags.id = matches.tag_id ) 1128 WHERE tags.tag IN ($tagList) 1129 GROUP BY matches.object_id 1130 HAVING num_common_tags >= $threshold 1131 ORDER BY num_common_tags DESC 1132 LIMIT 0, $max_objects 1133 "; 1134 1135 $rs = $adb->query($sql) or die("Syntax Error: $sql, Error: " . $adb->ErrorMsg()); 1136 while(!$rs->EOF) { 1137 $retarr[] = array ( 1138 'object_id' => $rs->fields['object_id'], 1139 'strength' => ($rs->fields['num_common_tags'] / $numTags) 1140 ); 1141 $rs->MoveNext(); 1142 } 1143 1144 return $retarr; 1145 } 1146 1147 1148 /* 1149 * Prints debug text if debug is enabled. 1150 * 1151 * @param string The text to output 1152 * @return boolean Always returns true 1153 */ 1154 function debug_text($text) { 1155 if ($this->_debug) { 1156 echo "$text<br>\n"; 1157 } 1158 return true; 1159 } 1160 1161 } 1162
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 10:22:19 2007 | par Balluche grâce à PHPXref 0.7 |