-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGeneticMarkerSearch.inc
326 lines (290 loc) · 10.6 KB
/
GeneticMarkerSearch.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
<?php
/**
* Provides a search for SO:genetic_marker chado feature-based Tripal Content.
*
*/
class GeneticMarkerSearch extends KPSEARCH {
/**
* The human readable title of this search. This will be used in listings
* and shown on the search page as the title.
*/
public static $title = 'Genetic Marker Search';
/**
* The machine name of the module providing this search.
*/
public static $module = 'kp_searches';
/**
* A description of this search. This is shown at the top of the search page
* and used for the menu item.
*/
public static $description = 'While the term variant refers to a position in the genome with variation, genetic marker refers specifically to an assay which samples that variation.';
/**
* The machine names of the permissions with access to this search. This is
* used to map your search to existing permissions. It must be an array and
* is used in hook_menu(). Some examples include 'access content'
* and 'administer tripal'.
*/
public static $permissions = ['access content'];
/**
* If TRUE, this search will require the submit button to be clicked before
* executing the query; whereas, if FALSE it will be executed on the
* first page load without parameters.
*
* NOTE: to control the results without parameters check $this->submitted
* in getQuery() and if FALSE return your pre-submit query.
*/
public static $require_submit = TRUE;
/**
* Add a pager to search results
* with $num_items_per_page results on a single page.
* NOTE: Your query has to handle paging.
*/
public static $pager = TRUE;
public static $num_items_per_page = 50;
/**
* This defined the hook_menu definition for this search. At a minimum the
* path is required.
*/
public static $menu = [
'path' => 'search/markers',
// @todo support menu items.
];
/**
* Add CSS/JS to the form/results page.
* NOTE: paths supplied should be relative to $module.
*/
public static $attached = [
'css' => [
'css/all_kp_searches.css',
],
'js' => [],
];
/**
* Information regarding the fields and filters for this search.
*/
public static $info = [
// Lists the columns in your results table.
'fields' => [
'name' => [
'title' => 'Name',
'entity_link' => [
'chado_table' => 'feature',
'id_column' => 'feature_id'
],
],
'type' => [
'title' => 'Marker Type',
],
'original_loc' => [
'title' => 'Original Location',
],
'species' => [
'title' => 'Source Species',
'entity_link' => [
'chado_table' => 'organism',
'id_column' => 'organism_id'
],
],
],
// The filter criteria available to the user.
// This is used to generate a search form which can be altered.
'filters' => [
'genus' => [
'title' => 'Genus',
'help' => 'The legume species the genetic marker was designed for (e.g. Lens culinaris).',
],
'species' => [
'title' => 'Species',
'help' => '',
],
'type' => [
'title' => 'Marker Type',
'help' => 'The type of marker you are interested in (e.g. Illumina Golden Gate).',
//'default' => 'Exome Capture',
],
'project' => [
'title' => 'Experiment',
'help' => 'The experiment you are interested in (e.g. AGILE; partial names are accepted).',
],
'start-backbone' => [
'title' => 'Start: Backbone',
'help' => 'The name of the sequence the markers are located on.'
],
'start-pos' => [
'title' => 'Start: Position',
'help' => 'The numeric start position of the range you are interested in.'
],
'end-pos' => [
'title' => 'End: Position',
'help' => 'The numeric end position of the range you are interested in.'
],
'name' => [
'title' => 'Name',
'help' => 'The name or accession of the marker (e.g. LcC00002p390; partial names are accepted).',
],
],
];
/**
* Text that should appear on the button at the bottom of the importer
* form.
*/
public static $button_text = 'Search';
/**
* Generate the filter form.
*
* The base class will generate textfields for each filter defined in $info,
* set defaults, labels and descriptions, as well as, create the search
* button.
*
* Extend this method to alter the filter form.
*/
public function form($form, $form_state) {
$form = parent::form($form, $form_state);
// Add a crop selector.
$this->addCropFormElement($form, $form_state);
// Add a Scientific name selector.
$this->addSpeciesFormElement($form, $form_state);
// Make the marker type a drop-down.
$options = unserialize(variable_get('kp_searches_marker_types', 'a:0{}'));
$form['type']['#type'] = 'select';
$form['type']['#options'] = $options;
$form['type']['#empty_option'] = ' - Select -';
// Make the project an autocomplete.
// DEPENDENCY: nd_genotypes.
$form['project']['#autocomplete_path'] = 'tripal_ajax/nd_genotypes/project/name';
// Add a sequence range element.
$description = 'The range of the genome you would like to display variants from.';
$form['seq_range'] = array(
'#type' => 'markup',
'#prefix' => '<div class="seq-range-element form-item"><label>Genome Range</label>',
'#suffix' => '<div class="description">' . $description . '</div></div>',
);
// Group the sequence range elements.
$form['seq_range']['start-label'] = [
'#type' => 'item',
'#markup' => 'From',
];
$form['seq_range']['start-backbone'] = $form['start-backbone'];
$form['seq_range']['start-backbone']['#attributes']['placeholder'] = 'Sequence Name';
unset($form['start-backbone']);
$form['seq_range']['start-pos'] = $form['start-pos'];
$form['seq_range']['start-pos']['#attributes']['placeholder'] = 'Start Position';
unset($form['start-pos']);
$form['seq_range']['end-label'] = [
'#type' => 'item',
'#markup' => 'to',
];
$form['seq_range']['end-pos'] = $form['end-pos'];
$form['seq_range']['end-pos']['#attributes']['placeholder'] = 'End Position';
unset($form['end-pos']);
return $form;
}
/**
* Allows custom searches to validate the form results.
* Use form_set_error() to signal invalid values.
*/
public function validateForm($form, $form_state) {
$values = $form_state['values'];
// If any of the range elements are filled out...
if ($values['start-backbone'] != ''
OR $values['start-pos'] != ''
OR $values['end-pos'] != '') {
// Then they all need to be!
if ($values['start-backbone'] == '') {
form_set_error('start-backbone',
'Genome Range: The sequence name is required.');
}
if ($values['start-pos'] == '') {
form_set_error('start-pos',
'Genome Range: The range start position is required.');
}
if ($values['end-pos'] == '') {
form_set_error('end-pos',
'Genome Range: The range end position is required.');
}
}
}
/**
* Determine the query for the genetic marker search.
*
* @param string $query
* The full SQL query to execute. This will be executed using chado_query()
* so use curly brackets appropriately. Use :placeholders for any values.
* @param array $args
* An array of arguments to pass to chado_query(). Keys must be the
* placeholders in the query and values should be what you want them set to.
*/
public function getQuery(&$query, &$args, $offset) {
// Retrieve the filter results already set.
$filter_results = $this->values;
// @debug dpm($filter_results, '$filter_results');
$query = "
SELECT
marker.feature_id, marker.name as name,
type.value as type,
olocparent.name||':'||original_loc.fmin||'..'||original_loc.fmax as original_loc,
o.organism_id, o.genus||' '||o.species as species
FROM {feature} marker
LEFT JOIN {organism} o ON o.organism_id=marker.organism_id
LEFT JOIN {featureloc} original_loc ON original_loc.feature_id = marker.feature_id AND original_loc.locgroup=0
LEFT JOIN {feature} olocparent ON olocparent.feature_id=original_loc.srcfeature_id
LEFT JOIN {featureprop} type ON type.feature_id = marker.feature_id
AND type.type_id IN
(SELECT cvterm_id FROM chado.cvterm WHERE name='additionalType') ";
$where = ["marker.type_id IN (SELECT cvterm_id FROM {cvterm} WHERE name='genetic_marker')"];
$joins = [];
// -- Genus.
if ($filter_results['genus'] != '') {
$where[] = "o.genus ~* :genus";
$args[':genus'] = $filter_results['genus'];
}
// -- Species.
if ($filter_results['species'] != '') {
$where[] = "o.species ~* :species";
$args[':species'] = $filter_results['species'];
}
// -- Type.
if ($filter_results['type'] != '') {
$where[] = "type.value ~ :type";
$args[':type'] = $filter_results['type'];
}
// -- Project.
if ($filter_results['project'] != '') {
$where[] = "project.name ~ :project";
$args[':project'] = $filter_results['project'];
$joins[] = 'LEFT JOIN {project_feature} pf ON pf.feature_id=marker.feature_id';
$joins[] = 'LEFT JOIN {project} project ON project.project_id=pf.project_id';
}
// -- Name.
if ($filter_results['name'] != '') {
$where[] = "(marker.name ~ :name OR marker.uniquename = :name)";
$args[':name'] = $filter_results['name'];
}
// -- Genome Range.
if ($filter_results['start-pos'] != ''
AND $filter_results['end-pos'] != '') {
$joins[] = 'LEFT JOIN {featureloc} loc
ON loc.feature_id=marker.feature_id';
$where[] = 'loc.fmin BETWEEN :start AND :end';
$args[':start'] = $filter_results['start-pos'];
$args[':end'] = $filter_results['end-pos'];
$where[] = 'loc.srcfeature_id IN
(SELECT feature_id FROM {feature}
WHERE name=:backbone OR uniquename=:backbone)';
$args[':backbone'] = $filter_results['start-backbone'];
}
// Finally, add it to the query.
if (!empty($joins)) {
$query .= implode("\n",$joins);
}
if (!empty($where)) {
$query .= "\n" . ' WHERE ' . implode(' AND ',$where);
}
// Sort even though it is SLOW b/c ppl expect it.
$query .= "\n" . ' ORDER BY marker.name ASC';
// Handle paging.
$limit = $this::$num_items_per_page + 1;
$query .= "\n" . ' LIMIT ' . $limit . ' OFFSET ' . $offset;
// @debug dpm(strtr(str_replace(['{','}'], ['chado.', ''], $query), $args), 'query');
}
}