Newer
Older
<?php
// $Id$
/**
* @file
* Provide views data and handlers for search.module
*/
/**
* @defgroup views_search_module search.module handlers
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
*
* Includes the tables 'search_index'
* @{
*/
/**
* Implementation of hook_views_data()
*/
function search_views_data() {
// Basic table information.
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
$data['search_index']['table']['group'] = t('Search');
// For other base tables, explain how we join
$data['search_index']['table']['join'] = array(
'node' => array(
'left_field' => 'nid',
'field' => 'sid',
),
'users' => array(
'left_field' => 'uid',
'field' => 'sid',
),
);
$data['search_total']['table']['join'] = array(
'node' => array(
'left_table' => 'search_index',
'left_field' => 'word',
'field' => 'word',
),
'users' => array(
'left_table' => 'search_index',
'left_field' => 'word',
'field' => 'word',
)
);
$data['search_dataset']['table']['join'] = array(
'node' => array(
'left_table' => 'search_index',
'left_field' => 'sid',
'field' => 'sid',
),
'users' => array(
'left_table' => 'search_index',
'left_field' => 'sid',
'field' => 'sid',
),
);
// ----------------------------------------------------------------
// Fields
// score
$data['search_index']['score'] = array(
'title' => t('Score'), // The item it appears as on the UI,
'help' => t('The score of the search item.'), // The help that appears on the UI,
// Information for displaying a title as a field
'field' => array(
'field' => 'score', // the real field
'group' => t('Search'), // The group it appears in on the UI,
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
// Information for sorting on a search score.
'sort' => array(
'handler' => 'views_handler_sort',
),
);
Earl Miles
committed
// Search node links: forward links.
$data['search_node_links_from']['table']['group'] = t('Search');
$data['search_node_links_from']['table']['join'] = array(
'node' => array(
'arguments' => array('search_node_links', 'node', 'nid', 'nid', NULL, 'INNER'),
),
);
$data['search_node_links_from']['sid'] = array(
'title' => t('Links from'),
'help' => t('Nodes that link from the node.'),
Earl Miles
committed
'handler' => 'views_handler_argument_node_nid',
),
'filter' => array(
'handler' => 'views_handler_filter_equality',
Earl Miles
committed
// Search node links: backlinks.
$data['search_node_links_to']['table']['group'] = t('Search');
$data['search_node_links_to']['table']['join'] = array(
'node' => array(
'arguments' => array('search_node_links', 'node', 'nid', 'sid', NULL, 'INNER'),
),
);
$data['search_node_links_to']['nid'] = array(
'title' => t('Links to'),
'help' => t('Nodes that link to the node.'),
Earl Miles
committed
'handler' => 'views_handler_argument_node_nid',
),
'filter' => array(
'handler' => 'views_handler_filter_equality',
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
),
);
// search filter
$data['search_index']['keys'] = array(
'title' => t('Search Terms'), // The item it appears as on the UI,
'help' => t('The terms to search for.'), // The help that appears on the UI,
// Information for searching terms using the full search syntax
'filter' => array(
'handler' => 'views_handler_filter_search',
),
);
return $data;
}
/**
* Field handler to provide simple renderer that allows linking to a node.
*
* @ingroup views_field_handlers
*/
class views_handler_filter_search extends views_handler_filter {
/**
* Provide basic defaults for the equality operator
*/
function options(&$options) {
parent::options($options);
$options['operator'] = 'optional';
$options['value'] = '';
}
/**
* Provide simple equality operator
*/
function operator_form(&$form, &$form_state) {
$form['operator'] = array(
'#type' => 'radios',
'#title' => t('On empty input'),
'#default_value' => $this->operator,
'#options' => array(
'optional' => t('Show All'),
'required' => t('Show None'),
),
);
}
/**
* Provide a simple textfield for equality
*/
function exposed_form(&$form, &$form_state) {
$key = $this->options['expose']['identifier'];
$form[$key] = array(
'#type' => 'textfield',
'#title' => t('Search'),
'#size' => 15,
'#default_value' => $this->value,
'#attributes' => array('title' => t('Enter the terms you wish to search for.')),
);
}
/**
* Validate the options form.
*/
function exposed_validate($form, &$form_state) {
$key = $this->options['expose']['identifier'];
if (!empty($form_state['values'][$key])) {
$this->search_query = search_parse_query($form_state['values'][$key]);
$this->search_query[0] = str_replace('d.', 'search_data.', $this->search_query[0]);
$this->search_query[2] = str_replace('i.', 'search_index.', $this->search_query[2]);
if ($this->search_query[2] == '') {
form_set_error($key, t('You must include at least one positive keyword with @count characters or more.', array('@count' => variable_get('minimum_word_size', 3))));
}
if ($this->search_query[6]) {
if ($this->search_query[6] == 'or') {
drupal_set_message(t('Search for either of the two terms with uppercase <strong>OR</strong>. For example, <strong>cats OR dogs</strong>.'));
}
}
}
}
/**
* Add this filter to the query.
*
* Due to the nature of fapi, the value and the operator have an unintended
* level of indirection. You will find them in $this->operator
* and $this->value respectively.
*/
function query() {
$this->ensure_my_table();
if (!isset($this->search_query)) {
if ($this->operator == 'required') {
$this->query->add_where($this->options['group'], '0');
}
}
else {
$join = new views_join;
$join->construct('search_total', 'search_index', 'word', 'word');
$this->query->add_relationship(NULL, $join, 'search_index');
# $this->query->add_table('search_total', 'search_index', $join);
$this->query->add_field('', "SUM(search_index.score * search_total.count)", 'score');
$this->query->add_where($this->options['group'], $this->search_query[2], $this->search_query[3]);
$this->query->add_where($this->options['group'], "search_index.type = '%s'", $this->view->base_table);
if (!$this->search_query[5]) {
$join = new views_join_search_dataset;
$join->construct();
$this->query->add_relationship(NULL, $join, 'search_index');
$this->query->add_table('search_dataset', 'search_index', $join);
$this->query->add_where($this->options['group'], $this->search_query[0], $this->search_query[1]);
}
// @note: i don't think that this needed since we restrict based on type
// $this->query->add_groupby('node.type'); // isn't this the same as search_index.type?
$this->query->add_groupby("search_index.sid");
$this->query->add_having($this->options['group'], 'COUNT(*) >= %d', $this->search_query[4]);
// @todo: normalize the score
}
}
}
class views_join_search_dataset extends views_join {
function construct() {
parent::construct('search_dataset', 'sid', array(), 'LEFT');
}
function join($table, &$query) {
$output = parent::join($table, $query);
$output .= " AND table[alias].type = search_dataset.type";
return $output;
}
}
/**
* @}
*/
/**
* Implementation of hook_views_plugins
*/
function search_views_plugins() {
return array(
'module' => 'views', // This just tells our themes are elsewhere.
'row' => array(
'search' => array(
'title' => t('Search'),
'help' => t('Display the results with standard search view.'),
'handler' => 'views_plugin_row_search_view',
'theme' => 'views_view_row_search',
'base' => array('node'), // only works with 'node' as base.
),
),
);
}
/**
* Plugin which performs a node_view on the resulting object.
*
* @ingroup views_row_plugins
*/
class views_plugin_row_search_view extends views_plugin_row {
function options(&$options) {
$options['score'] = TRUE;
}
function options_form(&$form, &$form_state) {
$form['score'] = array(
'#type' => 'checkbox',
'#title' => t('Display score'),
'#default_value' => $this->options['score'],
);
}
/**
* Override the behavior of the render() function.
*/
function render($row) {
Earl Miles
committed
return theme($this->theme_functions(), $this->view, $this->options, $row);
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
}
}
/**
* Template helper for theme_views_view_row_search
*/
function template_preprocess_views_view_row_search(&$vars) {
$vars['node'] = ''; // make sure var is defined.
$nid = $vars['row']->nid;
if (!is_numeric($nid)) {
return;
}
$node = node_load($nid);
if (empty($node)) {
return;
}
// Build the node body.
$node = node_build_content($node, FALSE, FALSE);
$node->body = drupal_render($node->content);
// Fetch comments for snippet
$node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
// Fetch terms for snippet
$node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
$vars['url'] = url('node/'. $nid);
$vars['title'] = check_plain($node->title);
$info = array();
$info['type'] = node_get_types('name', $node);
$info['user'] = theme('username', $node);
$info['date'] = format_date($node->changed, 'small');
$extra = node_invoke_nodeapi($node, 'search result');
if (isset($extra) && is_array($extra)) {
$info = array_merge($info, $extra);
}
$vars['info_split'] = $info;
$vars['info'] = implode(' - ', $info);
$vars['node'] = $node;
// @todo: get score from ???
//$vars['score'] = $item->score;
$vars['snippet'] = search_excerpt($vars['view']->value, $node->body);
}
/**
* @}
*/