| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: project_solr.module,v 1.62 2009/09/22 21:52:30 dww Exp $ 3 4 //---------------------------------------- 5 // Core hooks 6 //---------------------------------------- 7 8 /** 9 * Implementation of hook_menu(). 10 */ 11 function project_solr_menu() { 12 $items = array(); 13 $items['project'] = array( 14 'title' => 'Project summary', 15 'description' => '', 16 'page callback' => 'project_solr_browse_summary_page', 17 'access arguments' => array('access content'), 18 'type' => MENU_NORMAL_ITEM, 19 ); 20 $items['project/%'] = array( 21 'title' => 'Project summary', 22 'description' => '', 23 'page callback' => 'project_solr_browse_page', 24 'page arguments' => array(1), 25 'access arguments' => array('access content'), 26 'type' => MENU_NORMAL_ITEM, 27 ); 28 return $items; 29 } 30 31 /** 32 * Implementation of hook_theme(). 33 */ 34 function project_solr_theme() { 35 return array( 36 'project_solr_no_count_facet_link' => array( 37 'arguments' => array( 38 'facet_text' => NULL, 39 'path' => '', 40 'options' => '', 41 'active' => FALSE, 42 'num_found' => NULL, 43 ), 44 ), 45 ); 46 } 47 48 /** 49 * Implementation of hook_nodeapi(). 50 * 51 * Whenever a release node is edited or submitted, if the node is now 52 * published, reindex the project node associated with that release. 53 */ 54 function project_solr_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { 55 switch ($op) { 56 case 'update': 57 case 'insert': 58 if ($node->type == 'project_release' && $node->status) { 59 apachesolr_mark_node($node->project_release['pid']); 60 } 61 break; 62 } 63 } 64 65 /** 66 * Implementation of hook_form_alter(). 67 */ 68 function project_solr_form_apachesolr_delete_index_form_alter(&$form, $form_state) { 69 $form['reindex_project'] = array( 70 '#type' => 'submit', 71 '#value' => t('Re-index all projects'), 72 '#submit' => array('project_solr_reindex_projects'), 73 ); 74 $form['reindex_project_desc'] = array( 75 '#type' => 'item', 76 '#description' => t('This will only re-index the project content on your site.'), 77 ); 78 } 79 80 function project_solr_reindex_projects($form, $form_state) { 81 db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid IN (SELECT nid FROM {node} WHERE type = 'project_project')", time()); 82 drupal_set_message(t('Marked all project content to be reindexed by Apache Solr.')); 83 } 84 85 //---------------------------------------- 86 // Solr-related hooks 87 //---------------------------------------- 88 89 /** 90 * Implementation of hook_apachesolr_update_index(). 91 * 92 * This adds information about releases for the project to the Solr document 93 * so we can facet on releases (API compatibility terms, usage, etc), along 94 * with other project-specific metadata (e.g. shortname/uri). 95 * 96 * Beware that this hook is invoked for all nodes, so we should be careful in 97 * here to check that we're really dealing with a project node before trying 98 * to access any project-specifc data. 99 */ 100 function project_solr_apachesolr_update_index(&$document, $node) { 101 if (!empty($node->project['uri'])) { 102 $document->ss_project_uri = $node->project['uri']; 103 } 104 if (module_exists('project_release') && !empty($node->project_release['releases'])) { 105 $document->is_project_has_releases = 1; 106 107 $max_filetime = 0; 108 $max_official_filetime = 0; 109 $term_query = db_query("SELECT DISTINCT(tn.tid) FROM {node} n INNER JOIN {project_release_nodes} prn ON n.nid = prn.nid INNER JOIN {term_node} tn ON n.nid = tn.nid INNER JOIN {term_data} td ON tn.tid = td.tid WHERE prn.pid = %d AND td.vid = %d", $node->nid, _project_release_get_api_vid()); 110 while ($term = db_fetch_object($term_query)) { 111 $document->setMultiValue('im_project_release_api_tids', $term->tid); 112 $latest_activity = db_fetch_object(db_query_range("SELECT f.timestamp, prn.rebuild FROM {node} n INNER JOIN {project_release_nodes} prn ON n.nid = prn.nid INNER JOIN {project_release_file} prf ON prn.nid = prf.nid INNER JOIN {term_node} tn ON prn.nid = tn.nid INNER JOIN {files} f ON prf.fid = f.fid WHERE n.status = 1 AND tn.tid = %d AND prn.pid = %d ORDER BY f.timestamp DESC", $term->tid, $node->nid, 0, 1)); 113 $filetime = $latest_activity->timestamp; 114 $key = 'ds_project_latest_activity_'. $term->tid; 115 $document->$key = apachesolr_date_iso($filetime); 116 if ($filetime > $max_filetime) { 117 $max_filetime = $filetime; 118 } 119 120 // Now, look for the most recent official release for this API version. 121 $key = 'ds_project_latest_release_'. $term->tid; 122 if ($latest_activity->rebuild == 0) { 123 // The latest activity is official, we're done. 124 $document->$key = apachesolr_date_iso($filetime); 125 if ($filetime > $max_official_filetime) { 126 $max_official_filetime = $filetime; 127 } 128 } 129 else { 130 $filetime = db_result(db_query_range("SELECT f.timestamp FROM {node} n INNER JOIN {project_release_nodes} prn ON n.nid = prn.nid INNER JOIN {project_release_file} prf ON prn.nid = prf.nid INNER JOIN {term_node} tn ON prn.nid = tn.nid INNER JOIN {files} f ON prf.fid = f.fid WHERE n.status = 1 AND prn.rebuild = 0 AND tn.tid = %d AND prn.pid = %d ORDER BY f.timestamp DESC", $term->tid, $node->nid, 0, 1)); 131 if (!empty($filetime)) { 132 $document->$key = apachesolr_date_iso($filetime); 133 } 134 if ($filetime > $max_official_filetime) { 135 $max_official_filetime = $filetime; 136 } 137 } 138 } 139 $document->ds_project_latest_activity = apachesolr_date_iso($max_filetime); 140 if (!empty($max_official_filetime)) { 141 $document->ds_project_latest_release = apachesolr_date_iso($max_official_filetime); 142 } 143 144 if (module_exists('project_usage')) { 145 $weeks = variable_get('project_usage_active_weeks', array()); 146 $week = reset($weeks); 147 $total_usage = 0; 148 $query = db_query("SELECT * FROM {project_usage_week_project} WHERE nid = %d AND timestamp = %d", $node->nid, $week); 149 while ($usage = db_fetch_object($query)) { 150 $key = 'sis_project_release_usage_'. $usage->tid; 151 $document->$key = $usage->count; 152 $total_usage += $usage->count; 153 } 154 $document->sis_project_release_usage = $total_usage; 155 } 156 } 157 } 158 159 //---------------------------------------- 160 // Page callbacks 161 //---------------------------------------- 162 163 /** 164 * Summary project browsing page. 165 */ 166 function project_solr_browse_summary_page() { 167 $vid = _project_get_vid(); 168 $tree = taxonomy_get_tree($vid, 0, -1, 1); 169 $items = array(); 170 foreach ($tree as $term) { 171 $items[] = theme('project_type', $term); 172 } 173 drupal_set_title(t('Project types')); 174 return theme('item_list', $items); 175 } 176 177 function project_solr_browse_page($term_name) { 178 try { 179 $output = ''; 180 181 $parent_term = db_fetch_object(db_query("SELECT t.tid, t.name, t.description FROM {term_data} t WHERE t.vid = %d AND LOWER(t.name) = LOWER('%s')", _project_get_vid(), $term_name)); 182 183 if (!$parent_term) { 184 // XXX: this is the Drupal 5 way... 185 return drupal_not_found(); 186 } 187 drupal_set_title(check_plain($parent_term->name)); 188 if (!empty($parent_term->description)) { 189 $output .= theme('project_type_description', $parent_term); 190 } 191 192 $text_query = isset($_GET['text']) ? $_GET['text'] : ''; 193 $filters = isset($_GET['filters']) ? $_GET['filters'] : ''; 194 195 $sort = isset($_GET['solrsort']) ? check_plain($_GET['solrsort']) : ''; 196 197 // Validate sort parameter 198 if ((!isset($sort) || !preg_match('/^([a-z0-9_]+ (asc|desc)(,)?)+$/i', $sort)) && empty($text_query)) { 199 $sort = variable_get('project_solr_default_sort', 'sort_title asc'); 200 } 201 202 include_once drupal_get_path('module', 'project_solr') .'/ProjectSolrQuery.php'; 203 204 $query = new ProjectSolrQuery(apachesolr_get_solr(), $text_query, $filters, $sort); 205 if (is_null($query)) { 206 throw new Exception(t('Could not construct a Solr query.')); 207 } 208 209 $query->add_field_aliases(array('im_project_release_api_tids' => 'drupal_core')); 210 211 $params = array( 212 'fl' => 'id,nid,title,body,format,comment_count,type,created,changed,score,url,uid,name,sis_project_release_usage,ds_project_latest_release,ds_project_latest_activity', 213 'rows' => variable_get('apachesolr_rows', 10), 214 'facet' => 'true', 215 'facet.mincount' => 1, 216 'facet.sort' => 'true', 217 'facet.field' => array( 218 'im_vid_'. _project_get_vid(), 219 'im_project_release_api_tids', 220 ), 221 'facet.limit' => 200, 222 ); 223 224 $page = isset($_GET['page']) ? $_GET['page'] : 0; 225 $params['start'] = $page * $params['rows']; 226 227 // This is the object that does the communication with the solr server. 228 $solr = apachesolr_get_solr(); 229 230 // This hook allows modules to modify the query and params objects. 231 apachesolr_modify_query($query, $params, 'project_solr'); 232 if (!$query) { 233 return array(); 234 } 235 236 // Force sort to be by the corresponding core compatibility if filtered. 237 $sort = $query->get_solrsort(); 238 if (in_array($sort['#name'], array('ds_project_latest_release', 'ds_project_latest_activity')) 239 && ($api_filters = $query->get_filters('im_project_release_api_tids'))) { 240 $first_filter = reset($api_filters); 241 $params['sort'] = $sort['#name'] .'_'. $first_filter['#value'] .' '. $sort['#direction']; 242 } 243 244 // We add 'fq' (filter query) parameters here to include all the constant 245 // filters for the query -- project nodes of the given top-level type that 246 // have releases (if project_release is enabled). 247 $fq[] = 'type:project_project'; 248 $fq[] = 'im_vid_'. _project_get_vid() .':'. $parent_term->tid; 249 if (module_exists('project_release')) { 250 $fq[] = 'is_project_has_releases:1'; 251 } 252 $params['fq'][] = '('. implode(' AND ', $fq) .')'; 253 254 $response = $solr->search($query->get_query_basic(), $params['start'], $params['rows'], $params); 255 256 // The response is cached so that it is accessible to the blocks and anything 257 // else that needs it beyond the initial search. 258 $total = $response->response->numFound; 259 260 project_solr_response_cache(array($query, $response, $parent_term)); 261 262 // Set breadcrumb 263 $breadcrumb = menu_get_active_breadcrumb(); 264 drupal_set_breadcrumb($breadcrumb); 265 266 $output .= '<div id="project-overview">'; 267 pager_query("SELECT %d", $params['rows'], 0, NULL, $total); 268 if ($total > 0) { 269 foreach ($response->response->docs as $doc) { 270 $doc->created = strtotime($doc->created); 271 $doc->changed = strtotime($doc->changed); 272 $output .= project_solr_render_search_result($doc); 273 } 274 } 275 else { 276 $output .= t('No projects found in this category.'); 277 } 278 279 $output .= '</div>'; // id="project-overview" 280 $output .= theme('pager', NULL, $params['rows'], 0); 281 } 282 catch (Exception $e) { 283 watchdog('Apache Solr', $e->getMessage(), NULL, WATCHDOG_ERROR); 284 apachesolr_failure(t('Solr search'), is_null($query) ? $keys : $query->get_query_basic()); 285 } 286 287 return $output; 288 } 289 290 function project_solr_response_cache($set = FALSE) { 291 static $cache = NULL; 292 if ($set !== FALSE) { 293 $cache = $set; 294 } 295 return $cache; 296 } 297 298 //---------------------------------------- 299 // Blocks 300 //---------------------------------------- 301 302 /** 303 * Implementation of hook_block(). 304 */ 305 function project_solr_block($op = 'list', $delta = 0, $edit = array()) { 306 if ($op == 'list') { 307 return array( 308 'project_solr_categories' => array( 309 'info' => t('Project: categories'), 310 'cache' => BLOCK_CACHE_PER_PAGE, 311 ), 312 'project_solr_order' => array( 313 'info' => t('Project: ordering'), 314 'cache' => BLOCK_CACHE_PER_PAGE, 315 ), 316 'project_solr_compability' => array( 317 'info' => t('Project: core compatibility'), 318 'cache' => BLOCK_CACHE_PER_PAGE, 319 ), 320 'project_solr_text' => array( 321 'info' => t('Project: text search'), 322 'cache' => BLOCK_CACHE_PER_PAGE, 323 ), 324 ); 325 } 326 327 if ($op == 'view' && ($search = project_solr_response_cache())) { 328 list($query, $response, $parent_term) = $search; 329 330 if ($delta == 'project_solr_categories') { 331 $facet = 'im_vid_'. _project_get_vid(); 332 $terms = array(); 333 334 // Get the terms at the current depth. 335 $current_tid = $parent_term->tid; 336 foreach ($query->get_filters() as $filter) { 337 if ($filter['#name'] == 'tid') { 338 $current_tid = $filter['#value']; 339 break; 340 } 341 } 342 $current_level_terms = array(); 343 $tree = taxonomy_get_tree(_project_get_vid(), $current_tid, -1, 1); 344 foreach ($tree as $term) { 345 $current_level_terms[$term->tid] = $term; 346 } 347 348 foreach ($response->facet_counts->facet_fields->$facet as $tid => $count) { 349 $active = $query->has_filter('tid', $tid); 350 if (!isset($current_level_terms[$tid]) && (!$active || $tid != $current_tid)) { 351 continue; 352 } 353 $unclick_link = ''; 354 $term = taxonomy_get_term($tid); 355 $new_query = clone $query; 356 357 $path = 'project/' . drupal_strtolower($parent_term->name); 358 $options = array(); 359 if ($active) { 360 $new_query->remove_filter('tid', $term->tid); 361 $options['query'] = $new_query->get_url_queryvalues(); 362 $link = theme('apachesolr_unclick_link', $term->name, $path, $options); 363 } 364 else { 365 $new_query->add_filter('tid', $term->tid); 366 $options['query'] = $new_query->get_url_queryvalues(); 367 $link = theme('apachesolr_facet_link', $term->name, $path, $options, $count, $active, $response->numFound); 368 } 369 $countsort = $count == 0 ? '' : 1 / $count; 370 // if numdocs == 1 and !active, don't add. 371 if ($response->numFound == 1 && !$active) { 372 // skip 373 } 374 else { 375 $terms[$active ? $countsort . $term->name : 1 + $countsort . $term->name] = $link; 376 } 377 } 378 $vocab = taxonomy_vocabulary_load(_project_get_vid()); 379 380 if (!empty($terms)) { 381 ksort($terms); 382 383 // The currently selected term should be first. 384 if (isset($terms[$current_tid])) { 385 $current_term = $terms[$current_tid]; 386 unset($terms[$current_tid]); 387 $terms = array_merge(array($current_tid => $current_term), $terms); 388 } 389 390 return array( 391 'subject' => $vocab->name, 392 'content' => theme('apachesolr_facet_list', $terms, 200), 393 ); 394 } 395 return; 396 } 397 else if ($delta == 'project_solr_order') { 398 $sorts = $query->default_sorts(); 399 $solrsort = $query->get_solrsort(); 400 401 $sort_links = array(); 402 $path = 'project/' . drupal_strtolower($parent_term->name); 403 $new_query = clone $query; 404 $toggle = array('asc' => 'desc', 'desc' => 'asc'); 405 foreach ($sorts as $name => $sort) { 406 $active = $solrsort['#name'] == $name; 407 $direction = $active ? $solrsort['#direction'] : ''; 408 $new_direction = $active ? $toggle[$direction] : $sort['default']; 409 $new_query->set_solrsort($name, $new_direction); 410 $sort_links[] = theme('apachesolr_sort_link', $sort['title'], $path, array('query' => $new_query->get_url_queryvalues()), $active, $direction); 411 } 412 return array( 413 'subject' => t('Sort by'), 414 'content' => theme('apachesolr_sort_list', $sort_links), 415 ); 416 } 417 else if (module_exists('project_release') && $delta == 'project_solr_compability') { 418 $vid = _project_release_get_api_vid(); 419 $facet = 'im_project_release_api_tids'; 420 $terms = array(); 421 $active_terms = array_reverse(project_release_compatibility_list(FALSE), TRUE); 422 423 $active_term_counts = array(); 424 foreach ($response->facet_counts->facet_fields->$facet as $tid => $count) { 425 if (!empty($active_terms[$tid])) { 426 $active_term_counts[$tid] = $count; 427 } 428 } 429 430 foreach ($active_terms as $tid => $term_name) { 431 if (!empty($active_term_counts[$tid])) { 432 $active = $query->has_filter('im_project_release_api_tids', $tid); 433 $path = 'project/' . drupal_strtolower($parent_term->name); 434 $new_query = clone $query; 435 $new_query->remove_filter('im_project_release_api_tids', $term->tid); 436 $options = array(); 437 if ($active) { 438 $options['query'] = $new_query->get_url_queryvalues(); 439 $link = theme('apachesolr_unclick_link', $term_name, $path, $options); 440 } 441 else { 442 $new_query->add_filter('im_project_release_api_tids', $tid); 443 $options['query'] = project_solr_append_api_term($new_query->get_url_queryvalues(), $tid); 444 $link = theme('project_solr_no_count_facet_link', $term_name, $path, $options, $active, $response->response->numFound); 445 } 446 $terms[$term_name] = $link; 447 } 448 } 449 450 if (!empty($terms)) { 451 return array( 452 'subject' => t('Filter by compatibility'), 453 'content' => theme('apachesolr_facet_list', $terms, 200), 454 ); 455 } 456 return; 457 } 458 else if ($delta == 'project_solr_text') { 459 return array( 460 'subject' => t('Search @project_type', array('@project_type' => drupal_strtolower($parent_term->name))), 461 'content' => drupal_get_form('project_sort_freetext'), 462 ); 463 } 464 } 465 } 466 467 /** 468 * Append the API tid to selected fields that might be in the string. 469 */ 470 function project_solr_append_api_term($values, $tid) { 471 $api_fields = array('ds_project_latest_release', 'sis_project_release_usage', 'ds_project_latest_activity'); 472 foreach($values as $k => $v) { 473 if (in_array($k, $api_fields)) { 474 unset($values[$k]); 475 $values[$k . '_' . $tid] = $v; 476 } 477 } 478 return $values; 479 } 480 481 /** 482 * Form callback; display a free text form. 483 */ 484 function project_sort_freetext() { 485 list($query, $response, $parent_term) = project_solr_response_cache(); 486 487 $form = array(); 488 $form['text'] = array( 489 '#type' => 'textfield', 490 '#default_value' => $_GET['querypath'], 491 '#size' => 20, 492 ); 493 $form['path'] = array( 494 '#type' => 'value', 495 '#value' => 'project/' . drupal_strtolower($parent_term->name), 496 ); 497 $form['query'] = array( 498 '#type' => 'value', 499 '#value' => $query, 500 ); 501 $form['submit'] = array( 502 '#type' => 'submit', 503 '#value' => t('Submit'), 504 ); 505 return $form; 506 } 507 508 /** 509 * Submit handler for project_sort_freetext(). 510 */ 511 function project_sort_freetext_submit($form, &$form_state) { 512 $query = $form_state['values']['query']; 513 $queryvalues = $query->get_url_queryvalues(); 514 $queryvalues['text'] = $form_state['values']['text']; 515 unset($queryvalues['solrsort']); 516 $form_state['redirect'] = array($form_state['values']['path'], $queryvalues); 517 } 518 519 //---------------------------------------- 520 // Theme-related functions 521 //---------------------------------------- 522 523 /** 524 * Perform the business logic to 525 */ 526 function project_solr_render_search_result($result) { 527 $project = node_load($result->nid); 528 $project = node_build_content($project, TRUE, FALSE); 529 $project->body = $project->teaser; 530 $project->solr_result = $result; 531 532 if (!empty($project->project_release['releases'])) { 533 $project->download_table = project_release_table($project, 'recommended', 'all', t('Version'), FALSE, FALSE); 534 } 535 536 $project->links = array(); 537 $project->links['read_more'] = array( 538 'title' => t('Find out more'), 539 'href' => "node/$project->nid", 540 ); 541 if (!empty($project->project_issue['issues'])) { 542 $project->links['issues'] = array( 543 'title' => t('Bugs and feature requests'), 544 'href' => 'project/issues/'. $project->project['uri'], 545 ); 546 } 547 return theme('project_summary', $project); 548 } 549 550 function theme_project_solr_no_count_facet_link($facet_text, $path, $options = array(), $active = FALSE, $num_found = NULL) { 551 $options['attributes']['class'][] = 'apachesolr-facet'; 552 if ($active) { 553 $options['attributes']['class'][] = 'active'; 554 } 555 $options['attributes']['class'] = implode(' ', $options['attributes']['class']); 556 return apachesolr_l($facet_text, $path, $options); 557 } 558
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |