tags.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php
  2. /**
  3. * Elgg tags
  4. * Functions for managing tags and tag clouds.
  5. *
  6. * @package Elgg.Core
  7. * @subpackage Tags
  8. */
  9. /**
  10. * Takes in a comma-separated string and returns an array of tags
  11. * which have been trimmed
  12. *
  13. * @param string $string Comma-separated tag string
  14. *
  15. * @return mixed An array of strings or the original data if input was not a string
  16. */
  17. function string_to_tag_array($string) {
  18. if (!is_string($string)) {
  19. return $string;
  20. }
  21. $ar = explode(",", $string);
  22. $ar = array_map('trim', $ar);
  23. $ar = array_filter($ar, 'is_not_null');
  24. $ar = array_map('strip_tags', $ar);
  25. return $ar;
  26. }
  27. /**
  28. * Get popular tags and their frequencies
  29. *
  30. * Supports similar arguments as elgg_get_entities()
  31. *
  32. * @param array $options Array in format:
  33. *
  34. * threshold => INT minimum tag count
  35. *
  36. * tag_names => array() metadata tag names - must be registered tags
  37. *
  38. * limit => INT number of tags to return (default from settings)
  39. *
  40. * types => null|STR entity type (SQL: type = '$type')
  41. *
  42. * subtypes => null|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2))
  43. * Use ELGG_ENTITIES_NO_VALUE to match the default subtype.
  44. * Use ELGG_ENTITIES_ANY_VALUE to match any subtype.
  45. *
  46. * type_subtype_pairs => null|ARR (array('type' => 'subtype'))
  47. * array(
  48. * 'object' => array('blog', 'file'), // All objects with subtype of 'blog' or 'file'
  49. * 'user' => ELGG_ENTITY_ANY_VALUE, // All users irrespective of subtype
  50. * );
  51. *
  52. * owner_guids => null|INT entity guid
  53. *
  54. * container_guids => null|INT container_guid
  55. *
  56. * site_guids => null (current_site)|INT site_guid
  57. *
  58. * created_time_lower => null|INT Created time lower boundary in epoch time
  59. *
  60. * created_time_upper => null|INT Created time upper boundary in epoch time
  61. *
  62. * modified_time_lower => null|INT Modified time lower boundary in epoch time
  63. *
  64. * modified_time_upper => null|INT Modified time upper boundary in epoch time
  65. *
  66. * wheres => array() Additional where clauses to AND together
  67. *
  68. * joins => array() Additional joins
  69. *
  70. * @return object[]|false If no tags or error, false
  71. * otherwise, array of objects with ->tag and ->total values
  72. * @since 1.7.1
  73. */
  74. function elgg_get_tags(array $options = array()) {
  75. global $CONFIG;
  76. $defaults = array(
  77. 'threshold' => 1,
  78. 'tag_names' => array(),
  79. 'limit' => elgg_get_config('default_limit'),
  80. 'types' => ELGG_ENTITIES_ANY_VALUE,
  81. 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
  82. 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
  83. 'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
  84. 'container_guids' => ELGG_ENTITIES_ANY_VALUE,
  85. 'site_guids' => $CONFIG->site_guid,
  86. 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
  87. 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
  88. 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
  89. 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
  90. 'joins' => array(),
  91. 'wheres' => array(),
  92. );
  93. $options = array_merge($defaults, $options);
  94. $singulars = array('type', 'subtype', 'owner_guid', 'container_guid', 'site_guid', 'tag_name');
  95. $options = _elgg_normalize_plural_options_array($options, $singulars);
  96. $registered_tags = elgg_get_registered_tag_metadata_names();
  97. if (!is_array($options['tag_names'])) {
  98. return false;
  99. }
  100. // empty array so use all registered tag names
  101. if (count($options['tag_names']) == 0) {
  102. $options['tag_names'] = $registered_tags;
  103. }
  104. $diff = array_diff($options['tag_names'], $registered_tags);
  105. if (count($diff) > 0) {
  106. elgg_deprecated_notice('Tag metadata names must be registered by elgg_register_tag_metadata_name()', 1.7);
  107. // return false;
  108. }
  109. $wheres = $options['wheres'];
  110. // catch for tags that were spaces
  111. $wheres[] = "msv.string != ''";
  112. $sanitised_tags = array();
  113. foreach ($options['tag_names'] as $tag) {
  114. $sanitised_tags[] = '"' . sanitise_string($tag) . '"';
  115. }
  116. $tags_in = implode(',', $sanitised_tags);
  117. $wheres[] = "(msn.string IN ($tags_in))";
  118. $wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'],
  119. $options['subtypes'], $options['type_subtype_pairs']);
  120. $wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
  121. $wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
  122. $wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
  123. $wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
  124. $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
  125. // see if any functions failed
  126. // remove empty strings on successful functions
  127. foreach ($wheres as $i => $where) {
  128. if ($where === false) {
  129. return false;
  130. } elseif (empty($where)) {
  131. unset($wheres[$i]);
  132. }
  133. }
  134. // remove identical where clauses
  135. $wheres = array_unique($wheres);
  136. $joins = $options['joins'];
  137. $joins[] = "JOIN {$CONFIG->dbprefix}metadata md on md.entity_guid = e.guid";
  138. $joins[] = "JOIN {$CONFIG->dbprefix}metastrings msv on msv.id = md.value_id";
  139. $joins[] = "JOIN {$CONFIG->dbprefix}metastrings msn on md.name_id = msn.id";
  140. // remove identical join clauses
  141. $joins = array_unique($joins);
  142. foreach ($joins as $i => $join) {
  143. if ($join === false) {
  144. return false;
  145. } elseif (empty($join)) {
  146. unset($joins[$i]);
  147. }
  148. }
  149. $query = "SELECT msv.string as tag, count(msv.id) as total ";
  150. $query .= "FROM {$CONFIG->dbprefix}entities e ";
  151. // add joins
  152. foreach ($joins as $j) {
  153. $query .= " $j ";
  154. }
  155. // add wheres
  156. $query .= ' WHERE ';
  157. foreach ($wheres as $w) {
  158. $query .= " $w AND ";
  159. }
  160. // Add access controls
  161. $query .= _elgg_get_access_where_sql();
  162. $threshold = sanitise_int($options['threshold']);
  163. $query .= " GROUP BY msv.string HAVING total >= {$threshold} ";
  164. $query .= " ORDER BY total DESC ";
  165. $limit = sanitise_int($options['limit']);
  166. $query .= " LIMIT {$limit} ";
  167. return get_data($query);
  168. }
  169. /**
  170. * Registers a metadata name as containing tags for an entity.
  171. * This is required if you are using a non-standard metadata name
  172. * for your tags.
  173. *
  174. * @param string $name Tag name
  175. *
  176. * @return bool
  177. * @since 1.7.0
  178. */
  179. function elgg_register_tag_metadata_name($name) {
  180. global $CONFIG;
  181. if (!isset($CONFIG->registered_tag_metadata_names)) {
  182. $CONFIG->registered_tag_metadata_names = array();
  183. }
  184. if (!in_array($name, $CONFIG->registered_tag_metadata_names)) {
  185. $CONFIG->registered_tag_metadata_names[] = $name;
  186. }
  187. return true;
  188. }
  189. /**
  190. * Returns an array of valid metadata names for tags.
  191. *
  192. * @return array
  193. * @since 1.7.0
  194. */
  195. function elgg_get_registered_tag_metadata_names() {
  196. global $CONFIG;
  197. $names = (isset($CONFIG->registered_tag_metadata_names)) ? $CONFIG->registered_tag_metadata_names : array();
  198. return $names;
  199. }
  200. /**
  201. * @access private
  202. */
  203. function _elgg_tags_init() {
  204. // register the standard tags metadata name
  205. elgg_register_tag_metadata_name('tags');
  206. }
  207. return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
  208. $events->registerHandler('init', 'system', '_elgg_tags_init');
  209. };