PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/assets/snippets/ditto/classes/ditto.class.inc.php

https://github.com/good-web-master/modx.evo.custom
PHP | 1226 lines | 903 code | 138 blank | 185 comment | 244 complexity | 0c765593e29740d0df53ccabb9eac001 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, MIT, BSD-3-Clause
  1. <?php
  2. /*
  3. * Title: Main Class
  4. * Purpose:
  5. * The Ditto class contains all functions relating to Ditto's
  6. * functionality and any supporting functions they need
  7. */
  8. class ditto {
  9. var $template,$resource,$format,$debug,$advSort,$sqlOrderBy,$customReset,$fields,$constantFields,$prefetch,$sortOrder,$customPlaceholdersMap;
  10. function ditto($dittoID,$format,$language,$debug) {
  11. $this->format = $format;
  12. $GLOBALS["ditto_lang"] = $language;
  13. $this->prefetch = false;
  14. $this->advSort = false;
  15. $this->sqlOrderBy = array();
  16. $this->customReset = array();
  17. $this->constantFields[] = array("db","tv");
  18. $this->constantFields["db"] = array("id","type","contentType","pagetitle","longtitle","description","alias","link_attributes","published","pub_date","unpub_date","parent","isfolder","introtext","content","richtext","template","menuindex","searchable","cacheable","createdby","createdon","editedby","editedon","deleted","deletedon","deletedby","publishedon","publishedby","menutitle","donthit","haskeywords","hasmetatags","privateweb","privatemgr","content_dispo","hidemenu");
  19. $this->constantFields["tv"] = $this->getTVList();
  20. $GLOBALS["ditto_constantFields"] = $this->constantFields;
  21. $this->fields = array("display"=>array(),"backend"=>array("tv"=>array(),"db"=>array("id", "published")));
  22. $this->sortOrder = false;
  23. $this->customPlaceholdersMap = array();
  24. $this->template = new template();
  25. if (!is_null($debug)) {$this->debug = new debug($debug);}
  26. }
  27. // ---------------------------------------------------
  28. // Function: getTVList
  29. // Get a list of all available TVs
  30. // ---------------------------------------------------
  31. function getTVList() {
  32. global $modx;
  33. $table = $modx->getFullTableName("site_tmplvars");
  34. $tvs = $modx->db->select("name", $table);
  35. // TODO: make it so that it only pulls those that apply to the current template
  36. $dbfields = array();
  37. while ($dbfield = $modx->db->getRow($tvs))
  38. $dbfields[] = $dbfield['name'];
  39. return $dbfields;
  40. }
  41. // ---------------------------------------------------
  42. // Function: addField
  43. // Add a field to the internal field detection system
  44. // ---------------------------------------------------
  45. function addField($name,$location,$type=false) {
  46. if ($type === false) {
  47. $type = $this->getDocVarType($name);
  48. }
  49. if ($type == "tv:prefix") {
  50. $type = "tv";
  51. $name = substr($name, 2);
  52. }
  53. if ($location == "*") {
  54. $this->fields["backend"][$type][] = $name;
  55. $this->fields["display"][$type][] = $name;
  56. } else {
  57. $this->fields[$location][$type][] = $name;
  58. }
  59. }
  60. // ---------------------------------------------------
  61. // Function: addFields
  62. // Add a field to the internal field detection system
  63. // from an array or delimited string
  64. // ---------------------------------------------------
  65. function addFields($fields,$location='*',$delimiter=',',$callback=false) {
  66. if (empty($fields)) return false;
  67. if (!is_array($fields)) {
  68. if (strpos($fields,$delimiter) !== false) {
  69. $fields = explode($delimiter,$fields);
  70. } else {
  71. $fields = array($fields);
  72. }
  73. }
  74. foreach ($fields as $field) {
  75. if (is_array($field)) {
  76. $type = isset($field[2]) ? $field[2] : false;
  77. $name = $field[0];
  78. } else {
  79. $name = $field;
  80. $type = false;
  81. }
  82. $this->addField($name,$location,$type);
  83. if ($callback !== false) {
  84. call_user_func_array($callback, array($name));
  85. }
  86. }
  87. return true;
  88. }
  89. // ---------------------------------------------------
  90. // Function: removeField
  91. // Remove a field to the internal field detection system
  92. // ---------------------------------------------------
  93. function removeField($name,$location,$type) {
  94. $key = array_search ($name, $this->fields[$location][$type]);
  95. if ($key !== false) {
  96. unset($this->fields[$location][$type][$key]);
  97. }
  98. }
  99. // ---------------------------------------------------
  100. // Function: setDisplayFields
  101. // Move the detected fields into the Ditto fields array
  102. // ---------------------------------------------------
  103. function setDisplayFields($fields,$hiddenFields) {
  104. $this->fields["display"] = $fields;
  105. if (count($this->fields["display"]['qe']) > 0) {
  106. $this->addField("pagetitle","display","db");
  107. }
  108. if ($hiddenFields) {
  109. $this->addFields($hiddenFields,"display");
  110. }
  111. }
  112. // ---------------------------------------------------
  113. // Function: getDocVarType
  114. // Determine if the provided field is a tv, a database field, or something else
  115. // ---------------------------------------------------
  116. function getDocVarType($field) {
  117. global $ditto_constantFields;
  118. $tvFields = $ditto_constantFields["tv"];
  119. $dbFields = $ditto_constantFields["db"];
  120. if(in_array($field, $tvFields)){
  121. return "tv";
  122. }else if(in_array(substr($field,2), $tvFields)) {
  123. return "tv:prefix";
  124. // TODO: Remove TV Prefix support
  125. } else if(in_array($field, $dbFields)){
  126. return "db";
  127. } else {
  128. return "unknown";
  129. }
  130. }
  131. // ---------------------------------------------------
  132. // Function: parseOrderBy
  133. // Parse out orderBy parameter string
  134. // ---------------------------------------------------
  135. function parseOrderBy($orderBy,$randomize) {
  136. if ($randomize != 0) {return false;}
  137. $orderBy['sql'] = array();
  138. foreach ($orderBy['parsed'] as $item) {
  139. $this->addFields($item[0],'backend');
  140. $this->checkAdvSort($item[0],$item[1]);
  141. }
  142. foreach ($orderBy['custom'] as $item) {
  143. $this->addFields($item[0],'backend');
  144. $this->checkAdvSort($item[0]);
  145. }
  146. if (!is_null($orderBy['unparsed'])) {
  147. $inputs = explode(',',$orderBy['unparsed']);
  148. foreach ($inputs as $input) {
  149. $input = trim($input);
  150. $position = strrpos($input,' ');
  151. // find last space
  152. $sortBy = substr($input,0,$position);
  153. $sortBy = !empty($sortBy) ? $sortBy : 'id';
  154. $sortDir = substr($input,$position);
  155. $sortDir = !empty($sortDir) ? trim($sortDir) : 'asc';
  156. $sortBy = $this->checkAdvSort($sortBy,$sortDir);
  157. $this->addField($sortBy,"backend");
  158. $orderBy['parsed'][] = array($sortBy,strtoupper($sortDir));
  159. }
  160. }
  161. $orderBy['sql'] = implode(', ',$this->sqlOrderBy);
  162. unset($orderBy['unparsed']);
  163. return $orderBy;
  164. }
  165. // ---------------------------------------------------
  166. // Function: checkAdvSort
  167. // Check the advSortString
  168. // ---------------------------------------------------
  169. function checkAdvSort($sortBy,$sortDir='asc') {
  170. $advSort = array ("pub_date","unpub_date","editedon","deletedon","publishedon");
  171. $type = $this->getDocVarType($sortBy);
  172. switch($type) {
  173. case "tv:prefix":
  174. $sortBy = substr($sortBy, 2);
  175. $this->advSort = true;
  176. break;
  177. case "tv":
  178. $this->advSort = true;
  179. break;
  180. case "db":
  181. if (in_array($sortBy, $advSort)) {
  182. $this->advSort = true;
  183. $this->customReset[] = $sortBy;
  184. } else {
  185. $this->sqlOrderBy[] = 'sc.'.$sortBy.' '.$sortDir;
  186. }
  187. break;
  188. }
  189. return $sortBy;
  190. }
  191. // ---------------------------------------------------
  192. // Function: parseFilters
  193. // Split up the filters into an array and add the required fields to the fields array
  194. // ---------------------------------------------------
  195. function parseFilters($filter=false,$cFilters=false,$pFilters = false,$globalDelimiter,$localDelimiter) {
  196. $parsedFilters = array("basic"=>array(),"custom"=>array());
  197. $filters = explode($globalDelimiter, $filter);
  198. if ($filter && count($filters) > 0) {
  199. foreach ($filters AS $filter) {
  200. if (!empty($filter)) {
  201. $filterArray = explode($localDelimiter, $filter);
  202. $source = $filterArray[0];
  203. $this->addField($source,"backend");
  204. $value = $filterArray[1];
  205. $mode = (isset ($filterArray[2])) ? $filterArray[2] : 1;
  206. $parsedFilters["basic"][] = array("source"=>$source,"value"=>$value,"mode"=>$mode);
  207. }
  208. }
  209. }
  210. if ($cFilters) {
  211. foreach ($cFilters as $name=>$value) {
  212. if (!empty($name) && !empty($value)) {
  213. $parsedFilters["custom"][$name] = $value[1];
  214. $this->addFields($value[0],"backend");
  215. }
  216. } // TODO: Replace addField with addFields with callback
  217. }
  218. if($pFilters) {
  219. foreach ($pFilters as $filter) {
  220. foreach ($filter as $name=>$value) {
  221. $parsedFilters["basic"][] = $value;
  222. $this->addFields($value["source"],"backend");
  223. }
  224. } // TODO: Replace addField with addFields with callback
  225. }
  226. return $parsedFilters;
  227. }
  228. // ---------------------------------------------------
  229. // Function: render
  230. // Render the document output
  231. // ---------------------------------------------------
  232. function render($resource, $template, $removeChunk,$dateSource,$dateFormat,$ph=array(),$phx=1,$x=0) {
  233. global $modx,$ditto_lang;
  234. if (!is_array($resource)) {
  235. return $ditto_lang["resource_array_error"];
  236. }
  237. $placeholders = array();
  238. $contentVars = array();
  239. foreach ($resource as $name=>$value) {
  240. $placeholders["$name"] = $value;
  241. $contentVars["[*$name*]"] = $value;
  242. }
  243. // set author placeholder
  244. if (in_array("author",$this->fields["display"]["custom"])) {
  245. $placeholders['author'] = $this->getAuthor($resource['createdby']);
  246. }
  247. // set title placeholder
  248. if (in_array("title",$this->fields["display"]["custom"])) {
  249. $placeholders['title'] = $resource['pagetitle'];
  250. }
  251. // set sequence placeholder
  252. if (in_array("ditto_iteration",$this->fields["display"]["custom"])) {
  253. $placeholders['ditto_iteration'] = $x;
  254. }
  255. //Added by Andchir
  256. //if (in_array("ditto_index",$this->fields["display"]["custom"])) {
  257. $r_start = isset($_GET['start']) ? $_GET['start'] : 0;
  258. $placeholders['ditto_index'] = $r_start+$x+1;
  259. //}
  260. // set url placeholder
  261. if (in_array("url",$this->fields["display"]["custom"])) {
  262. $placeholders['url'] = $modx->makeURL($resource['id'],'','','full');
  263. }
  264. if (in_array("date",$this->fields["display"]["custom"])) {
  265. $timestamp = ($resource[$dateSource] != "0") ? $resource[$dateSource] : $resource["createdon"];
  266. $placeholders['date'] = strftime($dateFormat,$timestamp);
  267. }
  268. if (in_array("content",$this->fields["display"]["db"]) && $this->format != "html") {
  269. $resource['content'] = $this->relToAbs($resource['content'], $modx->config['site_url']);
  270. }
  271. if (in_array("introtext",$this->fields["display"]["db"]) && $this->format != "html") {
  272. $resource['introtext'] = $this->relToAbs($resource['introtext'], $modx->config['site_url']);
  273. }
  274. $customPlaceholders = $ph;
  275. // set custom placeholder
  276. foreach ($ph as $name=>$value) {
  277. if ($name != "*") {
  278. $placeholders[$name] = call_user_func($value[1],$resource);
  279. unset($customPlaceholders[$name]);
  280. }
  281. }
  282. foreach ($customPlaceholders as $name=>$value) {
  283. $placeholders = call_user_func($value,$placeholders);
  284. }
  285. if (count($this->fields["display"]['qe']) > 0) {
  286. $placeholders = $this->renderQELinks($this->template->fields['qe'],$resource,$ditto_lang["edit"]." : ".$resource['pagetitle']." : ",$placeholders);
  287. // set QE Placeholders
  288. }
  289. if ($phx == 1) {
  290. $PHs = $placeholders;
  291. foreach($PHs as $key=>$output) {
  292. $placeholders[$key] = str_replace( array_keys( $contentVars ), array_values( $contentVars ), $output );
  293. }
  294. unset($PHs);
  295. $phx = new prePHx($template);
  296. $phx->setPlaceholders($placeholders);
  297. $output = $phx->output();
  298. } else {
  299. $output = $this->template->replace($placeholders,$template);
  300. $output = $this->template->replace($contentVars,$output);
  301. }
  302. if ($removeChunk) {
  303. foreach ($removeChunk as $chunk) {
  304. $output = str_replace('{{'.$chunk.'}}',"",$output);
  305. $output = str_replace($modx->getChunk($chunk),"",$output);
  306. // remove chunk that is not wanted
  307. }
  308. }
  309. return $output;
  310. }
  311. // ---------------------------------------------------
  312. // Function: parseFields
  313. // Find the fields that are contained in the custom placeholders or those that are needed in other functions
  314. // ---------------------------------------------------
  315. function parseFields($placeholders,$seeThruUnpub,$dateSource,$randomize) {
  316. $this->parseCustomPlaceholders($placeholders);
  317. $this->parseDBFields($seeThruUnpub);
  318. if ($randomize != 0) {
  319. $this->addField($randomize,"backend");
  320. }
  321. $this->addField("id","display","db");
  322. $this->addField("pagetitle","display","db");
  323. $checkOptions = array("pub_date","unpub_date","editedon","deletedon","publishedon");
  324. if (in_array($dateSource,$checkOptions)) {
  325. $this->addField("createdon","display");
  326. }
  327. if (in_array("date",$this->fields["display"]["custom"])) {
  328. $this->addField($dateSource,"display");
  329. }
  330. $this->fields = $this->arrayUnique($this->fields);
  331. }
  332. // ---------------------------------------------------
  333. // Function: arrayUnique
  334. // Make fields array unique
  335. // ---------------------------------------------------
  336. function arrayUnique($array) {
  337. foreach($array as $u => $a) {
  338. foreach ($a as $n => $b) {
  339. $array[$u][$n] = array_unique($b);
  340. }
  341. }
  342. return $array;
  343. }
  344. // ---------------------------------------------------
  345. // Function: parseCustomPlaceholders
  346. // Parse the required fields out of the custom placeholders
  347. // ---------------------------------------------------
  348. function parseCustomPlaceholders($placeholders) {
  349. foreach ($placeholders as $name=>$value) {
  350. $this->addField($name,"display","custom");
  351. $this->removeField($name,"display","unknown");
  352. $source = $value[0];
  353. $qe = $value[2];
  354. if(is_array($source)) {
  355. if(strpos($source[0],",")!==false){
  356. $fields = explode(",",$source[0]);
  357. foreach ($fields as $field) {
  358. if (!empty($field)) {
  359. $this->addField($field,$source[1]);
  360. $this->customPlaceholdersMap[$name] = $field;
  361. }
  362. }
  363. } else {
  364. $this->addField($source[0],$source[1]);
  365. $this->customPlaceholdersMap[$name] = $source[0];
  366. } // TODO: Replace addField with addFields with callback
  367. } else if(is_array($value)) {
  368. $fields = explode(",",$source);
  369. foreach ($fields as $field) {
  370. if (!empty($field)) {
  371. $this->addField($field,"display");
  372. $this->customPlaceholdersMap[$name] = $field;
  373. }
  374. }
  375. }
  376. if (!is_null($qe)) {
  377. $this->customPlaceholdersMap[$name] = array('qe',$qe);
  378. }
  379. }
  380. }
  381. // ---------------------------------------------------
  382. // Function: parseDBFields
  383. // Parse out the fields required for each state
  384. // ---------------------------------------------------
  385. function parseDBFields($seeThruUnpub) {
  386. if (!$seeThruUnpub) {
  387. $this->addField("parent","backend","db");
  388. }
  389. if (in_array("author",$this->fields["display"]["custom"])) {
  390. $this->fields["display"]["db"][] = "createdby";
  391. }
  392. if (count($this->fields["display"]["tv"]) >= 0) {
  393. $this->addField("published","display","db");
  394. }
  395. }
  396. // ---------------------------------------------------
  397. // Function: renderQELinks
  398. // Render QE links when needed
  399. // ---------------------------------------------------
  400. function renderQELinks($fields, $resource, $QEPrefix,$placeholders) {
  401. global $modx,$dittoID;
  402. $table = $modx->getFullTableName("site_modules");
  403. $idResult = $modx->db->select("id", $table,"name='QuickEdit'","id","1");
  404. $id = $modx->db->getRow($idResult);
  405. $id = $id["id"];
  406. $custom = array("author","date","url","title");
  407. $set = $modx->hasPermission('exec_module');
  408. foreach ($fields as $dv) {
  409. $ds = $dv;
  410. if ($dv == "title") {
  411. $ds = "pagetitle";
  412. }
  413. if (!in_array($dv,$custom) && in_array($dv,$this->fields["display"]["custom"])) {
  414. $value = $this->customPlaceholdersMap[$dv];
  415. $ds = $value;
  416. if (is_array($value) && $value[0] == "qe") {
  417. $value = $value[1];
  418. if (substr($value,0,7) == "@GLOBAL") {
  419. $key = trim(substr($value,7));
  420. $ds = $GLOBALS[$key];
  421. }
  422. }
  423. }
  424. $js = "window.open('".$modx->config["site_url"]."manager/index.php?a=112&id=".$id."&doc=".$resource["id"]."&var=".$ds."', 'QuickEditor', 'width=525, height=300, toolbar=0, menubar=0, status=0, alwaysRaised=1, dependent=1');";
  425. $url = $this->buildURL("qe_open=true",$modx->documentIdentifier,$dittoID);
  426. unset($custom[3]);
  427. if ($set && !in_array($dv,$custom)) {
  428. $placeholders["#$dv"] = $placeholders["$dv"].'<a href="'.$url.'#" onclick="javascript: '.$js.'" title="'.$QEPrefix.$dv.'" class="QE_Link">&laquo; '.$QEPrefix.$dv.'</a>';
  429. } else {
  430. $placeholders["#$dv"] = $placeholders["$dv"];
  431. }
  432. }
  433. return $placeholders;
  434. }
  435. // ---------------------------------------------------
  436. // Function: getAuthor
  437. // Get the author name, or if not available the username
  438. // ---------------------------------------------------
  439. function getAuthor($createdby) {
  440. global $modx;
  441. $user = false;
  442. if ($createdby > 0) {
  443. $user = $modx->getUserInfo($createdby);
  444. } else {
  445. $user = $modx->getWebUserInfo(abs($createdby));
  446. }
  447. if ($user === false) {
  448. // get admin user name
  449. $user = $modx->getUserInfo(1);
  450. }
  451. return ($user['fullname'] != "") ? $user['fullname'] : $user['username'];
  452. }
  453. // ---------------------------------------------------
  454. // Function: customSort
  455. // Sort resource array if advanced sorting is needed
  456. // ---------------------------------------------------
  457. function customSort($data, $fields, $order) {
  458. // Covert $fields string to array
  459. // user contributed
  460. foreach (explode(',', $fields) as $s)
  461. $sortfields[] = trim($s);
  462. $code = "";
  463. for ($c = 0; $c < count($sortfields); $c++)
  464. $code .= "\$retval = strnatcmp(\$a['$sortfields[$c]'], \$b['$sortfields[$c]']); if(\$retval) return \$retval; ";
  465. $code .= "return \$retval;";
  466. $params = ($order == 'ASC') ? '$a,$b' : '$b,$a';
  467. uasort($data, create_function($params, $code));
  468. return $data;
  469. }
  470. // ---------------------------------------------------
  471. // Function: userSort
  472. // Sort the resource array by a user defined function
  473. // ---------------------------------------------------
  474. function userSort($resource,$sort) {
  475. foreach ($sort['custom'] as $item) {
  476. usort($resource,$item[1]);
  477. }
  478. return $resource;
  479. }
  480. // ---------------------------------------------------
  481. // Function: multiSort
  482. // Sort the resource array by multiple fields
  483. // Rows->Columns portion by Jon L. -- intel352@gmail.com
  484. // Link: http://de3.php.net/manual/en/function.array-multisort.php#73498
  485. // ---------------------------------------------------
  486. function multiSort($resource,$orderBy) {
  487. $sort_arr = array();
  488. foreach($resource AS $uniqid => $row){
  489. foreach($row AS $key=>$value){
  490. $sort_arr[$key][$uniqid] = $value;
  491. }
  492. }
  493. $array_multisort = 'return array_multisort(';
  494. foreach ($orderBy['parsed'] as $sort) {
  495. $array_multisort .= '$sort_arr["'.$sort[0].'"], SORT_'.$sort[1].', ';
  496. }
  497. $array_multisort .= '$resource);';
  498. eval($array_multisort);
  499. return $resource;
  500. }
  501. // ---------------------------------------------------
  502. // Function: determineIDs
  503. // Get Document IDs for future use
  504. // ---------------------------------------------------
  505. function determineIDs($IDs, $IDType, $TVs, $orderBy, $depth, $showPublishedOnly, $seeThruUnpub, $hideFolders, $hidePrivate, $showInMenuOnly, $myWhere, $keywords, $dateSource, $limit, $summarize, $filter, $paginate, $randomize) {
  506. global $modx;
  507. if (($summarize == 0 && $summarize != "all") || count($IDs) == 0 || ($IDs == false && $IDs != "0")) {
  508. return array();
  509. }
  510. // Get starting IDs;
  511. switch($IDType) {
  512. case "parents":
  513. $IDs = explode(",",$IDs);
  514. $documentIDs = $this->getChildIDs($IDs, $depth);
  515. break;
  516. case "documents":
  517. $documentIDs = explode(",",$IDs);
  518. break;
  519. }
  520. if ($this->advSort == false && $hideFolders==0 && $showInMenuOnly==0 && $myWhere == "" && $filter == false && $hidePrivate == 1 && $keywords==0) {
  521. $this->prefetch = false;
  522. $documents = $this->getDocumentsIDs($documentIDs, $showPublishedOnly);
  523. $documentIDs = array();
  524. if ($documents) {
  525. foreach ($documents as $null=>$doc) {
  526. $documentIDs[] = $doc["id"];
  527. }
  528. }
  529. return $documentIDs;
  530. } else {
  531. $this->prefetch = true;
  532. }
  533. // Create where clause
  534. $where = array ();
  535. if ($hideFolders) {
  536. $where[] = 'isfolder = 0';
  537. }
  538. if ($showInMenuOnly) {
  539. $where[] = 'hidemenu = 0';
  540. }
  541. if ($myWhere != '') {
  542. $where[] = $myWhere;
  543. }
  544. $where = implode(" AND ", $where);
  545. $limit = ($limit == 0) ? "" : $limit;
  546. // set limit
  547. $customReset = $this->customReset;
  548. if ($keywords) {$this->addField("haskeywords","*","db");$this->addField("hasmetatags","*","db");}
  549. if ($this->debug) {$this->addField("pagetitle","backend","db");}
  550. if (count($customReset) > 0) {$this->addField("createdon","backend","db");}
  551. $resource = $this->getDocuments($documentIDs,$this->fields["backend"]["db"],$TVs,$orderBy,$showPublishedOnly,0,$hidePrivate,$where,$limit,$keywords,$randomize,$dateSource);
  552. if ($resource !== false) {
  553. $resource = array_values($resource);
  554. // remove #'s from keys
  555. $recordCount = count($resource);
  556. // count number of records
  557. if (!$seeThruUnpub) {
  558. $parentList = $this->getParentList();
  559. // get parent list
  560. }
  561. for ($i = 0; $i < $recordCount; $i++) {
  562. if (!$seeThruUnpub) {
  563. $published = $parentList[$resource[$i]["parent"]];
  564. if ($published == "0")
  565. unset ($resource[$i]);
  566. }
  567. if (count($customReset) > 0) {
  568. foreach ($customReset as $field) {
  569. if ($resource[$i][$field] === "0") {
  570. $resource[$i][$field] = $resource[$i]["createdon"];
  571. }
  572. }
  573. }
  574. }
  575. if ($this->debug) {
  576. $dbg_resource = $resource;
  577. }
  578. if ($filter != false) {
  579. $filterObj = new filter();
  580. $resource = $filterObj->execute($resource, $filter);
  581. }
  582. if (count($resource) < 1) return array();
  583. if ($this->advSort == true && $randomize==0) {
  584. $resource = $this->multiSort($resource,$orderBy);
  585. }
  586. if (count($orderBy['custom']) > 0) {
  587. $resource = $this->userSort($resource,$orderBy);
  588. }
  589. $fields = (array_intersect($this->fields["backend"],$this->fields["display"]));
  590. $readyFields = array();
  591. foreach ($fields as $field) {
  592. $readyFields = array_merge($readyFields,$field);
  593. }
  594. $processedIDs = array ();
  595. $keep = array();
  596. foreach ($resource as $key => $value) {
  597. $processedIDs[] = $value['id'];
  598. $iKey = '#'.$value['id'];
  599. foreach ($value as $key=>$v) {
  600. if (in_array($key,$readyFields)) {
  601. $keep[$iKey][$key] = $v;
  602. }
  603. if ($this->getDocVarType($key) == "tv:prefix") {
  604. if (in_array(substr($key,2),$readyFields)) {
  605. $keep[$iKey][$key] = $v;
  606. }
  607. }
  608. }
  609. }
  610. $this->prefetch = array("resource"=>$keep,"fields"=>$fields);
  611. if ($this->debug) {
  612. $this->prefetch["dbg_resource"] = $dbg_resource;
  613. $this->prefetch["dbg_IDs_pre"] = $documentIDs;
  614. $this->prefetch["dbg_IDs_post"] = $processedIDs;
  615. }
  616. if (count($processedIDs) > 0) {
  617. if ($randomize != 0) {shuffle($processedIDs);}
  618. $this->sortOrder = array_flip($processedIDs);
  619. // saves the order of the documents for use later
  620. }
  621. return $processedIDs;
  622. } else {
  623. return array();
  624. }
  625. }
  626. // ---------------------------------------------------
  627. // Function: weightedRandom
  628. // Execute a random order sort
  629. // ---------------------------------------------------
  630. function weightedRandom($resource,$field,$show) {
  631. $type = $this->getDocVarType($field);
  632. if ($type == "unknown") {
  633. return $resource;
  634. // handle vad field passed
  635. }
  636. $random = new random();
  637. foreach ($resource as $document) {
  638. $doc = $document;
  639. $random->add($doc,abs(intval($document[$field])));
  640. }
  641. $resource = $random->select_weighted_unique($show);
  642. shuffle($resource);
  643. return $resource;
  644. }
  645. // ---------------------------------------------------
  646. // Function: getParentList
  647. // Get a list of all available parents
  648. // ---------------------------------------------------
  649. function getParentList() {
  650. global $modx;
  651. $kids = array();
  652. foreach ($modx->documentMap as $null => $document) {
  653. foreach ($document as $parent => $id) {
  654. $kids[$parent][] = $id;
  655. }
  656. }
  657. $parents = array();
  658. foreach ($kids as $item => $value) {
  659. if ($item != 0) {
  660. $pInfo = $modx->getPageInfo($item,0,"published");
  661. } else {
  662. $pInfo["published"] = "1";
  663. }
  664. $parents[$item] = $pInfo["published"];
  665. }
  666. return $parents;
  667. }
  668. // ---------------------------------------------------
  669. // Function: appendTV
  670. // Apeend a TV to the documents array
  671. // ---------------------------------------------------
  672. function appendTV($tvname="",$docIDs){
  673. global $modx;
  674. $baspath= $modx->config["base_path"] . "manager/includes";
  675. include_once $baspath . "/tmplvars.format.inc.php";
  676. include_once $baspath . "/tmplvars.commands.inc.php";
  677. $tb1 = $modx->getFullTableName("site_tmplvar_contentvalues");
  678. $tb2 = $modx->getFullTableName("site_tmplvars");
  679. $query = "SELECT stv.name,stc.tmplvarid,stc.contentid,stv.type,stv.display,stv.display_params,stc.value";
  680. $query .= " FROM ".$tb1." stc LEFT JOIN ".$tb2." stv ON stv.id=stc.tmplvarid ";
  681. $query .= " WHERE stv.name='".$tvname."' AND stc.contentid IN (".implode($docIDs,",").") ORDER BY stc.contentid ASC;";
  682. $rs = $modx->db->query($query);
  683. $tot = $modx->db->getRecordCount($rs);
  684. $resourceArray = array();
  685. for($i=0;$i<$tot;$i++) {
  686. $row = @$modx->fetchRow($rs);
  687. $resourceArray["#".$row['contentid']][$row['name']] = getTVDisplayFormat($row['name'], $row['value'], $row['display'], $row['display_params'], $row['type'],$row['contentid']);
  688. $resourceArray["#".$row['contentid']]["tv".$row['name']] = $resourceArray["#".$row['contentid']][$row['name']];
  689. }
  690. if ($tot != count($docIDs)) {
  691. $query = "SELECT name,type,display,display_params,default_text";
  692. $query .= " FROM $tb2";
  693. $query .= " WHERE name='".$tvname."' LIMIT 1";
  694. $rs = $modx->db->query($query);
  695. $row = @$modx->fetchRow($rs);
  696. if (strtoupper($row['default_text']) == '@INHERIT') {
  697. foreach ($docIDs as $id) {
  698. $defaultOutput = getTVDisplayFormat($row['name'], $row['default_text'], $row['display'], $row['display_params'], $row['type'], $id);
  699. if (!isset($resourceArray["#".$id])) {
  700. $resourceArray["#$id"][$tvname] = $defaultOutput;
  701. $resourceArray["#$id"]["tv".$tvname] = $resourceArray["#$id"][$tvname];
  702. }
  703. }
  704. } else {
  705. $defaultOutput = getTVDisplayFormat($row['name'], $row['default_text'], $row['display'], $row['display_params'], $row['type'],$row['contentid']);
  706. foreach ($docIDs as $id) {
  707. if (!isset($resourceArray["#".$id])) {
  708. $resourceArray["#$id"][$tvname] = $defaultOutput;
  709. $resourceArray["#$id"]["tv".$tvname] = $resourceArray["#$id"][$tvname];
  710. }
  711. }
  712. }
  713. }
  714. return $resourceArray;
  715. }
  716. // ---------------------------------------------------
  717. // Function: appendKeywords
  718. // Append keywords's to the resource array
  719. // ---------------------------------------------------
  720. function appendKeywords($resource) {
  721. $keys = $this->fetchKeywords($resource);
  722. $resource["keywords"] = "$keys";
  723. return $resource;
  724. }
  725. // ---------------------------------------------------
  726. // Function: fetchKeywords
  727. // Helper function to <appendKeywords>
  728. // ---------------------------------------------------
  729. function fetchKeywords($resource) {
  730. global $modx;
  731. if($resource['haskeywords']==1) {
  732. // insert keywords
  733. $metas = implode(",",$modx->getKeywords($resource["id"]));
  734. }
  735. if($resource['hasmetatags']==1){
  736. // insert meta tags
  737. $tags = $modx->getMETATags($resource["id"]);
  738. foreach ($tags as $n=>$col) {
  739. $tag = strtolower($col['tag']);
  740. $metas.= ",".$col['tagvalue'];
  741. }
  742. }
  743. return $metas;
  744. }
  745. // ---------------------------------------------------
  746. // Function: getChildIDs
  747. // Get the IDs ready to be processed
  748. // Similar to the modx version by the same name but much faster
  749. // ---------------------------------------------------
  750. function getChildIDs($IDs, $depth) {
  751. global $modx;
  752. $depth = intval($depth);
  753. $kids = array();
  754. $docIDs = array();
  755. if ($depth == 0 && $IDs[0] == 0 && count($IDs) == 1) {
  756. foreach ($modx->documentMap as $null => $document) {
  757. foreach ($document as $parent => $id) {
  758. $kids[] = $id;
  759. }
  760. }
  761. return $kids;
  762. } else if ($depth == 0) {
  763. $depth = 10000;
  764. // Impliment unlimited depth...
  765. }
  766. foreach ($modx->documentMap as $null => $document) {
  767. foreach ($document as $parent => $id) {
  768. $kids[$parent][] = $id;
  769. }
  770. }
  771. foreach ($IDs AS $seed) {
  772. if (!empty($kids[intval($seed)])) {
  773. $docIDs = array_merge($docIDs,$kids[intval($seed)]);
  774. unset($kids[intval($seed)]);
  775. }
  776. }
  777. $depth--;
  778. while($depth != 0) {
  779. $valid = $docIDs;
  780. foreach ($docIDs as $child=>$id) {
  781. if (!empty($kids[intval($id)])) {
  782. $docIDs = array_merge($docIDs,$kids[intval($id)]);
  783. unset($kids[intval($id)]);
  784. }
  785. }
  786. $depth--;
  787. if ($valid == $docIDs) $depth = 0;
  788. }
  789. return array_unique($docIDs);
  790. }
  791. // ---------------------------------------------------
  792. // Function: getDocuments
  793. // Get documents and append TVs + Prefetch Data, and sort
  794. // ---------------------------------------------------
  795. function getDocuments($ids= array (), $fields, $TVs, $orderBy, $published= 1, $deleted= 0, $public= 1, $where= '', $limit= "",$keywords=0,$randomize=0,$dateSource=false) {
  796. global $modx;
  797. if (count($ids) == 0) {
  798. return false;
  799. } else {
  800. sort($ids);
  801. $limit= ($limit != "") ? "LIMIT $limit" : ""; // LIMIT capabilities - rad14701
  802. $tblsc= $modx->getFullTableName("site_content");
  803. $tbldg= $modx->getFullTableName("document_groups");
  804. $tbltvc = $modx->getFullTableName("site_tmplvar_contentvalues");
  805. // modify field names to use sc. table reference
  806. $fields= "sc.".implode(",sc.",$fields);
  807. if ($randomize != 0) {
  808. $sort = "RAND()";
  809. } else {
  810. $sort= $orderBy['sql'];
  811. }
  812. //Added by Andchir (http://modx-shopkeeper.ru/)
  813. if(substr($where, 0, 5)=="@SQL:"){
  814. $where = ($where == "") ? "" : substr(str_replace('@eq','=',$where), 5);
  815. $left_join_tvc = "LEFT JOIN $tbltvc tvc ON sc.id = tvc.contentid";
  816. }else{
  817. $where = ($where == "") ? "" : 'AND sc.' . implode('AND sc.', preg_replace("/^\s/i", "", explode('AND', $where)));
  818. $left_join_tvc = '';
  819. }
  820. if ($public) {
  821. // get document groups for current user
  822. if ($docgrp= $modx->getUserDocGroups())
  823. $docgrp= implode(",", $docgrp);
  824. $access= ($modx->isFrontend() ? "sc.privateweb=0" : "1='" . $_SESSION['mgrRole'] . "' OR sc.privatemgr=0") .
  825. (!$docgrp ? "" : " OR dg.document_group IN ($docgrp)");
  826. }
  827. $published = ($published) ? "AND sc.published=1" : "";
  828. //$sql = "SELECT DISTINCT $fields FROM $tblsc sc
  829. $sql = "SELECT DISTINCT $fields FROM $tblsc sc $left_join_tvc
  830. LEFT JOIN $tbldg dg on dg.document = sc.id
  831. WHERE sc.id IN (" . join($ids, ",") . ") $published AND sc.deleted=$deleted $where
  832. ".($public ? 'AND ('.$access.')' : '')." GROUP BY sc.id" .
  833. ($sort ? " ORDER BY $sort" : "") . " $limit ";
  834. $result= $modx->db->query($sql);
  835. $resourceArray= array ();
  836. $cnt = @$modx->db->getRecordCount($result);
  837. $TVData = array();
  838. $TVIDs = array();
  839. if ($cnt) {
  840. for ($i= 0; $i < $cnt; $i++) {
  841. $resource = $modx->fetchRow($result);
  842. if ($modx->config["server_offset_time"] != 0 && $dateSource !== false) {
  843. $dateValue = (is_int($resource[$dateSource]) !== true) ? $resource[$dateSource] : strtotime($resource[$dateSource]);
  844. $resource[$dateSource] = $dateValue + $modx->config["server_offset_time"];
  845. }
  846. if($keywords) {
  847. $resource = $this->appendKeywords($resource);
  848. }
  849. if ($this->prefetch == true && $this->sortOrder !== false) $resource["ditto_sort"] = $this->sortOrder[$resource["id"]];
  850. $TVIDs[] = $resource["id"];
  851. $resourceArray["#".$resource["id"]] = $resource;
  852. if (count($this->prefetch["resource"]) > 0) {
  853. $x = "#".$resource["id"];
  854. $resourceArray[$x] = array_merge($resource,$this->prefetch["resource"][$x]);
  855. // merge the prefetch array and the normal array
  856. }
  857. }
  858. $TVs = array_unique($TVs);
  859. if (count($TVs) > 0) {
  860. foreach($TVs as $tv){
  861. $TVData = array_merge_recursive($this->appendTV($tv,$TVIDs),$TVData);
  862. }
  863. }
  864. $resourceArray = array_merge_recursive($resourceArray,$TVData);
  865. if ($this->prefetch == true && $this->sortOrder !== false) {
  866. $resourceArray = $this->customSort($resourceArray,"ditto_sort","ASC");
  867. }
  868. return $resourceArray;
  869. } else {
  870. return false;
  871. }
  872. }
  873. }
  874. // ---------------------------------------------------
  875. // Function: getDocumentsLite
  876. // Get an array of documents
  877. // ---------------------------------------------------
  878. function getDocumentsIDs($ids= array (), $published= 1) {
  879. global $modx;
  880. if (count($ids) == 0) {
  881. return false;
  882. } else {
  883. $tblsc= $modx->getFullTableName("site_content");
  884. $tbldg= $modx->getFullTableName("document_groups");
  885. if ($docgrp= $modx->getUserDocGroups())
  886. $docgrp= implode(",", $docgrp);
  887. $access= ($modx->isFrontend() ? "sc.privateweb=0" : "1='" . $_SESSION['mgrRole'] . "' OR sc.privatemgr=0") .
  888. (!$docgrp ? "" : " OR dg.document_group IN ($docgrp)");
  889. $published = ($published) ? "AND sc.published=1" : "";
  890. $sql= "SELECT DISTINCT sc.id FROM $tblsc sc
  891. LEFT JOIN $tbldg dg on dg.document = sc.id
  892. WHERE (sc.id IN (" . join($ids, ",") . ") $published AND sc.deleted=0)
  893. AND ($access)
  894. GROUP BY sc.id ";
  895. $result= $modx->dbQuery($sql);
  896. $resourceArray= array ();
  897. for ($i= 0; $i < @ $modx->recordCount($result); $i++) {
  898. array_push($resourceArray, @ $modx->fetchRow($result));
  899. }
  900. return $resourceArray;
  901. }
  902. }
  903. // ---------------------------------------------------
  904. // Function: cleanIDs
  905. // Clean the IDs of any dangerous characters
  906. // ---------------------------------------------------
  907. function cleanIDs($IDs) {
  908. //Define the pattern to search for
  909. $pattern = array (
  910. '`(,)+`', //Multiple commas
  911. '`^(,)`', //Comma on first position
  912. '`(,)$`' //Comma on last position
  913. );
  914. //Define replacement parameters
  915. $replace = array (
  916. ',',
  917. '',
  918. ''
  919. );
  920. //Clean startID (all chars except commas and numbers are removed)
  921. $IDs = preg_replace($pattern, $replace, $IDs);
  922. return $IDs;
  923. }
  924. // ---------------------------------------------------
  925. // Function: buildURL
  926. // Build a URL with regard to Ditto ID
  927. // ---------------------------------------------------
  928. function buildURL($args,$id=false,$dittoIdentifier=false) {
  929. global $modx, $dittoID;
  930. $dittoID = ($dittoIdentifier !== false) ? $dittoIdentifier : $dittoID;
  931. $query = array();
  932. foreach ($_GET as $param=>$value) {
  933. if ($param != 'id' && $param != 'q') {
  934. if(is_array($value)) {
  935. //$query[$param] = $value;
  936. foreach($value as $key => $val) {
  937. $query[htmlspecialchars($param, ENT_QUOTES)][] = htmlspecialchars($val, ENT_QUOTES);
  938. }
  939. }else{
  940. $query[htmlspecialchars($param, ENT_QUOTES)] = htmlspecialchars($value, ENT_QUOTES);
  941. }
  942. }
  943. }
  944. if (!is_array($args)) {
  945. $args = explode("&",$args);
  946. foreach ($args as $arg) {
  947. $arg = explode("=",$arg);
  948. $query[$dittoID.$arg[0]] = urlencode(trim($arg[1]));
  949. }
  950. } else {
  951. foreach ($args as $name=>$value) {
  952. $query[$dittoID.$name] = urlencode(trim($value));
  953. }
  954. }
  955. $queryString = "";
  956. foreach ($query as $param=>$value){
  957. //$queryString .= '&'.$param.'='.(is_array($value) ? implode(",",$value) : $value);
  958. if(!is_array($value)){
  959. $queryString .= '&'.$param.'='.$value;
  960. }else{
  961. foreach ($value as $key=>$val){
  962. $queryString .= '&'.$param.'[]='.$val;
  963. }
  964. }
  965. }
  966. $cID = ($id !== false) ? $id : $modx->documentObject['id'];
  967. $url = $modx->makeURL(trim($cID), '', $queryString);
  968. return ($modx->config['xhtml_urls']) ? $url : str_replace("&","&amp;",$url);
  969. }
  970. // ---------------------------------------------------
  971. // Function: getParam
  972. // Get a parameter or use the default language value
  973. // ---------------------------------------------------
  974. function getParam($param,$langString){
  975. // get a parameter value and if it is not set get the default language string value
  976. global $modx,$ditto_lang;
  977. $out = "";
  978. if ($this->template->fetch($param) != "") {
  979. return $modx->getChunk($param);
  980. } else if(!empty($param)) {
  981. return $param;
  982. }else{
  983. return $ditto_lang[$langString];
  984. }
  985. }
  986. // ---------------------------------------------------
  987. // Function: paginate
  988. // Paginate the documents
  989. // ---------------------------------------------------
  990. function paginate($start, $stop, $total, $summarize, $tplPaginateNext, $tplPaginatePrevious, $tplPaginateNextOff, $tplPaginatePreviousOff, $tplPaginatePage, $tplPaginateCurrentPage, $paginateAlwaysShowLinks, $paginateSplitterCharacter) {
  991. global $modx, $dittoID,$ditto_lang;
  992. if ($stop == 0 || $total == 0 || $summarize==0) {
  993. return false;
  994. }
  995. $next = $start + $summarize;
  996. $rNext = $this->template->replace(array('url'=>$this->buildURL("start=$next"),'lang:next'=>$ditto_lang['next']),$tplPaginateNext);
  997. $previous = $start - $summarize;
  998. $rPrevious = $this->template->replace(array('url'=>$this->buildURL("start=$previous"),'lang:previous'=>$ditto_lang['prev']),$tplPaginatePrevious);
  999. $limten = $summarize + $start;
  1000. if ($paginateAlwaysShowLinks == 1) {
  1001. $previousplaceholder = $this->template->replace(array('lang:previous'=>$ditto_lang['prev']),$tplPaginatePreviousOff);
  1002. $nextplaceholder = $this->template->replace(array('lang:next'=>$ditto_lang['next']),$tplPaginateNextOff);
  1003. } else {
  1004. $previousplaceholder = "";
  1005. $nextplaceholder = "";
  1006. }
  1007. $split = "";
  1008. if ($previous > -1 && $next < $total)
  1009. $split = $paginateSplitterCharacter;
  1010. if ($previous > -1)
  1011. $previousplaceholder = $rPrevious;
  1012. if ($next < $total)
  1013. $nextplaceholder = $rNext;
  1014. if ($start < $total)
  1015. $stop = $limten;
  1016. if ($limten > $total) {
  1017. $limiter = $total;
  1018. } else {
  1019. $limiter = $limten;
  1020. }
  1021. $totalpages = ceil($total / $summarize);
  1022. $max_paginate = 10;
  1023. $max_previous = 5;
  1024. $cur_x = floor($start / $summarize);
  1025. $min_x = $cur_x - $max_previous;
  1026. if ($min_x < 0) $min_x = 0;
  1027. $max_x = $min_x + $max_paginate - 1;
  1028. if ($max_x > $totalpages - 1) {
  1029. $max_x = $totalpages - 1;
  1030. $min_x = $max_x - $max_paginate + 1;
  1031. }
  1032. for ($x = 0; $x <= $totalpages -1; $x++) {
  1033. $inc = $x * $summarize;
  1034. $display = $x +1;
  1035. if (($x < $min_x) || ($x > $max_x)) continue;
  1036. if ($inc != $start) {
  1037. $pages .= $this->template->replace(array('url'=>$this->buildURL("start=$inc"),'page'=>$display),$tplPaginatePage);
  1038. } else {
  1039. $modx->setPlaceholder($dittoID."currentPage", $display);
  1040. $pages .= $this->template->replace(array('page'=>$display),$tplPaginateCurrentPage);
  1041. }
  1042. }
  1043. if ($totalpages>1){
  1044. $modx->setPlaceholder($dittoID."next", $nextplaceholder);
  1045. $modx->setPlaceholder($dittoID."previous", $previousplaceholder);
  1046. $modx->setPlaceholder($dittoID."pages", $pages);
  1047. }
  1048. $modx->setPlaceholder($dittoID."splitter", $split);
  1049. $modx->setPlaceholder($dittoID."start", $start +1);
  1050. $modx->setPlaceholder($dittoID."urlStart", $start);
  1051. $modx->setPlaceholder($dittoID."stop", $limiter);
  1052. $modx->setPlaceholder($dittoID."total", $total);
  1053. $modx->setPlaceholder($dittoID."perPage", $summarize);
  1054. $modx->setPlaceholder($dittoID."totalPages", $totalpages);
  1055. $modx->setPlaceholder($dittoID."ditto_pagination_set", true);
  1056. }
  1057. // ---------------------------------------------------
  1058. // Function: noResults
  1059. // Render the noResults output
  1060. // ---------------------------------------------------
  1061. function noResults($text,$paginate) {
  1062. global $modx, $dittoID;
  1063. $set = $modx->getPlaceholder($dittoID."ditto_pagination_set");
  1064. if ($paginate && $set !== true) {
  1065. $modx->setPlaceholder($dittoID."next", "");
  1066. $modx->setPlaceholder($dittoID."previous", "");
  1067. $modx->setPlaceholder($dittoID."splitter", "");
  1068. $modx->setPlaceholder($dittoID."start", 0);
  1069. $modx->setPlaceholder($dittoID."urlStart", "#start");
  1070. $modx->setPlaceholder($dittoID."stop", 0);
  1071. $modx->setPlaceholder($dittoID."total", 0);
  1072. $modx->setPlaceholder($dittoID."pages", "");
  1073. $modx->setPlaceholder($dittoID."perPage", 0);
  1074. $modx->setPlaceholder($dittoID."totalPages", 0);
  1075. $modx->setPlaceholder($dittoID."currentPage", 0);
  1076. }
  1077. return $text;
  1078. }
  1079. // ---------------------------------------------------
  1080. // Function: relToAbs
  1081. // Convert relative urls to absolute URLs
  1082. // Based on script from http://wintermute.com.au/bits/2005-09/php-relative-absolute-links/
  1083. // ---------------------------------------------------
  1084. function relToAbs($text, $base) {
  1085. return preg_replace('#(href|src)="([^:"]*)(?:")#','$1="'.$base.'$2"',$text);
  1086. }
  1087. }
  1088. ?>