Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
search_page.inc
1 <?php
17 require_once SQ_CORE_PACKAGE_PATH.'/page/page.inc';
18 require_once SQ_FUDGE_PATH.'/general/text.inc';
19 require_once SQ_FUDGE_PATH.'/general/general.inc';
20 require_once SQ_FUDGE_PATH.'/general/datetime.inc';
21 require_once SQ_PACKAGES_PATH.'/cms/listing_engine/listing_engine.inc';
22 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
23 require_once SQ_FUDGE_PATH.'/datetime_field/datetime_field.inc';
24 
38 {
39 
44  var $bodycopies = Array(
45  'initial' => 'Initial Search Page Layout',
46  'results' => 'Results Page Layout',
47  'no_results' => 'No Results Page Layout',
48  );
49 
55  var $defaults = Array ('query_width' => 25);
56 
62  var $keywords = Array(
63  'initial' => Array(
64  'submit_button',
65  'results_per_page',
66  'structured_root_node',
67  ),
68  'results' => Array(
69  'result_list',
70  'result_count',
71  'current_result_page',
72  'total_result_pages',
73  'result_page_index',
74  'previous_result_page_link',
75  'next_result_page_link',
76  'previous_result_page_href',
77  'next_result_page_href',
78  'initial_layout',
79  'category_list_linked',
80  'structured_root_node',
81  'initial_result_count',
82  ),
83  'no_results' => Array(
84  'initial_layout',
85  ),
86  );
87 
88 
95  function __construct($assetid=0)
96  {
97  $this->_ser_attrs = TRUE;
98  parent::__construct($assetid);
99 
100  }//end constructor
101 
102 
123  function _createAdditional(Array &$link)
124  {
125  if (!parent::_createAdditional($link)) return FALSE;
126 
127  // Grab the attributes lock
128  if (!$lock_held = $GLOBALS['SQ_SYSTEM']->am->acquireLock($this->id, 'attributes')) {
129  return FALSE;
130  }
131 
132  // Set the Sort Order to "Descending" by default, so the most relevant results are at the top (ref. Feature #2886)
133  $this->setAttrValue('reverse_sort', TRUE);
134  $this->saveAttributes();
135 
136  if ($lock_held == 1) {
137  $GLOBALS['SQ_SYSTEM']->am->releaseLock($this->id, 'attributes');
138  }
139 
140  return TRUE;
141 
142  }//end _createAdditional()
143 
144 
153  function _createBodycopies()
154  {
155  foreach ($this->bodycopies as $value => $name) {
156  $copy_link = Array(
157  'asset' => &$this,
158  'link_type' => SQ_LINK_TYPE_2,
159  'is_dependant' => 1,
160  'is_exclusive' => 1,
161  'value' => $value,
162  );
163 
164  $bodycopy = new Bodycopy();
165  $bodycopy->setAttrValue('name', $name);
166  $args = Array('content' => $this->_getDefaultBodycopyContent($value));
167  if (!$bodycopy->create($copy_link, $args)) {
168  return FALSE;
169  }
170  }
171 
172  return TRUE;
173 
174  }//end _createBodycopies()
175 
176 
185  function _getDefaultBodycopyContent($bodycopy_code)
186  {
187  switch ($bodycopy_code) {
188  case 'initial':
189  return '<p>'.translate('sch_page_search_for').'</p><p>%submit_button%</p>';
190  case 'results':
191  return '<p>'.translate('sch_page_x_results_found', '%result_count%').'</p>%result_list%';
192  case 'no_results':
193  return '<p>'.translate('sch_page_no_results_try_again').'</p>%initial_layout%';
194  }
195  return parent::_getDefaultBodycopyContent($bodycopy_code);
196 
197  }//end _getDefaultBodycopyContent()
198 
199 
220  function prepareLink(&$asset, $side_of_link, &$link_type, &$value, &$sort_order, &$dependant, &$exclusive)
221  {
222  // if a bodycopy is linking to us then we need to make it a dependant link
223  if ($side_of_link == 'major' && ($asset instanceof Bodycopy) && $dependant != '1') {
224  $dependant = '1';
225  return TRUE;
226  }
227 
228  return FALSE;
229 
230  }//end prepareLink()
231 
232 
241  function isDeletableLink($linkid)
242  {
243  // the only reason why we would object to this link being
244  // deleted is if it is the bodycopy linked to us
245  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid);
246 
247  if ($bodycopy_link['minor_type_code'] == 'bodycopy' && in_array($bodycopy_link['value'], $this->bodycopies) && !$GLOBALS['SQ_PURGING_TRASH']) {
248  return translate('sch_page_cannot_delete_bodycopies');
249  }
250 
251  return parent::isDeletableLink($linkid);
252 
253  }//end isDeletableLink()
254 
255 
263  function _getAllowedLinks()
264  {
265  $page_links = parent::_getAllowedLinks();
266  $page_links[SQ_LINK_TYPE_2]['bodycopy'] = Array('card' => 'M', 'exclusive' => TRUE);
267  $page_links[SQ_LINK_TYPE_2]['folder'] = Array('card' => 4, 'exclusive' => FALSE);
268  $page_links[SQ_LINK_TYPE_3]['folder'] = Array('card' => 1, 'exclusive' => FALSE);
269  $page_links[SQ_LINK_NOTICE]['asset'] = Array('card' => 'M', 'exclusive' => FALSE);
270  return $page_links;
271 
272  }//end _getAllowedLinks()
273 
274 
283  function describeLink($linkid)
284  {
285  $link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid);
286  switch (strtolower($link['value'])) {
287  case 'root' :
288  return translate('sch_page_root_node_link_desc');
289  break;
290  default :
291  return parent::describeLink($linkid);
292  break;
293  }
294 
295  }//end describeLink()
296 
297 
304  function printContents()
305  {
306  // start performance mode timer
307  $GLOBALS['SQ_SYSTEM']->pm->startTimer($this, 'prepareSearchQuery');
308 
309  if (isset($_REQUEST[$this->getPrefix().'_submit_button']) && empty($_REQUEST['mode'])) {
310  $_REQUEST['mode'] = 'results';
311  }
312 
313  $mode = array_get_index($_REQUEST, 'mode', '');
314 
315  if (empty($mode)) {
316  // we dont know what button was pressed, so see if we have any query vars
317  // that show evidence that a search has been performed without submitting
318  // the button value
319  $queries = $this->_getSearchedQueries();
320  foreach ($queries as $field_name => $value) {
321  if (!empty($value)) {
322  $mode = 'results';
323  break;
324  } else {
325  unset($queries[$field_name]);
326  }
327  }
328 
329  $this->_tmp['searched_queries'] = $queries;
330  }
331 
332  if (empty($_SESSION['SQ_LAST_SEARCH'][$this->id])) {
333  $_SESSION['SQ_LAST_SEARCH'][$this->id] = Array();
334  } else {
335  switch ($mode) {
336  case 'sis':
337  // do nothing
338  break;
339 
340  case 'results':
341  // preserve the previous query
342  $this->_tmp['potential_searched_queries'] = $_SESSION['SQ_LAST_SEARCH'][$this->id];
343 
344  // we intentionally fall-through to default
345  default:
346  $_SESSION['SQ_LAST_SEARCH'][$this->id] = Array();
347  break;
348  }
349  }
350 
351  if (empty($mode)) $mode = 'initial';
352 
353  // get the corresponding bodycopy attached to us
354  $GLOBALS['SQ_SYSTEM']->am->includeAsset('bodycopy');
355 
356  $listing_result_page = (int) array_get_index($_REQUEST, 'result_'.$this->id.'_result_page', 0);
357  $search_result_page = (int) array_get_index($_REQUEST, 'current_result_page', 1);
358  if ($listing_result_page === 0) {
359  $current_result_page = $search_result_page;
360  } else {
361  $current_result_page = $listing_result_page;
362  }//end if
363  $results_per_page = (int) array_get_index($_REQUEST, 'results_per_page', $this->_getNumPerPage());
364  $submitted_category = htmlentities(array_get_index($_REQUEST, 'search_category', array_get_index($_REQUEST, 'submitted_search_category')));
365 
366  if (empty($_REQUEST['search_category']) && !empty($submitted_category)) {
367  $_REQUEST['search_category'] = $submitted_category;
368  }
369 
370  // Set this variable to pass to the processSearch() function
371  $search_vars = $this->processSearchVars();
372 
373  // If Stored Query is to be used, then jump to the results page directly
374  if ($this->attr('stored_query_show_results') && $mode == 'initial' && $this->_tmp['jump_to_result']) {
375  $mode = 'results';
376  }//end if
377 
378  // stop performance mode timer
379  $GLOBALS['SQ_SYSTEM']->pm->stopTimer($this, 'prepareSearchQuery');
380 
381  // start performance mode timer
382  $GLOBALS['SQ_SYSTEM']->pm->startTimer($this, 'printBody');
383 
384  switch ($mode) {
385  case 'results':
386  case 'sis' :
387  $this->printResultsBody($search_vars);
388  break;
389 
390  case 'initial':
391  default:
392  echo $this->getBodycopyContents('initial', $this->getInitialBodyReplacements());
393  break;
394  }
395 
396  // only print if submit buttons are printed
397  if (!empty($this->_tmp['prints_submit'])) {
398  ?>
399  <div>
400  <input type="hidden" name="current_result_page" value="<?php echo $current_result_page; ?>" />
401  <input type="hidden" name="results_per_page" value="<?php echo $results_per_page; ?>" />
402  <?php
403  $this->registerFormField('result_page');
404  $this->registerFormField('current_result_page');
405  $this->registerFormField('results_per_page');
406 
407  ?>
408  <input type="hidden" name="submitted_search_category" value="<?php echo $submitted_category; ?>" />
409  <input type="hidden" name="mode" value="" />
410  </div>
411  <?php
412  $this->registerFormField('submitted_search_category');
413  $this->registerFormField('mode');
414  }
415 
416  // stop performance mode timer
417  $GLOBALS['SQ_SYSTEM']->pm->stopTimer($this, 'printBody');
418  }//end printContents()
419 
420 
429  function printResultsBody($search=Array())
430  {
431  $results = $this->processSearch($search);
432 
433  // exclude root nodes themselves if it is required
434  if ($this->attr('exclude_self')) {
435  $root_nodes = $this->getRootNodes();
436  foreach ($root_nodes as $exclude_assetid) {
437  if (isset($results[$exclude_assetid])) {
438  unset($results[$exclude_assetid]);
439  }
440  }
441  }
442 
443  if($this->attr('exclude_current_asset')) {
444  foreach ($results as $assetid => $data) {
445  $url = strip_url($GLOBALS['SQ_SYSTEM']->am->getAssetURL($assetid));
446  $requester = strip_url(current_url());
447  if ($requester === $url) {
448  unset($results[$assetid]);
449  }
450  }
451  }
452 
453  $this->_tmp['initial_results'] = $results;
454  $results =& $this->convertProxyAssetTypes($results);
455  $this->_tmp['search_results'] =& $results;
456  $bc_name = 'results';
457  if (empty($results)) $bc_name = 'no_results';
458 
459  $bodycopy =& $this->getBodycopy($bc_name);
460  $keywords = $bodycopy->getKeywords();
461 
462  echo $this->getBodycopyContents($bc_name, $this->getResultsBodyReplacements($results, $bc_name));
463 
464  // there is no asset listing keyword in the contents, so we dont
465  // need to do all the extra processing for the listing
466  if (!in_array('select_all_js_code', $keywords)) {
468  }
469 
470  }//end printResultsBody()
471 
472 
486  function filterAssetStatuses(&$todo)
487  {
488  return;
489 
490  }//end filterAssetStatuses()
491 
492 
504  function sortAssetList($asset_list, $sort_info)
505  {
506  if (count($asset_list) == 1 || empty($sort_info)) {
507  return $asset_list;
508  }
509 
510  if ((!isset($sort_info['type']) || ($sort_info['type'] == '')) && (!isset($sort_info['params']['field']) || $sort_info['params']['field'] == '')) {
511  if (!empty($asset_list)) arsort($asset_list);
512  }
513 
514  // Search Page-specific sorting
515  if (isset($sort_info['params']['field'])) {
516  $reverse_sort = $this->isDescending();
517 
518  // sort assets by score (relevance)
519  if ($sort_info['params']['field'] == 'score') {
520  if ($reverse_sort) {
521  arsort($asset_list);
522  } else {
523  asort($asset_list);
524  }
525 
526  return $asset_list;
527  }
528  }
529 
530  return parent::sortAssetList($asset_list, $sort_info);
531 
532  }//end sortAssetList()
533 
534 
546  function &getBodycopy($name)
547  {
548  $bodycopy = NULL;
549 
550  if (array_key_exists($name, $this->bodycopies)) {
551  $am =& $GLOBALS['SQ_SYSTEM']->am;
552  $link = $am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, $name, 'major', '1');
553  $bodycopy = $am->getAsset($link['minorid'], $link['minor_type_code']);
554  }
555 
556  return $bodycopy;
557 
558  }//end getBodycopy()
559 
560 
572  function &getBodycopyContents($name, $replacements=Array())
573  {
574  $bodycopy =& $this->getBodycopy($name);
575  if (is_null($bodycopy)) return '';
576 
577  $bodycopy->setKeywordReplacements($replacements);
578 
579  ob_start();
580  $bodycopy->printBody();
581  $html = ob_get_contents();
582  ob_end_clean();
583 
584  return $html;
585 
586  }//end getBodycopyContents()
587 
588 
602  function _hasMixedFieldTypes($field)
603  {
604  $mixed_ds_types = FALSE;
605  if (count($field['data_sources']) > 1) {
606  // several data sources, see what we can do
607  $first_ds_type = NULL;
608  $first_field_type = NULL;
609  foreach ($field['data_sources'] as $ds) {
610  if (is_null($first_ds_type)) {
611  $first_ds_type = $ds['type'];
612  }
613  if ($ds['type'] != $first_ds_type) {
614  $mixed_ds_types = TRUE;
615  break;
616  }
617  $this_field_type = NULL;
618  switch ($ds['type']) {
619  case 'metadata':
620  $assetid = $ds['params']['assetid'];
621  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
622  if (!is_null($asset)) {
623  $this_field_type = get_class_lower($asset);
624  }
625  break;
626  case 'asset_attrib':
627  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($ds['params']['attrid']);
628  $this_field_type = $attribute->type();
629  break;
630  case 'standard' :
631  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
632  if (isset($sm->standard_date_fields[$ds['params']['field']])) {
633  $this_field_type = 'date';
634  } else {
635  $this_field_type = 'text';
636  }
637  break;
638  }
639  if (is_null($first_field_type)) {
640  $first_field_type = $this_field_type;
641  }
642  if ($this_field_type != $first_field_type) {
643  $mixed_ds_types = TRUE;
644  break;
645  }
646  if (in_array(strtolower($this_field_type), Array('selection', 'metadata_field_select', 'metadata_field_hierarchy'))) {
647  $mixed_ds_types = TRUE;
648  break;
649  }
650  }//end foreach
651  }//end if
652  return $mixed_ds_types;
653 
654  }//end _hasMixedFieldTypes()
655 
656 
665  function &_getDateField($field_name)
666  {
667  $parameters = Array(
668  'min' => '0000-01-01 00:00:00',
669  'max' => '9999-12-31 23:59:59',
670  'allow_circa' => '0',
671  'print_format' => '',
672  'show' => Array('y', 'm', 'd'),
673  'null' => Array('y', 'm', 'd'),
674  'style' => Array(
675  'y' => 't',
676  'm' => 's',
677  'd' => 's',
678  ),
679  );
680 
681  $value = '---------- --:--:--';
682  $field = new DateTime_Field($field_name, $value, $parameters, TRUE);
683  return $field;
684 
685  }//end _getDateField()
686 
687 
696  function _printDateRangeDescription($current_value)
697  {
698  if (!isset($current_value['from'])) {
699  $current_value['from'] = '---------- --:--:--';
700  }
701 
702  if (!isset($current_value['to'])) {
703  $current_value['to'] = '---------- --:--:--';
704  }
705 
706  $from_string = '';
707  if ($current_value['from'] != '---------- --:--:--') {
708  $from = iso8601_ts($current_value['from']);
709  $from_string = date('j M Y', $from);
710  }
711 
712  $to_string = '';
713  if ($current_value['to'] != '---------- --:--:--') {
714  $to = iso8601_ts($current_value['to']);
715  $to_string = date('j M Y', $to);
716  }
717 
718  if (empty($from_string) && empty($to_string)) {
719  return;
720  } else if (empty($from_string)) {
721  echo translate('sch_page_date_range_prior_to', $to_string);
722  } else if (empty($to_string)) {
723  echo translate('sch_page_date_range_onwards', $from_string);
724  } else if ($from_string == $to_string) {
725  echo $from_string;
726  } else {
727  echo $from_string.' - '.$to_string;
728  }
729 
730  }//end _printDateRangeDescription()
731 
732 
743  function _printDateRange($field_name, $current_value=Array(), $read_only=FALSE)
744  {
745  if (!isset($current_value['from'])) {
746  $current_value['from'] = '---------- --:--:--';
747  }
748 
749  if (!isset($current_value['to'])) {
750  $current_value['to'] = '---------- --:--:--';
751  }
752 
753  if ($this->attr('use_picker')) {
754  require_once SQ_LIB_PATH.'/js_calendar/js_calendar.inc';
755  if (!JS_Calendar::isInit()) {
756  ?><script src="<?php echo sq_web_path('lib'); ?>/html_form/html_form.js"
757  type="text/javascript"></script><?php
758  }
759  }
760 
761  ?>
762  <table border="0" cellspacing="0" cellpadding="0">
763  <tr>
764  <td align="right"><?php echo ucfirst(translate('from')) ?>:</td>
765  <td>
766  <?php
767  if ($read_only && $current_value['from'] != '---------- --:--:--') {
768  $from = iso8601_ts($current_value['from']);
769  echo date('j M Y', $from);
770  } else {
771  $field = $this->_getDateField($field_name.'_from');
772  if (!$field->processField() || $field->value == '---------- --:--:--') {
773  $field->setValue($current_value['from']);
774  }
775  $field->printField();
776  }
777  ?>
778  </td>
779  <?php
780  if ($this->attr('use_picker') && (!$read_only || $current_value['from'] == '---------- --:--:--')) {
781  ?>
782  <td>
783  &nbsp;
784  <?php
785  // print the JS calendar popup date selecta
786  $calendar = new JS_Calendar();
787  $calendar->changeSetting('onDayClick', 'datetime_set_date');
788  $calendar->paint($field_name.'_from', '', TRUE);
789  ?>
790  </td>
791  <?php
792  }
793  ?>
794  </tr>
795  <tr>
796  <td align="right"><?php echo ucfirst(translate('to')) ?>:</td>
797  <td>
798  <?php
799  if ($read_only && $current_value['to'] != '---------- --:--:--') {
800  $to = iso8601_ts($current_value['to']);
801  echo date('j M Y', $to);
802  } else {
803  $field = $this->_getDateField($field_name.'_to');
804  if (!$field->processField() || $field->value == '---------- --:--:--') {
805  $field->setValue($current_value['to']);
806  }
807  $field->printField();
808  }
809  ?>
810  </td>
811  <?php
812  if ($this->attr('use_picker') && (!$read_only || $current_value['to'] == '---------- --:--:--')) {
813  ?>
814  <td>
815  &nbsp;
816  <?php
817  // print the JS calendar popup date selecta
818  $calendar = new JS_Calendar();
819  $calendar->changeSetting('onDayClick', 'datetime_set_date');
820  $calendar->paint($field_name.'_to', '', TRUE);
821  ?>
822  </td>
823  <?php
824  }
825  ?>
826  </tr>
827  </table>
828  <?php
829 
830  }//end _printDateRange()
831 
832 
841  function _processDateRange($field_name)
842  {
843  $result = Array();
844 
845  $field = $this->_getDateField($field_name.'_from');
846  if ($field->processField()) {
847  $result['from'] = $field->value;
848  }
849 
850  $field = $this->_getDateField($field_name.'_to');
851  if ($field->processField()) {
852  $result['to'] = $field->value;
853  }
854 
855  return $result;
856 
857  }//end _processDateRange()
858 
859 
871  function _printNumericRangeDescription($current_value, $sub_field, $params)
872  {
873  switch (array_get_index($params, 'numeric_search', 'exact')) {
874  case 'exact':
875  if ($sub_field == '') print $current_value['lower'];
876  break;
877 
878  case 'range':
879  if (!isset($current_value['upper'])) {
880  $current_value['upper'] = NULL;
881  }
882 
883  if (!isset($current_value['lower'])) {
884  $current_value['lower'] = NULL;
885  }
886 
887  if ($sub_field == 'lower') {
888  print array_get_index($current_value, 'lower', '');
889  } else if ($sub_field == 'upper') {
890  print array_get_index($current_value, 'upper', '');
891  } else {
892  if (is_null($current_value['lower'])) {
893  echo '&lt;= '.$current_value['upper'];
894  } else if (is_null($current_value['upper'])) {
895  echo '&gt;= '.$current_value['lower'];
896  } else {
897  echo $current_value['lower'].' to '.$current_value['upper'];
898  }
899  }
900  break;
901 
902  case 'custom':
903  $custom_ranges = Array();
904  $range_name = '';
905  foreach ($params['custom_num_search'] as $key => $num_search_data) {
906  if (!empty($num_search_data['name']) && ($current_value['lower'] == $num_search_data['min']) && ($current_value['upper'] == $num_search_data['max'])) {
907  $range_name = $num_search_data['name'];
908  break;
909  }
910  }
911 
912  if ($sub_field == 'lower') {
913  print array_get_index($current_value, 'lower', '');
914  } else if ($sub_field == 'upper') {
915  print array_get_index($current_value, 'upper', '');
916  } else if ($sub_field == '') {
917  print $range_name;
918  }
919  break;
920 
921  }//end switch
922 
923  }//end _printNumericRangeDescription()
924 
925 
942  function _printNumericRange($field_name, $current_value=NULL, $params, $sub_field='', $read_only=FALSE)
943  {
944  switch (array_get_index($params, 'numeric_search', 'exact')) {
945  case 'exact':
946  if ($sub_field == '') {
947  text_box('queries_'.$field_name, array_get_index($current_value, 'lower', ''), 5);
948  }
949  break;
950 
951  case 'range':
952  $current_value = NULL;
953 
954  if (!isset($current_value['upper'])) {
955  $current_value['upper'] = NULL;
956  }
957 
958  if (!isset($current_value['lower'])) {
959  $current_value['lower'] = NULL;
960  }
961 
962  if ($sub_field == 'lower') {
963  text_box('queries_'.$field_name.'_lower', $current_value['lower'], 5);
964  } else if ($sub_field == 'upper') {
965  text_box('queries_'.$field_name.'_upper', $current_value['upper'], 5);
966  } else {
967  text_box('queries_'.$field_name.'_lower', $current_value['lower'], 5);
968  echo ' to ';
969  text_box('queries_'.$field_name.'_upper', $current_value['upper'], 5);
970  }
971  break;
972 
973  case 'custom':
974  $custom_ranges = Array();
975  foreach ($params['custom_num_search'] as $key => $num_search_data) {
976  if (!empty($num_search_data['name'])) {
977  $custom_ranges[$key] = $num_search_data['name'];
978  }
979  }
980  if ($sub_field == '') {
981  combo_box('queries_'.$field_name, $custom_ranges, FALSE, $current_value);
982  }
983  break;
984 
985  }//end switch
986 
987  }//end _printNumericRange()
988 
989 
1001  function getCategoryChooserReplacement($cat_set_name, $cat_set_details, $default='', $show_empty=TRUE)
1002  {
1003  $prefix = $this->getPrefix();
1004  $options = Array();
1005 
1006  if ($show_empty) {
1007  $options[''] = $cat_set_details['unselected_text'];
1008  }
1009 
1010  foreach ($cat_set_details['options'] as $code_name => $cat_option) {
1011  $options[$code_name] = $cat_option['full_name'];
1012  }
1013  ob_start();
1014  $this->registerFormField('category_'.$cat_set_name);
1015  combo_box('category_'.$cat_set_name, $options, FALSE, $default);
1016  $res = ob_get_contents();
1017  ob_end_clean();
1018  return $res;
1019 
1020  }//end getCategoryChooserReplacement()
1021 
1022 
1032  function getFieldReplacement($field_name, $sub_field='')
1033  {
1034  $query_var = $field_name.'_query';
1035  $fields = $this->attr('fields');
1036  if (!isset($fields[$field_name])) return;
1037  $this->registerFormField('queries_'.$query_var.'%');
1038  $query = '';
1039 
1040  if (isset($_SESSION['SQ_LAST_SEARCH'][$this->id])) {
1041  $query = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, '');
1042  }
1043  $read_only = FALSE;
1044 
1045  // Check if a stored stored session variable is set and set query to match
1046  // But don't touch it if there was some SESSION var already set
1047  $pmap = $this->getAttribute('stored_query_session');
1048  $pmap_params = $pmap->getParameters();
1049  if (empty($query) && is_array($pmap_params) && !empty($pmap_params)) {
1050  // Check for all fields
1051  if (in_array('stored_query', $pmap_params)) {
1052  $key_field = array_search('stored_query', $pmap_params);
1053  $query = $pmap->getParameterValue($pmap_params[$key_field]);
1054  }
1055 
1056  // Check for current field
1057  if (in_array($field_name, $pmap_params)) {
1058  $key_field = array_search($field_name, $pmap_params);
1059  $query = $pmap->getParameterValue($pmap_params[$key_field]);
1060  }
1061  replace_global_keywords($query);
1062  }
1063 
1064  ob_start();
1065 
1066  if (empty($fields[$field_name]['data_sources']) || $this->_hasMixedFieldTypes($fields[$field_name])) {
1067  text_box('queries_'.$query_var, $query, $this->defaults['query_width']);
1068  } else {
1069  // only one data source, or all matching; we'll base our format on the first one
1070  $data_source = $fields[$field_name]['data_sources'][0];
1071 
1072  switch ($data_source['type']) {
1073 
1074  case 'metadata' :
1075  $assetid = $data_source['params']['assetid'];
1076  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1077 
1078  if (!is_null($asset)) {
1079  $params = $asset->vars;
1080  switch (get_class_lower($asset)) {
1081  case 'metadata_field_date' :
1082  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1083  $this->_printDateRange('queries_'.$query_var, $current_value);
1084  break;
1085  case 'metadata_field_text' :
1086  case 'metadata_field_thesaurus':
1087  case 'metadata_field_multiple_text':
1088  case 'metadata_field_wysiwyg':
1089  text_box('queries_'.$query_var, $query, $this->defaults['query_width']);
1090  break;
1091  case 'metadata_field_hierarchy' :
1092  $hierarchy = $asset->getHierarchyAttribute();
1093 
1094  if (!empty($query)) $hierarchy->value = $query;
1095  if ($asset->attr('hier_sort')) {
1096  $sort = $asset->attr('hier_sort');
1097  $fmt = $asset->attr('hier_structure');
1098  $edit_fns = $asset->getEditFns();
1099  $options = $hierarchy->_params['options'];
1100  $options = $edit_fns->_sortHierarchyOptions($options, $sort, $fmt);
1101  $hierarchy->_params['options'] = $options;
1102  }
1103  $hierarchy->paint('queries_'.$query_var);
1104  break;
1105  case 'metadata_field_select' :
1106  $selection = $asset->getSelectionAttribute();
1107  if (!empty($query)) $selection->setValue($query);
1108  $selection->paint('queries_'.$query_var);
1109  break;
1110  }//end switch
1111  } else {
1112  // not printing a field, set read-only
1113  $read_only = TRUE;
1114  }//end if metadata asset exists
1115  break;
1116 
1117  case 'asset_attrib' :
1118  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($data_source['params']['attrid']);
1119 
1120  if ($attribute->type() == 'datetime') {
1121 
1122  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1123  $this->_printDateRange('queries_'.$query_var, $current_value);
1124 
1125  } else if (($attribute->type() == 'int' || $attribute->type() == 'float')) {
1126  $this->_printNumericRange($query_var, $query, $data_source['params'], $sub_field);
1127 
1128  } else {
1129 
1130  // if this is a boolean or selection field, we want to make sure blank options are allowed
1131  if ($attribute->type() == 'boolean' || $attribute->type() == 'selection') {
1132  $attribute->_params['allow_empty'] = TRUE;
1133  }
1134 
1135  // set the current value of the search field
1136  $attribute->setValue($query);
1137 
1138  // give the attribute our custom search styles if we have them
1139  $search_styles = $this->attr('search_styles');
1140  if (isset($search_styles[$attribute->id])) {
1141  $attribute->_edit_params = array_merge($attribute->_edit_params, $search_styles[$attribute->id]);
1142  }
1143 
1144  $attribute->paint('queries_'.$query_var, FALSE);
1145  }
1146  break;
1147 
1148  case 'standard' :
1149  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
1150  if (isset($sm->standard_date_fields[$data_source['params']['field']])) {
1151  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1152  $this->_printDateRange('queries_'.$query_var, $current_value);
1153  } else if (isset($sm->standard_text_fields[$data_source['params']['field']])) {
1154  text_box('queries_'.$query_var, $query, $this->defaults['query_width']);
1155  }
1156  break;
1157 
1158  default :
1159  text_box('queries_'.$query_var, $query, $this->defaults['query_width']);
1160  break;
1161 
1162  }//end switch field type
1163  }//end else
1164 
1165  if (!$read_only) {
1166  $this->registerFormField('queries_'.$query_var);
1167  }
1168 
1169  $replacement = ob_get_contents();
1170 
1171  ob_end_clean();
1172 
1173  return $replacement;
1174 
1175  }//end getFieldReplacement()
1176 
1177 
1186  function getSisFieldReplacement($field_name)
1187  {
1188  $query_var = $field_name.'_query_sis';
1189  $query = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, '');
1190  $fields = $this->attr('fields');
1191  $read_only = FALSE;
1192 
1193  ob_start();
1194 
1195  if (!$this->_hasMixedFieldTypes($fields[$field_name])) {
1196  $data_source = $fields[$field_name]['data_sources'][0];
1197 
1198  switch ($data_source['type']) {
1199 
1200  case 'metadata' :
1201  $assetid = $data_source['params']['assetid'];
1202  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1203  if (!is_null($asset)) {
1204  $params = $asset->vars;
1205  $this->registerFormField('queries_'.$query_var);
1206  switch (get_class_lower($asset)) {
1207  case 'metadata_field_date' :
1208  $read_only = TRUE;
1209  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1210  $this->_printDateRange('queries_'.$query_var, $current_value, TRUE);
1211  break;
1212  case 'metadata_field_text' :
1213  case 'metadata_field_thesaurus':
1214  case 'metadata_field_multiple_text':
1215  text_box('queries_'.$query_var, '', $this->defaults['query_width']);
1216  break;
1217  case 'metadata_field_hierarchy' :
1218  $hierarchy = $asset->getHierarchyAttribute();
1219  if (!empty($query)) $hierarchy->value = $query;
1220  if ($asset->attr('hier_sort')) {
1221  $sort = $asset->attr('hier_sort');
1222  $fmt = $asset->attr('hier_structure');
1223  $edit_fns = $asset->getEditFns();
1224  $options = $hierarchy->_params['options'];
1225  $options = $edit_fns->_sortHierarchyOptions($options, $sort, $fmt);
1226  $hierarchy->_params['options'] = $options;
1227  }
1228  $hierarchy->paint('queries_'.$query_var);
1229  break;
1230  case 'metadata_field_select' :
1231  $selection = $asset->getSelectionAttribute();
1232  $value = Array();
1233 
1234  if (empty($selection->_params['multiple'])) {
1235  if (isset($selection->_params['options'][$query])) {
1236  $read_only = TRUE;
1237  }
1238  // set the value outside the if condition so that if
1239  // empty text has been selected, it will get saved as the option,
1240  // but the selection attribute will NOT be read only ie. they
1241  // will be able to select another option in the sis form
1242  $selection->value = $query;
1243  } else {
1244  if (!empty($query)) {
1245  echo '<div class="search_current_options">';
1246  foreach ($query as $option) {
1247  if (!isset($selection->_params['options'][$option])) {
1248  continue;
1249  }
1250  echo $selection->_params['options'][$option].'<br />';
1251  unset($selection->_params['options'][$option]);
1252  }
1253  echo '</div>';
1254  }
1255  }
1256 
1257  $selection->paint('queries_'.$query_var, $read_only);
1258  break;
1259  }//end switch
1260 
1261  } else {
1262  // not printing a field, set read-only
1263  $read_only = TRUE;
1264  }//end if metadata asset exists
1265  break;
1266 
1267  case 'asset_attrib' :
1268  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($data_source['params']['attrid']);
1269 
1270  if ($attribute->type() == 'datetime') {
1271 
1272  $read_only = TRUE;
1273  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1274  $this->_printDateRange('queries_'.$query_var, $current_value, $read_only);
1275 
1276  } else {
1277 
1278  // if this is a boolean or selection field, we want to make sure blank options are allowed
1279  if ($attribute->type() == 'boolean' || $attribute->type() == 'selection') {
1280  $attribute->_params['allow_empty'] = TRUE;
1281  }
1282 
1283  // give the attribute our custom search styles if we have them
1284  $search_styles = $this->attr('search_styles');
1285  if (isset($search_styles[$attribute->id])) {
1286  $attribute->_edit_params = $search_styles[$attribute->id];
1287  }
1288 
1289  switch ($attribute->type()) {
1290  case 'selection' :
1291  if (empty($attribute->_params['multiple'])) {
1292  if (isset($attribute->_params['options'][$query])) {
1293  $read_only = TRUE;
1294  }
1295  } else {
1296  if (!empty($query)) {
1297  echo '<div class="search_current_options">';
1298  foreach ($query as $option) {
1299  if (!isset($attribute->_params['options'][$option])) {
1300  continue;
1301  }
1302  echo $attribute->_params['options'][$option].'<br />';
1303  unset($attribute->_params['options'][$option]);
1304  }
1305  echo '</div>';
1306  }
1307  }
1308  break;
1309 
1310  case 'boolean' :
1311  if ($query != '') $read_only = TRUE;
1312  break;
1313 
1314  case 'text' :
1315  $attribute->value = '';
1316  break;
1317  }//end switch
1318 
1319  $attribute->paint('queries_'.$query_var, $read_only);
1320  }//end else
1321  break;
1322 
1323  case 'standard' :
1324  $read_only = TRUE;
1325  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
1326  if (isset($sm->standard_date_fields[$data_source['params']['field']])) {
1327  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1328  $this->_printDateRange('queries_'.$query_var, $current_value, $read_only);
1329  } else if (isset($sm->standard_text_fields[$data_source['params']['field']])) {
1330  text_box('queries_'.$query_var, '', $this->defaults['query_width']);
1331  }
1332  break;
1333 
1334  default :
1335  // not a metadata field, just a normal text field
1336  text_box('queries_'.$query_var, '', $this->defaults['query_width']);
1337  break;
1338 
1339  }//end switch field type
1340  } else {
1341  // when there are multiple (or 0) data sources supplied the format is always text (for now)
1342  text_box('queries_'.$query_var, $query, $this->defaults['query_width']);
1343  }
1344 
1345  if (!$read_only) {
1346  $this->registerFormField('queries_'.$query_var);
1347  }
1348 
1349  $replacement = ob_get_contents();
1350 
1351  ob_end_clean();
1352 
1353  return $replacement;
1354 
1355  }//end getSisFieldReplacement()
1356 
1357 
1368  function getSearchedFieldReplacement($field_name, $sub_field='', $escape=TRUE)
1369  {
1370  $query_var = $field_name.'_query_sis';
1371  $query = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, '');
1372  $fields = $this->attr('fields');
1373 
1374  ob_start();
1375 
1376  if (!$this->_hasMixedFieldTypes($fields[$field_name])) {
1377  switch ($fields[$field_name]['data_sources'][0]['type']) {
1378 
1379  case 'metadata' :
1380  $assetid = $fields[$field_name]['data_sources'][0]['params']['assetid'];
1381  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1382  if (!is_null($asset)) {
1383  $params = $asset->vars;
1384  switch (get_class_lower($asset)) {
1385  case 'metadata_field_date' :
1386  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1387  $this->_printDateRangeDescription($current_value);
1388  break;
1389  case 'metadata_field_text' :
1390  case 'metadata_field_thesaurus':
1391  case 'metadata_field_multiple_text':
1392  echo ($escape ? htmlspecialchars($query) : $query);
1393  break;
1394  case 'metadata_field_hierarchy' :
1395  $hierarchy = $asset->getHierarchyAttribute();
1396  if (!empty($query)) $hierarchy->value = $query;
1397  if ($asset->attr('hier_sort')) {
1398  $sort = $asset->attr('hier_sort');
1399  $fmt = $asset->attr('hier_structure');
1400  $edit_fns = $asset->getEditFns();
1401  $options = $hierarchy->_params['options'];
1402  $options = $edit_fns->_sortHierarchyOptions($options, $sort, $fmt);
1403  $hierarchy->_params['options'] = $options;
1404  }
1405  $hierarchy->paint('queries_'.$query_var);
1406  break;
1407  case 'metadata_field_select' :
1408  // NOTE: if the selection field allows multiple selections, then the selection cannot be paint()ed unescaped
1409  $selection = $asset->getSelectionAttribute();
1410  if (!empty($query)) $selection->setValue($query);
1411  $selection->paint('queries_'.$query_var, TRUE);
1412  break;
1413  }//end switch
1414 
1415  }//end if metadata asset exists
1416  break;
1417 
1418  case 'asset_attrib' :
1419  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($fields[$field_name]['data_sources'][0]['params']['attrid']);
1420 
1421  if ($attribute->type() == 'datetime') {
1422 
1423  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1424  $this->_printDateRangeDescription($current_value);
1425 
1426  } else if (($attribute->type() == 'int' || $attribute->type() == 'float')) {
1427  $current_value = array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $field_name, Array());
1428  $this->_printNumericRangeDescription($current_value, $sub_field, $fields[$field_name]['data_sources'][0]['params']);
1429 
1430  } else {
1431  // if this is a boolean or selection field, we want to make sure blank options are allowed
1432  if ($attribute->type() == 'boolean' || $attribute->type() == 'selection') {
1433  $attribute->_params['allow_empty'] = TRUE;
1434  }
1435 
1436  // give the attribute our custom search styles if we have them
1437  $search_styles = $this->attr('search_styles');
1438  if (isset($search_styles[$attribute->id])) {
1439  $attribute->_edit_params = $search_styles[$attribute->id];
1440  }
1441 
1442  $attribute->value = $query;
1443 
1444  $attribute->paint('queries_'.$query_var, TRUE);
1445  }
1446  break;
1447 
1448  default :
1449  if (is_array($query) && isset($query['from']) && isset($query['to'])) {
1450  // this is a date field
1451  $this->_printDateRangeDescription($query);
1452  } else {
1453  // just a standard text field
1454  echo ($escape ? htmlspecialchars($query) : $query);
1455  }
1456  break;
1457 
1458  }//end switch field type
1459  } else {
1460  // many (or zero) data sources for this field, so we'll assume it was just text
1461  echo ($escape ? htmlspecialchars($query) : $query);
1462  }
1463 
1464  $replacement = ob_get_contents();
1465 
1466  ob_end_clean();
1467 
1468  return $replacement;
1469 
1470  }//end getSearchedFieldReplacement()
1471 
1472 
1481  function getGeneralReplacement($keyword)
1482  {
1483  $prefix = $this->getPrefix();
1484  $replacement = '';
1485  switch ($keyword) {
1486 
1487  case 'search_button' :
1488  case 'submit_button' :
1489  $field_name = $prefix.'_submit_button';
1490  $this->registerFormField($field_name);
1491  $this->_tmp['prints_submit'] = TRUE;
1492 
1493  // if we are on the initial search page, don't use javascript
1494  // for the submit button so enter will submit the form
1495  $mode = array_get_index($_REQUEST, 'mode', 'initial');
1496  // Extra hidden field to make IE submit the form with a single field (See bug #5279)
1497  $replacement = '<input type="text" name="'.$prefix.'_extra_field" id="'.$prefix.'_extra_field" disabled="disabled" style="display:none" />';
1498  if ($mode == 'initial') {
1499  $replacement .= '<input type="submit" name="'.$field_name.'"
1500  value="'.$this->attr('submit_button_text').'" />';
1501  } else {
1502  $replacement .= '<input type="submit" name="'.$field_name.'" onclick="listing_form = document.getElementById(\''.$this->getPrefix().'\');
1503  listing_form.current_result_page.value=\'1\';
1504  if (typeof listing_form.mode != \'undefined\') listing_form.mode.value = \'results\';
1505  return true;
1506  " value="'.$this->attr('submit_button_text').'" />';
1507  }
1508  break;
1509 
1510  case 'search_in_search_button' :
1511  $field_name = 'sis_search_button';
1512  $this->registerFormField($field_name);
1513  $this->_tmp['prints_submit'] = TRUE;
1514 
1515  $replacement = '<input type="submit" name="'.$field_name.'" onclick="listing_form = document.getElementById(\''.$this->getPrefix().'\');
1516  listing_form.current_result_page.value=\'1\';
1517  listing_form.mode.value = \'sis\';
1518  return TRUE;
1519  " value="'.$this->attr('sis_button_text').'" />';
1520  break;
1521 
1522  case 'search_form':
1523  $bodycopy_link = $this->getFormatBodycopyLink('search_form');
1524 
1525  if (!empty($bodycopy_link) && $bodycopy_link['link_type'] == SQ_LINK_TYPE_2) {
1526  $replacements = $this->getFormFormatReplacements('search_form');
1527  $replacement = $this->getFormFormatContents('search_form', $replacements);
1528  } else {
1529  $replacement = '';
1530  }
1531  break;
1532 
1533  case 'search_in_search_form':
1534  $bodycopy_link = $this->getFormatBodycopyLink('sis_form');
1535 
1536  if (!empty($bodycopy_link) && $bodycopy_link['link_type'] == SQ_LINK_TYPE_2) {
1537  $replacements = $this->getFormFormatReplacements('sis_form');
1538  $replacement = $this->getFormFormatContents('sis_form', $replacements);
1539  } else {
1540  $replacement = '';
1541  }
1542  break;
1543 
1544  case 'results_per_page' :
1545  $results_per_page = array_get_index($_REQUEST, 'results_per_page', $this->_getNumPerPage());
1546  $field_name = 'results_per_page_text_box';
1547  $this->registerFormField($field_name);
1548  $replacement = '<input type="text" name="'.$field_name.'" onchange="listing_form = document.getElementById(\''.$this->getPrefix().'\');
1549  listing_form.results_per_page.value = this.value;
1550  " value="'.$results_per_page.'" size="5" />';
1551  break;
1552 
1553  default :
1554  $replacement = $this->getKeywordReplacement($keyword);
1555  break;
1556 
1557  }//end switch
1558 
1559  return $replacement;
1560 
1561  }//end getGeneralReplacement()
1562 
1563 
1570  function getInitialBodyReplacements()
1571  {
1572  $bodycopy =& $this->getBodycopy('initial');
1573  $keywords = $bodycopy->getKeywords();
1574  $replaces = Array();
1575 
1576  $fields = $this->attr('fields');
1577  $categories = $this->attr('categories');
1578 
1579  foreach ($keywords as $keyword) {
1580  if (preg_match('/(.+)_query_logic$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1581  $current_logic = array_get_index($_REQUEST, $keyword, array_get_index($fields[$matches[1]], 'word_logic'));
1582  $options = Array(
1583  'AND' => translate('sch_page_format_logic_and'),
1584  'OR' => translate('sch_page_format_logic_or'),
1585  );
1586  ob_start();
1587  $this->registerFormField($keyword);
1588  combo_box($keyword, $options, FALSE, $current_logic);
1589  $replaces[$keyword] = ob_get_contents();
1590  ob_end_clean();
1591  } else if (preg_match('/(.+)_query_(.+)$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1592  $replaces[$keyword] = $this->getFieldReplacement($matches[1], $matches[2]);
1593  } else if (preg_match('/(.+)_query$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1594  $replaces[$keyword] = $this->getFieldReplacement($matches[1]);
1595  } else if (substr($keyword, -17) == '_category_chooser') {
1596  $cat_name = substr($keyword, 0, -17);
1597  $replaces[$keyword] = $this->getCategoryChooserReplacement($cat_name, $categories[$cat_name]);
1598  } else {
1599  $replaces[$keyword] = $this->getGeneralReplacement($keyword);
1600  }
1601  }
1602 
1603  return $replaces;
1604 
1605  }//end getInitialBodyReplacements()
1606 
1607 
1616  function getFormFormatReplacements($form_name)
1617  {
1618  $bodycopy =& $this->getFormatBodycopy($form_name);
1619  if (is_null($bodycopy)) return Array();
1620 
1621  $fields = $this->attr('fields');
1622  $keywords = $bodycopy->getKeywords();
1623 
1624  $replacements = Array();
1625  foreach ($keywords as $keyword) {
1626  if (preg_match('/(.+)_query_terms$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1627  $replacements[$keyword] = $this->getSearchedFieldReplacement($matches[1]);
1628  } else if (preg_match('/(.+)_query$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1629  if ($form_name == 'sis_form') {
1630  $replacements[$keyword] = $this->getSisFieldReplacement($matches[1]);
1631  } else {
1632  $replacements[$keyword] = $this->getFieldReplacement($matches[1]);
1633  }
1634  } else {
1635  if ($form_name == 'sis_form' || $form_name == 'search_form') {
1636  if (substr($keyword, -17) == '_category_chooser') {
1637  $categories = $this->attr('categories');
1638  $cat_name = substr($keyword, 0, -17);
1639  $selected_option = array_get_index($_REQUEST, 'category_'.$cat_name, '');
1640 
1641  $replacements[$keyword] = $this->getCategoryChooserReplacement($cat_name, $categories[$cat_name], $selected_option);
1642  } else {
1643  $replacements[$keyword] = $this->getGeneralReplacement($keyword);
1644  }
1645  } else {
1646  $replacements[$keyword] = $this->getGeneralReplacement($keyword);
1647  }
1648  }
1649  }//end foreach
1650 
1651  return $replacements;
1652 
1653  }//end getFormFormatReplacements()
1654 
1655 
1666  function getFormFormatContents($form_name, $replacements)
1667  {
1668  $bodycopy =& $this->getFormatBodycopy($form_name);
1669  if (is_null($bodycopy)) return '';
1670 
1671  $bodycopy->setKeywordReplacements($replacements);
1672 
1673  ob_start();
1674  $bodycopy->printBody();
1675  $html = ob_get_contents();
1676  ob_end_clean();
1677 
1678  return $html;
1679 
1680  }//end getFormFormatContents()
1681 
1682 
1697  function filterAssetTypes(&$todo)
1698  {
1699  // the search manager uses the type_code column in the search indexing table
1700  // to filter on asset types for performance reasons, so we don't need to
1701  // do any filtering
1702  return $todo;
1703 
1704  }//end filterAssetTypes()
1705 
1706 
1716  function getResultsBodyReplacements(&$results, $bc_name='results')
1717  {
1718  $mode = array_get_index($_REQUEST, 'mode', 'results');
1719  $bodycopy =& $this->getBodycopy($bc_name);
1720  $keywords = $bodycopy->getKeywords();
1721 
1722  // if we have %page_list_X% keywords in the array before the %result_list%
1723  // rip it off and put it at the end of the array or else it will not be
1724  // replace at all #4527 Matrix search page results has no output for page_list_X keywords
1725  $page_list_keywords = Array();
1726  foreach ($keywords as $index => $keyword) {
1727  if (preg_match('/page_list_([0-9]+)/', $keyword, $matches)) {
1728  $page_list_keywords[] = $keyword;
1729  unset($keywords[$index]);
1730  }
1731  }
1732 
1733  $keywords = array_merge($keywords, $page_list_keywords);
1734  $replaces = Array();
1735 
1736  $listing_result_page = (int) array_get_index($_REQUEST, 'result_'.$this->id.'_result_page', 0);
1737  $search_result_page = (int) array_get_index($_REQUEST, 'current_result_page', 1);
1738  if ($listing_result_page === 0) {
1739  $current_result_page = $search_result_page;
1740  } else {
1741  $current_result_page = $listing_result_page;
1742  }//end if
1743  $results_per_page = array_get_index($_REQUEST, 'results_per_page', $this->_getNumPerPage());
1744  $this->_tmp['start_element'] = ($current_result_page - 1) * $results_per_page;
1745  $queries = '';
1746  foreach ($_GET as $query_name => $query_value) {
1747  // skip some get vars that will be added later by the keyword replacements
1748  if (!in_array($query_name, Array('mode', 'current_result_page', 'results_per_page', 'result_'.$this->id.'_result_page'))) {
1749  if (is_array($query_value)) {
1750  foreach ($query_value as $value_index => $value_contents) {
1751  $queries .= '&'.urlencode($query_name).'['.urlencode($value_index).']='.urlencode($value_contents);
1752  }
1753  } else {
1754  $queries .= '&'.urlencode($query_name).'='.urlencode($query_value);
1755  }
1756  }
1757  }
1758 
1759  // if we are to use the listing engine stuff then we need to change
1760  // to a getAssetList() style format
1761 
1762  if (!empty($results)) {
1763  $sort_info = $this->getSortInfo();
1764  $asset_info = $this->sortAssetList($results, $sort_info);
1765  }
1766 
1767  $this->filterAssetList($asset_info);
1768 
1769  if (!is_array($asset_info)) $asset_info = Array();
1770 
1771  // Important!!! Missing these values in the overridden Listing Engine type of asset
1772  // will generate numerous notice errors when they try to group the result by asset type
1773  $this->_tmp['assets_info'] = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(array_keys($asset_info));
1774  $this->_tmp['asset_urls'] = $GLOBALS['SQ_SYSTEM']->am->getAssetURL(array_keys($asset_info));
1775 
1776  if ($results_per_page != 0) {
1777  $total_pages = ceil(count($asset_info) / $results_per_page);
1778  } else {
1779  $total_pages = 1;
1780  }
1781 
1782  // get any extra keyword replacements from asset_listing
1783  $parent_replaces = $this->getContentsKeywordReplacements($keywords);
1784  foreach ($keywords as $keyword) {
1785  $full_keyword = $keyword;
1786  $replacement = "%$full_keyword%";
1787  $keyword = parse_keyword($keyword, $modifiers);
1788  $apply_modifiers = TRUE;
1789 
1790  switch ($keyword) {
1791  case 'result_list':
1792  // the groupAssetsRecursively() method must be called before the getChunk() method because the getChunk()
1793  // method expect the data structure returned by the groupAssetsRecursively() method. Otherwise, there will
1794  // be PHP errors in _groupChunk() function ($todo is not an array like it is expected) if asset grouping
1795  // is used to format the search results
1796  $result_list = $asset_info;
1797 
1798  if ($this->attr('group_by') == 'grouped') {
1799  $this->groupAssetsRecursively($this->attr('asset_grouping'), $result_list, $result_list);
1800  $this->sortGroups($this->attr('asset_grouping'), $result_list, $result_list);
1801  }
1802 
1803  $result_list = $this->getChunk($result_list, $parent_replaces, $keywords, $current_result_page, $results_per_page);
1804 
1805  // For the 'select all' code
1806  $relations = $this->_analyseCheckAllRelations($result_list);
1807 
1808  // print the asset list from the listing engine
1809  ob_start();
1810  $this->printAssetList($result_list);
1811  $replacement = ob_get_contents();
1812  ob_end_clean();
1813  break;
1814 
1815  case 'initial_result_count' :
1816  $initial_results = $this->_tmp['initial_results'];
1817  $replacement = count($initial_results);
1818  break;
1819 
1820  case 'result_count':
1821  $replacement = $this->_arrayCountRecursive($asset_info);
1822  break;
1823 
1824  case 'current_result_page':
1825  $replacement = min($current_result_page, $total_pages);
1826  break;
1827 
1828  case 'current_result_page_start':
1829  $start_record = ($current_result_page==1) ? $current_result_page : ((($current_result_page-1)*$results_per_page)+1);
1830  $replacement = $start_record;
1831  break;
1832 
1833  case 'current_result_page_end':
1834  $end_record = (($current_result_page) * $results_per_page);
1835  if ($end_record > $this->_arrayCountRecursive($asset_info)) {
1836  $end_record = $this->_arrayCountRecursive($asset_info);
1837  }//end if
1838  $replacement = $end_record;
1839 
1840  break;
1841 
1842  case 'total_result_pages':
1843  $replacement = $total_pages;
1844  break;
1845 
1846  case 'result_page_index':
1847  $replacement = '';
1848  $current_page_format = $this->attr('current_page_format');
1849  $page_link_format = $this->attr('page_link_format');
1850 
1851  for ($i = 1; $i <= $total_pages; $i++) {
1852  if ($i == $current_result_page) {
1853  $replacement .= str_replace('%page_number%', $i, $current_page_format);
1854  } else {
1855  $href = ($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.$i.'&results_per_page='.$results_per_page.$queries);
1856  $replacement .= str_replace(Array('%page_number%', '%page_link%'), Array($i, $href), $page_link_format);
1857  }
1858  }
1859  break;
1860 
1861  case 'previous_result_page_link':
1862  if ($current_result_page <= 1) {
1863  $replacement = $this->attr('hide_no_href_links') ? '' : $this->attr('prev_page_text');
1864  break;
1865  }
1866  $replacement = '<a href="'.($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page - 1).'&results_per_page='.$results_per_page.$queries).'">'.$this->attr('prev_page_text').'</a>';
1867  break;
1868 
1869  case 'next_result_page_link':
1870  if ($current_result_page >= $total_pages) {
1871  $replacement = $this->attr('hide_no_href_links') ? '' : $this->attr('next_page_text');
1872  break;
1873  }
1874  $replacement = '<a href="'.($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page + 1).'&results_per_page='.$results_per_page.$queries).'">'.$this->attr('next_page_text').'</a>';
1875  break;
1876 
1877  case 'previous_result_page_href':
1878  if ($current_result_page <= 1) {
1879  $replacement = '';
1880  break;
1881  }
1882  $replacement = ($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page - 1).'&results_per_page='.$results_per_page.$queries);
1883  break;
1884 
1885  case 'next_result_page_href':
1886  if ($current_result_page >= $total_pages) {
1887  $replacement = '';
1888  break;
1889  }
1890  $replacement = ($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page + 1).'&results_per_page='.$results_per_page.$queries);
1891  break;
1892 
1893  case 'initial_layout':
1894  $replacement = $this->getBodycopyContents('initial', $this->getInitialBodyReplacements());
1895  break;
1896 
1897  default:
1898  $fields = $this->attr('fields');
1899 
1900  if (preg_match('/(.+)_query_logic$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1901 
1902  $current_logic = array_get_index($_REQUEST, $keyword, 'AND');
1903  $options = Array('AND' => translate('sch_page_format_logic_and'), 'OR' => translate('sch_page_format_logic_or'));
1904  ob_start();
1905  $this->registerFormField($keyword);
1906  combo_box($keyword, $options, FALSE, $current_logic);
1907  $replacement = ob_get_contents();
1908  ob_end_clean();
1909 
1910  } else if (preg_match('/(.+)_query_terms_(.+)$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1911 
1912  $replacement = $this->getSearchedFieldReplacement($matches[1], $matches[2]);
1913 
1914  } else if (preg_match('/(.+)_query_terms$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1915 
1916  $replacement = $this->getSearchedFieldReplacement($matches[1]);
1917 
1918  } else if (preg_match('/(.+)_query_synonym_search_message$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1919 
1920  if (!empty($this->_tmp['auto_synonym_search_used'])) {
1921  $replacement = $this->attr('auto_synonym_string');
1922  }
1923 
1924  } else if (preg_match('/(.+)_query_suggestions(_message)?$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1925 
1926  // spell-checking suggestions
1927  $field_name = $matches[1];
1928  if (isset($this->_tmp['search_suggestions'][$field_name])) {
1929  $queries_temp = str_replace('queries_'.$field_name.'_query='.urlencode($this->getSearchedFieldReplacement($field_name, '', FALSE)), 'queries_'.$field_name.'_query='.urlencode($this->_tmp['search_suggestions'][$field_name]), $queries);
1930  $spell_check_string = '<a href="'.($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?mode='.$mode.'&current_result_page='.$current_result_page.'&results_per_page='.$results_per_page.$queries_temp.'">'.htmlspecialchars($this->_tmp['search_suggestions'][$field_name]).'</a>';
1931  } else {
1932  $spell_check_string = '';
1933  }
1934 
1935  if (!empty($spell_check_string)) {
1936  if (substr($keyword, -8) == '_message') {
1937  $message = $this->attr('spell_check_string');
1938  $replacement = str_replace('%suggestions%', $spell_check_string, $message);
1939  } else {
1940  $replacement = $spell_check_string;
1941  }
1942  }
1943 
1944  } else if (preg_match('/(.+)_query_synonyms(_message)?$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1945 
1946  // synonym searching
1947  $field_name = $matches[1];
1948  $synonym_string = Array();
1949  if (isset($this->_tmp['search_synonyms'])) {
1950  foreach (array_get_index($this->_tmp['search_synonyms'], $field_name, Array()) as $word => $synonyms) {
1951  foreach ($synonyms as $synonym) {
1952  $queries_temp = str_replace('queries_'.$field_name.'_query='.urlencode($this->getSearchedFieldReplacement($field_name, '', FALSE)), 'queries_'.$field_name.'_query='.urlencode($synonym), $queries);
1953  $synonym_string[] = '<a href="'.($this->attr('submit_to_page_url') ? $this->getURL() : current_url()).'?mode='.$mode.'&current_result_page='.$current_result_page.'&results_per_page='.$results_per_page.$queries_temp.'">'.htmlspecialchars($synonym).'</a>';
1954  }
1955  }
1956  }
1957  $synonym_string = implode(', ', $synonym_string);
1958 
1959  if (!empty($synonym_string)) {
1960  if (substr($keyword, -8) == '_message') {
1961  $message = $this->attr('synonym_string');
1962  $replacement = str_replace('%suggestions%', $synonym_string, $message);
1963  } else {
1964  $replacement = $synonym_string;
1965  }
1966  }
1967 
1968  } else if (preg_match('/(.+)_query_(.+)$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1969 
1970  $replacement = $this->getFieldReplacement($matches[1], $matches[2]);
1971 
1972  } else if (preg_match('/(.+)_query$/', $keyword, $matches) && array_key_exists($matches[1], $fields)) {
1973 
1974  $replacement = $this->getFieldReplacement($matches[1]);
1975 
1976  } else if (substr($keyword, -7) == '_linked') {
1977 
1978  if ($keyword == 'category_list_linked') {
1979  // printing the list of seach categories
1980  $categories = $this->attr('categories');
1981  if (!empty($categories)) {
1982  $query_string_vars = Array(
1983  'mode' => $mode,
1984  'current_result_page' => 1,
1985  );
1986  ob_start();
1987  ?>
1988  <div id="search_category_list">
1989  <?php
1990  foreach ($categories as $cat_name => $cat_data) {
1991  ?>
1992  <ul>
1993  <?php
1994  $current_option = array_get_index($_GET, 'category_'.$cat_name, '');
1995  $cat_data['options'] = Array('' => Array('full_name' => $cat_data['unselected_text'])) + $cat_data['options'];
1996  foreach ($cat_data['options'] as $key => $data) {
1997  $query_string_vars['category_'.$cat_name] = $key;
1998  $url = htmlspecialchars(replace_query_string_vars($query_string_vars));
1999  ?>
2000  <li<?php echo ($current_option == $key) ? ' id="current"' : ''; ?>>
2001  <a href="<?php echo $url; ?>">
2002  <?php echo $data['full_name']; ?>
2003  </a>
2004  </li>
2005  <?php
2006  }
2007  unset($query_string_vars['category_'.$cat_name]);
2008  ?>
2009  </ul>
2010  <?php
2011  }
2012  ?>
2013  </div>
2014  <?php
2015  $replacement = ob_get_contents();
2016  ob_end_clean();
2017  } else {
2018  $replacement = '';
2019  }
2020 
2021  } else if (substr($keyword, -13) == '_query_linked') {
2022 
2023  $options = Array();
2024  $not_selected_text = '';
2025 
2026  $query_var = substr($keyword, 0, (strlen($keyword) - 13));
2027  $fields = $this->attr('fields');
2028 
2029  if ($fields[$query_var]['type'] == 'metadata') {
2030 
2031  $assetid = $fields[$query_var]['params']['assetid'];
2032  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
2033  $params = $asset->vars;
2034  // metadata dropdown selection
2035  if (isset($params['select_options'])) {
2036  $options = $params['select_options']['value'];
2037  }
2038 
2039  } else if ($fields[$query_var]['type'] == 'asset_attrib') {
2040 
2041  $search_styles = $this->attr('search_styles');
2042  $not_selected_text = '';
2043 
2044  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($fields[$query_var]['params']['attrid']);
2045 
2046  if ($attribute->type() == 'selection') {
2047  if (empty($attribute->_params['multiple'])) {
2048  $options = $attribute->_params['options'];
2049  }
2050  $not_selected_text = array_get_index($search_styles[$attribute->id], 'empty_text');
2051  } else if ($attribute->type() == 'boolean') {
2052  if (isset($search_styles[$attribute->id])) {
2053  $options = Array(
2054  '0' => $search_styles[$attribute->id]['false_text'],
2055  '1' => $search_styles[$attribute->id]['true_text'],
2056  );
2057  } else {
2058  $options = Array('0' => translate('false'), '1' => translate('true'));
2059  }
2060  $not_selected_text = array_get_index($search_styles[$attribute->id], 'empty_text');
2061  }
2062  }//end if an attribute
2063 
2064  if (!empty($options)) {
2065  $query_key = 'queries_'.$query_var.'_query';
2066  $current_value = (string) array_get_index($_SESSION['SQ_LAST_SEARCH'][$this->id], $query_var, '');
2067 
2068  $base_url = $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
2069  $base_url = preg_replace('|([&?])mode=([^&]+)|', '\\1mode='.$mode, $base_url);
2070  $base_url = preg_replace('|&'.$query_key.'=([^&]+)?|', '', $base_url);
2071  $base_url = preg_replace('|&current_result_page=([^&]+)?|', '&current_result_page=1', $base_url);
2072  $base_url .= '&'.$query_key.'=';
2073 
2074  if ($not_selected_text == '') {
2075  $not_selected_text = translate('no_selection');
2076  }
2077  ob_start();
2078  ?>
2079  <div id="search_<?php echo $query_var; ?>_query_list">
2080  <ul>
2081  <li<?php echo ($current_value == '') ? ' id="current"' : ''; ?>>
2082  <a href="<?php echo $base_url; ?>"><?php echo $not_selected_text; ?></a>
2083  </li>
2084  <?php
2085  foreach ($options as $key => $value) {
2086  $key = (string) $key;
2087  ?>
2088  <li<?php echo ($current_value == $key) ? ' id="current"' : ''; ?>>
2089  <a href="<?php echo $base_url.$key; ?>"><?php echo $value; ?></a>
2090  </li>
2091  <?php
2092  }
2093  ?>
2094  </ul>
2095  </div>
2096  <?php
2097  $replacement = ob_get_contents();
2098  ob_end_clean();
2099  }//end if
2100  }//end if category links
2101 
2102  } else {
2103 
2104  // use the parent's replacement if it exists, otherwise revert to the default
2105  if (isset($parent_replaces[$keyword])) {
2106  $replacement = $parent_replaces[$keyword];
2107  } else {
2108  // Avoid messing with globals and other keywords in the fallback to Asset::getKeywordReplacement() by passing the full keyword.
2109  $replacement = $this->getGeneralReplacement($full_keyword);
2110  $apply_modifiers = FALSE;
2111  }
2112 
2113  }
2114  break;
2115  }//end switch
2116 
2117  if ($apply_modifiers && $replacement != "%$full_keyword%"){
2118  apply_keyword_modifiers($replacement, $modifiers, Array('assetid' => $this->id));
2119  }
2120 
2121  $replaces[$full_keyword] = $replacement;
2122 
2123  }//end foreach
2124 
2125  return $replaces;
2126 
2127  }//end getResultsBodyReplacements()
2128 
2129 
2138  function getResultElementBodyReplacements($assetid)
2139  {
2140  $bodycopy =& $this->getBodycopy('result_element');
2141  $keywords = $bodycopy->getKeywords();
2142 
2143  $am =& $GLOBALS['SQ_SYSTEM']->am;
2144  $asset = $am->getAsset($assetid);
2145 
2146  $mm = $GLOBALS['SQ_SYSTEM']->getMetadataManager();
2147  $replaces = $mm->generateKeywordReplacements($asset, $keywords, FALSE);
2148 
2149  $metadata_keywords = Array();
2150  foreach ($keywords as $key) {
2151  if (substr($key, 0, 15) == 'asset_metadata_') {
2152  $metadata_keywords[$key] = substr($key, 15);
2153  }
2154  }
2155  if (!empty($metadata_keywords)) {
2156  $metadata_values = $mm->getMetadataFieldValues($assetid, array_values($metadata_keywords));
2157  foreach ($metadata_keywords as $key => $field) {
2158  if (isset($metadata_values[$field])) {
2159  $replaces[$key] = $metadata_values[$field];
2160  }
2161  }
2162  }
2163 
2164  $asset_keywords = $asset->getAvailableKeywords();
2165  foreach ($asset_keywords as $key => $description) {
2166  if (in_array($key, $keywords)) {
2167  $replaces[$key] = $asset->getKeywordReplacement($key);
2168  }
2169  }
2170 
2171  foreach ($keywords as $keyword) {
2172 
2173  $replacement =& $replaces[$keyword];
2174  switch ($keyword) {
2175  case 'asset_id':
2176  $replacement = $assetid;
2177  break;
2178 
2179  case 'asset_name_linked':
2180  $replacement = '<a href="'.$asset->getUrl().'">'.$asset->name.'</a>';
2181  break;
2182 
2183  case 'asset_short_name_linked':
2184  $replacement = '<a href="'.$asset->getUrl().'">'.$asset->short_name.'</a>';
2185  break;
2186 
2187  case 'asset_lineage':
2188  case 'asset_lineage_linked':
2189  $replacement = '';
2190  $first = TRUE;
2191  $found_root = FALSE;
2192  $nurl = $asset->getUrl();
2193  $unrl = strip_url($nurl);
2194  $nurl = stristr($nurl,'/');
2195  $nurl = substr($nurl,2);
2196  $parent_asset_ids = $am->getLineageFromURL(NULL,$nurl);
2197  // searching for the root asset
2198  $root_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, '', FALSE, 'root');
2199  $root_assetid = empty($root_link) ? 0 : $root_link['minorid'];
2200  foreach ($parent_asset_ids as $parent_asset_id) {
2201  if ($parent_asset_id == $root_assetid) {
2202  $found_root = TRUE;
2203  }
2204  if (!$found_root) continue;
2205  if (!$first) {
2206  $replacement .= $this->attr('lineage_seperator');
2207  }
2208  $first = FALSE;
2209  $ancestor_asset = $am->getAsset($parent_asset_id);
2210  if ($keyword == 'asset_lineage_linked') {
2211  $replacement .= '<a href="'.$ancestor_asset->getUrl().'">';
2212  }
2213  $replacement .= $ancestor_asset->short_name;
2214  if ($keyword == 'asset_lineage_linked') {
2215  $replacement .= '</a>';
2216  }
2217  $am->forgetAsset($ancestor_asset);
2218  }
2219  break;
2220  }//end switch
2221  }//end foreach
2222 
2223  return $replaces;
2224 
2225  }//end getResultElementBodyReplacements()
2226 
2227 
2239  function getExtendedAssetKeywordReplacements()
2240  {
2241  // We are only replacing them with their own replacement so they can be
2242  // cached out like this, then score and result number can be added later
2243  return Array(
2244  'result_number' => '%result_number%',
2245  'score' => '%score%',
2246  );
2247 
2248  }//end getExtendedAssetKeywordReplacements()
2249 
2250 
2262  function _addDateRangeRestriction (&$fields, &$queries)
2263  {
2264  $restrict_date_field = $this->attr('restrict_date_field');
2265  $to = $this->getAttribute('restrict_date_range_to');
2266  $from = $this->getAttribute('restrict_date_range_from');
2267 
2268  // return if restriction is not set
2269  if(empty($restrict_date_field) || ( $to->value === '---------- --:--:--' && $from->value === '---------- --:--:--')) {
2270  return;
2271  }
2272  $from = $from->getISO8601();
2273  $from_date = iso8601_date_component($from);
2274  if (!empty($from_date)) {
2275  // invalid FROM date?
2276  if (!preg_match_all('|^\d{4}-\d{2}-\d{2}$|', $from_date, $matches)) {
2277  trigger_localised_error('CMS0053', E_USER_WARNING, $from_date);
2278  return;
2279  }
2280 
2281  $from_time = iso8601_time_component($from);
2282  if (empty($from_time)) $from_time = '00:00:00';
2283 
2284  // invalid FROM time?
2285  if (!preg_match_all('|^\d{2}:\d{2}:\d{2}$|', $from_time, $matches)) {
2286  trigger_localised_error('CMS0054', E_USER_WARNING, $from_time);
2287  return;
2288  }
2289  $restrict_date_range_from = $from_date.' '.$from_time;
2290  }
2291 
2292  $to = $to->getISO8601();
2293  $to_date = iso8601_date_component($to);
2294  if (!empty($to_date)) {
2295  // invalid TO date?
2296  if (!preg_match_all('|^\d{4}-\d{2}-\d{2}$|', $to_date, $matches)) {
2297  trigger_localised_error('CMS0055', E_USER_WARNING, $to_date);
2298  return;
2299  }
2300 
2301  $to_time = iso8601_time_component($to);
2302  if (empty($to_time)) $to_time = '23:59:59';
2303 
2304  // invalid TO time?
2305  if (!preg_match_all('|^\d{2}:\d{2}:\d{2}$|', $to_time, $matches)) {
2306  trigger_localised_error('CMS0056', E_USER_WARNING, $to_time);
2307  return;
2308  }
2309  $restrict_date_range_to = $to_date.' '.$to_time;
2310  }
2311 
2312  $content = Array();
2313  $content['name'] = 'matrix_search_page_date_range';
2314  $content['word_logic'] = 'AND';
2315  $content['specific_field_logic'] = 'AND';
2316  $content['data_sources'] = Array (
2317  0 => Array (
2318  'type' => 'standard',
2319  'params' => Array ('field' => $restrict_date_field)
2320  )
2321  );
2322  $fields['matrix_search_page_date_range'] = $content;
2323  $queries['matrix_search_page_date_range'] = Array (
2324  'from' => isset($restrict_date_range_from) ? $restrict_date_range_from : '---------- --:--:--',
2325  'to' => isset($restrict_date_range_to) ? $restrict_date_range_to : '---------- --:--:--'
2326  );
2327  }//end _addDateRangeRestriction()
2328 
2329 
2330 
2343  function processSearch($search=Array())
2344  {
2345  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
2346 
2347  $fields = $this->attr('fields');
2348  $queries = $this->_getSearchedQueries();
2349 
2350  // Add date range restriction as a search field and query.
2351  $this->_addDateRangeRestriction($fields, $queries);
2352 
2353  // If the search params were passed, get them and use them, if the search queries are empty
2354  if (!empty($search) || count($search)>0) {
2355  foreach ($search as $search_key => $search_value) {
2356  if (!isset($_REQUEST['queries_'.$search_key.'_query_posted'])) {
2357  if (!isset($queries[$search_key]) || empty($queries[$search_key])) {
2358  $queries[$search_key] = $search_value;
2359  }//end if
2360  }//end if
2361  }//end foreach
2362  }//end if
2363 
2364  // check if we are allowing the keywords to be replaced in user input
2365  if($this->attr('disable_keyword_replacements')) {
2366  $queries = $this->_sanitizeQueries($queries);
2367  }
2368 
2369  // save the search terms into the session so that we can use them for
2370  // search within search results
2371  $_SESSION['SQ_LAST_SEARCH'][$this->id] = $queries;
2372 
2373  // get the basic search settings based on the current category (if any)
2374  $search_info = $this->populateBaseSearchInfo();
2375  if (empty($search_info['fields'])) {
2376  $search_info['fields'] = Array();
2377  }
2378 
2379  $query_fields_exist = FALSE;
2380 
2381  foreach ($queries as $field_name => $value) {
2382 
2383  if (empty($value)) continue;
2384 
2385  $empty_numeric = Array(
2386  'upper' => NULL,
2387  'lower' => NULL,
2388  );
2389  if ($value == $empty_numeric) continue;
2390 
2391  $empty_dates = Array(
2392  'from' => '---------- --:--:--',
2393  'to' => '---------- --:--:--',
2394  );
2395  if ($value == $empty_dates) continue;
2396 
2397  if (count($fields[$field_name]['data_sources']) == 0) {
2398  trigger_localised_error('SCH0028', E_USER_NOTICE, $field_name);
2399  continue;
2400  }
2401 
2402  if (!$this->_hasMixedFieldTypes($fields[$field_name]) && $fields[$field_name]['data_sources'][0]['type'] == 'asset_attrib') {
2403  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($fields[$field_name]['data_sources'][0]['params']['attrid']);
2404  if (!is_null($attribute) && $attribute->type() == 'boolean') {
2405  // we need to convert the value into a word representation,
2406  // since indexing service will not operate just 0 or 1
2407  // do not localise this!!
2408  if ($value == '0') {
2409  $value = 'false';
2410  } else if ($value == '1') {
2411  $value = 'true';
2412  }
2413  }//end if
2414  }//end if
2415  $search_info['fields'][$field_name] = $fields[$field_name];
2416  $search_info['fields'][$field_name]['words'] = $value;
2417  $search_info['fields'][$field_name]['exclude_field'] = array_get_index($fields[$field_name], 'exclude_field', FALSE);
2418 
2419  // If there is aleast one "regular" search field, we have the query fields
2420  if (!$search_info['fields'][$field_name]['exclude_field']) {
2421  $query_fields_exist = TRUE;
2422  }
2423 
2424  $submitted_word_logic = strtoupper(array_get_index($_REQUEST, $field_name.'_query_logic', ''));
2425  if (in_array($submitted_word_logic, Array('AND', 'OR'))) {
2426  $search_info['fields'][$field_name]['word_logic'] = $submitted_word_logic;
2427  }
2428 
2429  }//end foreach fields
2430 
2431  // spell-check suggestions
2432  if (!empty($search_info['fields'])) {
2433  foreach ($search_info['fields'] as $field_name => $field_content) {
2434  $words = $field_content['words'];
2435  if (!is_array($words)) $words = explode(' ', $words);
2436  if ($sm->spellCheckAvailable()) {
2437  // suggestion 'string' - this will be imploded later with spaces
2438  $suggestion_string = Array();
2439  $needs_suggestions = FALSE;
2440 
2441  // loop over each word
2442  foreach ($words as $word) {
2443 
2444  // figure out quote positioning
2445  preg_match_all('/"/', $word, $raw_positions, PREG_OFFSET_CAPTURE);
2446  $quote_positions = Array();
2447  if (!empty($raw_positions)) {
2448  foreach ($raw_positions[0] as $position) {
2449  $quote_positions[] = $position[1];
2450  }
2451  }
2452 
2453  $suggestions = $sm->spellCheckWord($word);
2454  if (!empty($suggestions)) {
2455  $needs_suggestions = TRUE;
2456  $suggestion = $suggestions[0];
2457 
2458  foreach ($quote_positions as $position) {
2459  // we can easily re-add quotes to the beginning and
2460  // end of a word, but in the middle is a bit tricky
2461  if ($position == 0) {
2462  $suggestion = '"'.$suggestion;
2463  } else if ($position == strlen($word) - 1) {
2464  $suggestion = $suggestion.'"';
2465  }
2466  }
2467 
2468  $suggestion_string[] = $suggestion;
2469  } else {
2470  $suggestion_string[] = $word;
2471  }
2472  }
2473 
2474  if ($needs_suggestions) {
2475  $this->_tmp['search_suggestions'][$field_name] = implode(' ', $suggestion_string);
2476  }
2477  }//end if spell check available
2478 
2479  // thesaurus synonym searching
2480  $t_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, 'asset', FALSE, 'thesaurus');
2481 
2482  $synonyms =& $this->_tmp['search_synonyms'];
2483 
2484  if (!empty($t_link)) {
2485  $thesaurus = $GLOBALS['SQ_SYSTEM']->am->getAsset($t_link['minorid']);
2486  $synonyms[$field_name] = Array();
2487 
2488  // loop over each word, find synonyms
2489  foreach ($words as $word) {
2490  if (!isset($synonyms[$field_name][$word])) {
2491  $synonyms[$field_name][$word] = $thesaurus->getSynonymsForTerm($word);
2492  }
2493  }
2494  }//end thesaurus exists
2495  }//end foreach
2496  }//end if
2497 
2498  // Metadata Hierarchy
2499  // requires us to go back up and down the tree we have to add the extra looking here
2500  if (isset($search_info['fields'])) {
2501  foreach ($search_info['fields'] as $fieldname => $field) {
2502  foreach ($field['data_sources'] as $data_src) {
2503  if (isset($data_src['type']) && $data_src['type'] == 'metadata') {
2504  if (isset($data_src['params']['assetid'])) {
2505  $m_field_id = $data_src['params']['assetid'];
2506  }
2507  if ($m_field_id > 0) {
2508  $m_field = $GLOBALS['SQ_SYSTEM']->am->getAsset($m_field_id);
2509  if (!is_null($m_field)) {
2510  if ($m_field->type() == 'metadata_field_hierarchy') {
2511  $options = $m_field->attr('hierarchy_options');
2512  $depth = $m_field->attr('hier_depth');
2513  $edit_fns = $m_field->getEditFns();
2514  if (is_array($search_info['fields'][$fieldname]['words'])) {
2515  // If multiple entries submitted, they arrive as an array, so convert to string
2516  $word_list = implode(' ', $search_info['fields'][$fieldname]['words']);
2517  $search_info['fields'][$fieldname]['words'] = $word_list;
2518  }
2519  $search_info['fields'][$fieldname]['words'] = $edit_fns->getHierarchyTree($search_info['fields'][$fieldname]['words'], $options, ' ');
2520  $search_info['fields'][$fieldname]['word_logic'] = 'OR';
2521  }//end if
2522  }//end if
2523  }//end if
2524  }//end if
2525  }//end foreach()
2526 
2527  // Seperate "exclude" fields from regular "search" fields
2528  if ($field['exclude_field']) {
2529  $search_info['exclude'][$fieldname] = $search_info['fields'][$fieldname];
2530  unset($search_info['fields'][$fieldname]);
2531  }//end if
2532 
2533  }//end foreach()
2534  }//end if
2535 
2536  if ($query_fields_exist) {
2537 
2538  // If date range restriction is the only query field set, it's actually an empty search.
2539  // Return empty array if empty search is not allowed.
2540  if(!$this->attr('allow_empty_search') && count($search_info['fields']) == 1 && isset($search_info['fields']['matrix_search_page_date_range'])){
2541  return Array();
2542  }
2543 
2544  $auto_ss_field = $this->attr('auto_synonym_search_field');
2545  $search_results = $sm->processSearch($search_info);
2546 
2547  if (($this->attr('enable_multi_word_synonym_lookups')) && (!empty($auto_ss_field))) {
2548  $search_results = $this->getMultiWordSynonymSearchResults($search_results, $search_info, $auto_ss_field, $thesaurus);
2549  }
2550 
2551  // If there are no results, check to see whether there is an auto
2552  // synonym search set up, and if so, use that
2553  if (empty($search_results)) {
2554  if (!empty($auto_ss_field) && isset($search_info['fields'][$auto_ss_field])) {
2555  // Search with a copy of the original search info, because
2556  // we don't want to interfere with the original search
2557  $syn_search_info = $search_info;
2558  $this->_tmp['auto_synonym_search_used'] = TRUE;
2559 
2560  $search_field = $search_info['fields'][$auto_ss_field];
2561  $words = $search_field['words'];
2562  if (!is_array($words)) $words = explode(' ', $words);
2563 
2564  // automatically search by synonyms
2565  $synonym_words = Array();
2566 
2567  // Note that even if the original query had word logic of
2568  // AND, we will search for all synonyms found using OR.
2569  // The next logical step would be to provide some way where
2570  // each word's synonyms are ANDed together, but this would
2571  // require a large overhaul to get this to work in
2572  // PostgreSQL
2573  foreach ($words as $word) {
2574  $synonym_words += $synonyms[$auto_ss_field][$word];
2575  }
2576 
2577  if (!empty($synonym_words)) {
2578  $syn_search_info['fields'][$auto_ss_field]['words'] = implode(' ', $synonym_words);
2579  $search_results = $sm->processSearch($syn_search_info);
2580  }
2581  }
2582 
2583  }//end if
2584 
2585  return $search_results;
2586 
2587  } else if ($this->attr('allow_empty_search')) {
2588  return $sm->processBasicSearch($search_info);
2589  } else {
2590  return Array();
2591  }
2592 
2593  }//end processSearch()
2594 
2595 
2596  /*
2597  * Returns all combinations of words from a string, of length 2 to "string length" words.
2598  * "Combinations" as in the contiguous mathematical sense.
2599  *
2600  * For example:
2601  * supplied words = 'high', 'climbing', 'walls'
2602  * combinations = 'high climbing', 'climbing walls', 'high climbing walls'
2603  *
2604  * @param array $words The search words to iterate (in order)
2605  *
2606  * @return array
2607  * @access private
2608  */
2609  private function _getWordCombinations(Array $words)
2610  {
2611  $word_combinations = Array();
2612 
2613  // Only return combinations if we have at least three words, otherwise return a string of what was supplied
2614  $num_words = count($words);
2615  if ($num_words < 3) {
2616  return Array(implode(' ', $words));
2617  }
2618 
2619  // Chunk is back. Grab "string length" down to two-word combinations at each step
2620  // This is better illustrated with coloured pencils
2621  for ($chunk_size=$num_words; $chunk_size >= 2; $chunk_size--)
2622  {
2623  for ($start_index=0; $start_index <= $num_words - $chunk_size; $start_index++)
2624  {
2625  $combination = '';
2626  for ($n=0; $n < $chunk_size; $n++)
2627  {
2628  $word_index = $start_index + $n;
2629  $combination .= $words[$word_index].' ';
2630  }
2631 
2632  // Add combination to our list and trim trailing space
2633  $word_combinations[] = rtrim($combination);
2634  }
2635  }
2636 
2637  return $word_combinations;
2638 
2639  }//end _getWordCombinations()
2640 
2641 
2652  {
2653  if (isset($this->_tmp['searched_queries'])) {
2654  return $this->_tmp['searched_queries'];
2655  }
2656 
2657  $fields = $this->attr('fields');
2658  $mode = array_get_index($_REQUEST, 'mode', 'results');
2659  if ($mode == '') $mode = 'results';
2660  $suffix = ($mode == 'results') ? '_query' : '_query_sis';
2661  $queries = Array();
2662  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
2663  foreach ($fields as $field_name => $field_details) {
2664 
2665  $queries[$field_name] = '';
2666  $query_var = 'queries_'.$field_name.$suffix;
2667  // Bug #3002
2668  // If there is a period (.) in the field name, REQUEST var changes it to a underscore (_), so when
2669  // setting the query_var string, we need to look for underscores and not periods in the REQUEST var
2670  // It should be noted that query_var is used elsewhere too.
2671  $clean_query_var = str_replace('.', '_', $query_var);
2672 
2673  if (!empty($field_details['data_sources']) && !$this->_hasMixedFieldTypes($field_details)) {
2674  $data_source = $field_details['data_sources'][0];
2675  switch ($data_source['type']) {
2676  case 'include_all' :
2677  $queries[$field_name] = array_get_index($_REQUEST, $clean_query_var, '');
2678  break;
2679 
2680  case 'standard' :
2681  if (isset($sm->standard_date_fields[$data_source['params']['field']])) {
2682  $queries[$field_name] = $this->_processDateRange($query_var);
2683  } else if (isset($sm->standard_text_fields[$data_source['params']['field']])) {
2684  $queries[$field_name] = array_get_index($_REQUEST, $clean_query_var, '');
2685  }
2686  break;
2687 
2688  case 'asset_attrib' :
2689  $attribute = $GLOBALS['SQ_SYSTEM']->am->getAttribute($data_source['params']['attrid']);
2690  if (!is_null($attribute)) {
2691  if ($attribute->type() == 'datetime') {
2692  $queries[$field_name] = $this->_processDateRange($query_var);
2693  } else if (($attribute->type() == 'int') || ($attribute->type() == 'float')) {
2694  $queries[$field_name] = Array();
2695 
2696  switch (array_get_index($data_source['params'], 'numeric_search', 'exact')) {
2697  case 'exact':
2698  $query = array_get_index($_REQUEST, $clean_query_var, NULL);
2699  if (!is_null($query)) {
2700  $queries[$field_name]['lower'] = $query;
2701  $queries[$field_name]['upper'] = $queries[$field_name]['lower'];
2702  }
2703  break;
2704 
2705  case 'range':
2706  $query_lower = array_get_index($_REQUEST, $clean_query_var.'_lower', NULL);
2707  $query_upper = array_get_index($_REQUEST, $clean_query_var.'_upper', NULL);
2708  if (!is_null($query_lower) || !is_null($query_upper)) {
2709  $queries[$field_name]['lower'] = ($query_lower == '') ? NULL : $query_lower;
2710  $queries[$field_name]['upper'] = ($query_upper == '') ? NULL : $query_upper;
2711  }
2712  break;
2713 
2714  case 'custom':
2715  $key = array_get_index($_REQUEST, $clean_query_var, NULL);
2716 
2717  if (!is_null($key)) {
2718  $custom_range = array_get_index($data_source['params']['custom_num_search'], $key, Array());
2719  $queries[$field_name]['lower'] = ($custom_range['min'] == '') ? NULL : $custom_range['min'];
2720  $queries[$field_name]['upper'] = ($custom_range['max'] == '') ? NULL : $custom_range['max'];
2721  }
2722  break;
2723  }
2724  } else {
2725  if ($attribute->type() == 'boolean' || $attribute->type() == 'selection') {
2726  $attribute->_params['allow_empty'] = TRUE;
2727  }
2728  $attribute->process($query_var);
2729  $queries[$field_name] = trim($attribute->value);
2730  if ($attribute->type() == 'selection' && !empty($attribute->_params['multiple'])) {
2731  $queries[$field_name] = array_keys($attribute->getValueArray());
2732  }
2733  }
2734  }//end if
2735  break;
2736 
2737  case 'metadata' :
2738  if (empty($data_source['params']['assetid'])) {
2739  trigger_localised_error('SCH0027', E_USER_NOTICE, $field_name);
2740  $queries[$field_name] = '';
2741  break;
2742  }
2743  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($data_source['params']['assetid']);
2744  if (!is_null($asset)) {
2745  $params = $asset->vars;
2746  switch (get_class_lower($asset)) {
2747  case 'metadata_field_date' :
2748  $queries[$field_name] = $this->_processDateRange($query_var);
2749  break;
2750 
2751  default :
2752  $queries[$field_name] = array_get_index($_REQUEST, $clean_query_var, '');
2753  break;
2754  }
2755  }
2756  break;
2757  }//end switch query type
2758  } else {
2759  $queries[$field_name] = array_get_index($_REQUEST, $clean_query_var, '');
2760  }
2761 
2762  }//end foreach fields
2763 
2764  if ($mode == 'sis') {
2765  $last_search = $_SESSION['SQ_LAST_SEARCH'][$this->id];
2766 
2767  foreach ($queries as $field_name => $value) {
2768 
2769  if (is_scalar($value)) $value = trim($value);
2770  if (empty($value)) continue;
2771  $empty_dates = Array(
2772  'from' => '---------- --:--:--',
2773  'to' => '---------- --:--:--',
2774  );
2775  if ($value == $empty_dates) continue;
2776 
2777  if (!isset($last_search[$field_name]) || $last_search[$field_name] == '') {
2778  $last_search[$field_name] = $value;
2779  } else {
2780  // trim the current value before we append more words to it
2781  if (is_scalar($last_search[$field_name])) {
2782  $last_search[$field_name] = trim($last_search[$field_name]);
2783  }
2784  if (!is_array($value)) {
2785  $last_search[$field_name] .= ' '.$value;
2786  } else if (isset($value['from']) || isset($value['to'])) {
2787  // this is a date field
2788  if (isset($value['from'])) {
2789  $last_search[$field_name]['from'] = $value['from'];
2790  }
2791  if (isset($value['to'])) {
2792  $last_search[$field_name]['to'] = $value['to'];
2793  }
2794  } else {
2795  $last_search[$field_name] = array_merge($value, $last_search[$field_name]);
2796  }
2797  }
2798  }//end foreach
2799 
2800  $queries = $last_search;
2801  }//end if
2802 
2803  // if it seems that nothing is submitted, check if there was a previous query
2804  // and use its details
2805  if (empty($queries) && !empty($this->_tmp['potential_searched_queries'])) {
2806  $queries = $this->_tmp['potential_searched_queries'];
2807  }
2808 
2809  return $queries;
2810 
2811  }//end _getSearchedQueries()
2812 
2813 
2821  {
2822  $prefix = $this->getPrefix();
2823 
2824  // first, see if a category has been supplied
2825  $categories = $this->attr('categories');
2826  $active_cats = Array();
2827  foreach ($categories as $set_name => $cat_data) {
2828  if (!empty($_GET['category_'.$set_name])) {
2829  if (isset($cat_data['options'][$_GET['category_'.$set_name]])) {
2830  $code_name = $_GET['category_'.$set_name];
2831  $active_cats[$set_name.'_'.$code_name] = $cat_data['options'][$code_name];
2832  }
2833  }
2834  }
2835 
2836  $search_roots = Array();
2837  $statuses_customised = FALSE;
2838  $root_logic = 'AND'; // if there are no roots from categories this will get changed below
2839  if (!empty($active_cats)) {
2840  include_once SQ_INCLUDE_PATH.'/general_occasional.inc';
2841  $search_statuses = array_keys(get_status_names());
2842  foreach ($active_cats as $set_option_name => $cat) {
2843  if (isset($cat['statuses'])) {
2844  $statuses_customised = TRUE;
2845  $search_statuses = array_intersect($search_statuses, $cat['statuses']);
2846  }
2847  if (isset($cat['root_assetid'])) {
2848  $link_value = 'root_'.$set_option_name;
2849  $root_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, '', FALSE, $link_value);
2850  $root_id = array_get_index($root_link, 'minorid');
2851  if ($root_id) $search_roots[] = $root_id;
2852  }
2853  }
2854  }
2855 
2856  if (!$statuses_customised) {
2857  // use default status choices
2858  $search_statuses = $this->attr('statuses');
2859  }
2860 
2861  if (empty($search_roots)) {
2862  // use default search roots because no categories chosen or not customised
2863  $search_roots = $this->getRootNodes();
2864  $root_logic = 'OR';
2865  // if no default root nodes were specified, we search everything
2866  if (empty($search_roots)) $search_roots = 0;
2867  }
2868 
2869  $search_info = Array();
2870  $search_info['statuses'] = $search_statuses;
2871  $search_info['roots'] = $search_roots;
2872  $search_info['root_logic'] = $root_logic;
2873  $search_info['field_logic'] = $this->attr('logic');
2874  $search_info['requester'] = $this->id;
2875  $search_info['asset_types'] = $this->attr('types');
2876  $search_info['search_as_public_user'] = $this->attr('search_as_public_user');
2877  $search_info['no_roles_check'] = $this->attr('no_roles_check');
2878  $search_info['no_group_access_check'] = $this->attr('no_group_access_check');
2879 
2880  return $search_info;
2881 
2882  }//end populateBaseSearchInfo()
2883 
2884 
2892  {
2893  $link = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'folder', TRUE, 'major', 'format_folder');
2894  return (!empty($link)) ? $link[0] : Array();
2895 
2896  }//end getFormatFolderLink()
2897 
2898 
2905  function &getFormatFolder()
2906  {
2907  $folder = NULL;
2908 
2909  $link = $this->getFormatFolderLink();
2910  if (!empty($link)) {
2911  $folder = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], $link['minor_type_code']);
2912  }
2913 
2914  return $folder;
2915 
2916  }//end getFormatFolder()
2917 
2918 
2927  function getFormatBodycopyLink($link_value)
2928  {
2929  $format_folder =& $this->getFormatFolder();
2930  if (is_null($format_folder)) return Array();
2931 
2932  $link = $GLOBALS['SQ_SYSTEM']->am->getLinks($format_folder->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'bodycopy', TRUE, 'major', $link_value);
2933  return (!empty($link)) ? $link[0] : Array();
2934 
2935  }//end getFormatBodycopyLink()
2936 
2937 
2949  function &getFormatBodycopy($link_value)
2950  {
2951  $bodycopy = NULL;
2952 
2953  $bodycopy_link = $this->getFormatBodycopyLink($link_value);
2954  if (!empty($bodycopy_link)) {
2955  $bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_link['minorid'], $bodycopy_link['minor_type_code']);
2956  }
2957 
2958  return $bodycopy;
2959 
2960  }//end getFormatBodycopy()
2961 
2962 
2976  function _printAsset($assetid, $list_position, $num_items=0)
2977  {
2978  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
2979  $cache_key = $assetid.'-ctx'.$contextid;
2980 
2981  // the $this->_tmp[] variables are set in getResultsBodyReplacements()
2982  $cm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('cache_manager');
2983  $element_contents = $cm->loadFromCache($this->id, $this->type(), $cache_key);
2984 
2985  if ($element_contents === FALSE) {
2986  // keyword replacements for %result_number% and %score% are now handled
2987  // by the "extended asset" keywords replacements defined in getExtendedAssetKeywordReplacements()
2988 
2989  ob_start();
2990  parent::_printAsset($assetid, $list_position, $num_items);
2991 
2992  $element_contents = ob_get_contents();
2993  ob_end_clean();
2994  $cm->saveToCache($this->id, $this->type(), $cache_key, $element_contents);
2995  }
2996 
2997  // summon the scores at this point. and work with new DAL result format
2998  $score =& $this->_tmp['search_results'];
2999  $score = (isset($score['type_code'])) ? $score['type_code'] : $score;
3000  $weight = (is_array($score[$assetid])) ? $score[$assetid][0]['weight'] : $score[$assetid];
3001 
3002  $element_replacements = Array(
3003  'score' => $weight,
3004  'result_number' => $this->_tmp['start_element'] + $list_position,
3005 
3006  );
3007 
3008  replace_keywords($element_contents, $element_replacements);
3009 
3010  echo $element_contents;
3011 
3012  }//end _printAsset()
3013 
3014 
3025  function getQueryFieldValue($field_name='')
3026  {
3027  $field_value = '';
3028 
3029  if (empty($field_name)) return '';
3030 
3031  $fields = $this->attr('fields');
3032  $field_data = array_get_index($fields, $field_name);
3033  if (empty($field_data)) return '';
3034 
3035  $query_var = 'queries_'.$field_name.'_query';
3036  $field_value = array_get_index($_REQUEST, $query_var,'');
3037 
3038  if (empty($field_value) && isset($_SESSION['SQ_LAST_SEARCH'][$this->id][$field_name])) {
3039  $field_value = $_SESSION['SQ_LAST_SEARCH'][$this->id][$field_name];
3040  }
3041 
3042  return $field_value;
3043 
3044  }//end getQueryFieldValue()
3045 
3046 
3047 //-- KEYWORD DESCRIPTION --//
3048 
3049 
3060  function onRequestKeywords(&$broadcaster, $vars=Array())
3061  {
3062  $vars['keywords'] = isset($vars['keywords']) ? $vars['keywords'] : Array();
3063 
3064  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'bodycopy', TRUE);
3065  $bodycopy_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'bodycopy');
3066 
3067  // if there is a search in search bodycopy add it to the bodycopy list
3068  // it will need some of the initial page keywords
3069  $sis_bodycopy_link = $this->getFormatBodycopyLink('sis_form');
3070  if (!empty($sis_bodycopy_link)) {
3071  $bodycopy_links[] = $sis_bodycopy_link;
3072  }
3073 
3074  // if there is a search in search bodycopy add it to the bodycopy list
3075  // it will need some of the initial page keywords
3076  $search_bodycopy_link = $this->getFormatBodycopyLink('search_form');
3077  if (!empty($search_bodycopy_link)) {
3078  $bodycopy_links[] = $search_bodycopy_link;
3079  }
3080 
3081  $bodycopies = Array();
3082  $type_formats = Array();
3083  $keywords = Array();
3084 
3085  foreach ($bodycopy_links as $link_info) {
3086  if (isset($parents[$link_info['minorid']])) {
3087  $bodycopies[] = $link_info['value'];
3088  }
3089  }
3090 
3091  // ATTENTION!
3092  // this check relies on the fact that ALL single asset formats like type, default or position
3093  // are located in subfolders of this asset, and only its context bodycopies are its direct children
3094  if (empty($bodycopies)) {
3095  parent::onRequestKeywords($broadcaster, $vars);
3096  return;
3097  }
3098 
3099  // work out if forms are customised
3100  $search_bodycopy_link = $this->getFormatBodycopyLink('search_form');
3101  $search_customised = !empty($search_bodycopy_link) && $search_bodycopy_link['link_type'] != SQ_LINK_TYPE_3;
3102  $sis_customised = !empty($sis_bodycopy_link) && $sis_bodycopy_link['link_type'] != SQ_LINK_TYPE_3;
3103 
3104  foreach ($bodycopies as $bodycopy) {
3105  if ($bodycopy == 'initial' || $bodycopy == 'sis_form' || $bodycopy == 'search_form') {
3106  // work out the query field keywords
3107  $fields = $this->attr('fields');
3108  foreach ($fields as $field => $field_data) {
3109  $keywords[$field.'_query'] = translate('sch_page_keyword_search_field', $field);
3110  if ($bodycopy == 'initial') {
3111  $keywords[$field.'_query_logic'] = translate('sch_page_keyword_search_field_logic', $field);
3112  }
3113  }
3114  // work out search category keywords
3115  foreach ($this->attr('categories') as $cat_name => $cat_details) {
3116  $keywords[$cat_name.'_category_chooser'] = 'Dropdown box for category set '.$cat_name;
3117  }
3118  }
3119 
3120  // add in the buttons for the customisation bodycopies
3121  if ($bodycopy == 'search_form') {
3122  $keywords['submit_button'] = translate('cms_listing_keyword_submit_button');
3123  }
3124  if ($bodycopy == 'sis_form') {
3125  $keywords['search_in_search_button'] = translate('sch_page_keyword_sis_button');
3126  }
3127 
3128  if ($bodycopy != 'sis_form' && $bodycopy != 'search_form') {
3129  foreach ($this->keywords[$bodycopy] as $keyword) {
3130  $keywords[$keyword] = ucwords(str_replace('_', ' ', $keyword));
3131  }
3132 
3133  // customised forms
3134  if ($search_customised) {
3135  $keywords += $this->_getCustomisedFormKeywords();
3136  }
3137 
3138  // search in search
3139  if ($sis_customised && $bodycopy == 'results') {
3140  $keywords += $this->_getSearchInSearchKeywords();
3141  }
3142  }
3143  }//end foreach
3144 
3145  $vars['keywords'] = array_merge($vars['keywords'], $keywords);
3146 
3147  }//end onRequestKeywords()
3148 
3149 
3160  {
3161  $keywords = parent::_getAdditionalSingleAssetFormatKeywords();
3162 
3163  $keywords['result_number'] = translate('sch_page_keyword_result_number');
3164  $keywords['score'] = translate('sch_page_keyword_search_score');
3165 
3166  return $keywords;
3167 
3168  }//end _getAdditionalSingleAssetFormatKeywords()
3169 
3170 
3178  {
3179  $keywords = Array();
3180 
3181  $keywords['search_form'] = translate('sch_page_keyword_search_form');
3182 
3183  return $keywords;
3184 
3185  }//end _getCustomisedFormKeywords()
3186 
3187 
3195  {
3196  $keywords = Array();
3197 
3198  $keywords['search_form'] = translate('sch_page_keyword_search_form');
3199  $keywords['search_in_search_form'] = translate('sch_page_keyword_sis_form');
3200  $keywords['search_in_search_button'] = translate('sch_page_keyword_sis_button');
3201 
3202  return $keywords;
3203 
3204  }//end _getSearchInSearchKeywords()
3205 
3206 
3219  public function getMultiWordSynonymSearchResults(Array $original_search_results, Array $original_search_info, $auto_ss_field, Thesaurus $thesaurus)
3220  {
3221  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('search_manager');
3222 
3223  $search_field = $original_search_info['fields'][$auto_ss_field];
3224  $words = $search_field['words'];
3225  if (!is_array($words)) $words = explode(' ', $words);
3226 
3227  // Loop over each group of words (2 words or more) and add synonyms of these multi-word-words to the search string
3228  $syn_search_info = $original_search_info;
3229 
3230  $synonym_words = Array();
3231  $word_combinations = $this->_getWordCombinations($words);
3232 
3233  $search_logic = Array();
3234  $search_string = $syn_search_info['fields'][$auto_ss_field]['words'];
3235 
3236  // If we are just two words, don't forget to check each term as a synonym too (eg; fred flautist -> fred (no match) -> flautist (flute player) = fred flautist flute player)
3237  if (count($words) == 2) {
3238  $word_combinations[] = $words[0];
3239  $word_combinations[] = $words[1];
3240  }
3241 
3242  foreach ($word_combinations as $word_combination) {
3243  $combination_synonyms = $thesaurus->getSynonymsForTerm($word_combination);
3244  $num_synonyms = count($combination_synonyms);
3245  $synonym_words += $combination_synonyms;
3246 
3247  // Keep track of search logic
3248  if ($num_synonyms > 0) {
3249  $search_logic[$word_combination] = $combination_synonyms;
3250 
3251  // Remove word combination from search string
3252  $search_string = str_ireplace($word_combination, '', $search_string);
3253  }
3254  }
3255 
3256  // Only modify the search query if we have matching synonyms
3257  if (!empty($synonym_words)) {
3258  // Append found synonyms to the current search
3259  // For example:
3260  // original search = fred flute player
3261  // found synonym = flautist (for 'flute player')
3262  // new search = fred flute.player flautist
3263 
3264  $syn_search_results = Array();
3265 
3266  // We need to ensure that the matching multi-word terms are separated with AND logic
3267  // First, perform a search for any search terms that are not synonyms or have not been matched with synonyms
3268  $syn_search_info['fields'][$auto_ss_field]['words'] = $search_string;
3269 
3270  // Keep note of the outer logic, as we have to ensure that we eliminate some results that are not common if it is AND
3271  $outer_word_logic = $syn_search_info['fields'][$auto_ss_field]['word_logic'];
3272 
3273  // Perform a search for terms which did not match synonyms (eg; "fred" in "fred flute player")
3274  $initial_search_results = Array();
3275  if (!empty($search_string)) {
3276  $initial_search_results = $sm->processSearch($syn_search_info);
3277  }
3278 
3279  // If we are using AND word logic and can't match the outer terms (eg; "fred") then unfortunately any
3280  // synonym expansion is not going to return any results common to all terms. Time to exit here with our
3281  // original search result as we haven't found anything else of use
3282  if (($outer_word_logic == 'AND') && (empty($initial_search_results))) {
3283  return $original_search_results;
3284  }
3285 
3286  // Keep an overall tally
3287  $common_search_results = Array();
3288  foreach ($initial_search_results as $result => $weighting) {
3289  $common_search_results[][$result] = $weighting;
3290  }
3291 
3292  // Now perform a search for each synonym match so we can aggregate these at the end with AND
3293  // eg; (flute.player + flautist)
3294  foreach ($search_logic as $original_term => $matching_synonyms) {
3295  // Search for user-supplied term (flute player)
3296  $syn_search_info = $original_search_info;
3297  $syn_search_info['fields'][$auto_ss_field]['words'] = $original_term;
3298  $term_exploded = explode(' ', $original_term);
3299 
3300  // Multiple words, use AND logic
3301  if (count($term_exploded) > 1) {
3302  $syn_search_info['fields'][$auto_ss_field]['word_logic'] = 'AND';
3303  }
3304 
3305  $term_search_results = Array();
3306 
3307  $results = $sm->processSearch($syn_search_info);
3308  if (count($results) > 0) {
3309  foreach ($results as $result => $weighting) {
3310  if (isset($term_search_results[$result])) {
3311  $term_search_results[$result] += $weighting;
3312  } else {
3313  $term_search_results[$result] = $weighting;
3314  }
3315  }
3316  }
3317 
3318  // Search for synonym terms (flautist)
3319  $synonym_term_search_results = Array();
3320  foreach ($matching_synonyms as $matching_synonym) {
3321  $syn_search_info = $original_search_info;
3322  $syn_search_info['fields'][$auto_ss_field]['words'] = $matching_synonym;
3323  $term_exploded = explode(' ', $matching_synonym);
3324 
3325  // Multiple words, use AND logic
3326  if (count($term_exploded) > 1) {
3327  $syn_search_info['fields'][$auto_ss_field]['word_logic'] = 'AND';
3328  }
3329 
3330  $results = $sm->processSearch($syn_search_info);
3331  if (count($results) > 0) {
3332  foreach ($results as $result => $weighting) {
3333  if (isset($term_search_results[$result])) {
3334  $term_search_results[$result] += $weighting;
3335  } else {
3336  $term_search_results[$result] = $weighting;
3337  }
3338  }
3339  }
3340  }
3341 
3342  $common_search_results[] = $term_search_results;
3343  }
3344 
3345  // Flatten common search results. These are the results from our synonym term searches
3346  $synonym_search_results = Array();
3347  if ($outer_word_logic == 'AND') {
3348  // We need to eliminate any items that are not common between results, adding weightings of "keepers" as we go
3349  $common = Array();
3350  $first_time = TRUE;
3351  foreach ($common_search_results as $result) {
3352  if ($first_time) {
3353  if (!empty($result)) {
3354  $common = array_keys($result);
3355  }
3356  }
3357 
3358  foreach ($result as $asset_id => $weighting) {
3359  // Only add to results the second time around if we have common terms
3360  // This was added for increased complexity
3361  if ($first_time || (!$first_time && in_array($asset_id, $common))) {
3362  if (isset($synonym_search_results[$asset_id])) {
3363  $synonym_search_results[$asset_id] += $weighting;
3364  } else {
3365  $synonym_search_results[$asset_id] = $weighting;
3366  }
3367  }
3368  }
3369 
3370  $first_time = FALSE;
3371  }
3372  } else {
3373  // Simply flatten and add
3374  foreach ($common_search_results as $result) {
3375  foreach ($result as $asset_id => $weighting) {
3376  if (isset($synonym_search_results[$asset_id])) {
3377  $synonym_search_results[$asset_id] += $weighting;
3378  } else {
3379  $synonym_search_results[$asset_id] = $weighting;
3380  }
3381  }
3382  }
3383  }
3384 
3385  // Combine all term results with those of the original search
3386  foreach ($original_search_results as $result => $weighting) {
3387  if (isset($synonym_search_results[$result])) {
3388  $synonym_search_results[$result] += $weighting;
3389  } else {
3390  $synonym_search_results[$result] = $weighting;
3391  }
3392  }
3393 
3394  // Tell the wider world!
3395  $original_search_results = $synonym_search_results;
3396  }
3397 
3398  return $original_search_results;
3399 
3400  }//end getMultiWordSynonymSearchResults
3401 
3402 
3412  private function _sanitizeQueries(Array $queries)
3413  {
3414  foreach($queries as $field => $query) {
3415  if(is_array($query)) {
3416  $queries[$field] = $this->_sanitizeQueries($query);
3417  } else {
3418  // sanitise it by removing '%' from keywords so that
3419  // they dont go ahead and try to fetch it replacement
3420  $keywords = extract_keywords($query);
3421  foreach ($keywords as $keyword) {
3422  $pattern = '/(%*)'.$keyword.'(%*)/';
3423  $query = preg_replace($pattern, $keyword, $query);
3424  }
3425  $queries[$field] = $query;
3426  }
3427  }
3428 
3429  return $queries;
3430 
3431  }//end _sanitizeQueries()
3432 
3433 
3443  {
3444  $search_vars = Array();
3445  // If the search is stored, then process the search and show the results
3446  // The initial check is here, so it will still allow sis searches
3447  $pmap = $this->getAttribute('stored_query_session');
3448  $pmap_params = $pmap->getParameters();
3449  $fields = $this->attr('fields');
3450  $this->_tmp['jump_to_result'] = FALSE;
3451  if (is_array($pmap_params) && !empty($pmap_params)) {
3452  foreach ($pmap_params as $params) {
3453  $sq_index = $pmap->getParameterValue($params);
3454 
3455  if (!is_null($sq_index)) {
3456  replace_global_keywords($sq_index);
3457  // If a pipe separated list remove
3458  $sq_index = str_replace('|', ' ', $sq_index);
3459 
3460  // Now set these variables into $_REQUEST so search_page can read them directly
3461  if ($params == 'stored_query') {
3462  // Direct match to all fields
3463  foreach ($fields as $fieldname => $fieldvalue) {
3464  $search_vars[$fieldname] = $sq_index;
3465  }
3466  } else {
3467  // Else match the request to the field
3468  $search_vars[$params] = $sq_index;
3469  }//end if
3470 
3471  // This stops the search if set and empty
3472  if (isset($this->_tmp['searched_queries']) && empty($this->_tmp['searched_queries'])) {
3473  unset($this->_tmp['searched_queries']);
3474  }
3475 
3476  // Parameter Value loaded, so go to the Results page if the attribute is set
3477  $this->_tmp['jump_to_result'] = TRUE;
3478 
3479  }//end if
3480  }//end foreach
3481  }//end if
3482 
3483  return $search_vars;
3484 
3485  }//end processSearchVars()
3486 
3487 
3488 }//end class
3489 
3490 ?>