PageRenderTime 175ms CodeModel.GetById 86ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 0ms

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