26.include.cache.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. <?php
  2. /**
  3. * getResources
  4. *
  5. * A general purpose Resource listing and summarization snippet for MODX 2.x.
  6. *
  7. * @author Jason Coward
  8. * @copyright Copyright 2010-2013, Jason Coward
  9. *
  10. * TEMPLATES
  11. *
  12. * tpl - Name of a chunk serving as a resource template
  13. * [NOTE: if not provided, properties are dumped to output for each resource]
  14. *
  15. * tplOdd - (Opt) Name of a chunk serving as resource template for resources with an odd idx value
  16. * (see idx property)
  17. * tplFirst - (Opt) Name of a chunk serving as resource template for the first resource (see first
  18. * property)
  19. * tplLast - (Opt) Name of a chunk serving as resource template for the last resource (see last
  20. * property)
  21. * tpl_{n} - (Opt) Name of a chunk serving as resource template for the nth resource
  22. *
  23. * tplCondition - (Opt) Defines a field of the resource to evaluate against keys defined in the
  24. * conditionalTpls property. Must be a resource field; does not work with Template Variables.
  25. * conditionalTpls - (Opt) A JSON object defining a map of field values and the associated tpl to
  26. * use when the field defined by tplCondition matches the value. [NOTE: tplOdd, tplFirst, tplLast,
  27. * and tpl_{n} will take precedence over any defined conditionalTpls]
  28. *
  29. * tplWrapper - (Opt) Name of a chunk serving as a wrapper template for the output
  30. * [NOTE: Does not work with toSeparatePlaceholders]
  31. *
  32. * SELECTION
  33. *
  34. * parents - Comma-delimited list of ids serving as parents
  35. *
  36. * context - (Opt) Comma-delimited list of context keys to limit results by; if empty, contexts for all specified
  37. * parents will be used (all contexts if 0 is specified) [default=]
  38. *
  39. * depth - (Opt) Integer value indicating depth to search for resources from each parent [default=10]
  40. *
  41. * tvFilters - (Opt) Delimited-list of TemplateVar values to filter resources by. Supports two
  42. * delimiters and two value search formats. The first delimiter || represents a logical OR and the
  43. * primary grouping mechanism. Within each group you can provide a comma-delimited list of values.
  44. * These values can be either tied to a specific TemplateVar by name, e.g. myTV==value, or just the
  45. * value, indicating you are searching for the value in any TemplateVar tied to the Resource. An
  46. * example would be &tvFilters=`filter2==one,filter1==bar%||filter1==foo`
  47. * [NOTE: filtering by values uses a LIKE query and % is considered a wildcard.]
  48. * [NOTE: this only looks at the raw value set for specific Resource, i. e. there must be a value
  49. * specifically set for the Resource and it is not evaluated.]
  50. *
  51. * tvFiltersAndDelimiter - (Opt) Custom delimiter for logical AND, default ',', in case you want to
  52. * match a literal comma in the tvFilters. E.g. &tvFiltersAndDelimiter=`&&`
  53. * &tvFilters=`filter1==foo,bar&&filter2==baz` [default=,]
  54. *
  55. * tvFiltersOrDelimiter - (Opt) Custom delimiter for logical OR, default '||', in case you want to
  56. * match a literal '||' in the tvFilters. E.g. &tvFiltersOrDelimiter=`|OR|`
  57. * &tvFilters=`filter1==foo||bar|OR|filter2==baz` [default=||]
  58. *
  59. * where - (Opt) A JSON expression of criteria to build any additional where clauses from. An example would be
  60. * &where=`{{"alias:LIKE":"foo%", "OR:alias:LIKE":"%bar"},{"OR:pagetitle:=":"foobar", "AND:description:=":"raboof"}}`
  61. *
  62. * sortby - (Opt) Field to sort by or a JSON array, e.g. {"publishedon":"ASC","createdon":"DESC"} [default=publishedon]
  63. * sortbyTV - (opt) A Template Variable name to sort by (if supplied, this precedes the sortby value) [default=]
  64. * sortbyTVType - (Opt) A data type to CAST a TV Value to in order to sort on it properly [default=string]
  65. * sortbyAlias - (Opt) Query alias for sortby field [default=]
  66. * sortbyEscaped - (Opt) Escapes the field name(s) specified in sortby [default=0]
  67. * sortdir - (Opt) Order which to sort by [default=DESC]
  68. * sortdirTV - (Opt) Order which to sort by a TV [default=DESC]
  69. * limit - (Opt) Limits the number of resources returned [default=5]
  70. * offset - (Opt) An offset of resources returned by the criteria to skip [default=0]
  71. * dbCacheFlag - (Opt) Controls caching of db queries; 0|false = do not cache result set; 1 = cache result set
  72. * according to cache settings, any other integer value = number of seconds to cache result set [default=0]
  73. *
  74. * OPTIONS
  75. *
  76. * includeContent - (Opt) Indicates if the content of each resource should be returned in the
  77. * results [default=0]
  78. * includeTVs - (Opt) Indicates if TemplateVar values should be included in the properties available
  79. * to each resource template [default=0]
  80. * includeTVList - (Opt) Limits the TemplateVars that are included if includeTVs is true to those specified
  81. * by name in a comma-delimited list [default=]
  82. * prepareTVs - (Opt) Prepares media-source dependent TemplateVar values [default=1]
  83. * prepareTVList - (Opt) Limits the TVs that are prepared to those specified by name in a comma-delimited
  84. * list [default=]
  85. * processTVs - (Opt) Indicates if TemplateVar values should be rendered as they would on the
  86. * resource being summarized [default=0]
  87. * processTVList - (opt) Limits the TemplateVars that are processed if included to those specified
  88. * by name in a comma-delimited list [default=]
  89. * tvPrefix - (Opt) The prefix for TemplateVar properties [default=tv.]
  90. * idx - (Opt) You can define the starting idx of the resources, which is an property that is
  91. * incremented as each resource is rendered [default=1]
  92. * first - (Opt) Define the idx which represents the first resource (see tplFirst) [default=1]
  93. * last - (Opt) Define the idx which represents the last resource (see tplLast) [default=# of
  94. * resources being summarized + first - 1]
  95. * outputSeparator - (Opt) An optional string to separate each tpl instance [default="\n"]
  96. * wrapIfEmpty - (Opt) Indicates if the tplWrapper should be applied if the output is empty [default=0]
  97. *
  98. */
  99. $output = array();
  100. $outputSeparator = isset($outputSeparator) ? $outputSeparator : "\n";
  101. /* set default properties */
  102. $tpl = !empty($tpl) ? $tpl : '';
  103. $includeContent = !empty($includeContent) ? true : false;
  104. $includeTVs = !empty($includeTVs) ? true : false;
  105. $includeTVList = !empty($includeTVList) ? explode(',', $includeTVList) : array();
  106. $processTVs = !empty($processTVs) ? true : false;
  107. $processTVList = !empty($processTVList) ? explode(',', $processTVList) : array();
  108. $prepareTVs = !empty($prepareTVs) ? true : false;
  109. $prepareTVList = !empty($prepareTVList) ? explode(',', $prepareTVList) : array();
  110. $tvPrefix = isset($tvPrefix) ? $tvPrefix : 'tv.';
  111. $parents = (!empty($parents) || $parents === '0') ? explode(',', $parents) : array($modx->resource->get('id'));
  112. array_walk($parents, 'trim');
  113. $parents = array_unique($parents);
  114. $depth = isset($depth) ? (integer) $depth : 10;
  115. $tvFiltersOrDelimiter = isset($tvFiltersOrDelimiter) ? $tvFiltersOrDelimiter : '||';
  116. $tvFiltersAndDelimiter = isset($tvFiltersAndDelimiter) ? $tvFiltersAndDelimiter : ',';
  117. $tvFilters = !empty($tvFilters) ? explode($tvFiltersOrDelimiter, $tvFilters) : array();
  118. $where = !empty($where) ? $modx->fromJSON($where) : array();
  119. $showUnpublished = !empty($showUnpublished) ? true : false;
  120. $showDeleted = !empty($showDeleted) ? true : false;
  121. $sortby = isset($sortby) ? $sortby : 'publishedon';
  122. $sortbyTV = isset($sortbyTV) ? $sortbyTV : '';
  123. $sortbyAlias = isset($sortbyAlias) ? $sortbyAlias : 'modResource';
  124. $sortbyEscaped = !empty($sortbyEscaped) ? true : false;
  125. $sortdir = isset($sortdir) ? $sortdir : 'DESC';
  126. $sortdirTV = isset($sortdirTV) ? $sortdirTV : 'DESC';
  127. $limit = isset($limit) ? (integer) $limit : 5;
  128. $offset = isset($offset) ? (integer) $offset : 0;
  129. $totalVar = !empty($totalVar) ? $totalVar : 'total';
  130. $dbCacheFlag = !isset($dbCacheFlag) ? false : $dbCacheFlag;
  131. if (is_string($dbCacheFlag) || is_numeric($dbCacheFlag)) {
  132. if ($dbCacheFlag == '0') {
  133. $dbCacheFlag = false;
  134. } elseif ($dbCacheFlag == '1') {
  135. $dbCacheFlag = true;
  136. } else {
  137. $dbCacheFlag = (integer) $dbCacheFlag;
  138. }
  139. }
  140. /* multiple context support */
  141. $contextArray = array();
  142. $contextSpecified = false;
  143. if (!empty($context)) {
  144. $contextArray = explode(',',$context);
  145. array_walk($contextArray, 'trim');
  146. $contexts = array();
  147. foreach ($contextArray as $ctx) {
  148. $contexts[] = $modx->quote($ctx);
  149. }
  150. $context = implode(',',$contexts);
  151. $contextSpecified = true;
  152. unset($contexts,$ctx);
  153. } else {
  154. $context = $modx->quote($modx->context->get('key'));
  155. }
  156. $pcMap = array();
  157. $pcQuery = $modx->newQuery('modResource', array('id:IN' => $parents), $dbCacheFlag);
  158. $pcQuery->select(array('id', 'context_key'));
  159. if ($pcQuery->prepare() && $pcQuery->stmt->execute()) {
  160. foreach ($pcQuery->stmt->fetchAll(PDO::FETCH_ASSOC) as $pcRow) {
  161. $pcMap[(integer) $pcRow['id']] = $pcRow['context_key'];
  162. }
  163. }
  164. $children = array();
  165. $parentArray = array();
  166. foreach ($parents as $parent) {
  167. $parent = (integer) $parent;
  168. if ($parent === 0) {
  169. $pchildren = array();
  170. if ($contextSpecified) {
  171. foreach ($contextArray as $pCtx) {
  172. if (!in_array($pCtx, $contextArray)) {
  173. continue;
  174. }
  175. $options = $pCtx !== $modx->context->get('key') ? array('context' => $pCtx) : array();
  176. $pcchildren = $modx->getChildIds($parent, $depth, $options);
  177. if (!empty($pcchildren)) $pchildren = array_merge($pchildren, $pcchildren);
  178. }
  179. } else {
  180. $cQuery = $modx->newQuery('modContext', array('key:!=' => 'mgr'));
  181. $cQuery->select(array('key'));
  182. if ($cQuery->prepare() && $cQuery->stmt->execute()) {
  183. foreach ($cQuery->stmt->fetchAll(PDO::FETCH_COLUMN) as $pCtx) {
  184. $options = $pCtx !== $modx->context->get('key') ? array('context' => $pCtx) : array();
  185. $pcchildren = $modx->getChildIds($parent, $depth, $options);
  186. if (!empty($pcchildren)) $pchildren = array_merge($pchildren, $pcchildren);
  187. }
  188. }
  189. }
  190. $parentArray[] = $parent;
  191. } else {
  192. $pContext = array_key_exists($parent, $pcMap) ? $pcMap[$parent] : false;
  193. if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, "context for {$parent} is {$pContext}");
  194. if ($pContext && $contextSpecified && !in_array($pContext, $contextArray, true)) {
  195. $parent = next($parents);
  196. continue;
  197. }
  198. $parentArray[] = $parent;
  199. $options = !empty($pContext) && $pContext !== $modx->context->get('key') ? array('context' => $pContext) : array();
  200. $pchildren = $modx->getChildIds($parent, $depth, $options);
  201. }
  202. if (!empty($pchildren)) $children = array_merge($children, $pchildren);
  203. $parent = next($parents);
  204. }
  205. $parents = array_merge($parentArray, $children);
  206. /* build query */
  207. $criteria = array("modResource.parent IN (" . implode(',', $parents) . ")");
  208. if ($contextSpecified) {
  209. $contextResourceTbl = $modx->getTableName('modContextResource');
  210. $criteria[] = "(modResource.context_key IN ({$context}) OR EXISTS(SELECT 1 FROM {$contextResourceTbl} ctx WHERE ctx.resource = modResource.id AND ctx.context_key IN ({$context})))";
  211. }
  212. if (empty($showDeleted)) {
  213. $criteria['deleted'] = '0';
  214. }
  215. if (empty($showUnpublished)) {
  216. $criteria['published'] = '1';
  217. }
  218. if (empty($showHidden)) {
  219. $criteria['hidemenu'] = '0';
  220. }
  221. if (!empty($hideContainers)) {
  222. $criteria['isfolder'] = '0';
  223. }
  224. $criteria = $modx->newQuery('modResource', $criteria);
  225. if (!empty($tvFilters)) {
  226. $tmplVarTbl = $modx->getTableName('modTemplateVar');
  227. $tmplVarResourceTbl = $modx->getTableName('modTemplateVarResource');
  228. $conditions = array();
  229. $operators = array(
  230. '<=>' => '<=>',
  231. '===' => '=',
  232. '!==' => '!=',
  233. '<>' => '<>',
  234. '==' => 'LIKE',
  235. '!=' => 'NOT LIKE',
  236. '<<' => '<',
  237. '<=' => '<=',
  238. '=<' => '=<',
  239. '>>' => '>',
  240. '>=' => '>=',
  241. '=>' => '=>'
  242. );
  243. foreach ($tvFilters as $fGroup => $tvFilter) {
  244. $filterGroup = array();
  245. $filters = explode($tvFiltersAndDelimiter, $tvFilter);
  246. $multiple = count($filters) > 0;
  247. foreach ($filters as $filter) {
  248. $operator = '==';
  249. $sqlOperator = 'LIKE';
  250. foreach ($operators as $op => $opSymbol) {
  251. if (strpos($filter, $op, 1) !== false) {
  252. $operator = $op;
  253. $sqlOperator = $opSymbol;
  254. break;
  255. }
  256. }
  257. $tvValueField = 'tvr.value';
  258. $tvDefaultField = 'tv.default_text';
  259. $f = explode($operator, $filter);
  260. if (count($f) >= 2) {
  261. if (count($f) > 2) {
  262. $k = array_shift($f);
  263. $b = join($operator, $f);
  264. $f = array($k, $b);
  265. }
  266. $tvName = $modx->quote($f[0]);
  267. if (is_numeric($f[1]) && !in_array($sqlOperator, array('LIKE', 'NOT LIKE'))) {
  268. $tvValue = $f[1];
  269. if ($f[1] == (integer)$f[1]) {
  270. $tvValueField = "CAST({$tvValueField} AS SIGNED INTEGER)";
  271. $tvDefaultField = "CAST({$tvDefaultField} AS SIGNED INTEGER)";
  272. } else {
  273. $tvValueField = "CAST({$tvValueField} AS DECIMAL)";
  274. $tvDefaultField = "CAST({$tvDefaultField} AS DECIMAL)";
  275. }
  276. } else {
  277. $tvValue = $modx->quote($f[1]);
  278. }
  279. if ($multiple) {
  280. $filterGroup[] =
  281. "(EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.name = {$tvName} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id) " .
  282. "OR EXISTS (SELECT 1 FROM {$tmplVarTbl} tv WHERE tv.name = {$tvName} AND {$tvDefaultField} {$sqlOperator} {$tvValue} AND tv.id NOT IN (SELECT tmplvarid FROM {$tmplVarResourceTbl} WHERE contentid = modResource.id)) " .
  283. ")";
  284. } else {
  285. $filterGroup =
  286. "(EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.name = {$tvName} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id) " .
  287. "OR EXISTS (SELECT 1 FROM {$tmplVarTbl} tv WHERE tv.name = {$tvName} AND {$tvDefaultField} {$sqlOperator} {$tvValue} AND tv.id NOT IN (SELECT tmplvarid FROM {$tmplVarResourceTbl} WHERE contentid = modResource.id)) " .
  288. ")";
  289. }
  290. } elseif (count($f) == 1) {
  291. $tvValue = $modx->quote($f[0]);
  292. if ($multiple) {
  293. $filterGroup[] = "EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id)";
  294. } else {
  295. $filterGroup = "EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id)";
  296. }
  297. }
  298. }
  299. $conditions[] = $filterGroup;
  300. }
  301. if (!empty($conditions)) {
  302. $firstGroup = true;
  303. foreach ($conditions as $cGroup => $c) {
  304. if (is_array($c)) {
  305. $first = true;
  306. foreach ($c as $cond) {
  307. if ($first && !$firstGroup) {
  308. $criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_OR, null, $cGroup);
  309. } else {
  310. $criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_AND, null, $cGroup);
  311. }
  312. $first = false;
  313. }
  314. } else {
  315. $criteria->condition($criteria->query['where'][0][1], $c, $firstGroup ? xPDOQuery::SQL_AND : xPDOQuery::SQL_OR, null, $cGroup);
  316. }
  317. $firstGroup = false;
  318. }
  319. }
  320. }
  321. /* include/exclude resources, via &resources=`123,-456` prop */
  322. if (!empty($resources)) {
  323. $resourceConditions = array();
  324. $resources = explode(',',$resources);
  325. $include = array();
  326. $exclude = array();
  327. foreach ($resources as $resource) {
  328. $resource = (int)$resource;
  329. if ($resource == 0) continue;
  330. if ($resource < 0) {
  331. $exclude[] = abs($resource);
  332. } else {
  333. $include[] = $resource;
  334. }
  335. }
  336. if (!empty($include)) {
  337. $criteria->where(array('OR:modResource.id:IN' => $include), xPDOQuery::SQL_OR);
  338. }
  339. if (!empty($exclude)) {
  340. $criteria->where(array('modResource.id:NOT IN' => $exclude), xPDOQuery::SQL_AND, null, 1);
  341. }
  342. }
  343. if (!empty($where)) {
  344. $criteria->where($where);
  345. }
  346. $total = $modx->getCount('modResource', $criteria);
  347. $modx->setPlaceholder($totalVar, $total);
  348. $fields = array_keys($modx->getFields('modResource'));
  349. if (empty($includeContent)) {
  350. $fields = array_diff($fields, array('content'));
  351. }
  352. $columns = $includeContent ? $modx->getSelectColumns('modResource', 'modResource') : $modx->getSelectColumns('modResource', 'modResource', '', array('content'), true);
  353. $criteria->select($columns);
  354. if (!empty($sortbyTV)) {
  355. $criteria->leftJoin('modTemplateVar', 'tvDefault', array(
  356. "tvDefault.name" => $sortbyTV
  357. ));
  358. $criteria->leftJoin('modTemplateVarResource', 'tvSort', array(
  359. "tvSort.contentid = modResource.id",
  360. "tvSort.tmplvarid = tvDefault.id"
  361. ));
  362. if (empty($sortbyTVType)) $sortbyTVType = 'string';
  363. if ($modx->getOption('dbtype') === 'mysql') {
  364. switch ($sortbyTVType) {
  365. case 'integer':
  366. $criteria->select("CAST(IFNULL(tvSort.value, tvDefault.default_text) AS SIGNED INTEGER) AS sortTV");
  367. break;
  368. case 'decimal':
  369. $criteria->select("CAST(IFNULL(tvSort.value, tvDefault.default_text) AS DECIMAL) AS sortTV");
  370. break;
  371. case 'datetime':
  372. $criteria->select("CAST(IFNULL(tvSort.value, tvDefault.default_text) AS DATETIME) AS sortTV");
  373. break;
  374. case 'string':
  375. default:
  376. $criteria->select("IFNULL(tvSort.value, tvDefault.default_text) AS sortTV");
  377. break;
  378. }
  379. } elseif ($modx->getOption('dbtype') === 'sqlsrv') {
  380. switch ($sortbyTVType) {
  381. case 'integer':
  382. $criteria->select("CAST(ISNULL(tvSort.value, tvDefault.default_text) AS BIGINT) AS sortTV");
  383. break;
  384. case 'decimal':
  385. $criteria->select("CAST(ISNULL(tvSort.value, tvDefault.default_text) AS DECIMAL) AS sortTV");
  386. break;
  387. case 'datetime':
  388. $criteria->select("CAST(ISNULL(tvSort.value, tvDefault.default_text) AS DATETIME) AS sortTV");
  389. break;
  390. case 'string':
  391. default:
  392. $criteria->select("ISNULL(tvSort.value, tvDefault.default_text) AS sortTV");
  393. break;
  394. }
  395. }
  396. $criteria->sortby("sortTV", $sortdirTV);
  397. }
  398. if (!empty($sortby)) {
  399. if (strpos($sortby, '{') === 0) {
  400. $sorts = $modx->fromJSON($sortby);
  401. } else {
  402. $sorts = array($sortby => $sortdir);
  403. }
  404. if (is_array($sorts)) {
  405. while (list($sort, $dir) = each($sorts)) {
  406. if ($sortbyEscaped) $sort = $modx->escape($sort);
  407. if (!empty($sortbyAlias)) $sort = $modx->escape($sortbyAlias) . ".{$sort}";
  408. $criteria->sortby($sort, $dir);
  409. }
  410. }
  411. }
  412. if (!empty($limit)) $criteria->limit($limit, $offset);
  413. if (!empty($debug)) {
  414. $criteria->prepare();
  415. $modx->log(modX::LOG_LEVEL_ERROR, $criteria->toSQL());
  416. }
  417. $collection = $modx->getCollection('modResource', $criteria, $dbCacheFlag);
  418. $idx = !empty($idx) || $idx === '0' ? (integer) $idx : 1;
  419. $first = empty($first) && $first !== '0' ? 1 : (integer) $first;
  420. $last = empty($last) ? (count($collection) + $idx - 1) : (integer) $last;
  421. /* include parseTpl */
  422. include_once $modx->getOption('getresources.core_path',null,$modx->getOption('core_path').'components/getresources/').'include.parsetpl.php';
  423. $templateVars = array();
  424. if (!empty($includeTVs) && !empty($includeTVList)) {
  425. $templateVars = $modx->getCollection('modTemplateVar', array('name:IN' => $includeTVList));
  426. }
  427. /** @var modResource $resource */
  428. foreach ($collection as $resourceId => $resource) {
  429. $tvs = array();
  430. if (!empty($includeTVs)) {
  431. if (empty($includeTVList)) {
  432. $templateVars = $resource->getMany('TemplateVars');
  433. }
  434. /** @var modTemplateVar $templateVar */
  435. foreach ($templateVars as $tvId => $templateVar) {
  436. if (!empty($includeTVList) && !in_array($templateVar->get('name'), $includeTVList)) continue;
  437. if ($processTVs && (empty($processTVList) || in_array($templateVar->get('name'), $processTVList))) {
  438. $tvs[$tvPrefix . $templateVar->get('name')] = $templateVar->renderOutput($resource->get('id'));
  439. } else {
  440. $value = $templateVar->getValue($resource->get('id'));
  441. if ($prepareTVs && method_exists($templateVar, 'prepareOutput') && (empty($prepareTVList) || in_array($templateVar->get('name'), $prepareTVList))) {
  442. $value = $templateVar->prepareOutput($value);
  443. }
  444. $tvs[$tvPrefix . $templateVar->get('name')] = $value;
  445. }
  446. }
  447. }
  448. $odd = ($idx & 1);
  449. $properties = array_merge(
  450. $scriptProperties
  451. ,array(
  452. 'idx' => $idx
  453. ,'first' => $first
  454. ,'last' => $last
  455. ,'odd' => $odd
  456. )
  457. ,$includeContent ? $resource->toArray() : $resource->get($fields)
  458. ,$tvs
  459. );
  460. $resourceTpl = false;
  461. if ($idx == $first && !empty($tplFirst)) {
  462. $resourceTpl = parseTpl($tplFirst, $properties);
  463. }
  464. if ($idx == $last && empty($resourceTpl) && !empty($tplLast)) {
  465. $resourceTpl = parseTpl($tplLast, $properties);
  466. }
  467. $tplidx = 'tpl_' . $idx;
  468. if (empty($resourceTpl) && !empty($$tplidx)) {
  469. $resourceTpl = parseTpl($$tplidx, $properties);
  470. }
  471. if ($idx > 1 && empty($resourceTpl)) {
  472. $divisors = getDivisors($idx);
  473. if (!empty($divisors)) {
  474. foreach ($divisors as $divisor) {
  475. $tplnth = 'tpl_n' . $divisor;
  476. if (!empty($$tplnth)) {
  477. $resourceTpl = parseTpl($$tplnth, $properties);
  478. if (!empty($resourceTpl)) {
  479. break;
  480. }
  481. }
  482. }
  483. }
  484. }
  485. if ($odd && empty($resourceTpl) && !empty($tplOdd)) {
  486. $resourceTpl = parseTpl($tplOdd, $properties);
  487. }
  488. if (!empty($tplCondition) && !empty($conditionalTpls) && empty($resourceTpl)) {
  489. $conTpls = $modx->fromJSON($conditionalTpls);
  490. $subject = $properties[$tplCondition];
  491. $tplOperator = !empty($tplOperator) ? $tplOperator : '=';
  492. $tplOperator = strtolower($tplOperator);
  493. $tplCon = '';
  494. foreach ($conTpls as $operand => $conditionalTpl) {
  495. switch ($tplOperator) {
  496. case '!=':
  497. case 'neq':
  498. case 'not':
  499. case 'isnot':
  500. case 'isnt':
  501. case 'unequal':
  502. case 'notequal':
  503. $tplCon = (($subject != $operand) ? $conditionalTpl : $tplCon);
  504. break;
  505. case '<':
  506. case 'lt':
  507. case 'less':
  508. case 'lessthan':
  509. $tplCon = (($subject < $operand) ? $conditionalTpl : $tplCon);
  510. break;
  511. case '>':
  512. case 'gt':
  513. case 'greater':
  514. case 'greaterthan':
  515. $tplCon = (($subject > $operand) ? $conditionalTpl : $tplCon);
  516. break;
  517. case '<=':
  518. case 'lte':
  519. case 'lessthanequals':
  520. case 'lessthanorequalto':
  521. $tplCon = (($subject <= $operand) ? $conditionalTpl : $tplCon);
  522. break;
  523. case '>=':
  524. case 'gte':
  525. case 'greaterthanequals':
  526. case 'greaterthanequalto':
  527. $tplCon = (($subject >= $operand) ? $conditionalTpl : $tplCon);
  528. break;
  529. case 'isempty':
  530. case 'empty':
  531. $tplCon = empty($subject) ? $conditionalTpl : $tplCon;
  532. break;
  533. case '!empty':
  534. case 'notempty':
  535. case 'isnotempty':
  536. $tplCon = !empty($subject) && $subject != '' ? $conditionalTpl : $tplCon;
  537. break;
  538. case 'isnull':
  539. case 'null':
  540. $tplCon = $subject == null || strtolower($subject) == 'null' ? $conditionalTpl : $tplCon;
  541. break;
  542. case 'inarray':
  543. case 'in_array':
  544. case 'ia':
  545. $operand = explode(',', $operand);
  546. $tplCon = in_array($subject, $operand) ? $conditionalTpl : $tplCon;
  547. break;
  548. case 'between':
  549. case 'range':
  550. case '>=<':
  551. case '><':
  552. $operand = explode(',', $operand);
  553. $tplCon = ($subject >= min($operand) && $subject <= max($operand)) ? $conditionalTpl : $tplCon;
  554. break;
  555. case '==':
  556. case '=':
  557. case 'eq':
  558. case 'is':
  559. case 'equal':
  560. case 'equals':
  561. case 'equalto':
  562. default:
  563. $tplCon = (($subject == $operand) ? $conditionalTpl : $tplCon);
  564. break;
  565. }
  566. }
  567. if (!empty($tplCon)) {
  568. $resourceTpl = parseTpl($tplCon, $properties);
  569. }
  570. }
  571. if (!empty($tpl) && empty($resourceTpl)) {
  572. $resourceTpl = parseTpl($tpl, $properties);
  573. }
  574. if ($resourceTpl === false && !empty($debug)) {
  575. $chunk = $modx->newObject('modChunk');
  576. $chunk->setCacheable(false);
  577. $output[]= $chunk->process(array(), '<pre>' . print_r($properties, true) .'</pre>');
  578. } else {
  579. $output[]= $resourceTpl;
  580. }
  581. $idx++;
  582. }
  583. /* output */
  584. $toSeparatePlaceholders = $modx->getOption('toSeparatePlaceholders', $scriptProperties, false);
  585. if (!empty($toSeparatePlaceholders)) {
  586. $modx->setPlaceholders($output, $toSeparatePlaceholders);
  587. return '';
  588. }
  589. $output = implode($outputSeparator, $output);
  590. $tplWrapper = $modx->getOption('tplWrapper', $scriptProperties, false);
  591. $wrapIfEmpty = $modx->getOption('wrapIfEmpty', $scriptProperties, false);
  592. if (!empty($tplWrapper) && ($wrapIfEmpty || !empty($output))) {
  593. $output = parseTpl($tplWrapper, array_merge($scriptProperties, array('output' => $output)));
  594. }
  595. $toPlaceholder = $modx->getOption('toPlaceholder', $scriptProperties, false);
  596. if (!empty($toPlaceholder)) {
  597. $modx->setPlaceholder($toPlaceholder, $output);
  598. return '';
  599. }
  600. return $output;
  601. return;