Guest User

Untitled

a guest
Apr 21st, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.28 KB | None | 0 0
  1. <?php
  2. /**
  3. * To implment tagging behavior to be able to plug into any data model in the system
  4. *
  5. * Requirements
  6. * You are required to create "tags" table to hold all tag entries (id:int, name:string)
  7. * You are required to create a "[tableName]_tags" table for each object you
  8. * want to tag. for example, to implement tags for pages u need this table
  9. * pages_tags (page_id : int, tag_id:int)
  10. *
  11. *
  12. * Example Setup
  13. * class Page extends AppModel {
  14. * var $actsAs = array('Taggable');
  15. * var $hasAndBelongsToMany => array('Tag' => array('with'=>'PageTag','joinTable'=>'pages_tags');
  16. * }
  17. *
  18. * Done
  19. * now all tagging related features can be used in your models.
  20. * $this->Page->findPopularTags();
  21. * $this->Page->findRelatedTags(array('news'));
  22. *
  23. * Once $this->Page->id is set, you can all pages related to current page.
  24. * $this->Page->findRelatedTagged(10);
  25. *
  26. *
  27. */
  28. class TaggableBehavior extends ModelBehavior {
  29.  
  30. function tag(&$model, $name = null) {
  31. if (is_null($name)) return false;
  32. if ($existing = $model->Tag->find(array('name'=>$name), array('id'))) {
  33. return $existing['Tag']['id'];
  34. } else {
  35. $handle = Inflector::slug($name, '-');
  36. $model->Tag->create(array('name'=>$name,'handle'=>$handle));
  37. $model->Tag->save();
  38. return $model->Tag->getLastInsertId();
  39. }
  40. }
  41.  
  42. function afterFind(&$model, $results, $primary = false) {
  43. foreach($results as &$result) {
  44. if (isset($result['Tag'])) {
  45. $tags = join(', ', Set::extract($result['Tag'], '{n}.name'));
  46. $result[$model->alias]['tags'] = $tags;
  47. }
  48. }
  49. return $results;
  50. }
  51.  
  52. function beforeSave(&$model) {
  53. if (isset($model->data[$model->alias]['tags'])) {
  54. $tags = Set::normalize($model->data[$model->alias]['tags'], false);
  55. $ids = array();
  56. foreach ($tags as $tag) {
  57. $ids[] = $this->tag($model, $tag);
  58. }
  59. $model->data['Tag']['Tag'] = $ids;
  60. }
  61. return true;
  62. }
  63.  
  64. /**
  65. * Finds other records that share the most tags with the record passed as the
  66. * related parameter.
  67. * Useful for constructing æRelatedÆ or æSee AlsoÆ boxes and lists.
  68. *
  69. * Require Model::$data to be set so it points to current entry.
  70. * @param Model $model
  71. * @param integer $limit
  72. * @param integer $page
  73. * @return array - list of related entries
  74. */
  75. function findRelatedTagged(&$model, $limit = 20, $page = 1) {
  76. if (!isset($model->hasAndBelongsToMany['Tag']) || !$model->id) {
  77. return false;
  78. }
  79. extract($model->hasAndBelongsToMany['Tag'], EXTR_SKIP);
  80. $prefix = $model->tablePrefix;
  81. $tableName = Inflector::tableize($className);
  82. $offset = $limit * ($page-1);
  83.  
  84. # SQL query to get related items share most of tags.
  85. $sql = "SELECT {$model->alias}.*, COUNT( joinTable2.{$foreignKey} ) AS count
  86. FROM {$prefix}{$model->useTable} {$model->alias},
  87. {$prefix}{$joinTable} joinTable,
  88. {$prefix}{$joinTable} joinTable2,
  89. {$prefix}{$tableName} Tag
  90. WHERE joinTable.{$foreignKey} = {$model->id}
  91. AND Tag.{$model->primaryKey} = joinTable.{$associationForeignKey}
  92. AND joinTable2.{$foreignKey} != joinTable.{$foreignKey}
  93. AND joinTable2.{$associationForeignKey} = joinTable.{$associationForeignKey}
  94. AND {$model->alias}.{$model->primaryKey} = joinTable2.{$foreignKey}
  95. GROUP BY joinTable2.{$foreignKey} ORDER BY count DESC
  96. LIMIT {$offset}, {$limit};";
  97. $related = $model->query($sql);
  98. # Filter out count field from result
  99. if (!empty($related)) {
  100. $related = Set::remove($related, "{n}.0");
  101. }
  102. return $related;
  103. }
  104.  
  105. /**
  106. * Finds other tags that are related to the tags passed thru the tags parameter,
  107. * by finding common records that share similar sets of tags.
  108. * Useful for constructing æRelated tagsÆ lists.
  109. *
  110. * @param Model $model - instance of target model
  111. * @param mixed $tags - list of tags in string or array format
  112. * @return array - list of related Tags
  113. */
  114. function findRelatedTags(&$model, $tags = array()) {
  115. if (!isset($model->hasAndBelongsToMany['Tag']) || !$tags ) {
  116. return false;
  117. }
  118. extract($model->hasAndBelongsToMany['Tag'], EXTR_SKIP);
  119. if (is_string($tags)) {
  120. $tags = Set::normalize($tags, false);
  121. }
  122. $prefix = $model->tablePrefix;
  123. $tableName = Inflector::tableize($className);
  124. $tagsString = "'".join("', '", $tags)."'";
  125. $tagsCount = count($tags);
  126.  
  127. # Sql find related tags
  128. $sql = "SELECT Tags.*, COUNT(joinTable.{$foreignKey}) AS count
  129. FROM {$prefix}{$joinTable} joinTable,
  130. {$prefix}{$tableName} Tags
  131. WHERE joinTable.{$foreignKey} IN (
  132. SELECT joinTable.{$foreignKey}
  133. FROM {$prefix}{$joinTable} joinTable,
  134. {$prefix}{$tableName} Tags
  135. WHERE joinTable.{$associationForeignKey} = Tags.id
  136. AND Tags.name IN ({$tagsString})
  137. GROUP BY joinTable.{$foreignKey}
  138. HAVING COUNT(joinTable.{$foreignKey}) = {$tagsCount}
  139. )
  140. AND Tags.name NOT IN ({$tagsString})
  141. AND Tags.id = joinTable.{$associationForeignKey}
  142. GROUP BY joinTable.{$associationForeignKey}
  143. ORDER BY count DESC";
  144. $related = $model->query($sql);
  145.  
  146. # Filter out count field from result
  147. if (!empty($related)) {
  148. $related = Set::remove($related, "{n}.0");
  149. }
  150. return $related;
  151. }
  152.  
  153.  
  154. /**
  155. * Find most popular tags in relation to current model
  156. *
  157. * @param unknown_type $model
  158. * @param unknown_type $limit
  159. * @param unknown_type $page
  160. * @return unknown
  161. */
  162. function findPopularTags(&$model, $limit = 20, $page = 1) {
  163. extract($model->hasAndBelongsToMany['Tag'], EXTR_SKIP);
  164. $prefix = $model->tablePrefix;
  165. $tableName = Inflector::tableize($className);
  166. $offset = $limit * ($page-1);
  167.  
  168. $sql = "SELECT Tag.*, COUNT( joinTable.{$foreignKey} ) AS popularity
  169. FROM {$prefix}{$joinTable} joinTable,
  170. {$prefix}{$tableName} Tag
  171. WHERE Tag.{$model->primaryKey} = joinTable.{$associationForeignKey}
  172. GROUP BY joinTable.{$associationForeignKey}
  173. ORDER BY popularity DESC
  174. LIMIT {$offset}, {$limit};";
  175. $popular = $model->query($sql);
  176.  
  177. # Filter out popular field
  178. if (!empty($popular)) {
  179. $popular = Set::remove($related, "{n}.0");
  180. }
  181. return $popular;
  182. }
  183.  
  184. /**
  185. * Find all associated entry with tags
  186. *
  187. * @param Model $model
  188. * @param Array $tags - Find entries with these tags
  189. * @return $results
  190. */
  191. function findTaggedWith(&$model, $tags) {
  192. extract($model->hasAndBelongsToMany['Tag'], EXTR_SKIP);
  193.  
  194. $Tag = ClassRegistry::init('Tag');
  195. $ids = Set::extract($Tag->findAll(array('name'=>$tags), array('id')), '{n}.Tag.id');
  196.  
  197. $model->{$with}->bindModel(array(
  198. 'belongsTo'=>array($model->name, 'Tag'))
  199. );
  200. $results = $model->{$with}->findAll(array("{$with}.tag_id"=>$ids));
  201. return $results;
  202. }
  203.  
  204.  
  205. /**
  206. * Count the number of tags associated to current Model entry
  207. * Require Model::$data to be set so it points to current entry.
  208. *
  209. * @param Model $model
  210. * @return integer - Number of tags
  211. */
  212. function TagsCount(&$model) {
  213. if(!isset($model->id)) {
  214. return 0;
  215. }
  216. extract($model->hasAndBelongsToMany['Tag'], EXTR_SKIP);
  217.  
  218. $results = $model->{$with}->findCount(array(
  219. "{$with}.page_id" => $model->id
  220. ));
  221. return $results;
  222. }
  223.  
  224. }
  225. ?>
Add Comment
Please, Sign In to add comment