99.include.cache.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. /**
  3. * TaggerGetTags
  4. *
  5. * DESCRIPTION
  6. *
  7. * This Snippet allows you to list tags for resource(s), group(s) and all tags
  8. *
  9. * PROPERTIES:
  10. *
  11. * &resources string optional Comma separated list of resources for which will be listed Tags
  12. * &parents string optional Comma separated list of parents for which will be listed Tags
  13. * &groups string optional Comma separated list of Tagger Groups for which will be listed Tags
  14. * &rowTpl string optional Name of a chunk that will be used for each Tag. If no chunk is given, array with available placeholders will be rendered
  15. * &outTpl string optional Name of a chunk that will be used for wrapping all tags. If no chunk is given, tags will be rendered without a wrapper
  16. * &separator string optional String separator, that will be used for separating Tags
  17. * &limit int optional Limit number of returned tag Tags
  18. * &offset int optional Offset the output by this number of Tags
  19. * &totalPh string optional Placeholder to output the total number of Tags regardless of &limit and &offset
  20. * &target int optional An ID of a resource that will be used for generating URI for a Tag. If no ID is given, current Resource ID will be used
  21. * &showUnused int optional If 1 is set, Tags that are not assigned to any Resource will be included to the output as well
  22. * &showUnpublished int optional If 1 is set, Tags that are assigned only to unpublished Resources will be included to the output as well
  23. * &showDeleted int optional If 1 is set, Tags that are assigned only to deleted Resources will be included to the output as well
  24. * &linkCurrentTags int optional If 1 is set, Current Tags will be included in generated URL, default behavior is to generate links to a single tag
  25. * &linkOneTagPerGroup int optional If 1 is set, Only one tag will be placed to a group (in the URI tags from same group will swap places); Only available for linkCurrentTags=1; Default: 0
  26. * &contexts string optional If set, will display only tags for resources in given contexts. Contexts can be separated by a comma
  27. * &toPlaceholder string optional If set, output will return in placeholder with given name
  28. * &sort string optional Sort options in JSON. Example {"tag": "ASC"} or multiple sort options {"group_id": "ASC", "tag": "ASC"}
  29. * &friendlyURL int optional If set, will be used instead of friendly_urls system setting to generate URL
  30. * &linkTagScheme int|string optional Strategy to generate URLs, available values: -1, 0, 1, full, abs, http, https; Default: link_tag_scheme system setting
  31. *
  32. * USAGE:
  33. *
  34. * [[!TaggerGetTags? &showUnused=`1`]]
  35. *
  36. *
  37. * @package tagger
  38. */
  39. /** @var Tagger $tagger */
  40. $tagger = $modx->getService('tagger','Tagger',$modx->getOption('tagger.core_path',null,$modx->getOption('core_path').'components/tagger/').'model/tagger/',$scriptProperties);
  41. if (!($tagger instanceof Tagger)) return '';
  42. $resources = $modx->getOption('resources', $scriptProperties, '');
  43. $parents = $modx->getOption('parents', $scriptProperties, '');
  44. $groups = $modx->getOption('groups', $scriptProperties, '');
  45. $target = (int) $modx->getOption('target', $scriptProperties, $modx->resource->id, true);
  46. $showUnused = (int) $modx->getOption('showUnused', $scriptProperties, '0');
  47. $showUnpublished = (int) $modx->getOption('showUnpublished', $scriptProperties, '0');
  48. $showDeleted = (int) $modx->getOption('showDeleted', $scriptProperties, '0');
  49. $linkCurrentTags = (int) $modx->getOption('linkCurrentTags', $scriptProperties, '0');
  50. $linkOneTagPerGroup = (int) $modx->getOption('linkOneTagPerGroup', $scriptProperties, '0');
  51. $contexts = $modx->getOption('contexts', $scriptProperties, '');
  52. $translate = (int) $modx->getOption('translate', $scriptProperties, '0');
  53. $defaultRowTpl = $modx->getOption('rowTpl', $scriptProperties, '');
  54. $outTpl = $modx->getOption('outTpl', $scriptProperties, '');
  55. $wrapIfEmpty = $modx->getOption('wrapIfEmpty', $scriptProperties, 1);
  56. $separator = $modx->getOption('separator', $scriptProperties, '');
  57. $limit = intval($modx->getOption('limit', $scriptProperties, 0));
  58. $offset = intval($modx->getOption('offset', $scriptProperties, 0));
  59. $totalPh = $modx->getOption('totalPh', $scriptProperties, 'tags_total');
  60. $weight = (int) $modx->getOption('weight', $scriptProperties, '0');
  61. $friendlyURL = (int) $modx->getOption('friendlyURL', $scriptProperties, $modx->getOption('friendly_urls', null, 0));
  62. $linkTagScheme = $modx->getOption('linkTagScheme', $scriptProperties, $modx->getOption('link_tag_scheme', null, -1));
  63. $sort = $modx->getOption('sort', $scriptProperties, '{}');
  64. $sort = $modx->fromJSON($sort);
  65. if ($sort === null || $sort == '' || count($sort) == 0) {
  66. $sort = array(
  67. 'tag' => 'ASC'
  68. );
  69. }
  70. $resources = $tagger->explodeAndClean($resources);
  71. $parents = $tagger->explodeAndClean($parents);
  72. $groups = $tagger->explodeAndClean($groups);
  73. $contexts = $tagger->explodeAndClean($contexts);
  74. $toPlaceholder = $modx->getOption('toPlaceholder', $scriptProperties, '');
  75. $c = $modx->newQuery('TaggerTag');
  76. $c->leftJoin('TaggerTagResource', 'Resources');
  77. $c->leftJoin('TaggerGroup', 'Group');
  78. $c->leftJoin('modResource', 'Resource', array('Resources.resource = Resource.id'));
  79. if (!empty($parents)) {
  80. $c->where(array(
  81. 'Resource.parent:IN' => $parents,
  82. ));
  83. }
  84. if (!empty($contexts)) {
  85. $c->where(array(
  86. 'Resource.context_key:IN' => $contexts,
  87. ));
  88. }
  89. if ($showUnpublished == 0) {
  90. $c->where(array(
  91. 'Resource.published' => 1,
  92. 'OR:Resource.published:IN' => null,
  93. ));
  94. }
  95. if ($showDeleted == 0) {
  96. $c->where(array(
  97. 'Resource.deleted' => 0,
  98. 'OR:Resource.deleted:IS' => null,
  99. ));
  100. }
  101. if ($showUnused == 0) {
  102. $c->having(array(
  103. 'cnt > 0',
  104. ));
  105. }
  106. if (!empty($resources)) {
  107. $c->where(array(
  108. 'Resources.resource:IN' => $resources
  109. ));
  110. }
  111. if ($groups) {
  112. $c->where(array(
  113. 'Group.id:IN' => $groups,
  114. 'OR:Group.name:IN' => $groups,
  115. 'OR:Group.alias:IN' => $groups,
  116. ));
  117. }
  118. $c->select($modx->getSelectColumns('TaggerTag', 'TaggerTag'));
  119. $c->select($modx->getSelectColumns('TaggerGroup', 'Group', 'group_'));
  120. $c->select(array('cnt' => 'COUNT(Resources.tag)'));
  121. $c->groupby($modx->getSelectColumns('TaggerTag', 'TaggerTag') . ',' . $modx->getSelectColumns('TaggerGroup', 'Group'));
  122. $c->prepare();
  123. $countQuery = new xPDOCriteria($modx, "SELECT COUNT(*) as total, MAX(cnt) as max_cnt FROM ({$c->toSQL(false)}) cq", $c->bindings, $c->cacheFlag);
  124. $stmt = $countQuery->prepare();
  125. if ($stmt && $stmt->execute()) {
  126. $fetchedData = $stmt->fetch(PDO::FETCH_ASSOC);
  127. $total = intval($fetchedData['total']);
  128. $maxCnt = intval($fetchedData['max_cnt']);
  129. } else {
  130. $total = 0;
  131. $maxCnt = 0;
  132. }
  133. $modx->setPlaceholder($totalPh, $total);
  134. foreach ($sort as $field => $dir) {
  135. $dir = (strtolower($dir) == 'asc') ? 'asc' : 'desc';
  136. $c->sortby($field, $dir);
  137. }
  138. $c->limit($limit, $offset);
  139. $tags = $modx->getIterator('TaggerTag', $c);
  140. $out = array();
  141. // prep for &tpl_N
  142. $keys = array_keys($scriptProperties);
  143. $nthTpls = array();
  144. foreach($keys as $key) {
  145. $keyBits = $tagger->explodeAndClean($key, '_');
  146. if (isset($keyBits[0]) && $keyBits[0] === 'tpl') {
  147. if ($i = (int) $keyBits[1]) $nthTpls[$i] = $scriptProperties[$key];
  148. }
  149. }
  150. ksort($nthTpls);
  151. $idx = 1;
  152. $currentTags = $tagger->getCurrentTags();
  153. $currentTagsLink = array();
  154. if ($linkCurrentTags == 1) {
  155. foreach($currentTags as $currentTag) {
  156. $currentTagsLink[$currentTag['alias']] = array_keys($currentTag['tags']);
  157. }
  158. }
  159. foreach ($tags as $tag) {
  160. /** @var TaggerTag $tag */
  161. $phs = $tag->toArray();
  162. $group = $tag->Group;
  163. if (($linkOneTagPerGroup === 1) && $currentTagsLink[$group->alias]) {
  164. $linkData = $currentTagsLink;
  165. if (!in_array($tag->alias, $linkData[$group->alias])) {
  166. $linkData[$group->alias] = array($tag->alias);
  167. } else {
  168. $linkData[$group->alias] = array();
  169. }
  170. } else {
  171. $linkData = array_merge_recursive($currentTagsLink, array(
  172. $group->alias => array($tag->alias)
  173. ));
  174. }
  175. $linkData = array_filter(array_map(function($data) {
  176. return array_filter($data, function($value) use ($data) {
  177. return !(array_count_values($data)[$value] > 1);
  178. });
  179. }, $linkData));
  180. if ($friendlyURL == 1) {
  181. $linkPath = array_reduce(array_keys($linkData), function($carry, $item) use ($linkData) {
  182. return $carry . $item . '/' . implode('/', array_unique($linkData[$item])) . '/';
  183. }, '');
  184. $uri = rtrim($modx->makeUrl($target, '', '', $linkTagScheme), '/') . '/' . $linkPath;
  185. } else {
  186. $linkPath = http_build_query(
  187. array_map(function($values) {
  188. return is_array($values) ? implode(',', array_unique($values)) : $values;
  189. }, $linkData)
  190. );
  191. $uri = $modx->makeUrl($target, '', $linkPath, $linkTagScheme);
  192. }
  193. $phs['uri'] = $uri;
  194. $phs['idx'] = $idx;
  195. $phs['target'] = $target;
  196. $phs['max_cnt'] = $maxCnt;
  197. if (isset($currentTags[$group->alias]['tags'][$tag->alias])) {
  198. $phs['active'] = 1;
  199. } else {
  200. $phs['active'] = 0;
  201. }
  202. if ($weight > 0) {
  203. $phs['weight'] = intval(ceil($phs['cnt'] / ($maxCnt / $weight)));
  204. }
  205. if ($translate == 1) {
  206. $groupNameTranslated = $modx->lexicon('tagger.custom.' . $phs['group_alias']);
  207. $groupDescriptionTranslated = $modx->lexicon('tagger.custom.' . $phs['group_alias'] . '_desc');
  208. $phs['group_name_translated'] = ($groupNameTranslated == 'tagger.custom.' . $phs['group_alias']) ? $phs['group_name'] : $groupNameTranslated;
  209. $phs['group_description_translated'] = ($groupDescriptionTranslated == 'tagger.custom.' . $phs['group_alias'] . '_desc') ? $phs['group_description'] : $groupDescriptionTranslated;
  210. }
  211. $rowTpl = $defaultRowTpl;
  212. $phs['sp'] = $scriptProperties;
  213. if ($rowTpl == '') {
  214. $out[] = '<pre>' . print_r($phs, true) . '</pre>';
  215. } else {
  216. if (isset($nthTpls[$idx])) {
  217. $rowTpl = $nthTpls[$idx];
  218. } else {
  219. foreach ($nthTpls as $int => $tpl) {
  220. if ( ($idx % $int) === 0 ) $rowTpl = $tpl;
  221. }
  222. }
  223. $out[] = $tagger->getChunk($rowTpl, $phs);
  224. }
  225. $idx++;
  226. }
  227. $out = implode($separator, $out);
  228. if ($outTpl != '') {
  229. if (!empty($out) || $wrapIfEmpty) {
  230. $noActiveTags = (int)(count($currentTags) === 0);
  231. $out = $tagger->getChunk($outTpl, array('tags' => $out, 'sp' => $scriptProperties, 'noActiveTags' => $noActiveTags));
  232. }
  233. }
  234. if (!empty($toPlaceholder)) {
  235. $modx->setPlaceholder($toPlaceholder, $out);
  236. return '';
  237. }
  238. return $out;
  239. return;