[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/project/solr/ -> project_solr.module (source)

   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  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7