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

/app/lib/core/Search/SearchResult.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 1602 lines | 1196 code | 142 blank | 264 comment | 355 complexity | 99792584399b0f02c697a18fb6449536 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /** ---------------------------------------------------------------------
  3. * app/lib/core/Search/SearchResult.php : implements interface to results from a search
  4. * ----------------------------------------------------------------------
  5. * CollectiveAccess
  6. * Open-source collections management software
  7. * ----------------------------------------------------------------------
  8. *
  9. * Software by Whirl-i-Gig (http://www.whirl-i-gig.com)
  10. * Copyright 2008-2011 Whirl-i-Gig
  11. *
  12. * For more information visit http://www.CollectiveAccess.org
  13. *
  14. * This program is free software; you may redistribute it and/or modify it under
  15. * the terms of the provided license as published by Whirl-i-Gig
  16. *
  17. * CollectiveAccess is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  20. *
  21. * This source code is free and modifiable under the terms of
  22. * GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
  23. * the "license.txt" file for details, or visit the CollectiveAccess web site at
  24. * http://www.CollectiveAccess.org
  25. *
  26. * @package CollectiveAccess
  27. * @subpackage Search
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License version 3
  29. *
  30. * ----------------------------------------------------------------------
  31. */
  32. /**
  33. *
  34. */
  35. # ----------------------------------------------------------------------
  36. # --- Import classes
  37. # ----------------------------------------------------------------------
  38. include_once(__CA_LIB_DIR__."/core/BaseObject.php");
  39. include_once(__CA_LIB_DIR__."/core/Datamodel.php");
  40. include_once(__CA_LIB_DIR__."/core/Media/MediaInfoCoder.php");
  41. include_once(__CA_LIB_DIR__."/core/File/FileInfoCoder.php");
  42. include_once(__CA_LIB_DIR__."/core/Parsers/TimeExpressionParser.php");
  43. include_once(__CA_LIB_DIR__."/core/Parsers/TimecodeParser.php");
  44. include_once(__CA_LIB_DIR__."/core/ApplicationChangeLog.php");
  45. # ----------------------------------------------------------------------
  46. class SearchResult extends BaseObject {
  47. private $opo_datamodel;
  48. private $opo_search_config;
  49. private $opo_db;
  50. private $opn_table_num;
  51. private $ops_table_name;
  52. private $ops_table_pk;
  53. // ----
  54. private $opa_options;
  55. private $opo_engine_result;
  56. protected $opa_tables;
  57. private $opo_row_instance;
  58. private $opa_prefetch_cache;
  59. private $opa_rel_prefetch_cache;
  60. private $opa_timestamp_cache;
  61. private $opa_row_ids_to_prefetch_cache;
  62. private $opo_tep; // timeexpression parser
  63. # ------------------------------------------------------------------
  64. public function __construct($pn_subject_table_num=null, $po_engine_result=null, $pa_tables=null) {
  65. $this->opo_db = new Db();
  66. $this->opo_datamodel = Datamodel::load();
  67. $this->opa_prefetch_cache = array();
  68. $this->opa_rel_prefetch_cache = array();
  69. $this->opa_timestamp_cache = array();
  70. $this->opa_row_ids_to_prefetch_cache = array();
  71. if ($pn_subject_table_num) {
  72. $this->init($pn_subject_table_num, $po_engine_result, $pa_tables);
  73. }
  74. if (!$GLOBALS["_DbResult_time_expression_parser"]) { $GLOBALS["_DbResult_time_expression_parser"] = new TimeExpressionParser(); }
  75. if (!$GLOBALS["_DbResult_timecodeparser"]) { $GLOBALS["_DbResult_timecodeparser"] = new TimecodeParser(); }
  76. if (!$GLOBALS["_DbResult_mediainfocoder"]) { $GLOBALS["_DbResult_mediainfocoder"] = MediaInfoCoder::load(); }
  77. if (!$GLOBALS["_DbResult_fileinfocoder"]) { $GLOBALS["_DbResult_fileinfocoder"] = FileInfoCoder::load(); }
  78. // valid options and defaults
  79. $this->opa_options = array(
  80. // SearchResult::get() can load field data from database when it is not available directly from the search index (most fields are *not* available from the index)
  81. // It is almost always more efficient to grab multiple field values from a table in one query, and to do so for multiple rows, than to generate and execute queries
  82. // each time get() is called. Thus get() automatically "prefetches" field values for a given table when it is called; the "prefetch" option defined how many rows
  83. // beyond the current row are pre-loaded. You ideally want this value to match the number of rows you actually plan to use. If you're generating lists of search
  84. // results and page the results with 50 results per page then you'd want to the prefetch to be 50. If the number of rows you need is very large (> 200?) then it might
  85. // make sense to use a value less than the total number of rows since queries with many enumerated row_ids (which is what the prefetch mechanism uses) may run slowly
  86. // when a large number of ids are specified. The default for this is 50.
  87. //
  88. 'prefetch' => 50
  89. );
  90. $this->opo_tep = new TimeExpressionParser();
  91. }
  92. # ------------------------------------------------------------------
  93. public function init($pn_subject_table_num, $po_engine_result, $pa_tables) {
  94. $this->opn_table_num = $pn_subject_table_num;
  95. $this->opo_engine_result = $po_engine_result;
  96. $this->opa_tables = $pa_tables;
  97. $this->errors = array();
  98. $this->opo_row_instance = $this->opo_datamodel->getInstanceByTableNum($this->opn_table_num, true);
  99. $this->ops_table_name = $this->opo_row_instance->tableName();
  100. $this->ops_table_pk = $this->opo_row_instance->primaryKey();
  101. }
  102. # ------------------------------------------------------------------
  103. public function tableNum() {
  104. return $this->opn_table_num;
  105. }
  106. # ------------------------------------------------------------------
  107. public function tableName() {
  108. return $this->ops_table_name;
  109. }
  110. # ------------------------------------------------------------------
  111. public function numHits() {
  112. return $this->opo_engine_result->numHits();
  113. }
  114. # ------------------------------------------------------------------
  115. public function nextHit() {
  116. return $this->opo_engine_result->nextHit();
  117. }
  118. # ------------------------------------------------------------------
  119. public function previousHit() {
  120. $vn_index = $this->opo_engine_result->currentRow();
  121. if ($vn_index >= 0) {
  122. $this->opo_engine_result->seek($vn_index);
  123. }
  124. }
  125. # ------------------------------------------------------------------
  126. /**
  127. * Returns true if this current hit is the last in the set
  128. *
  129. * @return boolean True if current hit is the last in the results set, false otherwise
  130. */
  131. public function isLastHit() {
  132. $vn_index = $this->opo_engine_result->currentRow();
  133. $vn_num_hits = $this->opo_engine_result->numHits();
  134. if ($vn_index == ($vn_num_hits - 1)) { return true; }
  135. return false;
  136. }
  137. # ------------------------------------------------------------------
  138. /**
  139. *
  140. */
  141. private function getRowIDsToPrefetch($ps_tablename, $pn_start, $pn_num_rows) {
  142. if ($this->opa_row_ids_to_prefetch_cache[$ps_tablename.'/'.$pn_start.'/'.$pn_num_rows]) { return $this->opa_row_ids_to_prefetch_cache[$ps_tablename.'/'.$pn_start.'/'.$pn_num_rows]; }
  143. $va_row_ids = array();
  144. $vn_cur_row_index = $this->opo_engine_result->currentRow();
  145. $this->seek($pn_start);
  146. $vn_i=0;
  147. while(self::nextHit() && ($vn_i < $pn_num_rows)) {
  148. $va_row_ids[] = $this->opo_engine_result->get($this->ops_table_pk);
  149. $vn_i++;
  150. }
  151. $this->seek($vn_cur_row_index + 1);
  152. return $this->opa_row_ids_to_prefetch_cache[$ps_tablename.'/'.$pn_start.'/'.$pn_num_rows] = $va_row_ids;
  153. }
  154. # ------------------------------------------------------------------
  155. /**
  156. * TODO: implement prefetch of related and non-indexed-stored fields. Basically, instead of doing a query for every row via get() [which will still be an option if you're lazy]
  157. * prefetch() will allow you to tell SearchResult to preload values for a set of hits starting at $pn_start
  158. * Because this can be done in a single query it'll presumably be faster than lazy loading lots of rows
  159. */
  160. public function prefetch($ps_tablename, $pn_start, $pn_num_rows, $pa_element_ids=null) {
  161. //print "PREFETCH: ".$ps_tablename.' - '. $pn_start.' - '. $pn_num_rows."<br>";
  162. // get row_ids to fetch
  163. if (sizeof($va_row_ids = $this->getRowIDsToPrefetch($ps_tablename, $pn_start, $pn_num_rows)) == 0) { return false; }
  164. // do join
  165. $va_joins = array();
  166. $t_rel_instance = $this->opo_datamodel->getInstanceByTableName($ps_tablename, true);
  167. if ($ps_tablename != $this->ops_table_name) {
  168. $va_fields = $this->opa_tables[$ps_tablename]['fieldList'];
  169. $va_fields[] = $this->ops_table_name.'.'.$this->ops_table_pk;
  170. // Include type_id field for item table (eg. ca_entities.type_id)
  171. if (method_exists($t_rel_instance, "getTypeFieldName") && ($t_rel_instance->getTypeFieldName()) && ($vs_type_fld_name = $t_rel_instance->getTypeFieldName())) {
  172. $va_fields[] = $t_rel_instance->tableName().'.'.$vs_type_fld_name.' item_type_id';
  173. } else {
  174. // Include type_id field for item table (eg. ca_entities.type_id) when fetching labels
  175. if (method_exists($t_rel_instance, "getSubjectTableInstance")) {
  176. $t_label_subj_instance = $t_rel_instance->getSubjectTableInstance();
  177. if (method_exists($t_label_subj_instance, "getTypeFieldName") && ($vs_type_fld_name = $t_label_subj_instance->getTypeFieldName())) {
  178. $va_fields[] = $t_label_subj_instance->tableName().'.'.$vs_type_fld_name.' item_type_id';
  179. }
  180. }
  181. }
  182. $va_joined_table_info = $this->opa_tables[$ps_tablename];
  183. $va_linking_tables = $va_joined_table_info['joinTables'];
  184. if (!is_array($va_linking_tables)) { $va_linking_tables = array(); }
  185. array_push($va_linking_tables, $ps_tablename);
  186. $vs_left_table = $this->ops_table_name;
  187. foreach($va_linking_tables as $vs_right_table) {
  188. if ($va_rel = $this->opo_datamodel->getOneToManyRelations($vs_left_table, $vs_right_table)) {
  189. $va_joins[] = 'INNER JOIN '.$va_rel['many_table'].' ON '.$va_rel['one_table'].'.'.$va_rel['one_table_field'].' = '.$va_rel['many_table'].'.'.$va_rel['many_table_field'];
  190. $t_link = $this->opo_datamodel->getInstanceByTableName($va_rel['many_table'], true);
  191. if (is_a($t_link, 'BaseRelationshipModel') && $t_link->hasField('type_id')) {
  192. $va_fields[] = $va_rel['many_table'].'.type_id rel_type_id';
  193. }
  194. } else {
  195. if ($va_rel = $this->opo_datamodel->getOneToManyRelations($vs_right_table, $vs_left_table)) {
  196. $va_joins[] = 'INNER JOIN '.$va_rel['one_table'].' ON '.$va_rel['one_table'].'.'.$va_rel['one_table_field'].' = '.$va_rel['many_table'].'.'.$va_rel['many_table_field'];
  197. }
  198. }
  199. $vs_left_table = $vs_right_table;
  200. }
  201. } else {
  202. $va_fields = array('*');
  203. }
  204. $vs_criteria_sql = '';
  205. if (is_array($this->opa_tables[$ps_tablename]['criteria']) && (sizeof($this->opa_tables[$ps_tablename]['criteria']) > 0)) {
  206. $vs_criteria_sql = ' AND ('.join(' AND ', $this->opa_tables[$ps_tablename]['criteria']).')';
  207. }
  208. $vb_has_locale_id = true;
  209. if ($this->opo_row_instance->hasField('locale_id') && (!$t_rel_instance->hasField('locale_id'))) {
  210. $va_fields[] = $this->ops_table_name.'.locale_id';
  211. $vb_has_locale_id = true;
  212. }
  213. $vs_order_by = '';
  214. if ($t_rel_instance->hasField('idno_sort')) {
  215. $vs_order_by = " ORDER BY ".$t_rel_instance->tableName().".idno_sort";
  216. }
  217. $vs_rel_pk = $t_rel_instance->primaryKey();
  218. $vs_sql = "
  219. SELECT ".join(',', $va_fields)."
  220. FROM ".$this->ops_table_name."
  221. ".join("\n", $va_joins)."
  222. WHERE
  223. ".$this->ops_table_name.'.'.$this->ops_table_pk." IN (".join(',', $va_row_ids).") $vs_criteria_sql
  224. {$vs_order_by}
  225. ";
  226. //print "<pre>$vs_sql</pre>";
  227. $qr_rel = $this->opo_db->query($vs_sql);
  228. $va_rel_row_ids = array();
  229. while($qr_rel->nextRow()) {
  230. $va_row = $qr_rel->getRow();
  231. $vn_row_id = $va_row[$this->ops_table_pk];
  232. if ($vb_has_locale_id) {
  233. $vn_locale_id = $va_row['locale_id'];
  234. $this->opa_prefetch_cache[$ps_tablename][$vn_row_id][$vn_locale_id][] = $va_row;
  235. } else {
  236. $this->opa_prefetch_cache[$ps_tablename][$vn_row_id][1][] = $va_row;
  237. }
  238. }
  239. // Fill row_id values for which there is nothing to prefetch with an empty lists
  240. // otherwise we'll try and prefetch these again later wasting time.
  241. foreach($va_row_ids as $vn_row_id) {
  242. if (!isset($this->opa_prefetch_cache[$ps_tablename][$vn_row_id])) {
  243. $this->opa_prefetch_cache[$ps_tablename][$vn_row_id] = array();
  244. }
  245. }
  246. //print "<pre>".print_r($this->opa_prefetch_cache[$ps_tablename], true)."</pre>";
  247. }
  248. # ------------------------------------------------------------------
  249. /**
  250. *
  251. */
  252. public function prefetchRelated($ps_tablename, $pn_start, $pn_num_rows, $pa_options) {
  253. //print "PREFETCH RELATED: ".$ps_tablename.' - '. $pn_start.' - '. $pn_num_rows."<br>";
  254. unset($pa_options['request']);
  255. if (sizeof($va_row_ids = $this->getRowIDsToPrefetch($ps_tablename, $pn_start, $pn_num_rows)) == 0) { return false; }
  256. $vs_md5 = md5(print_r($pa_options, true));
  257. $va_rel_items = $this->opo_row_instance->getRelatedItems($ps_tablename, array_merge($pa_options, array('row_ids' => $va_row_ids, 'limit' => 100000))); // if there are more than 100,000 then we have a problem
  258. foreach($va_rel_items as $vn_relation_id => $va_rel_item) {
  259. $this->opa_rel_prefetch_cache[$ps_tablename][$va_rel_item['row_id']][$vs_md5][] = $va_rel_item;
  260. }
  261. // Fill row_id values for which there is nothing to prefetch with an empty lists
  262. // otherwise we'll try and prefetch these again later wasting time.
  263. foreach($va_row_ids as $vn_row_id) {
  264. if (!isset($this->opa_rel_prefetch_cache[$ps_tablename][$vn_row_id][$vs_md5])) {
  265. $this->opa_rel_prefetch_cache[$ps_tablename][$vn_row_id][$vs_md5] = array();
  266. }
  267. }
  268. return true;
  269. }
  270. # ------------------------------------------------------------------
  271. /**
  272. *
  273. */
  274. public function prefetchChangeLogData($ps_tablename, $pn_start, $pn_num_rows) {
  275. if (sizeof($va_row_ids = $this->getRowIDsToPrefetch($ps_tablename, $pn_start, $pn_num_rows)) == 0) { return false; }
  276. $vs_key = md5($ps_tablename.'/'.print_r($va_row_ids, true));
  277. if ($this->opa_timestamp_cache['fetched'][$vs_key]) { return true; }
  278. $o_log = new ApplicationChangeLog();
  279. if (!is_array($this->opa_timestamp_cache['created_on'][$ps_tablename])) { $this->opa_timestamp_cache['created_on'][$ps_tablename] = array(); }
  280. $this->opa_timestamp_cache['created_on'][$ps_tablename] += $o_log->getCreatedOnTimestampsForIDs($ps_tablename, $va_row_ids);
  281. if (!is_array($this->opa_timestamp_cache['last_changed'][$ps_tablename])) { $this->opa_timestamp_cache['last_changed'][$ps_tablename] = array(); }
  282. $this->opa_timestamp_cache['last_changed'][$ps_tablename] += $o_log->getLastChangeTimestampsForIDs($ps_tablename, $va_row_ids);
  283. $this->opa_timestamp_cache['fetched'][$vs_key] = true;
  284. return true;
  285. }
  286. # ------------------------------------------------------------------
  287. /**
  288. *
  289. */
  290. public function getPrimaryKeyValues($vn_limit=4000000000) {
  291. $vs_pk = $this->opo_row_instance->primaryKey();
  292. $this->opo_engine_result->seek(0);
  293. $va_ids = array();
  294. $vn_c = 0;
  295. while($this->opo_engine_result->nextHit()) {
  296. $va_ids[] = $this->opo_engine_result->get($vs_pk);
  297. $vn_c++;
  298. if ($vn_c >= $vn_limit) { break; }
  299. }
  300. return $va_ids;
  301. }
  302. # ------------------------------------------------------------------
  303. /**
  304. * Returns a value from the query result. This can be a single value if it is a field in the subject table (eg. objects table in an objects search), or
  305. * perhaps multiple related values (eg. related entities in an objects search). By default get() always returns a single value; for fields with multiple values
  306. * the value will be the first value encountered when loading the field data.
  307. *
  308. * You can fetch the values of attributes attached to the subject row (ie. if you're searching for ca_objects rows, the subject row is the ca_objects row)
  309. * by use the "virtual" field name <subject_table_name>.<element_code> (ex. ca_objects.date_created)
  310. * If the attribute is a multi-value container then you can fetch a specific value using the format <subject_table_name>.<attribute_element_code>/<value_element_code>
  311. * For example, if you want to get the "date_value" value out of a "date" attribute attached to a ca_objects row, then you'd call get()
  312. * with this fieldname: ca_objects.date/date_value
  313. *
  314. * If you want to get the other values for a multiple-value fields use the following options:
  315. *
  316. * returnAsArray = if true, return an array, otherwise return a string (default is false)
  317. * template = formats attribute values; precede element codes with a caret ("^"). Eg. "^address1<br/>^city, ^state ^postalcode ^country"; only used when returnAsArray is false and a scalar is therefore to be returned.
  318. * delimiter =
  319. * returnAllLocales =
  320. * convertCodesToDisplayText = if true then list_ids are automatically converted to display text in the current locale; default is false (return list_ids raw)
  321. * restrict_to_relationship_types - restricts returned items to those related to the current row by the specified relationship type(s). You can pass either an array of types or a single type. The types can be relationship type_code's or type_id's.
  322. * exclude_relationship_types - omits any items related to the current row with any of the specified types from the returned set of its. You can pass either an array of types or a single type. The types can be relationship type_code's or type_id's.
  323. * sort = optional array of bundles to sort returned values on. Currently only supported when getting related values via simple related <table_name> and <table_name>.related invokations. Eg. from a ca_objects results you can use the 'sort' option got get('ca_entities'), get('ca_entities.related') or get('ca_objects.related'). The bundle specifiers are fields with or without tablename. Only those fields returned for the related tables (intrinsics and label fields) are sortable. You cannot sort on attributes.
  324. * where = optional array of fields and field values to filter returned values on. The fields must be intrinsic and in the same table as the field being "get()'ed" Can be used to filter returned values from primary and related tables. This option can be useful when you want to fetch certain values from a related table. For example, you want to get the relationship source_info values, but only for relationships going to a specific related record. Note that multiple fields/values are effectively AND'ed together - all must match for a row to be returned - and that only equivalence is supported (eg. field equals value).
  325. */
  326. function get($ps_field, $pa_options=null) {
  327. if (!is_array($pa_options)) { $pa_options = array(); }
  328. $vb_return_as_array = (isset($pa_options['returnAsArray'])) ? (bool)$pa_options['returnAsArray'] : false;
  329. $vb_return_all_locales = (isset($pa_options['returnAllLocales'])) ? (bool)$pa_options['returnAllLocales'] : false;
  330. $va_get_where = (isset($pa_options['where']) && is_array($pa_options['where']) && sizeof($pa_options['where'])) ? $pa_options['where'] : null;
  331. $vo_request = $pa_options['request'];
  332. unset($pa_options['request']);
  333. // first see if the search engine can provide the field value directly (fastest)
  334. if(!(($vs_value = $this->opo_engine_result->get($ps_field, $pa_options)) === false)) {
  335. if ($vb_return_as_array) {
  336. if ($vb_return_all_locales) {
  337. return array(1 => $vs_value);
  338. } else {
  339. return array($vs_value);
  340. }
  341. } else {
  342. return $vs_value;
  343. }
  344. }
  345. $vs_template = (isset($pa_options['template'])) ? $pa_options['template'] : null;
  346. $vs_delimiter = (isset($pa_options['delimiter'])) ? $pa_options['delimiter'] : ' ';
  347. if ($vb_return_all_locales && !$vb_return_as_array) { $vb_return_as_array = true; }
  348. if(isset($pa_options['sort']) && !is_array($pa_options['sort'])) { $pa_options['sort'] = array($pa_options['sort']); }
  349. $va_sort_fields = (isset($pa_options['sort']) && is_array($pa_options['sort'])) ? $pa_options['sort'] : null;
  350. $vn_row_id = $this->opo_engine_result->get($this->ops_table_pk);
  351. // try to lazy load (slower)
  352. $va_path_components = $this->getFieldPathComponents($ps_field);
  353. //
  354. // are we getting timestamp (created on or last modified) info?
  355. //
  356. if (($va_path_components['table_name'] == $this->ops_table_name) && ($va_path_components['field_name'] == 'created')) {
  357. if (!isset($this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id])) {
  358. $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch'));
  359. }
  360. if ($vb_return_as_array) {
  361. return $this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id];
  362. } else {
  363. $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp';
  364. $vm_val = $this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id][$vs_subfield];
  365. if ($vs_subfield == 'timestamp') {
  366. $o_tep = new TimeExpressionParser();
  367. $o_tep->setUnixTimestamps($vm_val, $vm_val);
  368. $vm_val = $o_tep->getText($pa_options);
  369. }
  370. return $vm_val;
  371. }
  372. }
  373. if (($va_path_components['table_name'] == $this->ops_table_name) && ($va_path_components['field_name'] == 'lastModified')) {
  374. if (!isset($this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id])) {
  375. $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch'));
  376. }
  377. if ($vb_return_as_array) {
  378. return $this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id];
  379. } else {
  380. $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp';
  381. $vm_val = $this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id][$vs_subfield];
  382. if ($vs_subfield == 'timestamp') {
  383. $o_tep = new TimeExpressionParser();
  384. $o_tep->setUnixTimestamps($vm_val, $vm_val);
  385. $vm_val = $o_tep->getText($pa_options);
  386. }
  387. return $vm_val;
  388. }
  389. }
  390. if (!($t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true))) { return null; }
  391. // Simple related table get
  392. if (
  393. (($va_path_components['num_components'] == 1) && ($va_path_components['table_name'] !== $this->ops_table_name))
  394. ||
  395. (($va_path_components['num_components'] == 2) && ($va_path_components['field_name'] == 'related'))
  396. ||
  397. (($va_path_components['num_components'] == 2) && ($va_path_components['field_name'] == 'hierarchy'))
  398. ) {
  399. if (!($t_table = $this->opo_datamodel->getInstanceByTableName($this->ops_table_name, true))) { return null; }
  400. $vb_show_hierarachy = (bool)$va_path_components['field_name'];
  401. if ($va_path_components['num_components'] == 2) {
  402. $va_path_components['num_components'] = 1;
  403. $va_path_components['field_name'] = null;
  404. }
  405. $vs_opt_md5 = md5(print_R($pa_options, true));
  406. if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) {
  407. $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options);
  408. }
  409. $va_related_items = $this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5];
  410. if (!is_array($va_related_items)) { return null; }
  411. if (is_array($va_sort_fields) && sizeof($va_sort_fields)) {
  412. $va_related_items = caSortArrayByKeyInValue($va_related_items, $va_sort_fields);
  413. }
  414. if($vb_return_as_array) {
  415. if ($vb_return_all_locales) {
  416. return $va_related_items;
  417. } else {
  418. foreach($va_related_items as $vn_relation_id => $va_relation_info) {
  419. $va_relation_info['labels'] = caExtractValuesByUserLocale(array(0 => $va_relation_info['labels']));
  420. $va_related_items[$vn_relation_id]['labels'] = $va_relation_info['labels'];
  421. }
  422. return $va_related_items;
  423. }
  424. } else {
  425. $va_proc_labels = array();
  426. $va_row_ids = array();
  427. $vs_rel_pk = $t_instance->primaryKey();
  428. foreach($va_related_items as $vn_relation_id => $va_relation_info) {
  429. $va_row_ids[] = $va_relation_info[$vs_rel_pk];
  430. }
  431. if (!sizeof($va_row_ids)) { return ''; }
  432. $va_tags = array();
  433. if (preg_match_all("!\^([A-Za-z0-9_\.]+)!", $vs_template, $va_matches)) {
  434. $va_tags = $va_matches[1];
  435. }
  436. $qr_rel_items = $t_instance->makeSearchResult($va_path_components['table_name'], $va_row_ids);
  437. $qr_rel_items->setOption('prefetch', 1000);
  438. $va_values = array();
  439. while($qr_rel_items->nextHit()) {
  440. $va_relation_info = array_shift($va_related_items);
  441. if (sizeof($va_tags)) {
  442. $vs_value = $vs_template;
  443. foreach($va_tags as $vs_tag) {
  444. $vs_field_val = null;
  445. switch($vs_tag) {
  446. case 'label':
  447. case 'preferred_labels':
  448. case $va_path_components['table_name'].'.preferred_labels':
  449. $vs_field_val = $va_relation_info['label'];
  450. if ($vb_show_hierarachy && $t_instance->isHierarchical()) {
  451. if ($va_ids = $this->get($va_path_components['table_name'].'.hierarchy.'.$t_instance->primaryKey(), array_merge($pa_options, array('returnAsArray' => true)))) {
  452. $va_vals = array();
  453. foreach($va_ids as $vn_id) {
  454. if($t_instance->load($vn_id)) {
  455. $va_vals[] = $t_instance->get($va_path_components['table_name'].".preferred_labels", $pa_options);
  456. }
  457. }
  458. $vs_field_val = join($vs_delimiter, $va_vals);
  459. }
  460. }
  461. $vs_value = str_replace("^{$vs_tag}", $vs_field_val, $vs_value);
  462. break;
  463. case 'relationship_typename':
  464. $vs_field_val = $va_relation_info['relationship_typename'];
  465. break;
  466. default:
  467. $vs_field_val = $qr_rel_items->get($va_path_components['table_name'].".".$vs_tag);
  468. break;
  469. }
  470. if ($vs_field_val) {
  471. $vs_value = str_replace("^{$vs_tag}", $vs_field_val, $vs_value);
  472. } else {
  473. $vs_value = preg_replace("![^\^A-Za-z0-9_ ]*\^{$vs_tag}[ ]*[^A-Za-z0-9_ ]*[ ]*!", '', $vs_value);
  474. }
  475. }
  476. $va_values[] = $vs_value;
  477. } else {
  478. $va_values[] = $qr_rel_items->get($va_path_components['table_name'].'.preferred_labels');
  479. }
  480. }
  481. return join($vs_delimiter, $va_values);
  482. }
  483. }
  484. $vb_need_parent = false;
  485. $vb_need_children = false;
  486. //
  487. // Transform "preferred_labels" into tables for pre-fetching
  488. //
  489. $vb_is_get_for_labels = $vb_return_all_label_values = $vb_get_preferred_labels_only = $vb_get_nonpreferred_labels_only = false;
  490. if(in_array($va_path_components['field_name'], array('preferred_labels', 'nonpreferred_labels'))) {
  491. if (is_subclass_of($t_instance, 'LabelableBaseModelWithAttributes')) {
  492. $vb_get_preferred_labels_only = ($va_path_components['field_name'] == 'preferred_labels') ? true : false;
  493. $vb_get_nonpreferred_labels_only = ($va_path_components['field_name'] == 'nonpreferred_labels') ? true : false;
  494. if ($va_path_components['num_components'] == 2) {
  495. $vb_return_all_label_values = true;
  496. }
  497. $va_path_components['table_name'] = $t_instance->getLabelTableName();
  498. $t_label_instance = $t_instance->getLabelTableInstance();
  499. if (!$va_path_components['subfield_name'] || !$t_label_instance->hasField($va_path_components['subfield_name'])) {
  500. $va_path_components['field_name'] = $t_instance->getLabelDisplayField();
  501. } else {
  502. $va_path_components['field_name'] = $va_path_components['subfield_name'];
  503. }
  504. $va_path_components['subfield_name'] = null;
  505. $va_path_components = $this->getFieldPathComponents($va_path_components['table_name'].'.'.$va_path_components['field_name']);
  506. // Ok, convert the table instance to the label table since that's the table we'll be grabbing data from
  507. $t_instance = $t_label_instance;
  508. $vb_is_get_for_labels = true;
  509. }
  510. }
  511. if ($va_path_components['num_components'] >= 2) {
  512. switch($va_path_components['field_name']) {
  513. case 'parent':
  514. if (($t_instance->isHierarchical()) && ($vn_parent_id = $this->get($va_path_components['table_name'].'.'.$t_instance->getProperty('HIERARCHY_PARENT_ID_FLD')))) {
  515. //
  516. // TODO: support some kind of prefetching of parents?
  517. //
  518. unset($va_path_components['components'][1]);
  519. if ($t_instance->load($vn_parent_id)) {
  520. return $t_instance->get(join('.', array_values($va_path_components['components'])), $pa_options);
  521. }
  522. return null;
  523. }
  524. break;
  525. case 'children':
  526. if ($t_instance->isHierarchical()) {
  527. //unset($va_path_components['components'][1]); // remove 'children' from field path
  528. $vs_field_spec = join('.', array_values($va_path_components['components']));
  529. if ($vn_id = $this->get($va_path_components['table_name'].'.'.$t_instance->primaryKey(), array('returnAsArray' => false))) {
  530. if($t_instance->load($vn_id)) {
  531. return $t_instance->get($vs_field_spec, $pa_options);
  532. }
  533. }
  534. return null;
  535. }
  536. break;
  537. case 'related':
  538. // Regular related table call
  539. if ($va_path_components['table_name'] != $this->ops_table_name) {
  540. // just remove "related" from name and be on our way
  541. $va_tmp = $va_path_components['components'];
  542. array_splice($va_tmp, 1, 1);
  543. return $this->get(join('.', $va_tmp), $pa_options);
  544. }
  545. // Self-relations need special handling
  546. $vs_opt_md5 = md5(print_R($pa_options, true));
  547. if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) {
  548. $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options);
  549. }
  550. $va_related_items = $this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5];
  551. if (!($t_table = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true))) { return null; }
  552. $va_ids = array();
  553. foreach($va_related_items as $vn_relation_id => $va_item) {
  554. $va_ids[] = $va_item[$t_table->primaryKey()];
  555. }
  556. $va_vals = array();
  557. if ($qr_res = $t_table->makeSearchResult($va_path_components['table_name'], $va_ids)) {
  558. $va_tmp = $va_path_components['components'];
  559. unset($va_tmp[1]);
  560. $vs_rel_field = join('.', $va_tmp);
  561. while($qr_res->nextHit()) {
  562. if ($vb_return_as_array) {
  563. $va_vals = array_merge($va_vals, $qr_res->get($vs_rel_field, $pa_options));
  564. } else {
  565. $va_vals[] = $qr_res->get($vs_rel_field, $pa_options);
  566. }
  567. }
  568. }
  569. if (is_array($va_sort_fields) && sizeof($va_sort_fields)) {
  570. $va_vals = caSortArrayByKeyInValue($va_vals, $va_sort_fields);
  571. }
  572. if ($vb_return_as_array) {
  573. return $va_vals;
  574. } else {
  575. return join($vs_delimiter, $va_vals);
  576. }
  577. break;
  578. case 'hierarchy':
  579. if ($t_instance->isHierarchical()) {
  580. $vs_field_spec = join('.', array_values($va_path_components['components']));
  581. $vs_hier_pk_fld = $t_instance->primaryKey();
  582. if ($va_ids = $this->get($va_path_components['table_name'].'.'.$vs_hier_pk, array_merge($pa_options, array('returnAsArray' => true)))) {
  583. if ($va_path_components['field_name'] == $vs_hier_pk_fld) {
  584. $va_vals = $va_ids;
  585. } else {
  586. $va_vals = array();
  587. foreach($va_ids as $vn_id) {
  588. if($t_instance->load($vn_id)) {
  589. $va_vals[] = $t_instance->get($vs_field_spec.".preferred_labels", $pa_options);
  590. }
  591. }
  592. }
  593. if ($vb_return_as_array) {
  594. return $va_vals;
  595. } else {
  596. return join($vs_delimiter, $va_vals);
  597. }
  598. }
  599. return null;
  600. }
  601. break;
  602. }
  603. }
  604. // If the requested table was not added to the query via SearchEngine::addTable()
  605. // then auto-add it here. It's better to explicitly add it with addTables() as that call
  606. // gives you precise control over which fields are autoloaded and also lets you specify limiting criteria
  607. // for selection of related field data; and it also lets you explicitly define the tables used to join the
  608. // related table. Autoloading guesses and usually does what you want, but not always.
  609. if (!isset($this->opa_tables[$va_path_components['table_name']]) || !$this->opa_tables[$va_path_components['table_name']]) {
  610. $va_join_tables = $this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name']);
  611. array_shift($va_join_tables); // remove subject table
  612. array_pop($va_join_tables); // remove content table (we only need linking tables here)
  613. $this->opa_tables[$va_path_components['table_name']] = array(
  614. 'fieldList' => array($va_path_components['table_name'].'.*'),
  615. 'joinTables' => array_keys($va_join_tables),
  616. 'criteria' => array()
  617. );
  618. }
  619. if (($va_path_components['table_name'] === $this->ops_table_name) && !$t_instance->hasField($va_path_components['field_name']) && method_exists($t_instance, 'getAttributes')) {
  620. //
  621. // Return attribute values for primary table
  622. //
  623. if ($t_element = $t_instance->_getElementInstance($va_path_components['field_name'])) {
  624. $vn_element_id = $t_element->getPrimaryKey();
  625. } else {
  626. $vn_element_id = null;
  627. }
  628. if (!isset(ca_attributes::$s_get_attributes_cache[$this->opn_table_num.'/'.$vn_row_id][$vn_element_id])) {
  629. ca_attributes::prefetchAttributes($this->opo_db, $this->opn_table_num, $this->getRowIDsToPrefetch($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch')), ($vn_element_id ? array($vn_element_id) : null), array('dontFetchAlreadyCachedValues' => true));
  630. }
  631. if (!$vb_return_as_array) {
  632. if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($va_path_components['field_name'])) {
  633. $vs_template = '';
  634. if ($va_path_components['subfield_name']) {
  635. $vs_template = '^'.$va_path_components['subfield_name'];
  636. } else {
  637. if (isset($pa_options['template'])) { $vs_template = $pa_options['template']; }
  638. }
  639. return $t_instance->getAttributesForDisplay($va_path_components['field_name'], $vs_template, array_merge(array('row_id' => $vn_row_id), $pa_options));
  640. }
  641. if ($t_element && !$va_path_components['subfield_name'] && ($t_element->get('datatype') == 0)) {
  642. return $t_instance->getAttributesForDisplay($va_path_components['field_name'], null, array_merge($pa_options, array('row_id' => $vn_row_id)));
  643. } else {
  644. return $t_instance->getRawValue($vn_row_id, $va_path_components['field_name'], $va_path_components['subfield_name'], ',', $pa_options);
  645. }
  646. } else {
  647. $va_values = $t_instance->getAttributeDisplayValues($va_path_components['field_name'], $vn_row_id, $pa_options);
  648. if ($va_path_components['subfield_name']) {
  649. if ($vb_return_all_locales) {
  650. foreach($va_values as $vn_row_id => $va_values_by_locale) {
  651. foreach($va_values_by_locale as $vn_locale_id => $va_value_list) {
  652. foreach($va_value_list as $vn_attr_id => $va_attr_data) {
  653. $va_values[$vn_row_id][$vn_locale_id][$vn_attr_id] = $va_attr_data[$va_path_components['subfield_name']];
  654. }
  655. }
  656. }
  657. } else {
  658. $va_processed_value_list = array();
  659. foreach($va_values as $vn_row_id => $va_value_list) {
  660. foreach($va_value_list as $vn_attr_id => $va_attr_data) {
  661. $va_processed_value_list[$vn_attr_id] = $va_attr_data[$va_path_components['subfield_name']];
  662. }
  663. }
  664. $va_values = $va_processed_value_list;
  665. }
  666. } else {
  667. if (!$vb_return_all_locales) {
  668. $va_values = array_shift($va_values);
  669. }
  670. }
  671. return $va_values;
  672. }
  673. } else {
  674. // Prefetch intrinsic fields in primary and related tables
  675. if (!isset($this->opa_prefetch_cache[$va_path_components['table_name']][$vn_row_id])) {
  676. $this->prefetch($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch')); // try to prefetch ahead (usually doesn't hurt and very often helps performance)
  677. }
  678. }
  679. //
  680. // Prepare return value
  681. //
  682. $va_return_values = array();
  683. if (($va_path_components['table_name'] !== $this->ops_table_name) && ($va_path_components['field_name'] !== 'relationship_typename') && !$t_instance->hasField($va_path_components['field_name']) && method_exists($t_instance, 'getAttributes')) {
  684. //
  685. // Return attributes in a related table
  686. //
  687. $vs_pk = $t_instance->primaryKey();
  688. $vs_opt_md5 = md5(print_R($pa_options, true));
  689. if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) {
  690. $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options);
  691. }
  692. if (is_array($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_md5])) {
  693. foreach($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_md5] as $vn_i => $va_values) { //$vn_locale_id => $va_values_by_locale) {
  694. if (!$vb_return_as_array) {
  695. $vs_val = $t_instance->getAttributesForDisplay($va_path_components['field_name'], $vs_template, array_merge(array('row_id' => $va_values[$vs_pk]), $pa_options));
  696. } else {
  697. $vs_val = $t_instance->getAttributeDisplayValues($va_path_components['field_name'], $va_values[$vs_pk], $pa_options);
  698. }
  699. if ($vs_val) {
  700. if ($vb_return_as_array) {
  701. if (!$vb_return_all_locales) {
  702. foreach($vs_val as $vn_i => $va_values_list) {
  703. foreach($va_values_list as $vn_j => $va_values) {
  704. $va_return_values[] = $va_values;
  705. }
  706. }
  707. } else {
  708. foreach($vs_val as $vn_i => $va_values_list) {
  709. $va_return_values[] = $va_values_list;
  710. }
  711. }
  712. } else {
  713. $va_return_values[] = $vs_val;
  714. }
  715. }
  716. }
  717. }
  718. if ($vb_return_as_array) {
  719. return $va_return_values;
  720. } else {
  721. if (isset($pa_options['convertLineBreaks']) && $pa_options['convertLineBreaks']) {
  722. return caConvertLineBreaks(join($vs_delimiter, $va_return_values));
  723. } else {
  724. return join($vs_delimiter, $va_return_values);
  725. }
  726. }
  727. } else {
  728. //
  729. // Return fields in primary or related table
  730. //
  731. $t_list = $this->opo_datamodel->getInstanceByTableName('ca_lists', true);
  732. $va_value_list = array($vn_row_id => $this->opa_prefetch_cache[$va_path_components['table_name']][$vn_row_id]);
  733. if (is_array($va_get_where)) {
  734. $va_tmp = array();
  735. foreach($va_value_list as $vn_id => $va_by_locale) {
  736. foreach($va_by_locale as $vn_locale_id => $va_values) {
  737. foreach($va_values as $vn_i => $va_value) {
  738. foreach($va_get_where as $vs_fld => $vm_val) {
  739. if ($va_value[$vs_fld] != $vm_val) { continue(2); }
  740. }
  741. $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value;
  742. }
  743. }
  744. }
  745. $va_value_list = $va_tmp;
  746. }
  747. if (isset($pa_options['restrict_to_relationship_types']) && $pa_options['restrict_to_relationship_types']) {
  748. if (!is_array($pa_options['restrict_to_relationship_types'])) {
  749. $pa_options['restrict_to_relationship_types'] = array($pa_options['restrict_to_relationship_types']);
  750. }
  751. if (sizeof($pa_options['restrict_to_relationship_types'])) {
  752. $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true);
  753. $va_rel_types = array();
  754. $va_rel_path = array_keys($this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name']));
  755. foreach($pa_options['restrict_to_relationship_types'] as $vm_type) {
  756. if (!$vm_type) { continue; }
  757. if ($vn_type_id = $t_rel_type->getRelationshipTypeID($va_rel_path[1], $vm_type)) {
  758. $va_rel_types[] = $vn_type_id;
  759. if (is_array($va_children = $t_rel_type->getHierarchyChildren($vn_type_id, array('idsOnly' => true)))) {
  760. $va_rel_types = array_merge($va_rel_types, $va_children);
  761. }
  762. }
  763. }
  764. if (sizeof($va_rel_types)) {
  765. $va_tmp = array();
  766. foreach($va_value_list as $vn_id => $va_by_locale) {
  767. foreach($va_by_locale as $vn_locale_id => $va_values) {
  768. foreach($va_values as $vn_i => $va_value) {
  769. if (in_array($va_value['rel_type_id'], $va_rel_types)) {
  770. $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value;
  771. }
  772. }
  773. }
  774. }
  775. $va_value_list = $va_tmp;
  776. }
  777. }
  778. }
  779. if (isset($pa_options['exclude_relationship_types']) && $pa_options['exclude_relationship_types']) {
  780. if (!is_array($pa_options['exclude_relationship_types'])) {
  781. $pa_options['exclude_relationship_types'] = array($pa_options['exclude_relationship_types']);
  782. }
  783. if (sizeof($pa_options['exclude_relationship_types'])) {
  784. $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true);
  785. $va_rel_types = array();
  786. $va_rel_path = array_keys($this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name']));
  787. foreach($pa_options['exclude_relationship_types'] as $vm_type) {
  788. if ($vn_type_id = $t_rel_type->getRelationshipTypeID($va_rel_path[1], $vm_type)) {
  789. $va_rel_types[] = $vn_type_id;
  790. if (is_array($va_children = $t_rel_type->getHierarchyChildren($vn_type_id, array('idsOnly' => true)))) {
  791. $va_rel_types = array_merge($va_rel_types, $va_children);
  792. }
  793. }
  794. }
  795. if (sizeof($va_rel_types)) {
  796. $va_tmp = array();
  797. foreach($va_value_list as $vn_id => $va_by_locale) {
  798. foreach($va_by_locale as $vn_locale_id => $va_values) {
  799. foreach($va_values as $vn_i => $va_value) {
  800. if (!in_array($va_value['rel_type_id'], $va_rel_types)) {
  801. $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value;
  802. }
  803. }
  804. }
  805. }
  806. $va_value_list = $va_tmp;
  807. }
  808. }
  809. }
  810. if (isset($pa_options['restrict_to_types']) && $pa_options['restrict_to_types']) {
  811. if (!is_array($pa_options['restrict_to_types'])) {
  812. $pa_options['restrict_to_types'] = array($pa_options['restrict_to_types']);
  813. }
  814. if (sizeof($pa_options['restrict_to_types'])) {
  815. $vs_type_list_code = null;
  816. if (method_exists($t_instance, "getTypeFieldName")) {
  817. $vs_type_list_code = $t_instance->getTypeListCode();
  818. } else {
  819. if (method_exists($t_instance, "getSubjectTableInstance")) {
  820. $t_label_subj_instance = $t_instance->getSubjectTableInstance();
  821. if (method_exists($t_label_subj_instance, "getTypeFieldName")) {
  822. $vs_type_list_code = $t_label_subj_instance->getTypeListCode();
  823. }
  824. }
  825. }
  826. if ($vs_type_list_code) {
  827. $va_types = array();
  828. $t_item = $this->opo_datamodel->getInstanceByTableName('ca_list_items', true);
  829. foreach($pa_options['restrict_to_types'] as $vm_type) {
  830. $vn_type_id = null;
  831. if (is_numeric($vm_type)) {
  832. $vn_type_id = (int)$vm_type;
  833. } else {
  834. $vn_type_id = $t_list->getItemIDFromList($vs_type_list_code, $vm_type);
  835. }
  836. if ($vn_type_id) {
  837. $va_types[] = $vn_type_id;
  838. if (is_array($va_children = $t_item->getHierarchyChildren($vn_type_id, array('idsOnly' => true)))) {
  839. $va_types = array_merge($va_types, $va_children);
  840. }
  841. }
  842. }
  843. if (sizeof($va_types)) {
  844. $va_tmp = array();
  845. foreach($va_value_list as $vn_id => $va_by_locale) {
  846. foreach($va_by_locale as $vn_locale_id => $va_values) {
  847. foreach($va_values as $vn_i => $va_value) {
  848. if (in_array($va_value['item_type_id'], $va_types)) {
  849. $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value;
  850. }
  851. }
  852. }
  853. }
  854. $va_value_list = $va_tmp;
  855. }
  856. }
  857. }
  858. }
  859. // handle 'relationship_typename' call
  860. $vb_get_relationship_typename = false;
  861. if ($va_path_components['field_name'] == 'relationship_typename') {
  862. $va_path_components['field_name'] = 'rel_type_id';
  863. $vb_get_relationship_typename = true;
  864. }
  865. if ($vb_return_as_array) {
  866. if ($t_instance->hasField($va_path_components['field_name']) && ($va_path_components['table_name'] === $this->ops_table_name)) {
  867. $va_field_info = $t_instance->getFieldInfo($va_path_components['field_name']);
  868. switch($va_field_info['FIELD_TYPE']) {
  869. case FT_DATERANGE:
  870. case FT_HISTORIC_DATERANGE:
  871. $this->opo_tep->init();
  872. if ($va_field_info['FIELD_TYPE'] == FT_DATERANGE) {
  873. $this->opo_tep->setUnixTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]);
  874. } else {
  875. $this->opo_tep->setHistoricTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]);
  876. }
  877. $vs_prop = $this->opo_tep->getText();
  878. if ($vb_return_all_locales) {
  879. $va_return_values[$vn_row_id][$vn_locale_id][] = $vs_prop;
  880. } else {
  881. $va_return_values[] = $vs_prop;
  882. }
  883. break;
  884. default:
  885. // is intrinsic field in primary table
  886. foreach($va_value_list as $vn_id => $va_values_by_locale) {
  887. foreach($va_values_by_locale as $vn_locale_id => $va_values) {
  888. foreach($va_values as $vn_i => $va_value) {
  889. if (($vb_get_preferred_labels_only) && (!$va_value['is_preferred'])) { continue; }
  890. if (($vb_get_nonpreferred_labels_only) && ($va_value['is_preferred'])) { continue; }
  891. if ($vb_return_all_locales) {
  892. $va_return_values[$vn_row_id][$vn_locale_id][] = $va_value[$va_path_components['field_name']];
  893. } else {
  894. $va_return_values[] = $va_value[$va_path_components['field_name']];
  895. }
  896. }
  897. }
  898. }
  899. break;
  900. }
  901. } else {
  902. foreach($va_value_list as $vn_i => $va_values_by_locale) {
  903. foreach($va_values_by_locale as $vn_locale_id => $va_values) {
  904. foreach($va_values as $vn_i => $va_value) {
  905. if (($vb_get_preferred_labels_only) && (!$va_value['is_preferred'])) { continue; }
  906. if (($vb_get_nonpreferred_labels_only) && ($va_value['is_preferred'])) { continue; }
  907. // do we need to translate foreign key and choice list codes to display text?
  908. $t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true);
  909. $vs_prop = ($vb_return_all_label_values) ? $va_value[$t_instance->getProperty('LABEL_DISPLAY_FIELD')] : $va_value[$va_path_components['field_name']];
  910. if ($vb_get_relationship_typename) {
  911. if (!$t_rel_type) { $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true); }
  912. if (is_array($va_labels = $t_rel_type->getDisplayLabels(false, array('row_id' => (int)$vs_prop)))) {
  913. $va_label = array_shift($va_labels);
  914. $vs_prop = $va_label[0]['typename'];
  915. } else {
  916. $vs_prop = "?";
  917. }
  918. } else {
  919. if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'],"LIST_CODE"))) {
  920. $vs_prop = $t_list->getItemFromListForDisplayByItemID($vs_list_code, $vs_prop);
  921. } else {
  922. if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'],"LIST"))) {
  923. $vs_prop = $t_list->getItemFromListForDisplayByItemValue($vs_list_code, $vs_prop);
  924. } else {
  925. if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($va_path_components['field_name'] === 'locale_id') && ((int)$vs_prop > 0)) {
  926. $t_locale = new ca_locales($vs_prop);
  927. $vs_prop = $t_locale->getName();
  928. } else {
  929. if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && (is_array($va_list = $t_instance->getFieldInfo($va_path_components['field_name'],"BOUNDS_CHOICE_LIST")))) {
  930. foreach($va_list as $vs_option => $vs_value) {
  931. if ($vs_value == $vs_prop) {
  932. $vs_prop = $vs_option;
  933. break;
  934. }
  935. }
  936. }
  937. }
  938. }
  939. }
  940. }
  941. if ($vb_return_all_locales) {
  942. $va_return_values[$vn_row_id][$vn_locale_id][] = $vs_prop;
  943. } else {
  944. $va_return_values[] = $vs_prop;
  945. }
  946. }
  947. }
  948. }
  949. }
  950. return $va_return_values;
  951. } else {
  952. //
  953. // Return scalar
  954. //
  955. if ($vb_get_preferred_labels_only || $vb_get_nonpreferred_labels_only) {
  956. // We have to distinguish between preferred and non-preferred labels here
  957. // so that only appropriate labels are passed for output.
  958. $va_filtered_values = array();
  959. foreach($va_value_list as $vn_label_id => $va_labels_by_locale) {
  960. foreach($va_labels_by_locale as $vn_locale_id => $va_labels) {
  961. foreach($va_labels as $vn_i => $va_label) {
  962. if (
  963. ($vb_get_preferred_labels_only && ((!isset($va_label['is_preferred']) || $va_label['is_preferred'])))
  964. ||
  965. ($vb_get_nonpreferred_labels_only && !$va_label['is_preferred'])
  966. ) {
  967. $va_filtered_values[$vn_label_id][$vn_locale_id][] = $va_label;
  968. }
  969. }
  970. }
  971. }
  972. $va_value_list = $va_filtered_values;
  973. }
  974. $va_value_list = caExtractValuesByUserLocale($va_value_list);
  975. // do we need to translate foreign key and choice list codes to display text?
  976. $t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true);
  977. $va_field_info = $t_instance->getFieldInfo($va_path_components['field_name']);
  978. foreach($va_value_list as $vn_i => $va_values) {
  979. if (!is_array($va

Large files files are truncated, but you can click here to view the full file