updating poms for branch'release/5.42.0' with non-snapshot versions
[cdm-dataportal.git] / modules / cdm_dataportal / cdm_dataportal.search.php
1 <?php
2 /**
3 * @file
4 * Search related functions.
5 */
6
7 const SESSION_KEY_SEARCH_REGISTRATION_FILTER = "SESSION_KEY_SEARCH_REGISTRATION_FILTER";
8 const SESSION_KEY_SEARCH_TAXONGRAPH_FOR_REGISTRATION_FILTER = 'SESSION_KEY_SEARCH_TAXONGRAPH_FOR_REGISTRATION_FILTER';
9 const SESSION_KEY_SEARCH_AGENT_FILTER = 'SEARCH_AGENT_FILTER';
10
11 /**
12 * Returns a Drupal path to a search form for a CDM webservice.
13 *
14 * For a given CDM webservice end-point, the drupal page path to the
15 * according search form is returned.
16 * cdm webservice end points are defined in constant variables like:
17 * <code>CDM_WS_PORTAL_TAXON_FIND</code> and
18 * <code>CDM_WS_PORTAL_TAXON_FINDBY_DESCRIPTIONELEMENT_FULLTEXT</code>
19 *
20 * @param string $ws_endpoint
21 * The cdm webservice endpoint for which to find the search form path.
22 *
23 * @return string
24 * The Drupal path found.
25 */
26 function cdm_dataportal_search_form_path_for_ws($ws_endpoint) {
27 static $form_ws_map = array(
28 CDM_WS_PORTAL_TAXON_FIND => "cdm_dataportal/search",
29 CDM_WS_PORTAL_TAXON_SEARCH => "cdm_dataportal/search",
30 CDM_WS_PORTAL_TAXON_FINDBY_DESCRIPTIONELEMENT_FULLTEXT => "cdm_dataportal/search/taxon_by_description",
31 );
32 return $form_ws_map[$ws_endpoint];
33 }
34
35 /**
36 * Prepares a form array for a general purpose search form.
37 *
38 * The form is used for general purpose search functionality in the
39 * dataportal. The form returned is populated with all necessary fields
40 * for internal processing and has the textfield element $form['query']
41 * which holds the query term.
42 *
43 * @param string $action_path
44 * The Drupal path to be put into the action url to which the form will
45 * be submitted.
46 * @param string $search_webservice
47 * The cdm-remote webservice to be used, valid values are defined by
48 * the constants: FIXME.
49 * @param string $query_field_default_value
50 * A default text for the query field
51 * @param string $query_field_description
52 * The description text for the query field
53 *
54 * @return array
55 * The prepared form array.
56 */
57 function cdm_dataportal_search_form_prepare($action_path, $search_webservice, $query_field_default_value, $query_field_description) {
58
59
60 $form['#method'] = 'get';
61 $form['#action'] = url($action_path, array(
62 'absolute' => TRUE,
63 ));
64
65 $form['ws'] = array(
66 '#type' => 'hidden',
67 '#value' => $search_webservice,
68 '#name' => 'ws',
69 );
70
71 $form['query'] = array(
72 '#weight' => 0,
73 '#type' => 'textfield',
74 '#size' => 68,
75 // This causes the description to display also when hovering over
76 // the textfield.
77 // This is wanted behaviour for the simple seach but could
78 // be disabled for the advances search.
79 '#attributes' => array(
80 'title' => $query_field_description,
81 ),
82 '#description' => $query_field_description,
83 '#value' => $query_field_default_value,
84 // '#description' => $query_field_description,
85 );
86 if(variable_get(SIMPLE_SEARCH_AUTO_SUGGEST)){
87 $form['query']['#autocomplete_path'] = 'cdm_dataportal/taxon/autosuggest////';
88 }
89
90 $form['search'] = array(
91 '#weight' => 3,
92 '#tree' => TRUE,
93 // '#type' => $advanced_form ? 'fieldset': 'hidden',
94 '#title' => t('Options'),
95 );
96
97 // Clean URL get forms breaks if we don't give it a 'q'.
98 if (!(bool) variable_get('clean_url', '0')) {
99 $form['search']['q'] = array(
100 '#type' => 'hidden',
101 '#value' => $action_path,
102 '#name' => 'q',
103 );
104 }
105
106 $form['submit'] = array(
107 '#weight' => 5,
108 '#type' => 'submit',
109 '#name' => '',
110 '#value' => t('Search'),
111 );
112
113 return $form;
114 }
115
116 function cdm_dataportal_taxon_autosuggest($classificationUuid = NULL, $areaUuid = NULL, $status = NULL, $string) {
117 $matches = array();
118
119 $queryParams = array();
120 $queryParams['query'] = $string.'*';
121 if((is_null($classificationUuid) || $classificationUuid=='') && isset($_SESSION['cdm']['taxonomictree_uuid'])){
122 $classificationUuid = $_SESSION['cdm']['taxonomictree_uuid'];// if no classification uuid is set use the current one
123 }
124 if($classificationUuid){
125 $queryParams['classificationUuid'] = $classificationUuid;
126 }
127 if($areaUuid){
128 $queryParams['area'] = $areaUuid;
129 }
130 if($status){
131 $queryParams['status'] = $status ;
132 }
133 $queryParams['pageIndex'] = '0';
134 $queryParams['pageSize'] = '10';
135 $queryParams['doTaxa'] = true;
136 $queryParams['doSynonyms'] = true;
137 $queryParams['doMisappliedNames'] = true;
138 $queryParams['doTaxaByCommonNames'] = true;
139
140 $search_results = cdm_ws_get(CDM_WS_TAXON_SEARCH, NULL, queryString($queryParams));
141 foreach($search_results->records as $record){
142 $titleCache = $record->entity->titleCache;
143 preg_match('/(.*) sec.*/', $titleCache, $trimmedTitle); //remove sec reference
144 $trimmedTitle = trim($trimmedTitle[1]);
145 $matches[$trimmedTitle] = check_plain($trimmedTitle);
146 }
147 drupal_json_output($matches);
148 }
149
150
151 /**
152 * Creates a search form for searching on taxa.
153 *
154 * If advanced $advanced_form id TRUE the form will offer additional choices
155 *
156 * @param array $form
157 * A drupal form array
158 * @param array $form_state
159 * The drupal form state passed as reference
160 * @param bool $advanced_form
161 * default is FALSE
162 * @param bool $classification_select
163 * set TRUE to offer a classification selector in the form - default is FALSE
164 * if only available in the advanced mode
165 *
166 * @return array
167 * the form array
168 */
169 function cdm_dataportal_search_taxon_form($form, &$form_state, $advanced_form = FALSE, $classification_select = TRUE)
170 {
171
172 if ($form_state['build_info']['form_id'] == 'cdm_dataportal_search_blast_form') {
173 $form = cdm_dataportal_search_blast_form($form, $form_state);
174 } else {
175
176
177 $query_field_default_value = (isset($_SESSION['cdm']['search']['query']) ? $_SESSION['cdm']['search']['query'] : '');
178
179 if ($advanced_form || variable_get(SIMPLE_SEARCH_USE_LUCENE_BACKEND, FALSE)) {
180 $search_service_endpoint = CDM_WS_PORTAL_TAXON_SEARCH;
181 } else {
182 $search_service_endpoint = CDM_WS_PORTAL_TAXON_FIND;
183 }
184
185 $form = cdm_dataportal_search_form_prepare(
186 'cdm_dataportal/search/results/taxon',
187 $search_service_endpoint,
188 $query_field_default_value,
189 t('Enter the name or part of a name you wish to search for.
190 The asterisk character * can be used as wildcard, but must not be used as first character.')
191 );
192 }
193 if (!$advanced_form) {
194 $form['query']['#size'] = 20;
195 }
196
197 $form['search']['pageSize'] = array(
198 '#weight' => -1,
199 '#type' => 'hidden',
200 '#value' => variable_get(CDM_SEARCH_RESULT_PAGE_SIZE, CDM_SEARCH_RESULT_PAGE_SIZE_DEFAULT),
201 );
202
203 $form['search']['pageIndex'] = array(
204 '#weight' => -1,
205 '#type' => 'hidden',
206 '#value' => 0,
207 );
208
209 $search_taxa_mode_settings = get_array_variable_merged(
210 CDM_SEARCH_TAXA_MODE,
211 CDM_SEARCH_TAXA_MODE_DEFAULT
212 );
213 $preset_do_taxa = $search_taxa_mode_settings['doTaxa'] !== 0;
214 $preset_do_synonyms = $search_taxa_mode_settings['doSynonyms'] !== 0;
215 $preset_do_taxa_by_common_names = $search_taxa_mode_settings['doTaxaByCommonNames'] !== 0;
216 $preset_do_misapplied_names = $search_taxa_mode_settings['doMisappliedNames'] !== 0;
217
218 if ($advanced_form) {
219
220 // --- ADVANCED SEARCH FORM ---
221 //
222
223 // Get presets from settings.
224 $preset_classification_uuid = get_current_classification_uuid();
225
226 // Overwrite presets by user choice stored in session.
227 if (isset($_SESSION['cdm']['search'])) {
228 $preset_do_taxa = (isset($_SESSION['cdm']['search']['doTaxa']) ? 1 : 0);
229 $preset_do_synonyms = (isset($_SESSION['cdm']['search']['doSynonyms']) ? 1 : 0);
230 $preset_do_misapplied_names = (isset($_SESSION['cdm']['search']['doMisappliedNames']) ? 1 : 0);
231 $preset_do_taxa_by_common_names = (isset($_SESSION['cdm']['search']['doTaxaByCommonNames']) ? 1 : 0);
232 if (isset($_SESSION['cdm']['search']['tree'])) {
233 $preset_classification_uuid = $_SESSION['cdm']['search']['tree'];
234 }
235 }
236
237 if ($classification_select === TRUE) {
238 $form['search']['tree'] = array(
239 '#title' => t('Classification'),
240 '#weight' => 1,
241 '#type' => 'select',
242 '#default_value' => $preset_classification_uuid,
243 '#options' => cdm_get_taxontrees_as_options(
244 TRUE,
245 variable_get(CDM_TAXONTREE_INCLUDES, []) ),
246 '#description' => t('A filter to limit the search to a specific classification. Choosing <em>--- ALL ---</em> will disable this filter.'),
247 );
248 }
249
250 // General search parameters.
251 $form['search']['doTaxa'] = array(
252 '#weight' => 2,
253 '#type' => 'checkbox',
254 '#title' => t('Include') . ' ' . t('accepted taxa'),
255 '#value' => $preset_do_taxa,
256 );
257 $form['search']['doSynonyms'] = array(
258 '#weight' => 3,
259 '#type' => 'checkbox',
260 '#title' => t('Include') . ' ' . t('synonyms'),
261 '#value' => $preset_do_synonyms,
262 );
263 $form['search']['doMisappliedNames'] = array(
264 '#weight' => 4,
265 '#type' => 'checkbox',
266 '#title' => t('Include') . ' ' . t('misapplied names'),
267 '#value' => $preset_do_misapplied_names,
268 );
269 $form['search']['doTaxaByCommonNames'] = array(
270 '#weight' => 5,
271 '#type' => 'checkbox',
272 '#title' => t('Include') . ' ' . t('common names'),
273 '#value' => $preset_do_taxa_by_common_names,
274 );
275
276 $area_term_dtos = cdm_ws_fetch_all(
277 CDM_WS_DESCRIPTION_NAMEDAREAS_IN_USE,
278 array('includeAllParents' => 'true')
279 );
280
281 // create map: term_uuid => term
282 $term_map = array();
283 foreach ($area_term_dtos as $term_dto) {
284 $term_map[$term_dto->uuid] = $term_dto;
285 }
286
287 $term_tree = array();
288 // mixed_vocabularies will contain the uuid vocabularies which
289 // also contain terms of foreign vocabularies due to the term
290 // hierarchy
291 $mixed_vocabularies = array();
292
293 // Build hierarchy of the terms regardless of the vocabulary.
294 foreach ($term_map as $term_dto) {
295 if (!empty($term_dto->partOfUuid)) {
296 // Children.
297 $parent =& $term_map[$term_dto->partOfUuid];
298 if ($parent) {
299 if (!isset($parent->children)) {
300 $parent->children = array();
301 }
302 $parent->children[$term_dto->uuid] = $term_dto;
303 if ($parent->vocabularyUuid != $term_dto->vocabularyUuid) {
304 $mixed_vocabularies[$parent->vocabularyUuid] = $parent->vocabularyUuid;
305 }
306 }
307 }
308 else {
309 // group root nodes by vocabulary
310 if (!isset($term_tree[$term_dto->vocabularyUuid])) {
311 $term_tree[$term_dto->vocabularyUuid] = array();
312 }
313 $term_tree[$term_dto->vocabularyUuid][$term_dto->uuid] = $term_dto;
314 }
315 }
316
317 $show_area_filter = ! variable_get(CDM_SEARCH_AREA_FILTER_PRESET, '');
318
319 if($show_area_filter){
320 drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/search_area_filter.js');
321
322 drupal_add_js('jQuery(document).ready(function() {
323 jQuery(\'#edit-search-areas\').search_area_filter(\'#edit-search-areas-areas-filter\');
324 });
325 ', array('type' => 'inline'));
326
327 $form['search']['areas'] = array(
328 '#type' => 'fieldset',
329 '#title' => t('Filter by distribution areas'),
330 '#description' => t('The search will return taxa having distribution
331 information for at least one of the selected areas.') . ' '
332 .(count($term_tree) > 1 ? t('The areas are grouped
333 by the vocabularies to which the highest level areas belong.') : ''),
334 );
335 $form['search']['areas']['areas_filter'] = array(
336 '#type' => 'textfield',
337 '#description' => t('Type to filter the areas listed below.'),
338 );
339 $vocab_cnt = 0;
340 $areas_defaults = array();
341 if (isset($_SESSION['cdm']['search']['area'])) {
342 $areas_defaults = explode(',', $_SESSION['cdm']['search']['area']);
343 }
344 _add_js_resizable_element('.resizable-box', true);
345 foreach ($term_tree as $vocab_uuid => $term_dto_tree) {
346 $vocabulary = cdm_ws_get(CDM_WS_TERMVOCABULARY, array($vocab_uuid));
347 $areas_options = term_tree_as_options($term_dto_tree);
348 $form['search']['areas']['area'][$vocab_cnt++] = array(
349 '#prefix' => '<strong>' . $vocabulary->representation_L10n
350 . (isset($mixed_vocabularies[$vocab_uuid]) ? ' <span title="Contains terms of at least one other area vocabulary.">(' . t('mixed') . ')</span>': '')
351 . '</strong><div class="resizable-container"><div class="resizable-box">',
352 '#type' => 'checkboxes',
353 '#default_value' => $areas_defaults,
354 '#options' => $areas_options,
355 '#suffix' => '</div></div>'
356 );
357 }
358 }
359
360 }
361 else {
362 // --- SIMPLE SEARCH FORM ---
363 //
364
365 // Overwrite presets by user choice stored in session.
366 if (isset($_SESSION['cdm']['search'])) {
367 $preset_do_misapplied_names = (isset($_SESSION['cdm']['search']['doMisappliedNames']) ? 1 : 0);
368 }
369
370 $form['search']['doTaxa'] = array(
371 '#weight' => -2,
372 '#type' => 'hidden',
373 '#value' => $preset_do_taxa,
374 );
375 $form['search']['doSynonyms'] = array(
376 '#weight' => -3,
377 '#type' => 'hidden',
378 '#value' => $preset_do_synonyms,
379 );
380 $form['search']['doMisappliedNames'] = array(
381 '#weight' => -4,
382 '#type' => 'checkbox',
383 '#title' => t('Misapplied names'),
384 '#value' => $preset_do_misapplied_names,
385 );
386 $form['search']['doTaxaByCommonNames'] = array(
387 '#weight' => -5,
388 '#type' => 'hidden',
389 '#value' => $preset_do_taxa_by_common_names,
390 );
391 }
392
393 return $form;
394 }
395
396 /**
397 * Creates a search form for searching on taxa.
398 *
399 * If advanced $advanced_form id TRUE the form will offer additional choices
400 *
401 * @param array $form
402 * A drupal form array
403 * @param array $form_state
404 * The drupal form state passed as reference
405 * @param bool $advanced_form
406 * default is FALSE
407 * @param bool $classification_select
408 * set TRUE to offer a classification selector in the form - default is FALSE
409 * if only available in the advanced mode
410 *
411 * @return array
412 * the form array
413 */
414 function cdm_dataportal_search_blast_form($form, &$form_state) {
415
416 $query_field_default_value = (isset($_SESSION['cdm']['search']['query']) ? $_SESSION['cdm']['search']['query'] : '');
417
418 $search_service_endpoint = CDM_SEARCH_BLAST_SERVICE_URI;
419
420
421 $form = cdm_dataportal_search_blast_form_prepare(
422 'cdm_dataportal/search/results/specimen',
423 $search_service_endpoint,
424 $query_field_default_value,
425 t('Enter the sequence or part of a sequence you wish to search for.')
426 );
427
428
429
430 $form['search']['pageSize'] = array(
431 '#weight' => -1,
432 '#type' => 'hidden',
433 '#value' => variable_get(CDM_SEARCH_RESULT_PAGE_SIZE, CDM_SEARCH_RESULT_PAGE_SIZE_DEFAULT),
434 );
435
436 $form['search']['pageIndex'] = array(
437 '#weight' => -1,
438 '#type' => 'hidden',
439 '#value' => 0,
440 );
441
442
443
444
445
446 return $form;
447 }
448
449 /**
450 * Prepares a form array for a general purpose search form.
451 *
452 * The form is used for general purpose search functionality in the
453 * dataportal. The form returned is populated with all necessary fields
454 * for internal processing and has the textfield element $form['query']
455 * which holds the query term.
456 *
457 * @param string $action_path
458 * The Drupal path to be put into the action url to which the form will
459 * be submitted.
460 * @param string $search_webservice
461 * The cdm-remote webservice to be used, valid values are defined by
462 * the constants: FIXME.
463 * @param string $query_field_default_value
464 * A default text for the query field
465 * @param string $query_field_description
466 * The description text for the query field
467 * @param string $process
468 * The value for #process, if NULL (default), 'cdm_dataportal_search_process'
469 * is used.
470 *
471 * @return array
472 * The prepared form array.
473 */
474 function cdm_dataportal_search_blast_form_prepare($action_path, $search_webservice, $query_field_default_value, $query_field_description, $process = NULL) {
475
476 if ($process == NULL) {
477 $process = 'cdm_dataportal_search_process';
478 }
479
480 $form['#method'] = 'get';
481 //
482 // $form['#process'] = array(
483 // $process => array(),
484 // );
485 //
486 $form['#action'] = url($action_path, array(
487 'absolute' => TRUE,
488 ));
489
490 $form['ws'] = array(
491 '#type' => 'hidden',
492 '#value' => $search_webservice,
493 '#name' => 'ws',
494 );
495
496 $form['query'] = array(
497 '#weight' => 0,
498 '#type' => 'textarea',
499 '#size' => 68,
500 // This causes the description to display also when hovering over
501 // the textfield.
502 // This is wanted behaviour for the simple seach but could
503 // be disabled for the advances search.
504 '#attributes' => array(
505 'title' => $query_field_description,
506 ),
507 '#description' => $query_field_description,
508 // '#value' => $query_field_default_value,
509 // '#description' => $query_field_description,
510 );
511
512
513 $form['search'] = array(
514 '#weight' => 3,
515 '#tree' => TRUE,
516 // '#type' => $advanced_form ? 'fieldset': 'hidden',
517 '#title' => t('Options'),
518 );
519
520 // Clean URL get forms breaks if we don't give it a 'q'.
521 if (!(bool) variable_get('clean_url', '0')) {
522 $form['search']['q'] = array(
523 '#type' => 'hidden',
524 '#value' => $action_path,
525 '#name' => 'q',
526 );
527 }
528
529 $form['search']['word_size'] = array(
530 '#weight' => 1,
531 '#type' => 'textfield',
532 '#title' => t('Word size'),
533 '#default_value' => 7,
534 '#description' => t('Length of initial exact match'),
535 );
536
537 $form['search']['reward'] = array(
538 '#weight' => 2,
539 '#type' => 'textfield',
540 '#title' => t('Reward'),
541 '#default_value' => 1,
542 '#description' => t('Reward for Matching'),
543 );
544
545 $form['search']['penalty'] = array(
546 '#weight' => 3,
547 '#type' => 'textfield',
548 '#title' => t('Penalty'),
549 '#default_value' => -2,
550 '#description' => t('Penalty for mismatching'),
551 );
552
553 $form['search']['gap_open'] = array(
554 '#weight' => 4,
555 '#type' => 'textfield',
556 '#title' => t('Gap open'),
557 '#default_value' => 5,
558 '#description' => t('Cost to open a gap'),
559 );
560
561 $form['search']['gap_extend'] = array(
562 '#weight' => 5,
563 '#type' => 'textfield',
564 '#title' => t('Gap extend'),
565 '#default_value' => -2,
566 '#description' => t('Cost for extend a gap'),
567 );
568
569 $form['submit'] = array(
570 '#weight' => 5,
571 '#type' => 'submit',
572 '#name' => '',
573 '#value' => t('Search'),
574 );
575
576 return $form;
577 }
578 /**
579 * Wrapper function for cdm_dataportal_search_taxon_form().
580 *
581 * This function makes ot possible possible to just pass the
582 * correct $form_id 'cdm_dataportal_search_taxon_form_advanced' to
583 * drupal_get_form like:
584 * drupal_get_form('cdm_dataportal_search_taxon_form_advanced');
585 *
586 * @param array $form
587 * A drupal form array
588 * @param array $form_state
589 * The drupal form state passed as reference
590 *
591 * @return array
592 * The form array
593 */
594 function cdm_dataportal_search_taxon_form_advanced($form, &$form_state) {
595 return cdm_dataportal_search_taxon_form($form, $form_state, TRUE);
596 }
597
598 /**
599 * Form for searching taxa by the findByDescriptionElementFullText rest service.
600 */
601 function cdm_dataportal_search_taxon_by_description_form() {
602 $query_field_default_value = (isset($_SESSION['cdm']['search']['query']) ? $_SESSION['cdm']['search']['query'] : '');
603
604 $form = cdm_dataportal_search_form_prepare(
605 'cdm_dataportal/search/results/taxon',
606 CDM_WS_PORTAL_TAXON_FINDBY_DESCRIPTIONELEMENT_FULLTEXT,
607 $query_field_default_value,
608 t("Enter the text you wish to search for. The asterisk character * can be
609 used as wildcard, but must not be used as first character. Terms can be combined with 'AND'. To search for a
610 full phrase enclose the terms in parentheses. For more syntactical
611 options please refer to the !link.",
612 array(
613 '!link' => l(
614 t('Apache Lucene - Query Parser Syntax'),
615 'http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html', array(
616 'attributes' => array(
617 'absolute' => TRUE,
618 'html' => TRUE),
619 )
620 ),
621 )
622 )
623 );
624
625 $form['search']['tree'] = array(
626 '#weight' => -1,
627 '#type' => 'hidden',
628 '#value' => get_current_classification_uuid(),
629 );
630
631 $form['search']['hl'] = array(
632 '#weight' => -1,
633 '#type' => 'hidden',
634 '#value' => 1,
635 );
636
637 // Only available to admins:
638 if (!isset($_SESSION['cdm']['search']['clazz'])) {
639 $_SESSION['cdm']['search']['clazz'] = '';
640 }
641 if (module_exists("user") && user_access('administer')) {
642 $form['search']['clazz'] = array(
643 '#type' => 'select',
644 '#title' => t('Limit to description item type'),
645 '#default_value' => $_SESSION['cdm']['search']['clazz'],
646 '#options' => cdm_descriptionElementTypes_as_option(TRUE),
647 );
648 }
649
650 $profile_feature_tree = get_profile_feature_tree();
651 $feature_options = _featureTree_nodes_as_feature_options($profile_feature_tree->root);
652 if (isset($_SESSION['cdm']['search']['features'])) {
653 $form['search']['features'] = array(
654 '#type' => 'checkboxes',
655 '#title' => t('Limit to selected features'),
656 '#default_value' => $_SESSION['cdm']['search']['features'],
657 '#options' => $feature_options,
658 );
659 }
660 else {
661 $form['search']['features'] = array(
662 '#type' => 'checkboxes',
663 '#title' => t('Limit to selected features'),
664 '#options' => $feature_options,
665 );
666 }
667 return $form;
668 }
669
670 /**
671 * Processes the query parameters of the search form.
672 *
673 * Reads the query parameters from $_REQUEST and modifies and adds additional
674 * query parameters if necessary.
675 *
676 * - Filters $_REQUEST by a list of valid request parameters
677 * - modifies geographic_range parameters
678 * - adds taxon tree uuid if it is missing and if it should not be
679 * ignored (parameter value = 'IGNORE')
680 * - and more
681 *
682 * @param $search_endpoint string
683 * The web service endpoint which will be used for executing the search.
684 * Usually one of CDM_WS_PORTAL_TAXON_SEARCH, CDM_WS_PORTAL_TAXON_FIND,
685 * CDM_WS_PORTAL_TAXON_FINDBY_DESCRIPTIONELEMENT_FULLTEXT.
686 * @return array
687 * the processed request parameters submitted by the search form and
688 * also stores them in $_SESSION['cdm']['search']
689 */
690 function cdm_dataportal_search_request($search_endpoint)
691 {
692
693 $form_params = array();
694
695 if (isset($_REQUEST['search']) && is_array($_REQUEST['search'])) {
696 array_deep_copy($_REQUEST['search'], $form_params);
697 }
698
699 if (isset($_REQUEST['pager']) && is_array($_REQUEST['pager'])) {
700 $form_params = array_merge($form_params, $_REQUEST['pager']);
701 }
702
703 $form_params['query'] = trim($_REQUEST['query']);
704
705
706 // --- handle geographic range
707 // Split of geographic range.
708 unset($form_params['areas']);
709
710 $area_filter_preset = null;
711 if (variable_get(CDM_SEARCH_AREA_FILTER_PRESET, '')) {
712 $area_filter_preset = explode(',', variable_get(CDM_SEARCH_AREA_FILTER_PRESET, ''));
713 }
714
715 $area_uuids = array();
716 if($area_filter_preset){
717 $area_uuids = $area_filter_preset;
718 }
719 elseif (isset($_REQUEST['search']['areas']['area']) && is_array($_REQUEST['search']['areas']['area'])) {
720 foreach ($_REQUEST['search']['areas']['area'] as $areas) {
721 $area_uuids = array_merge($area_uuids, $areas);
722 }
723 // The area filter is limited to areas with non absent distribution status
724 $presence_terms_options = cdm_vocabulary_as_option(UUID_PRESENCE_ABSENCE_TERM, null, FALSE, array('absenceTerm' => '/false/'));
725 $presence_term_uuids = array_keys($presence_terms_options);
726 $form_params['status'] = $presence_term_uuids;
727 }
728 if(count($area_uuids) > 0){
729 $form_params['area'] = implode(',', $area_uuids);
730 }
731
732 // Simple search will not submit a 'tree' query parameter,
733 // so we add it here from what is stored in the session unless
734 // SIMPLE_SEARCH_IGNORE_CLASSIFICATION is checked in the settings.
735 if (!isset($form_params['tree']) && !variable_get(SIMPLE_SEARCH_IGNORE_CLASSIFICATION, 0)) {
736 $form_params['tree'] = get_current_classification_uuid();
737 }
738 // Store in session.
739 $_SESSION['cdm']['search'] = $form_params;
740
741 // ----------- further processing that must not be store in the session --------- //
742
743 if($search_endpoint == CDM_WS_PORTAL_TAXON_SEARCH){
744 // HACK to allow using dot characters
745 $form_params['query'] = str_replace('.', '*', $form_params['query']);
746 // lucene based taxon search always as phrase search if the query string contains a whitespace --> enclose it in "
747 if(preg_match("/\s+/", $form_params['query'])){
748 if(!str_beginsWith($form_params['query'], '"')){
749 $form_params['query'] = '"' . $form_params['query'];
750 }
751 if(!str_endsWith($form_params['query'], '"')){
752 $form_params['query'] = $form_params['query'] . '"' ;
753 }
754 }
755 }
756
757 // If the 'NONE' classification has been chosen (advanced search)
758 // delete the tree information to avoid unknown uuid exceptions in the
759 // cdm service.
760 if (isset($form_params['tree'])
761 && ($form_params['tree'] == 'NONE' || !is_uuid($form_params['tree']))
762 ) {
763 // $form_params['ignore_classification'] = TRUE;
764 unset($form_params['tree']);
765 }
766
767
768 // else {
769 // $form_params['ignore_classification'] = NULL;
770 // }
771
772
773 return $form_params;
774 }
775
776 /**
777 * Processes the query parameters of the blast search form.
778 *
779 * Reads the query parameters from $_REQUEST and modifies and adds additional
780 * query parameters if necessary.
781 *
782 * - Filters $_REQUEST by a list of valid request parameters
783 *
784 *
785 * @param $search_endpoint string
786 * The web service endpoint which will be used for executing the search.
787 *
788 * @return array
789 * the processed request parameters submitted by the search form and
790 * also stores them in $_SESSION['cdm']['search']
791 */
792 function cdm_dataportal_blast_search_request($search_endpoint)
793 {
794 $form_params = array();
795
796 if (isset($_REQUEST['search']) && is_array($_REQUEST['search'])) {
797 array_deep_copy($_REQUEST['search'], $form_params['data']);
798 }
799 $form_params['data'] = formatWSParams($_REQUEST['search']);
800 $form_params['query']= trim($_REQUEST['query']).$form_params['data'];
801 // Store in session.
802 $_SESSION['cdm']['search'] = $form_params;
803 return $form_params;
804 }
805
806 /**
807 * Provides the classification to which the last search has been limited to..
808 *
809 * This function should only be used after the cdm_dataportal_search_taxon_execute()
810 * handler has been run, otherwise it will return the information from the last
811 * search executed. The information is retrieved from
812 * the $_SESSION variable: $_SESSION['cdm']['search']['tree']
813 *
814 * @return object
815 * the CDM classification instance which has been used a filter for the
816 * last processed search
817 * or NULL, it it was on all classifications
818 */
819 function cdm_dataportal_searched_in_classification() {
820
821 $classification = &drupal_static(__FUNCTION__);
822
823 if (!isset($classification)) {
824 if (isset($_SESSION['cdm']['search']['tree'])) {
825 $classification = cdm_ws_get(CDM_WS_PORTAL_TAXONOMY, ($_SESSION['cdm']['search']['tree']));
826 }
827 else {
828 $classification = FALSE;
829 }
830 }
831
832 return $classification !== FALSE ? $classification : NULL;
833 }
834
835 /**
836 * Removed the drupal internal form parameters 'form_id', 'form_token', 'form_build_id' from the request array.
837 *
838 * @param $request array
839 * Pass $_REQUEST as paramter
840 * @return array
841 * The $request array without drupal internal form parameters
842 */
843 function remove_drupal_form_params($request) {
844
845 static $exclude_keys = array('form_id', 'form_token', 'form_build_id');
846 $request_sanitized = array();
847 foreach ($request as $key => $value) {
848 if(!array_search($key, $exclude_keys)){
849 $request_sanitized[$key] = $value;
850 }
851 }
852
853 return $request_sanitized;
854 }
855
856 /**
857 * Sends a search request to the cdm server.
858 *
859 * The parameters to build the query are taken obtained by calling
860 * cdm_dataportal_search_request() which reads the query parameters
861 * from $_REQUEST and add additional query parameters if nessecary.
862 *
863 * @see cdm_dataportal_search_request()
864 */
865 function cdm_dataportal_search_taxon_execute() {
866
867 // Store as last search in session.
868 $_SESSION['cdm']['last_search'] = $_SERVER['REQUEST_URI'];
869
870 // Validate the search webservice parameter:
871 if (!isset($_REQUEST['ws'])) {
872 drupal_set_message(
873 t("Invalid search, webservice parameter 'ws' is missing"), 'warning'
874 );
875 return NULL;
876 }
877 if (!cdm_dataportal_search_form_path_for_ws($_REQUEST['ws'])) {
878 // Endpoint is unknown.
879 drupal_set_message(
880 t("Invalid search webservice parameter 'ws' given"), 'warning'
881 );
882 return NULL;
883 }
884
885 // Read the query parameters from $_REQUEST and add additional query
886 // parameters if necessary.
887 $request_params = cdm_dataportal_search_request($_REQUEST['ws']);
888
889 $taxon_pager = cdm_ws_get($_REQUEST['ws'], NULL, queryString($request_params));
890
891 return $taxon_pager;
892 }
893
894 /**
895 * Sends a search request to the cdm server.
896 *
897 * The parameters to build the query are taken obtained by calling
898 * cdm_dataportal_search_request() which reads the query parameters
899 * from $_REQUEST and add additional query parameters if nessecary.
900 *
901 * @see cdm_dataportal_search_request()
902 */
903 function cdm_dataportal_search_blast_execute() {
904
905 // Store as last search in session.
906 $_SESSION['cdm']['last_blast_search'] = $_SERVER['REQUEST_URI'];
907
908 // Validate the search webservice parameter:
909 if (!isset($_REQUEST['ws'])) {
910 drupal_set_message(
911 t("Invalid search, webservice parameter 'ws' is missing"), 'warning'
912 );
913 return NULL;
914 }
915 // if (!cdm_dataportal_search_form_path_for_ws($_REQUEST['ws'])) {
916 // // Endpoint is unknown.
917 // drupal_set_message(
918 // t("Invalid search webservice parameter 'ws' given"), 'warning'
919 // );
920 // return NULL;
921 // }
922
923 // Read the query parameters from $_REQUEST and add additional query
924 // parameters if necessary.
925 $request_params = cdm_dataportal_blast_search_request($_REQUEST['ws']);
926 // $url = drupal_http_build_query($_REQUEST['ws'], $request_params);
927 $request_params['timeout'] = 200;
928 $taxon_pager = drupal_http_request($_REQUEST['ws'].'?sequence='.$request_params['query'], $request_params);
929
930 return $taxon_pager;
931 }
932
933
934
935 /**
936 * Sends a request for a registrations filter search to the cdm server.
937 */
938 function cdm_dataportal_search_registrations_filter_execute()
939 {
940
941 static $query_param_map = array(
942 'identifier' => 'identifierFilterPattern',
943 'taxon_name'=> 'taxonNameFilterPattern',
944 'reference_citation' => 'referenceFilterPattern',
945 'type_designation_status_uuids' => 'typeDesignationStatusUuids',
946 );
947
948 $session_key = SESSION_KEY_SEARCH_REGISTRATION_FILTER;
949 $request_params = cdm_dataportal_search_request_params($session_key, $query_param_map);
950
951 // cleanup
952 if(isset($request_params['typeDesignationStatusUuids'])){
953 if(!$request_params['typeDesignationStatusUuids']
954 || $request_params['typeDesignationStatusUuids'] == "0"
955 || (isset($request_params['typeDesignationStatusUuids'][0]) && !$request_params['typeDesignationStatusUuids'][0])){
956 unset($request_params['typeDesignationStatusUuids']);
957 }
958 }
959 if(isset($request_params['taxonNameFilterPattern'])){
960 // trim and remove empty taxon name query strings
961 $request_params['taxonNameFilterPattern'] = trim($request_params['taxonNameFilterPattern']);
962 if(!$request_params['taxonNameFilterPattern']){
963 unset($request_params['taxonNameFilterPattern']);
964 }
965 }
966 // reference_citation
967 if(isset($request_params['referenceFilterPattern'])){
968 // trim and remove empty taxon name query strings
969 $request_params['referenceFilterPattern'] = trim($request_params['referenceFilterPattern']);
970 if(!$request_params['referenceFilterPattern']){
971 unset($request_params['referenceFilterPattern']);
972 }
973 }
974
975 $registration_pager = cdm_ws_get('registrationDTO/find', NULL, queryString($request_params));
976
977 return $registration_pager;
978 }
979
980 /**
981 * Sends a request for a registrations taxongraph search to the cdm server.
982 */
983 function cdm_dataportal_search_registrations_taxongraph_execute()
984 {
985
986 static $query_param_map = array(
987 'taxon_name'=> 'taxonNameFilter'
988 );
989
990 $session_key = SESSION_KEY_SEARCH_TAXONGRAPH_FOR_REGISTRATION_FILTER;
991 $request_params = cdm_dataportal_search_request_params($session_key, $query_param_map);
992
993 // cleanup
994 if(isset($request_params['taxonNameFilter'])){
995 // trim and remove empty taxon name query strings
996 $request_params['taxonNameFilter'] = trim($request_params['taxonNameFilter']);
997 if(!$request_params['taxonNameFilter']){
998 unset($request_params['taxonNameFilter']);
999 }
1000 }
1001
1002 $registration_pager = cdm_ws_get('registrationDTO/findInTaxonGraph', NULL, queryString($request_params));
1003
1004 return $registration_pager;
1005 }
1006
1007 /**
1008 * @param $session_key
1009 * The key to be used for storing the search params in $_SESSION['cdm'][]
1010 * @param $query_param_map
1011 * An array which maps the filter_key to the web service query parameter.
1012 * The filter key may be used as form element name or as drupal url
1013 * query parameter.
1014 * @return array
1015 */
1016 function cdm_dataportal_search_request_params($session_key, $query_param_map)
1017 {
1018 // Read the query parameters from $_REQUEST and add additional query
1019 // parameters if necessary.
1020 $request_params = array();
1021
1022 $request = remove_drupal_form_params($_REQUEST);
1023
1024 if (count($request) > 0) {
1025 $_SESSION['cdm'][$session_key] = $request;
1026 foreach ($query_param_map as $filter_key => $query_param) {
1027 if (isset($request[$filter_key])) {
1028 $request_params[$query_param] = $request[$filter_key];
1029 }
1030 }
1031 if (isset($request['pager']['pageIndex'])) {
1032 $request_params['pageIndex'] = $request['pager']['pageIndex'];
1033 }
1034 }
1035
1036 if (count($request_params) == 0 && isset($_SESSION['cdm'][$session_key])) {
1037 foreach ($query_param_map as $filter_key => $query_param) {
1038 if (isset($_SESSION['cdm'][$session_key][$filter_key])) {
1039 $request_params[$query_param] = $_SESSION['cdm'][$session_key][$filter_key];
1040 }
1041 }
1042 if (isset($_SESSION['cdm'][$session_key]['pager']['pageIndex'])) {
1043 $request_params['pageIndex'] = $_SESSION['cdm'][$session_key]['pager']['pageIndex'];
1044 }
1045 }
1046 return $request_params;
1047 }
1048
1049 /**
1050 * Transforms the termDTO tree into options array.
1051 *
1052 * TermDto:
1053 * - partOfUuid:
1054 * - representation_L10n:
1055 * - representation_L10n_abbreviatedLabel:
1056 * - uuid:
1057 * - vocabularyUuid:
1058 * - children: array of TermDto
1059 *
1060 * The options array is suitable for drupal form API elements that
1061 * allow multiple choices.
1062 * @see http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#options
1063 *
1064 * @param array $term_dto_tree
1065 * a hierarchic array of CDM TermDto instances, with additional
1066 * 'children' field:
1067 * @param array $options
1068 * Internally used for recursive calls
1069 * @param string $prefix
1070 * Internally used for recursive calls
1071 *
1072 * @return array
1073 * the terms in an array as options for a form element that allows
1074 * multiple choices.
1075 */
1076 function term_tree_as_options($term_dto_tree, &$options = array(), $prefix = '') {
1077
1078 uasort($term_dto_tree, 'compare_terms_by_order_index');
1079 foreach ($term_dto_tree as $uuid => $dto) {
1080 $label = $prefix . '<span class="child-label">'
1081 . $dto->representation_L10n
1082 . '</span><span class="child-label-abbreviated"> (' . $dto->representation_L10n_abbreviatedLabel . ')</span>';
1083 $options[$uuid] = $label;
1084 if (isset($dto->children) && is_array($dto->children)) {
1085 term_tree_as_options(
1086 $dto->children,
1087 $options, $prefix
1088 . '<span data-cdm-parent="' . $uuid . '" class="parent"></span>'
1089 );
1090 }
1091 }
1092
1093 return $options;
1094 }
1095
1096
1097 function cdm_dataportal_search_registration_filter_form($form, &$form_state) {
1098
1099 static $filter_presets_empty = array(
1100 'identifier'=> null,
1101 'taxon_name'=> null,
1102 'reference_citation'=> null,
1103 'type_designation_status_uuids' => null
1104 );
1105
1106 _add_font_awesome_font();
1107
1108 if(isset($_REQUEST['q']) && ($_REQUEST['q'] == 'cdm_dataportal/registration-search/filter' || $_REQUEST['q'] == 'cdm_dataportal/registration-search')){
1109 // read the $request_params only if it was send from this form
1110 $request_params = remove_drupal_form_params($_REQUEST);
1111 } else {
1112 $request_params = array();
1113 }
1114 $filter_presets = (isset($_SESSION['cdm'][SESSION_KEY_SEARCH_REGISTRATION_FILTER]) ? $_SESSION['cdm'][SESSION_KEY_SEARCH_REGISTRATION_FILTER] : array());
1115 $filter_presets = array_merge($filter_presets_empty, $filter_presets, $request_params);
1116 $form['#action'] = url('/cdm_dataportal/registration-search/filter');
1117 $form['#method'] = 'get';
1118 $form['#attributes'] = array('class' => array('search-filter'));
1119 $form['identifier'] = array(
1120 '#type' => 'textfield',
1121 '#title' => t('Identifier'),
1122 '#default_value' => $filter_presets['identifier'],
1123 '#size' => 20,
1124 '#maxlength' => 128
1125 );
1126 $form['taxon_name'] = array(
1127 '#type' => 'textfield',
1128 '#title' => t('Scientific name'),
1129 '#default_value' => $filter_presets['taxon_name'],
1130 '#size' => 20,
1131 '#maxlength' => 128
1132 );
1133 $form['reference_citation'] = array(
1134 '#type' => 'textfield',
1135 '#title' => t('Publication'),
1136 '#default_value' => $filter_presets['reference_citation'],
1137 '#size' => 20,
1138 '#maxlength' => 128
1139 );
1140 $form['type_designation_status_uuids'] = array(
1141 '#type' => 'select',
1142 '#title' => t('Type designation status'),
1143 '#multiple' => true,
1144 '#options' => cdm_type_designation_status_filter_terms_as_options('- none -'),
1145 '#default_value' => $filter_presets['type_designation_status_uuids'],
1146 "#description" => '<i>' . t('Ctrl + Click to unselect') . '</i>'
1147 );
1148
1149 $form['submit'] = array(
1150 '#markup' => '<button type="submit" title="Search" class="form-submit">' . font_awesome_icon_markup('fa-search') . '</button>'
1151 // '#prefix' => "<div class=\"form-item\"><label>&nbsp</label>",
1152 // '#suffix' => "</div>"
1153
1154 );
1155 return $form;
1156 }
1157
1158
1159 function cdm_dataportal_search_registration_taxongraph_form($form, &$form_state) {
1160
1161 static $filter_presets_empty = array(
1162 'taxon_name'=> null
1163 );
1164
1165 _add_font_awesome_font();
1166
1167 if(isset($_REQUEST['q']) && $_REQUEST['q'] == 'cdm_dataportal/registration-search/taxongraph'){
1168 // read the $request_params only if it was send from this form
1169 $request_params = remove_drupal_form_params($_REQUEST);
1170 } else {
1171 $request_params = array();
1172 }
1173 $filter_presets = (isset($_SESSION['cdm'][SESSION_KEY_SEARCH_TAXONGRAPH_FOR_REGISTRATION_FILTER]) ? $_SESSION['cdm'][SESSION_KEY_SEARCH_TAXONGRAPH_FOR_REGISTRATION_FILTER] : array());
1174 $filter_presets = array_merge($filter_presets_empty, $filter_presets, $request_params);
1175
1176 $form['#action'] = url('/cdm_dataportal/registration-search/taxongraph');
1177 $form['#method'] = 'get';
1178 $form['#attributes'] = array('class' => array('search-filter'));
1179 $form['taxon_name'] = array(
1180 '#type' => 'textfield',
1181 '#title' => t('Scientific name'),
1182 '#default_value' => $filter_presets['taxon_name'],
1183 '#size' => 20,
1184 '#maxlength' => 128
1185 );
1186
1187 $form['submit'] = array(
1188 '#markup' => '<button type="submit" title="Search" class="form-submit">' . font_awesome_icon_markup('fa-search') . '</button>'
1189 // '#prefix' => "<div class=\"form-item\"><label>&nbsp</label>",
1190 // '#suffix' => "</div>"
1191
1192 );
1193 return $form;
1194 }
1195
1196 /**
1197 * Compose the result set of a registration search from a pager object
1198 *
1199 * @param $cdm_item_pager
1200 * The pager containing registration objects
1201 *
1202 * @return
1203 * A drupal render array.
1204 *
1205 * @ingroup compose
1206 *
1207 * TODO compose function into search.inc ?
1208 */
1209 function compose_search_results($cdm_item_pager, ItemComposeHandler $item_compose_handler){
1210
1211 $render_array = array();
1212 $render_array['pre'] = markup_to_render_array("<div class=\"cdm-item-list\">");
1213
1214 if($cdm_item_pager != null && count($cdm_item_pager->records) > 0){
1215 $items_render_array = array();
1216 foreach($cdm_item_pager->records as $registration_dto) {
1217
1218 $items_render_array[] = array(
1219 '#prefix' => "<div class=\"item\"><div class=\"" . $item_compose_handler->getClassAttributes($registration_dto) . "\">",
1220 'item_data' => $item_compose_handler->composeItem($registration_dto),
1221 '#suffix' => "</div></div>"
1222 );
1223 ;
1224 }
1225
1226 $render_array['items'] = $items_render_array;
1227 $render_array['pager'] = markup_to_render_array(theme('cdm_pager', array(
1228 'pager' => $cdm_item_pager,
1229 'path' => $_REQUEST['q'], // stay on same page
1230 'parameters' => $_REQUEST,
1231 )));
1232
1233 } else {
1234 if($cdm_item_pager != null && $cdm_item_pager->count > 0 && count($cdm_item_pager->records) == 0){
1235 $render_array['items'] = markup_to_render_array("<div id=\"no_results\">Result page out of range.</div>");
1236 } else {
1237 $render_array['items'] = markup_to_render_array("<div id=\"no_results\">No results found.</div>");
1238 }
1239 }
1240 $render_array['post'] = markup_to_render_array("</div>");
1241
1242 return $render_array;
1243
1244 }
1245
1246
1247 /**
1248 * Sends a search request for agents to the cdm server.
1249 */
1250 function cdm_dataportal_search_agent_execute()
1251 {
1252
1253 static $query_param_map = array(
1254 'markerType' => 'markerType',
1255 'cdmType' => 'class'
1256 );
1257
1258 $session_key = SESSION_KEY_SEARCH_AGENT_FILTER;
1259 $request_params = cdm_dataportal_search_request_params($session_key, $query_param_map);
1260
1261 // cleanup
1262 if(isset($request_params['taxonNameFilter'])){
1263 // trim and remove empty taxon name query strings
1264 $request_params['taxonNameFilter'] = trim($request_params['taxonNameFilter']);
1265 if(!$request_params['taxonNameFilter']){
1266 unset($request_params['taxonNameFilter']);
1267 }
1268 }
1269 $restrictions = [];
1270 if( isset($request_params['markerType'])){
1271 $restrictions = array(new Restriction("markers.markerType.uuid","EXACT", array($request_params['markerType']), 'AND'));
1272 }
1273 $init_strategy = array(
1274 "$",
1275 "titleCache",
1276 "extensions.$",
1277 "identifiers.type"
1278 );
1279
1280 $type_restriction = null;
1281 if(isset($request_params['class']) && ($request_params['class'] == 'Team' || $request_params['class'] == 'Person')){
1282 $type_restriction = $request_params['class'];
1283 }
1284 $page_index = 0;
1285 if(isset($_REQUEST['pager']['pageIndex'])){
1286 $page_index = $_REQUEST['pager']['pageIndex'];
1287 }
1288 $pager = cdm_ws_page_by_restriction('AgentBase', $type_restriction, $restrictions, $init_strategy, 50, $page_index);
1289
1290 return $pager;
1291 }
1292