PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/assets/snippets/wayfinder/wayfinder.inc.php

https://github.com/good-web-master/modx.evo.custom
PHP | 686 lines | 535 code | 47 blank | 104 comment | 183 complexity | 41554b7fb711a7e015b4a5278d52d9f6 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, MIT, BSD-3-Clause
  1. <?php
  2. /*
  3. ::::::::::::::::::::::::::::::::::::::::
  4. Snippet name: Wayfinder
  5. Short Desc: builds site navigation
  6. Version: 2.0.1
  7. Authors:
  8. Kyle Jaebker (muddydogpaws.com)
  9. Ryan Thrash (vertexworks.com)
  10. Date: February 27, 2006
  11. ::::::::::::::::::::::::::::::::::::::::
  12. */
  13. class Wayfinder {
  14. var $_config;
  15. var $_templates;
  16. var $_css;
  17. var $docs = array();
  18. var $parentTree = array();
  19. var $hasChildren = array();
  20. var $placeHolders = array(
  21. 'rowLevel' => array('[+wf.wrapper+]','[+wf.classes+]','[+wf.classnames+]','[+wf.link+]','[+wf.title+]','[+wf.linktext+]','[+wf.id+]','[+wf.alias+]','[+wf.attributes+]','[+wf.docid+]','[+wf.introtext+]','[+wf.description+]','[+wf.subitemcount+]'),
  22. 'wrapperLevel' => array('[+wf.wrapper+]','[+wf.classes+]','[+wf.classnames+]'),
  23. 'tvs' => array(),
  24. );
  25. var $tvList = array();
  26. var $debugInfo = array();
  27. function run() {
  28. global $modx;
  29. //setup here checking array
  30. $this->parentTree = $modx->getParentIds($modx->documentIdentifier);
  31. $this->parentTree[] = $modx->documentIdentifier;
  32. if ($this->_config['debug']) {
  33. $this->addDebugInfo("settings","Settings","Settings","Settings used to create this menu.",$this->_config);
  34. $this->addDebugInfo("settings","CSS","CSS Settings","Available CSS options.",$this->_css);
  35. }
  36. //Load the templates
  37. $this->checkTemplates();
  38. //Register any scripts
  39. if ($this->_config['cssTpl'] || $this->_config['jsTpl']) {
  40. $this->regJsCss();
  41. }
  42. //Get all of the documents
  43. $this->docs = $this->getData();
  44. if (!empty($this->docs)) {
  45. //Sort documents by level for proper wrapper substitution
  46. ksort($this->docs);
  47. //build the menu
  48. return $this->buildMenu();
  49. } else {
  50. $noneReturn = $this->_config['debug'] ? '<p style="color:red">No documents found for menu.</p>' : '';
  51. return $noneReturn;
  52. }
  53. }
  54. function buildMenu() {
  55. global $modx;
  56. //Loop through all of the menu levels
  57. foreach ($this->docs as $level => $subDocs) {
  58. //Loop through each document group (grouped by parent doc)
  59. foreach ($subDocs as $parentId => $docs) {
  60. //only process document group, if starting at root, hidesubmenus is off, or is in current parenttree
  61. if (!$this->_config['hideSubMenus'] || $this->isHere($parentId) || $level <= 1) {
  62. //Build the output for the group of documents
  63. $menuPart = $this->buildSubMenu($docs,$level);
  64. //If we are at the top of the menu start the output, otherwise replace the wrapper with the submenu
  65. if (($level == 1 && (!$this->_config['displayStart'] || $this->_config['id'] == 0)) || ($level == 0 && $this->_config['displayStart'])) {
  66. $output = $menuPart;
  67. } else {
  68. $output = str_replace("[+wf.wrapper.{$parentId}+]",$menuPart,$output);
  69. }
  70. }
  71. }
  72. }
  73. //Return the final Menu
  74. return $output;
  75. }
  76. function buildSubMenu($menuDocs,$level) {
  77. global $modx;
  78. $subMenuOutput = '';
  79. $firstItem = 1;
  80. $counter = 1;
  81. $numSubItems = count($menuDocs);
  82. //Loop through each document to render output
  83. foreach ($menuDocs as $docId => $docInfo) {
  84. $docInfo['level'] = $level;
  85. $docInfo['first'] = $firstItem;
  86. $firstItem = 0;
  87. //Determine if last item in group
  88. if ($counter == ($numSubItems) && $numSubItems > 1) {
  89. $docInfo['last'] = 1;
  90. } else {
  91. $docInfo['last'] = 0;
  92. }
  93. //Determine if document has children
  94. $docInfo['hasChildren'] = in_array($docInfo['id'],$this->hasChildren) ? 1 : 0;
  95. $numChildren = $docInfo['hasChildren'] ? count($this->docs[$level+1][$docInfo['id']]) : 0;
  96. //Render the row output
  97. $subMenuOutput .= $this->renderRow($docInfo,$numChildren);
  98. //Update counter for last check
  99. $counter++;
  100. }
  101. if ($level > 0) {
  102. //Determine which wrapper template to use
  103. if ($this->_templates['innerTpl'] && $level > 1) {
  104. $useChunk = $this->_templates['innerTpl'];
  105. $usedTemplate = 'innerTpl';
  106. } else {
  107. $useChunk = $this->_templates['outerTpl'];
  108. $usedTemplate = 'outerTpl';
  109. }
  110. //Determine wrapper class
  111. if ($level > 1) {
  112. $wrapperClass = 'innercls';
  113. } else {
  114. $wrapperClass = 'outercls';
  115. }
  116. //Get the class names for the wrapper
  117. $classNames = $this->setItemClass($wrapperClass);
  118. if ($classNames) $useClass = ' class="' . $classNames . '"';
  119. $phArray = array($subMenuOutput,$useClass,$classNames);
  120. //Process the wrapper
  121. $subMenuOutput = str_replace($this->placeHolders['wrapperLevel'],$phArray,$useChunk);
  122. //Debug
  123. if ($this->_config['debug']) {
  124. $debugParent = $docInfo['parent'];
  125. $debugDocInfo = array();
  126. $debugDocInfo['template'] = $usedTemplate;
  127. foreach ($this->placeHolders['wrapperLevel'] as $n => $v) {
  128. if ($v !== '[+wf.wrapper+]')
  129. $debugDocInfo[$v] = $phArray[$n];
  130. }
  131. $this->addDebugInfo("wrapper","{$debugParent}","Wrapper for items with parent {$debugParent}.","These fields were used when processing the wrapper for the following documents.",$debugDocInfo);
  132. }
  133. }
  134. //Return the submenu
  135. return $subMenuOutput;
  136. }
  137. //render each rows output
  138. function renderRow(&$resource,$numChildren) {
  139. global $modx;
  140. $output = '';
  141. //Determine which template to use
  142. if ($this->_config['displayStart'] && $resource['level'] == 0) {
  143. $usedTemplate = 'startItemTpl';
  144. } elseif ($resource['id'] == $modx->documentObject['id'] && $resource['isfolder'] && $this->_templates['parentRowHereTpl'] && ($resource['level'] < $this->_config['level'] || $this->_config['level'] == 0) && $numChildren) {
  145. $usedTemplate = 'parentRowHereTpl';
  146. } elseif ($resource['id'] == $modx->documentObject['id'] && $this->_templates['innerHereTpl'] && $resource['level'] > 1) {
  147. $usedTemplate = 'innerHereTpl';
  148. } elseif ($resource['id'] == $modx->documentObject['id'] && $this->_templates['hereTpl']) {
  149. $usedTemplate = 'hereTpl';
  150. } elseif ($resource['isfolder'] && $this->_templates['activeParentRowTpl'] && ($resource['level'] < $this->_config['level'] || $this->_config['level'] == 0) && $this->isHere($resource['id'])) {
  151. $usedTemplate = 'activeParentRowTpl';
  152. } elseif ($resource['isfolder'] && ($resource['template']=="0" || is_numeric(strpos($resource['link_attributes'],'rel="category"'))) && $this->_templates['categoryFoldersTpl'] && ($resource['level'] < $this->_config['level'] || $this->_config['level'] == 0)) {
  153. $usedTemplate = 'categoryFoldersTpl';
  154. } elseif ($resource['isfolder'] && $this->_templates['parentRowTpl'] && ($resource['level'] < $this->_config['level'] || $this->_config['level'] == 0) && $numChildren) {
  155. $usedTemplate = 'parentRowTpl';
  156. } elseif ($resource['level'] > 1 && $this->_templates['innerRowTpl']) {
  157. $usedTemplate = 'innerRowTpl';
  158. } else {
  159. $usedTemplate = 'rowTpl';
  160. }
  161. //Get the template
  162. $useChunk = $this->_templates[$usedTemplate];
  163. //Setup the new wrapper name and get the class names
  164. $useSub = $resource['hasChildren'] ? "[+wf.wrapper.{$resource['id']}+]" : "";
  165. $classNames = $this->setItemClass('rowcls',$resource['id'],$resource['first'],$resource['last'],$resource['level'],$resource['isfolder'],$resource['type']);
  166. if ($classNames) $useClass = ' class="' . $classNames . '"';
  167. //Setup the row id if a prefix is specified
  168. if ($this->_config['rowIdPrefix']) {
  169. $useId = ' id="' . $this->_config['rowIdPrefix'] . $resource['id'] . '"';
  170. } else {
  171. $useId = '';
  172. }
  173. //Load row values into placholder array
  174. $phArray = array($useSub,$useClass,$classNames,$resource['link'],$resource['title'],$resource['linktext'],$useId,$resource['alias'],$resource['link_attributes'],$resource['id'],$resource['introtext'],$resource['description'],$numChildren);
  175. //If tvs are used add them to the placeholder array
  176. if (!empty($this->tvList)) {
  177. $usePlaceholders = array_merge($this->placeHolders['rowLevel'],$this->placeHolders['tvs']);
  178. foreach ($this->tvList as $tvName) {
  179. $phArray[] = $resource[$tvName];
  180. }
  181. } else {
  182. $usePlaceholders = $this->placeHolders['rowLevel'];
  183. }
  184. //Debug
  185. if ($this->_config['debug']) {
  186. $debugDocInfo = array();
  187. $debugDocInfo['template'] = $usedTemplate;
  188. foreach ($usePlaceholders as $n => $v) {
  189. $debugDocInfo[$v] = $phArray[$n];
  190. }
  191. $this->addDebugInfo("row","{$resource['parent']}:{$resource['id']}","Doc: #{$resource['id']}","The following fields were used when processing this document.",$debugDocInfo);
  192. $this->addDebugInfo("rowdata","{$resource['parent']}:{$resource['id']}","Doc: #{$resource['id']}","The following fields were retrieved from the database for this document.",$resource);
  193. }
  194. //Process the row
  195. $output .= str_replace($usePlaceholders,$phArray,$useChunk);
  196. //Return the row
  197. return $output . $this->_config['nl'];
  198. }
  199. //determine style class for current item being processed
  200. function setItemClass($classType, $docId = 0, $first = 0, $last = 0, $level = 0, $isFolder = 0, $type = 'document') {
  201. global $modx;
  202. $returnClass = '';
  203. $hasClass = 0;
  204. if ($classType === 'outercls' && !empty($this->_css['outer'])) {
  205. //Set outer class if specified
  206. $returnClass .= $this->_css['outer'];
  207. $hasClass = 1;
  208. } elseif ($classType === 'innercls' && !empty($this->_css['inner'])) {
  209. //Set inner class if specified
  210. $returnClass .= $this->_css['inner'];
  211. $hasClass = 1;
  212. } elseif ($classType === 'rowcls') {
  213. //Set row class if specified
  214. if (!empty($this->_css['row'])) {
  215. $returnClass .= $this->_css['row'];
  216. $hasClass = 1;
  217. }
  218. //Set first class if specified
  219. if ($first && !empty($this->_css['first'])) {
  220. $returnClass .= $hasClass ? ' ' . $this->_css['first'] : $this->_css['first'];
  221. $hasClass = 1;
  222. }
  223. //Set last class if specified
  224. if ($last && !empty($this->_css['last'])) {
  225. $returnClass .= $hasClass ? ' ' . $this->_css['last'] : $this->_css['last'];
  226. $hasClass = 1;
  227. }
  228. //Set level class if specified
  229. if (!empty($this->_css['level'])) {
  230. $returnClass .= $hasClass ? ' ' . $this->_css['level'] . $level : $this->_css['level'] . $level;
  231. $hasClass = 1;
  232. }
  233. //Set parentFolder class if specified
  234. if ($isFolder && !empty($this->_css['parent']) && ($level < $this->_config['level'] || $this->_config['level'] == 0)) {
  235. $returnClass .= $hasClass ? ' ' . $this->_css['parent'] : $this->_css['parent'];
  236. $hasClass = 1;
  237. }
  238. //Set here class if specified
  239. if (!empty($this->_css['here']) && $this->isHere($docId)) {
  240. $returnClass .= $hasClass ? ' ' . $this->_css['here'] : $this->_css['here'];
  241. $hasClass = 1;
  242. }
  243. //Set self class if specified
  244. if (!empty($this->_css['self']) && $docId == $modx->documentIdentifier) {
  245. $returnClass .= $hasClass ? ' ' . $this->_css['self'] : $this->_css['self'];
  246. $hasClass = 1;
  247. }
  248. //Set class for weblink
  249. if (!empty($this->_css['weblink']) && $type == 'reference') {
  250. $returnClass .= $hasClass ? ' ' . $this->_css['weblink'] : $this->_css['weblink'];
  251. $hasClass = 1;
  252. }
  253. }
  254. return $returnClass;
  255. }
  256. //determine "you are here"
  257. function isHere($did) {
  258. return in_array($did,$this->parentTree);
  259. }
  260. //Add the specified css & javascript chunks to the page
  261. function regJsCss() {
  262. global $modx;
  263. //Debug
  264. if ($this->_config['debug']) {
  265. $jsCssDebug = array('js' => 'None Specified.', 'css' => 'None Specified.');
  266. }
  267. //Check and load the CSS
  268. if ($this->_config['cssTpl']) {
  269. $cssChunk = $this->fetch($this->_config['cssTpl']);
  270. if ($cssChunk) {
  271. $modx->regClientCSS($cssChunk);
  272. if ($this->_config['debug']) {$jsCssDebug['css'] = "The CSS in {$this->_config['cssTpl']} was registered.";}
  273. } else {
  274. if ($this->_config['debug']) {$jsCssDebug['css'] = "The CSS in {$this->_config['cssTpl']} was not found.";}
  275. }
  276. }
  277. //Check and load the Javascript
  278. if ($this->_config['jsTpl']) {
  279. $jsChunk = $this->fetch($this->_config['jsTpl']);
  280. if ($jsChunk) {
  281. $modx->regClientStartupScript($jsChunk);
  282. if ($this->_config['debug']) {$jsCssDebug['js'] = "The Javascript in {$this->_config['jsTpl']} was registered.";}
  283. } else {
  284. if ($this->_config['debug']) {$jsCssDebug['js'] = "The Javascript in {$this->_config['jsTpl']} was not found.";}
  285. }
  286. }
  287. //Debug
  288. if ($this->_config['debug']) {$this->addDebugInfo("settings","JSCSS","JS/CSS Includes","Results of CSS & Javascript includes.",$jsCssDebug);}
  289. }
  290. //Get all of the documents from the database
  291. function getData() {
  292. global $modx;
  293. $depth = !empty($this->_config['level']) ? $this->_config['level'] : 10;
  294. $ids = array();
  295. if (!$this->_config['hideSubMenus']) {
  296. $ids = $modx->getChildIds($this->_config['id'],$depth);
  297. } else { // then hideSubMenus is checked, we don`t need all children
  298. // first we always included the chilren of startId document
  299. // this fix problem with site root chidrens,
  300. // because site root not included in $modx->getParentIds
  301. $ids = $modx->getChildIds($this->_config['id'], 1, $ids);
  302. $parents = array($modx->documentIdentifier);
  303. $parents += $modx->getParentIds($modx->documentIdentifier);
  304. // if startId not in parents, only show children of startId
  305. if ($this->_config['id'] == 0 || in_array($this->_config['id'], $parents)){
  306. //remove parents higher than startId(including startId)
  307. $startId_parents = array($this->_config['id']);
  308. $startId_parents += $modx->getParentIds($this->_config['id']);
  309. $parents = array_diff($parents, $startId_parents);
  310. //remove parents lower than level of startId + level depth
  311. $parents = array_slice(array_reverse($parents), 0, $depth-1);
  312. foreach($parents as $p)
  313. $ids = $modx->getChildIds($p, 1, $ids);
  314. }
  315. }
  316. //Get all of the ids for processing
  317. if ($this->_config['displayStart'] && $this->_config['id'] !== 0) {
  318. $ids[] = $this->_config['id'];
  319. }
  320. if (!empty($ids)) {
  321. //Setup the fields for the query
  322. $fields = "sc.id, sc.menutitle, sc.pagetitle, sc.introtext, sc.menuindex, sc.published, sc.hidemenu, sc.parent, sc.isfolder, sc.description, sc.alias, sc.longtitle, sc.type,if(sc.type='reference',sc.content,'') as content, sc.template, sc.link_attributes";
  323. //Get the table names
  324. $tblsc = $modx->getFullTableName("site_content");
  325. $tbldg = $modx->getFullTableName("document_groups");
  326. //Add the ignore hidden option to the where clause
  327. if ($this->_config['ignoreHidden']) {
  328. $menuWhere = '';
  329. } else {
  330. $menuWhere = ' AND sc.hidemenu=0';
  331. }
  332. //add the include docs to the where clause
  333. if ($this->_config['includeDocs']) {
  334. $menuWhere .= " AND sc.id IN ({$this->_config['includeDocs']})";
  335. }
  336. //add the exclude docs to the where clause
  337. if ($this->_config['excludeDocs']) {
  338. $menuWhere .= " AND (sc.id NOT IN ({$this->_config['excludeDocs']}))";
  339. }
  340. //add the limit to the query
  341. if ($this->_config['limit']) {
  342. $sqlLimit = " LIMIT 0, {$this->_config['limit']}";
  343. } else {
  344. $sqlLimit = '';
  345. }
  346. //Determine sorting
  347. if (strtolower($this->_config['sortBy']) == 'random') {
  348. $sort = 'rand()';
  349. $dir = '';
  350. } else {
  351. // modify field names to use sc. table reference
  352. $sort = 'sc.'.implode(',sc.',preg_replace("/^\s/i","",explode(',',$this->_config['sortBy'])));
  353. }
  354. // get document groups for current user
  355. if($docgrp = $modx->getUserDocGroups()) $docgrp = implode(",",$docgrp);
  356. // build query
  357. $access = ($modx->isFrontend() ? "sc.privateweb=0" : "1='{$_SESSION['mgrRole']}' OR sc.privatemgr=0").(!$docgrp ? "" : " OR dg.document_group IN ({$docgrp})");
  358. $sql = "SELECT DISTINCT {$fields} FROM {$tblsc} sc LEFT JOIN {$tbldg} dg ON dg.document = sc.id WHERE sc.published=1 AND sc.deleted=0 AND ({$access}){$menuWhere} AND sc.id IN (".implode(',',$ids).") GROUP BY sc.id ORDER BY {$sort} {$this->_config['sortOrder']} {$sqlLimit};";
  359. //run the query
  360. $result = $modx->dbQuery($sql);
  361. $resourceArray = array();
  362. $numResults = @$modx->recordCount($result);
  363. $level = 1;
  364. $prevParent = -1;
  365. //Setup startlevel for determining each items level
  366. if ($this->_config['id'] == 0) {
  367. $startLevel = 0;
  368. } else {
  369. $startLevel = count($modx->getParentIds($this->_config['id']));
  370. $startLevel = $startLevel ? $startLevel+1 : 1;
  371. }
  372. $resultIds = array();
  373. //loop through the results
  374. for($i=0;$i<$numResults;$i++) {
  375. $tempDocInfo = $modx->fetchRow($result);
  376. $resultIds[] = $tempDocInfo['id'];
  377. //Create the link
  378. $linkScheme = $this->_config['fullLink'] ? 'full' : '';
  379. if ($this->_config['useWeblinkUrl'] !== 'FALSE' && $tempDocInfo['type'] == 'reference') {
  380. if (is_numeric($tempDocInfo['content'])) {
  381. $tempDocInfo['link'] = $modx->makeUrl(intval($tempDocInfo['content']),'','',$linkScheme);
  382. } else {
  383. $tempDocInfo['link'] = $tempDocInfo['content'];
  384. }
  385. } elseif ($tempDocInfo['id'] == $modx->config['site_start']) {
  386. $tempDocInfo['link'] = $modx->config['site_url'];
  387. } else {
  388. $tempDocInfo['link'] = $modx->makeUrl($tempDocInfo['id'],'','',$linkScheme);
  389. }
  390. //determine the level, if parent has changed
  391. if ($prevParent !== $tempDocInfo['parent']) {
  392. $level = count($modx->getParentIds($tempDocInfo['id'])) + 1 - $startLevel;
  393. }
  394. //add parent to hasChildren array for later processing
  395. if (($level > 1 || $this->_config['displayStart']) && !in_array($tempDocInfo['parent'],$this->hasChildren)) {
  396. $this->hasChildren[] = $tempDocInfo['parent'];
  397. }
  398. //set the level
  399. $tempDocInfo['level'] = $level;
  400. $prevParent = $tempDocInfo['parent'];
  401. //determine other output options
  402. $useTextField = (empty($tempDocInfo[$this->_config['textOfLinks']])) ? 'pagetitle' : $this->_config['textOfLinks'];
  403. $tempDocInfo['linktext'] = $tempDocInfo[$useTextField];
  404. $tempDocInfo['title'] = $tempDocInfo[$this->_config['titleOfLinks']];
  405. //If tvs were specified keep array flat otherwise array becomes level->parent->doc
  406. if (!empty($this->tvList)) {
  407. $tempResults[] = $tempDocInfo;
  408. } else {
  409. $resourceArray[$tempDocInfo['level']][$tempDocInfo['parent']][] = $tempDocInfo;
  410. }
  411. }
  412. //Process the tvs
  413. if (!empty($this->tvList) && !empty($resultIds)) {
  414. $tvValues = array();
  415. //loop through all tvs and get their values for each document
  416. foreach ($this->tvList as $tvName) {
  417. $tvValues = array_merge_recursive($this->appendTV($tvName,$resultIds),$tvValues);
  418. }
  419. //loop through the document array and add the tvar values to each document
  420. foreach ($tempResults as $tempDocInfo) {
  421. if (array_key_exists("#{$tempDocInfo['id']}",$tvValues)) {
  422. foreach ($tvValues["#{$tempDocInfo['id']}"] as $tvName => $tvValue) {
  423. $tempDocInfo[$tvName] = $tvValue;
  424. }
  425. }
  426. $resourceArray[$tempDocInfo['level']][$tempDocInfo['parent']][] = $tempDocInfo;
  427. }
  428. }
  429. }
  430. //return final docs
  431. return $resourceArray;
  432. }
  433. // ---------------------------------------------------
  434. // Function: appendTV taken from Ditto (thanks Mark)
  435. // Apeend a TV to the documents array
  436. // ---------------------------------------------------
  437. function appendTV($tvname,$docIDs){
  438. global $modx;
  439. $baspath= $modx->config["base_path"] . "manager/includes";
  440. include_once $baspath . "/tmplvars.format.inc.php";
  441. include_once $baspath . "/tmplvars.commands.inc.php";
  442. $tb1 = $modx->getFullTableName("site_tmplvar_contentvalues");
  443. $tb2 = $modx->getFullTableName("site_tmplvars");
  444. $query = "SELECT stv.name,stc.tmplvarid,stc.contentid,stv.type,stv.display,stv.display_params,stc.value";
  445. $query .= " FROM ".$tb1." stc LEFT JOIN ".$tb2." stv ON stv.id=stc.tmplvarid ";
  446. $query .= " WHERE stv.name='".$tvname."' AND stc.contentid IN (".implode($docIDs,",").") ORDER BY stc.contentid ASC;";
  447. $rs = $modx->db->query($query);
  448. $tot = $modx->db->getRecordCount($rs);
  449. $resourceArray = array();
  450. for($i=0;$i<$tot;$i++) {
  451. $row = @$modx->fetchRow($rs);
  452. $resourceArray["#{$row['contentid']}"][$row['name']] = getTVDisplayFormat($row['name'], $row['value'], $row['display'], $row['display_params'], $row['type'],$row['contentid']);
  453. }
  454. if ($tot != count($docIDs)) {
  455. $query = "SELECT name,type,display,display_params,default_text";
  456. $query .= " FROM $tb2";
  457. $query .= " WHERE name='".$tvname."' LIMIT 1";
  458. $rs = $modx->db->query($query);
  459. $row = @$modx->fetchRow($rs);
  460. $defaultOutput = getTVDisplayFormat($row['name'], $row['default_text'], $row['display'], $row['display_params'], $row['type']);
  461. foreach ($docIDs as $id) {
  462. if (!isset($resourceArray["#{$id}"])) {
  463. $resourceArray["#{$id}"][$tvname] = $defaultOutput;
  464. }
  465. }
  466. }
  467. return $resourceArray;
  468. }
  469. // ---------------------------------------------------
  470. // Get a list of all available TVs
  471. // ---------------------------------------------------
  472. function getTVList() {
  473. global $modx;
  474. $table = $modx->getFullTableName("site_tmplvars");
  475. $tvs = $modx->db->select("name", $table);
  476. // TODO: make it so that it only pulls those that apply to the current template
  477. $dbfields = array();
  478. while ($dbfield = $modx->db->getRow($tvs))
  479. $dbfields[] = $dbfield['name'];
  480. return $dbfields;
  481. }
  482. //debugging to check for valid chunks
  483. function checkTemplates() {
  484. global $modx;
  485. $nonWayfinderFields = array();
  486. foreach ($this->_templates as $n => $v) {
  487. $templateCheck = $this->fetch($v);
  488. if (empty($v) || !$templateCheck) {
  489. if ($n === 'outerTpl') {
  490. $this->_templates[$n] = '<ul[+wf.classes+]>[+wf.wrapper+]</ul>';
  491. } elseif ($n === 'rowTpl') {
  492. $this->_templates[$n] = '<li[+wf.id+][+wf.classes+]><a href="[+wf.link+]" title="[+wf.title+]" [+wf.attributes+]>[+wf.linktext+]</a>[+wf.wrapper+]</li>';
  493. } elseif ($n === 'startItemTpl') {
  494. $this->_templates[$n] = '<h2[+wf.id+][+wf.classes+]>[+wf.linktext+]</h2>[+wf.wrapper+]';
  495. } else {
  496. $this->_templates[$n] = FALSE;
  497. }
  498. if ($this->_config['debug']) { $this->addDebugInfo('template',$n,$n,"No template found, using default.",array($n => $this->_templates[$n])); }
  499. } else {
  500. $this->_templates[$n] = $templateCheck;
  501. $check = $this->findTemplateVars($templateCheck);
  502. if (is_array($check)) {
  503. $nonWayfinderFields = array_merge($check, $nonWayfinderFields);
  504. }
  505. if ($this->_config['debug']) { $this->addDebugInfo('template',$n,$n,"Template Found.",array($n => $this->_templates[$n])); }
  506. }
  507. }
  508. if (!empty($nonWayfinderFields)) {
  509. $nonWayfinderFields = array_unique($nonWayfinderFields);
  510. $allTvars = $this->getTVList();
  511. foreach ($nonWayfinderFields as $field) {
  512. if (in_array($field, $allTvars)) {
  513. $this->placeHolders['tvs'][] = "[+{$field}+]";
  514. $this->tvList[] = $field;
  515. }
  516. }
  517. if ($this->_config['debug']) { $this->addDebugInfo('tvars','tvs','Template Variables',"The following template variables were found in your templates.",$this->tvList); }
  518. }
  519. }
  520. function fetch($tpl){
  521. // based on version by Doze at http://modxcms.com/forums/index.php/topic,5344.msg41096.html#msg41096
  522. global $modx;
  523. $template = "";
  524. if ($modx->getChunk($tpl) != "") {
  525. $template = $modx->getChunk($tpl);
  526. } else if(substr($tpl, 0, 6) == "@FILE:") {
  527. $template = $this->get_file_contents(substr($tpl, 6));
  528. } else if(substr($tpl, 0, 6) == "@CODE:") {
  529. $template = substr($tpl, 6);
  530. } else {
  531. $template = FALSE;
  532. }
  533. return $template;
  534. }
  535. function get_file_contents($filename) {
  536. // Function written at http://www.nutt.net/2006/07/08/file_get_contents-function-for-php-4/#more-210
  537. // Returns the contents of file name passed
  538. if (!function_exists('file_get_contents')) {
  539. $fhandle = fopen($filename, "r");
  540. $fcontents = fread($fhandle, filesize($filename));
  541. fclose($fhandle);
  542. } else {
  543. $fcontents = file_get_contents($filename);
  544. }
  545. return $fcontents;
  546. }
  547. function findTemplateVars($tpl) {
  548. preg_match_all('~\[\+(.*?)\+\]~', $tpl, $matches);
  549. $cnt = count($matches[1]);
  550. $tvnames = array ();
  551. for ($i = 0; $i < $cnt; $i++) {
  552. if (strpos($matches[1][$i], "wf.") === FALSE) {
  553. $tvnames[] = $matches[1][$i];
  554. }
  555. }
  556. if (count($tvnames) >= 1) {
  557. return array_unique($tvnames);
  558. } else {
  559. return false;
  560. }
  561. }
  562. function addDebugInfo($group,$groupkey,$header,$message,$info) {
  563. $infoString = '<table border="1" cellpadding="3px">';
  564. $numInfo = count($info);
  565. $count = 0;
  566. foreach ($info as $key => $value) {
  567. $key = $this->modxPrep($key);
  568. if ($value === TRUE || $value === FALSE) {
  569. $value = $value ? 'TRUE' : 'FALSE';
  570. } else {
  571. $value = $this->modxPrep($value);
  572. }
  573. if ($count == 2) { $infoString .= '</tr>'; $count = 0; }
  574. if ($count == 0) { $infoString .= '<tr>'; }
  575. $value = empty($value) ? '&nbsp;' : $value;
  576. $infoString .= "<td><strong>{$key}</strong></td><td>{$value}</td>";
  577. $count++;
  578. }
  579. $infoString .= '</tr></table>';
  580. $this->debugInfo[$group][$groupkey] = array(
  581. 'header' => $this->modxPrep($header),
  582. 'message' => $this->modxPrep($message),
  583. 'info' => $infoString,
  584. );
  585. }
  586. function renderDebugOutput() {
  587. $output = '<table border="1" cellpadding="3px" width="100%">';
  588. foreach ($this->debugInfo as $group => $item) {
  589. switch ($group) {
  590. case 'template':
  591. $output .= "<tr><th style=\"background:#C3D9FF;font-size:200%;\">Template Processing</th></tr>";
  592. foreach ($item as $parentId => $info) {
  593. $output .= "
  594. <tr style=\"background:#336699;color:#fff;\"><th>{$info['header']} - <span style=\"font-weight:normal;\">{$info['message']}</span></th></tr>
  595. <tr><td>{$info['info']}</td></tr>";
  596. }
  597. break;
  598. case 'wrapper':
  599. $output .= "<tr><th style=\"background:#C3D9FF;font-size:200%;\">Document Processing</th></tr>";
  600. foreach ($item as $parentId => $info) {
  601. $output .= "<tr><table border=\"1\" cellpadding=\"3px\" style=\"margin-bottom: 10px;\" width=\"100%\">
  602. <tr style=\"background:#336699;color:#fff;\"><th>{$info['header']} - <span style=\"font-weight:normal;\">{$info['message']}</span></th></tr>
  603. <tr><td>{$info['info']}</td></tr>
  604. <tr style=\"background:#336699;color:#fff;\"><th>Documents included in this wrapper:</th></tr>";
  605. foreach ($this->debugInfo['row'] as $key => $value) {
  606. $keyParts = explode(':',$key);
  607. if ($parentId == $keyParts[0]) {
  608. $output .= "<tr style=\"background:#eee;\"><th>{$value['header']}</th></tr>
  609. <tr><td><div style=\"float:left;margin-right:1%;\">{$value['message']}<br />{$value['info']}</div><div style=\"float:left;\">{$this->debugInfo['rowdata'][$key]['message']}<br />{$this->debugInfo['rowdata'][$key]['info']}</div></td></tr>";
  610. }
  611. }
  612. $output .= '</table></tr>';
  613. }
  614. break;
  615. case 'settings':
  616. $output .= "<tr><th style=\"background:#C3D9FF;font-size:200%;\">Settings</th></tr>";
  617. foreach ($item as $parentId => $info) {
  618. $output .= "
  619. <tr style=\"background:#336699;color:#fff;\"><th>{$info['header']} - <span style=\"font-weight:normal;\">{$info['message']}</span></th></tr>
  620. <tr><td>{$info['info']}</td></tr>";
  621. }
  622. break;
  623. default:
  624. break;
  625. }
  626. }
  627. $output .= '</table>';
  628. return $output;
  629. }
  630. function modxPrep($value) {
  631. $value = (strpos($value,"<") !== FALSE) ? htmlentities($value) : $value;
  632. $value = str_replace("[","&#091;",$value);
  633. $value = str_replace("]","&#093;",$value);
  634. $value = str_replace("{","&#123;",$value);
  635. $value = str_replace("}","&#125;",$value);
  636. return $value;
  637. }
  638. }
  639. ?>