[ Root ] [ Search ] [ Index ]

PHP Cross Reference of bbPress Trunk

Provided by Yoast

title

Body

[close]

/bb-includes/ -> class.bb-query.php (source)

   1  <?php
   2  
   3  class BB_Query {
   4      var $type;
   5      var $query;
   6      var $query_id;
   7  
   8      var $query_vars = array();
   9      var $not_set = array();
  10      var $request;
  11      var $match_query = false;
  12  
  13      var $results;
  14      var $errors;
  15      var $count = 0;
  16      var $found_rows = false;
  17  
  18      // Can optionally pass unique id string to help out filters
  19  	function BB_Query( $type = 'topic', $query = '', $id = '' ) {
  20          $this->init( $type, $query, $id );
  21  
  22          if ( !empty($this->query) )
  23              $this->query();
  24      }
  25  
  26  	function init( $type = null, $query = null, $id = null ) {
  27          if ( !is_null($type) || !isset($this->type) )
  28              $this->type = is_null($type) ? 'topic' : $type;
  29          if ( !is_null($query) || !isset($this->query) )
  30              $this->query = $query;
  31          if ( !is_null($id) || !isset($this->query_id) )
  32              $this->query_id = $id;
  33  
  34          $this->query_vars = array();
  35          $this->not_set = array();
  36          unset($this->request);
  37          $this->match_query = false;
  38  
  39          unset($this->results, $this->errors);
  40          $this->count = 0;
  41          $this->found_rows = false;
  42      }
  43  
  44      function &query() {
  45          global $bbdb;
  46  
  47          if ( $args = func_get_args() )
  48              call_user_func_array( array(&$this, 'init'), $args );
  49  
  50          if ( !$this->generate_query() )
  51              return;
  52  
  53          do_action_ref_array( 'bb_query', array(&$this) );
  54  
  55          $key = md5( $this->request );
  56          if ( false === $cached_ids = wp_cache_get( $key, 'bb_query' ) ) {
  57              if ( 'post' == $this->type ) {
  58                  $this->results = bb_cache_posts( $this->request ); // This always appends meta
  59                  $_the_id = 'post_id';
  60                  $this->query_vars['append_meta'] = false;
  61              } else {
  62                  $this->results = $bbdb->get_results( $this->request );
  63                  $_the_id = 'topic_id';
  64              }
  65              $cached_ids = array();
  66              if ( is_array($this->results) )
  67                  foreach ( $this->results as $object )
  68                      $cached_ids[] = $object->$_the_id;
  69              wp_cache_set( $key, $cached_ids, 'bb_query' );
  70          } else {
  71              if ( 'post' == $this->type ) {
  72                  $_query_ids = array();
  73                  $_cached_posts = array();
  74                  foreach ( $cached_ids as $_cached_id ) {
  75                      if ( false !== $_post = wp_cache_get( $_cached_id, 'bb_post' ) ) {
  76                          $_cached_posts[$_post->post_id] = $_post;
  77                      } else {
  78                          $_query_ids[] = $_cached_id;
  79                      }
  80                  }
  81                  if ( count( $_query_ids ) ) {
  82                      $_query_ids = join( ',', array_map( 'intval', $_query_ids ) );
  83                      $results = $bbdb->get_results( "SELECT * FROM $bbdb->posts WHERE post_id IN($_query_ids)" );
  84                      $results = array_merge( $results, $_cached_posts );
  85                  } else {
  86                      $results = $_cached_posts;
  87                  }
  88                  $_the_id = 'post_id';
  89              } else {
  90                  $_query_ids = array();
  91                  $_cached_topics = array();
  92                  foreach ( $cached_ids as $_cached_id ) {
  93                      if ( false !== $_topic = wp_cache_get( $_cached_id, 'bb_topic' ) ) {
  94                          $_cached_topics[$_topic->topic_id] = $_topic;
  95                      } else {
  96                          $_query_ids[] = $_cached_id;
  97                      }
  98                  }
  99                  if ( count( $_query_ids ) ) {
 100                      $_query_ids = join( ',', array_map( 'intval', $_query_ids ) );
 101                      $results = $bbdb->get_results( "SELECT * FROM $bbdb->topics WHERE topic_id IN($_query_ids)" );
 102                      $results = array_merge( $results, $_cached_topics );
 103                  } else {
 104                      $results = $_cached_topics;
 105                  }
 106                  $_the_id = 'topic_id';
 107              }
 108  
 109              $this->results = array();
 110              $trans = array();
 111  
 112              foreach ( $results as $object )
 113                  $trans[$object->$_the_id] = $object;
 114              foreach ( $cached_ids as $cached_id )
 115                  $this->results[] = $trans[$cached_id];
 116          }
 117  
 118          $this->count = count( $this->results );
 119  
 120          if ( false === $this->found_rows && $this->query_vars['count'] ) // handles FOUND_ROWS() or COUNT(*)
 121              $this->found_rows = bb_count_last_query( $this->request );
 122          if ( 'post' == $this->type ) {
 123              if ( $this->query_vars['append_meta'] )
 124                  $this->results = bb_append_meta( $this->results, 'post' );
 125              if ( $this->query_vars['cache_users'] )
 126                  bb_post_author_cache( $this->results );
 127              if ( $this->query_vars['cache_topics'] )
 128                  bb_cache_post_topics( $this->results );
 129          } else {
 130              if ( $this->query_vars['append_meta'] )
 131                  $this->results = bb_append_meta( $this->results, 'topic' );
 132          }
 133  
 134          return $this->results;
 135      }
 136  
 137  	function generate_query() {
 138          if ( $args = func_get_args() )
 139              call_user_func_array( array(&$this, 'init'), $args );
 140  
 141          $this->parse_query();
 142  
 143          // Allow filter to abort query
 144          if ( false === $this->query_vars )
 145              return false;
 146  
 147          if ( 'post' == $this->type )
 148              $this->generate_post_sql();
 149          else
 150              $this->generate_topic_sql();
 151  
 152          return $this->request;
 153      }
 154  
 155      // $defaults = vars to use if not set in GET, POST or allowed
 156      // $allowed = array( key_name => value, key_name, key_name, key_name => value );
 157      //     key_name => value pairs override anything from defaults, GET, POST
 158      //    Lone key_names are a whitelist.  Only those can be set by defaults, GET, POST
 159      //    If there are no lone key_names, allow everything but still override with key_name => value pairs
 160      //    Ex: $allowed = array( 'topic_status' => 0, 'post_status' => 0, 'topic_author', 'started' );
 161      //        Will only take topic_author and started values from defaults, GET, POST and will query with topic_status = 0 and post_status = 0
 162      function &query_from_env( $type = 'topic', $defaults = null, $allowed = null, $id = '' ) {
 163          $this->init_from_env( $type, $defaults, $allowed, $id );
 164          return $this->query();
 165      }
 166  
 167  	function init_from_env( $type = 'topic', $defaults = null, $allowed = null, $id = '' ) {
 168          $vars = $this->fill_query_vars( array() );
 169  
 170          $defaults  = wp_parse_args($defaults);
 171          $get_vars  = stripslashes_deep( $_GET );
 172          $post_vars = stripslashes_deep( $_POST );
 173          $allowed   = wp_parse_args($allowed);
 174  
 175          $_allowed = array();
 176          foreach ( array_keys($allowed) as $k ) {
 177              if ( is_numeric($k) ) {
 178                  $_allowed[] = $allowed[$k];
 179                  unset($allowed[$k]);
 180              } elseif ( !isset($$k) ) {
 181                  $$k = $allowed[$k];
 182              }
 183          }
 184  
 185          extract($post_vars, EXTR_SKIP);
 186          extract($get_vars, EXTR_SKIP);
 187          extract($defaults, EXTR_SKIP);
 188  
 189          $vars = $_allowed ? compact($_allowed, array_keys($allowed)) : compact(array_keys($vars));
 190  
 191          $this->init( $type, $vars, $id );
 192      }
 193  
 194  	function fill_query_vars( $array ) {
 195          // Should use 0, '' for empty values
 196          // Function should return false iff not set
 197  
 198          // parameters commented out are handled farther down
 199  
 200          $ints = array(
 201  //            'page',        // Defaults to global or number in URI
 202  //            'per_page',    // Defaults to page_topics
 203              'tag_id',    // one tag ID
 204              'favorites'    // one user ID
 205          );
 206  
 207          $parse_ints = array(
 208              // Both
 209              'post_id',
 210              'topic_id',
 211              'forum_id',
 212  
 213              // Topics
 214              'topic_author_id',
 215              'post_count',
 216              'tag_count',
 217  
 218              // Posts
 219              'post_author_id',
 220              'position'
 221          );
 222  
 223          $dates = array(
 224              'started',    // topic
 225              'updated',    // topic
 226              'posted'    // post
 227          );
 228  
 229          $others = array(
 230              // Both
 231              'topic',    // one topic name
 232              'forum',    // one forum name
 233              'tag',        // one tag name
 234  
 235              // Topics
 236              'topic_author',    // one username
 237              'topic_status',    // *normal, deleted, all, parse_int ( and - )
 238              'open',            // *all, yes = open, no = closed, parse_int ( and - )
 239              'sticky',        // *all, no = normal, forum, super = front, parse_int ( and - )
 240              'meta_key',        // one meta_key ( and - )
 241              'meta_value',    // range
 242              'topic_title',    // LIKE search.  Understands "doublequoted strings"
 243              'search',        // generic search: topic_title OR post_text
 244                              // Can ONLY be used in a topic query
 245                              // Returns additional search_score and (concatenated) post_text columns
 246  
 247              // Posts
 248              'post_author',    // one username
 249              'post_status',    // *noraml, deleted, all, parse_int ( and - )
 250              'post_text',    // FULLTEXT search
 251                              // Returns additional search_score column (and (concatenated) post_text column if topic query)
 252              'poster_ip',    // one IPv4 address
 253  
 254              // SQL
 255              'index_hint',    // A full index hint using valid index hint syntax, can be multiple hints an array
 256              'order_by',        // fieldname
 257              'order',        // *DESC, ASC
 258              'count',        // *false = none, true = COUNT(*), found_rows = FOUND_ROWS()
 259              '_join_type',    // not implemented: For benchmarking only.  Will disappear. join (1 query), in (2 queries)
 260  
 261              // Utility
 262  //            'append_meta',    // *true, false: topics only
 263  //            'cache_users',    // *true, false
 264  //            'cache_topics,    // *true, false: posts only
 265              'cache_posts'    // not implemented: none, first, last
 266          );
 267  
 268          foreach ( $ints as $key )
 269              if ( ( false === $array[$key] = isset($array[$key]) ? (int) $array[$key] : false ) && isset($this) )
 270                  $this->not_set[] = $key;
 271  
 272          foreach ( $parse_ints as $key )
 273              if ( ( false === $array[$key] = isset($array[$key]) ? preg_replace( '/[^<=>0-9,-]/', '', $array[$key] ) : false ) && isset($this) )
 274                  $this->not_set[] = $key;
 275  
 276          foreach ( $dates as $key )
 277              if ( ( false === $array[$key] = isset($array[$key]) ? preg_replace( '/[^<>0-9-]/', '', $array[$key] ) : false ) && isset($this) )
 278                  $this->not_set[] = $key;
 279  
 280          foreach ( $others as $key ) {
 281              if ( !isset($array[$key]) )
 282                  $array[$key] = false;
 283              if ( isset($this) && false === $array[$key] )
 284                  $this->not_set[] = $key;
 285          }
 286  
 287          // Both
 288          if ( isset($array['page']) )
 289              $array['page'] = (int) $array['page'];
 290          elseif ( isset($GLOBALS['page']) )
 291              $array['page'] = (int) $GLOBALS['page'];
 292          else
 293              $array['page'] = bb_get_uri_page();
 294  
 295          if ( $array['page'] < 1 )
 296              $array['page'] = 1;
 297  
 298          $array['per_page'] = isset($array['per_page']) ? (int) $array['per_page'] : 0;
 299          if ( $array['per_page'] < -1 )
 300              $array['per_page'] = 1;
 301  
 302          // Posts
 303          if ( ( !$array['poster_ip'] = isset($array['poster_ip']) ? preg_replace("@[^0-9a-f:.]@i", '', $array['poster_ip']) : false ) && isset($this) ) {
 304              $this->not_set[] = 'poster_ip';
 305              $array['poster_ip'] = false;
 306          }
 307  
 308          // Utility
 309          $array['append_meta']  = isset($array['append_meta'])  ? (int) (bool) $array['append_meta']  : 1;
 310          $array['cache_users']  = isset($array['cache_users'])  ? (int) (bool) $array['cache_users']  : 1;
 311          $array['cache_topics'] = isset($array['cache_topics']) ? (int) (bool) $array['cache_topics'] : 1;
 312  
 313          // Only one FULLTEXT search per query please
 314          if ( $array['search'] )
 315              $array['post_text'] = false;
 316  
 317          return $array;
 318      }
 319  
 320      // Parse a query string and set query flag booleans.
 321  	function parse_query() {
 322          if ( $args = func_get_args() )
 323              call_user_func_array( array(&$this, 'init'), $args );
 324  
 325          if ( is_array($this->query) )
 326              $this->query_vars = $this->query;
 327          else
 328              wp_parse_str($this->query, $this->query_vars);
 329  
 330          do_action_ref_array('bb_parse_query', array(&$this));
 331  
 332          if ( false === $this->query_vars )
 333              return;
 334  
 335          $this->query_vars = $this->fill_query_vars($this->query_vars);
 336      }
 337  
 338  	function get($query_var) {
 339          return isset($this->query_vars[$query_var]) ? $this->query_vars[$query_var] : null;
 340      }
 341  
 342  	function set($query_var, $value) {
 343          $this->query_vars[$query_var] = $value;
 344      }
 345  
 346  	function generate_topic_sql( $_part_of_post_query = false ) {
 347          global $bbdb;
 348  
 349          $q =& $this->query_vars;
 350          $distinct = '';
 351          $sql_calc_found_rows = 'found_rows' === $q['count'] ? 'SQL_CALC_FOUND_ROWS' : ''; // unfiltered
 352          $fields = 't.*';
 353          $index_hint = '';
 354          $join = '';
 355          $where = '';
 356          $group_by = '';
 357          $having = '';
 358          $order_by = '';
 359  
 360          $post_where = '';
 361          $post_queries = array('post_author_id', 'post_author', 'posted', 'post_status', 'position', 'post_text', 'poster_ip');
 362  
 363          if ( !$_part_of_post_query && ( $q['search'] || array_diff($post_queries, $this->not_set) ) ) :
 364              $join .= " JOIN $bbdb->posts as p ON ( t.topic_id = p.topic_id )";
 365              $post_where = $this->generate_post_sql( true );
 366              if ( $q['search'] ) {
 367                  $post_where .= ' AND ( ';
 368                  $post_where .= $this->generate_topic_title_sql( $q['search'] );
 369                  $post_where .= ' OR ';
 370                  $post_where .= $this->generate_post_text_sql( $q['search'] );
 371                  $post_where .= ' )';
 372              }
 373  
 374              $group_by = 't.topic_id';
 375  
 376              $fields .= ", MIN(p.post_id) as post_id";
 377  
 378              if ( $bbdb->has_cap( 'GROUP_CONCAT', $bbdb->posts ) )
 379                  $fields .= ", GROUP_CONCAT(p.post_text SEPARATOR ' ') AS post_text";
 380              else
 381                  $fields .= ", p.post_text";
 382  
 383              if ( $this->match_query ) {
 384                  $fields .= ", AVG($this->match_query) AS search_score";
 385                  if ( !$q['order_by'] )
 386                      $q['order_by'] = 'search_score';
 387              } elseif ( $q['search'] || $q['post_text'] ) {
 388                  $fields .= ", 0 AS search_score";
 389              }
 390          endif;
 391  
 392          if ( !$_part_of_post_query ) :
 393              if ( $q['post_id'] ) :
 394                  $post_topics = $post_topics_no = array();
 395                  $op = substr($q['post_id'], 0, 1);
 396                  if ( in_array($op, array('>','<')) ) :
 397                      $post_topics = $bbdb->get_col( "SELECT DISTINCT topic_id FROM $bbdb->posts WHERE post_id $op '" . (int) substr($q['post_id'], 1) . "'" );
 398                  else :
 399                      $posts = explode(',', $q['post_id']);
 400                      $get_posts = array();
 401                      foreach ( $posts as $post_id ) {
 402                          $post_id = (int) $post_id;
 403                          $_post_id = abs($post_id);
 404                          $get_posts[] = $_post_id;
 405                      }
 406                      bb_cache_posts( $get_posts );
 407  
 408                      foreach ( $posts as $post_id ) :
 409                          $post = bb_get_post( abs($post_id) );
 410                          if ( $post_id < 0 )
 411                              $post_topics_no[] = $post->topic_id;
 412                          else
 413                              $post_topics[] = $post->topic_id;
 414                      endforeach;
 415                  endif;
 416                  if ( $post_topics )
 417                      $where .= " AND t.topic_id IN (" . join(',', $post_topics) . ")";
 418                  if ( $post_topics_no )
 419                      $where .= " AND t.topic_id NOT IN (" . join(',', $post_topics_no) . ")";
 420              endif;
 421  
 422              if ( $q['topic_id'] ) :
 423                  $where .= $this->parse_value( 't.topic_id', $q['topic_id'] );
 424              elseif ( $q['topic'] ) :
 425                  $q['topic'] = bb_slug_sanitize( $q['topic'] );
 426                  $where .= " AND t.topic_slug = '$q[topic]'";
 427              endif;
 428  
 429              if ( $q['forum_id'] ) :
 430                  $where .= $this->parse_value( 't.forum_id', $q['forum_id'] );
 431              elseif ( $q['forum'] ) :
 432                  if ( !$q['forum_id'] = bb_get_id_from_slug( 'forum', $q['forum'] ) )
 433                      $this->error( 'query_var:forum', 'No forum by that name' );
 434                  $where .= " AND t.forum_id = $q[forum_id]";
 435              endif;
 436  
 437              if ( $q['tag'] && !is_int($q['tag_id']) )
 438                  $q['tag_id'] = (int) bb_get_tag_id( $q['tag'] );
 439  
 440              if ( is_numeric($q['tag_id']) ) :
 441                  $join .= " JOIN `$bbdb->term_relationships` AS tr ON ( t.`topic_id` = tr.`object_id` AND tr.`term_taxonomy_id` = $q[tag_id] )";
 442              endif;
 443  
 444              if ( is_numeric($q['favorites']) && $f_user = bb_get_user( $q['favorites'] ) )
 445                  $where .= $this->parse_value( 't.topic_id', $f_user->favorites );
 446          endif; // !_part_of_post_query
 447  
 448          if ( $q['topic_title'] )
 449              $where .= ' AND ' . $this->generate_topic_title_sql( $q['topic_title'] );
 450  
 451          if ( $q['started'] )
 452              $where .= $this->date( 't.topic_start_time', $q['started'] );
 453  
 454          if ( $q['updated'] )
 455              $where .= $this->date( 't.topic_time', $q['updated'] );
 456  
 457          if ( $q['topic_author_id'] ) :
 458              $where .= $this->parse_value( 't.topic_poster', $q['topic_author_id'] );
 459          elseif ( $q['topic_author'] ) :
 460              $user = bb_get_user( $q['topic_author'], array( 'by' => 'login' ) );
 461              if ( !$q['topic_author_id'] = (int) $user->ID )
 462                  $this->error( 'query_var:user', 'No user by that name' );
 463              $where .= " AND t.topic_poster = $q[topic_author_id]";
 464          endif;
 465  
 466          if ( !$q['topic_status'] ) :
 467              $where .= " AND t.topic_status = '0'";
 468          elseif ( false === strpos($q['topic_status'], 'all') ) :
 469              $stati = array( 'normal' => 0, 'deleted' => 1 );
 470              $q['topic_status'] = str_replace(array_keys($stati), array_values($stati), $q['topic_status']);
 471              $where .= $this->parse_value( 't.topic_status', $q['topic_status'] );
 472          endif;
 473  
 474          if ( false !== $q['open'] && false === strpos($q['open'], 'all') ) :
 475              $stati = array( 'no' => 0, 'closed' => 0, 'yes' => 1, 'open' => 1 );
 476              $q['open'] = str_replace(array_keys($stati), array_values($stati), $q['open']);
 477              $where .= $this->parse_value( 't.topic_open', $q['open'] );
 478          endif;
 479  
 480          if ( false !== $q['sticky'] && false === strpos($q['sticky'], 'all') ) :
 481              $stickies = array( 'no' => 0, 'normal' => 0, 'forum' => 1, 'super' => 2, 'front' => 2, 'sticky' => '-0' );
 482              $q['sticky'] = str_replace(array_keys($stickies), array_values($stickies), $q['sticky']);
 483              $where .= $this->parse_value( 't.topic_sticky', $q['sticky'] );
 484          endif;
 485  
 486          if ( false !== $q['post_count'] )
 487              $where .= $this->parse_value( 't.topic_posts', $q['post_count'] );
 488  
 489          if ( false !== $q['tag_count'] )
 490              $where .= $this->parse_value( 't.tag_count', $q['tag_count'] );
 491  
 492          if ( $q['meta_key'] && $q['meta_key'] = preg_replace('|[^a-z0-9_-]|i', '', $q['meta_key']) ) :
 493              if ( '-' == substr($q['meta_key'], 0, 1) ) :
 494                  $join  .= " LEFT JOIN $bbdb->meta AS tm ON ( tm.object_type = 'bb_topic' AND t.topic_id = tm.object_id AND tm.meta_key = '" . substr( $q['meta_key'], 1 ) . "' )";
 495                  $where .= " AND tm.meta_key IS NULL";
 496              else :
 497                  $join  .= " JOIN $bbdb->meta AS tm ON ( tm.object_type = 'bb_topic' AND t.topic_id = tm.object_id AND tm.meta_key = '$q[meta_key]' )";
 498  
 499                  if ( $q['meta_value'] ) :
 500                      $q['meta_value'] = maybe_serialize( $q['meta_value'] );
 501                      if ( strpos( $q['meta_value'], 'NULL' ) !== false )
 502                          $join = ' LEFT' . $join;
 503                      $where .= $this->parse_value( 'tm.meta_value', $q['meta_value'] );
 504                  endif;
 505              endif;
 506          endif;
 507  
 508          // Just getting topic part for inclusion in post query
 509          if ( $_part_of_post_query )
 510              return $where;
 511  
 512          $where .= $post_where;
 513  
 514          if ( $where ) // Get rid of initial " AND " (this is pre-filters)
 515              $where = substr($where, 5);
 516  
 517          if ( $q['index_hint'] )
 518              $index_hint = $q['index_hint'];
 519  
 520          if ( $q['order_by'] )
 521              $order_by = $q['order_by'];
 522          else
 523              $order_by = 't.topic_time';
 524  
 525          $bits = compact( array('distinct', 'sql_calc_found_rows', 'fields', 'index_hint', 'join', 'where', 'group_by', 'having', 'order_by') );
 526          $this->request = $this->_filter_sql( $bits, "$bbdb->topics AS t" );
 527          return $this->request;
 528      }
 529  
 530  	function generate_post_sql( $_part_of_topic_query = false ) {
 531          global $bbdb;
 532  
 533          $q =& $this->query_vars;
 534          $distinct = '';
 535          $sql_calc_found_rows = 'found_rows' === $q['count'] ? 'SQL_CALC_FOUND_ROWS' : ''; // unfiltered
 536          $fields = 'p.*';
 537          $index_hint = '';
 538          $join = '';
 539          $where = '';
 540          $group_by = '';
 541          $having = '';
 542          $order_by = '';
 543  
 544          $topic_where = '';
 545          $topic_queries = array( 'topic_author_id', 'topic_author', 'topic_status', 'post_count', 'tag_count', 'started', 'updated', 'open', 'sticky', 'meta_key', 'meta_value', 'topic_title' );
 546          if ( !$_part_of_topic_query && array_diff($topic_queries, $this->not_set) ) :
 547              $join .= " JOIN $bbdb->topics as t ON ( t.topic_id = p.topic_id )";
 548              $topic_where = $this->generate_topic_sql( true );
 549          endif;
 550          
 551          if ( !$_part_of_topic_query ) :
 552              if ( $q['post_id'] )
 553                  $where .= $this->parse_value( 'p.post_id', $q['post_id'] );
 554  
 555              if ( $q['topic_id'] ) :
 556                  $where .= $this->parse_value( 'p.topic_id', $q['topic_id'] );
 557              elseif ( $q['topic'] ) :
 558                  if ( !$q['topic_id'] = bb_get_id_from_slug( 'topic', $q['topic'] ) )
 559                      $this->error( 'query_var:topic', 'No topic by that name' );
 560                  $where .= " AND p.topic_id = " . $q['topic_id'];
 561              endif;
 562  
 563              if ( $q['forum_id'] ) :
 564                  $where .= $this->parse_value( 'p.forum_id', $q['forum_id'] );
 565              elseif ( $q['forum'] ) :
 566                  if ( !$q['forum_id'] = bb_get_id_from_slug( 'forum', $q['forum'] ) )
 567                      $this->error( 'query_var:forum', 'No forum by that name' );
 568                  $where .= " AND p.forum_id = " . $q['forum_id'];
 569              endif;
 570  
 571              if ( $q['tag'] && !is_int($q['tag_id']) )
 572                  $q['tag_id'] = (int) bb_get_tag_id( $q['tag'] );
 573  
 574              if ( is_numeric($q['tag_id']) ) :
 575                  $join .= " JOIN `$bbdb->term_relationships` AS tr ON ( p.`topic_id` = tr.`object_id` AND tr.`term_taxonomy_id` = $q[tag_id] )";
 576              endif;
 577  
 578              if ( is_numeric($q['favorites']) && $f_user = bb_get_user( $q['favorites'] ) )
 579                  $where .= $this->parse_value( 'p.topic_id', $f_user->favorites );
 580          endif; // !_part_of_topic_query
 581  
 582          if ( $q['post_text'] ) :
 583              $where  .= ' AND ' . $this->generate_post_text_sql( $q['post_text'] );
 584              if ( $this->match_query ) {
 585                  $fields .= ", $this->match_query AS search_score";
 586                  if ( !$q['order_by'] )
 587                      $q['order_by'] = 'search_score';
 588              } else {
 589                  $fields .= ', 0 AS search_score';
 590              }
 591          endif;
 592  
 593          if ( $q['posted'] )
 594              $where .= $this->date( 'p.post_time', $q['posted'] );
 595  
 596          if ( $q['post_author_id'] ) :
 597              $where .= $this->parse_value( 'p.poster_id', $q['post_author_id'] );
 598          elseif ( $q['post_author'] ) :
 599              $user = bb_get_user( $q['post_author'], array( 'by' => 'login' ) );
 600              if ( !$q['post_author_id'] = (int) $user->ID )
 601                  $this->error( 'query_var:user', 'No user by that name' );
 602              $where .= " AND p.poster_id = $q[post_author_id]";
 603          endif;
 604  
 605          if ( !$q['post_status'] ) :
 606              $where .= " AND p.post_status = '0'";
 607          elseif ( false === strpos($q['post_status'], 'all') ) :
 608              $stati = array( 'normal' => 0, 'deleted' => 1 );
 609              $q['post_status'] = str_replace(array_keys($stati), array_values($stati), $q['post_status']);
 610              $where .= $this->parse_value( 'p.post_status', $q['post_status'] );
 611          endif;
 612  
 613          if ( false !== $q['position'] )
 614              $where .= $this->parse_value( 'p.post_position', $q['position'] );
 615  
 616          if ( false !== $q['poster_ip'] )
 617              $where .= " AND poster_ip = '" . $q['poster_ip'] . "'";
 618  
 619          // Just getting post part for inclusion in topic query
 620          if ( $_part_of_topic_query )
 621              return $where;
 622  
 623          $where .= $topic_where;
 624  
 625          if ( $where ) // Get rid of initial " AND " (this is pre-filters)
 626              $where = substr($where, 5);
 627  
 628          if ( $q['index_hint'] )
 629              $index_hint = $q['index_hint'];
 630  
 631          if ( $q['order_by'] )
 632              $order_by = $q['order_by'];
 633          else
 634              $order_by = 'p.post_time';
 635  
 636          $bits = compact( array('distinct', 'sql_calc_found_rows', 'fields', 'index_hint', 'join', 'where', 'group_by', 'having', 'order_by') );
 637          $this->request = $this->_filter_sql( $bits, "$bbdb->posts AS p" );
 638  
 639          return $this->request;
 640      }
 641  
 642  	function generate_topic_title_sql( $string ) {
 643          global $bbdb;
 644          $string = trim($string);
 645  
 646          if ( !preg_match_all('/".*?("|$)|((?<=[\s",+])|^)[^\s",+]+/', $string, $matches) ) {
 647              $string = $bbdb->escape($string);
 648              return "(t.topic_title LIKE '%$string%')";
 649          }
 650  
 651          $where = '';
 652  
 653          foreach ( $matches[0] as $match ) {
 654              $term = trim($match, "\"\n\r ");
 655              $term = $bbdb->escape($term);
 656              $where .= " AND t.topic_title LIKE '%$term%'";
 657          }
 658  
 659          if ( count($matches[0]) > 1 && $string != $matches[0][0] ) {
 660              $string = $bbdb->escape($string);
 661              $where .= " OR t.topic_title LIKE '%$string%'";
 662          }
 663  
 664          return '(' . substr($where, 5) . ')';
 665      }
 666  
 667  	function generate_post_text_sql( $string ) {
 668          global $bbdb;
 669          $string = trim($string);
 670          $_string = $bbdb->escape( $string );
 671          if ( strlen($string) < 5 )
 672              return "p.post_text LIKE '%$_string%'";
 673  
 674          return $this->match_query = "MATCH(p.post_text) AGAINST('$_string')";
 675      }
 676  
 677  	function _filter_sql( $bits, $from ) {
 678          global $bbdb;
 679  
 680          $q =& $this->query_vars;
 681  
 682          // MySQL 5.1 allows multiple index hints per query - earlier versions only get the first hint
 683          if ( $bits['index_hint'] ) {
 684              if ( !is_array( $bits['index_hint'] ) ) {
 685                  $bits['index_hint'] = array( (string) $bits['index_hint'] );
 686              }
 687              if ( $bbdb->has_cap( 'index_hint_for_any' ) ) {
 688                  // 5.1 <= MySQL
 689                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+(FOR\s+(JOIN|ORDER\s+BY|GROUP\s+BY)\s+)?\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 690              } elseif ( $bbdb->has_cap( 'index_hint_for_join' ) ) {
 691                  // 5.0 <= MySQL < 5.1
 692                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+(FOR\s+JOIN\s+)?\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 693              } else {
 694                  // MySQL < 5.0
 695                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 696              }
 697              $_index_hint = array();
 698              foreach ( $bits['index_hint'] as $_hint ) {
 699                  if ( preg_match( $_regex, $_hint ) ) {
 700                      $_index_hint[] = trim( $_hint );
 701                  }
 702              }
 703              unset( $_regex, $_hint );
 704              if ( $bbdb->has_cap( 'index_hint_lists' ) ) {
 705                  // 5.1 <= MySQL
 706                  $bits['index_hint'] = join( ' ', $_index_hint );
 707              } else {
 708                  // MySQL < 5.1
 709                  $bits['index_hint'] = isset( $_index_hint[0] ) ? $_index_hint[0] : '';
 710              }
 711              unset( $_index_hint );
 712          }
 713  
 714          $q['order'] = strtoupper($q['order']);
 715          if ( $q['order'] && in_array($q['order'], array('ASC', 'DESC')) )
 716              $bits['order_by'] .= " $q[order]";
 717          else
 718              $bits['order_by'] .= " DESC";
 719  
 720          if ( !$q['per_page'] )
 721              $q['per_page'] = (int) bb_get_option( 'page_topics' );
 722  
 723          $bits['limit'] = '';
 724          if ( $q['per_page'] > 0 ) :
 725              if ( $q['page'] > 1 )
 726                  $bits['limit'] .= $q['per_page'] * ( $q['page'] - 1 ) . ", ";
 727              $bits['limit'] .= $q['per_page'];
 728          endif;
 729  
 730          $name = "get_{$this->type}s_";
 731  
 732          // Unfiltered
 733          $sql_calc_found_rows = $bits['sql_calc_found_rows'];
 734          unset($bits['sql_calc_found_rows']);
 735  
 736          foreach ( $bits as $bit => $value ) {
 737              if ( $this->query_id )
 738                  $value = apply_filters( "{$this->query_id}_$bit", $value );
 739              $$bit = apply_filters( "$name$bit", $value );
 740          }
 741  
 742          if ( $where )
 743              $where = "WHERE $where";
 744          if ( $group_by )
 745              $group_by = "GROUP BY $group_by";
 746          if ( $having )
 747              $having = "HAVING $having";
 748          if ( $order_by )
 749              $order_by = "ORDER BY $order_by";
 750          if ( $limit )
 751              $limit = "LIMIT $limit";
 752  
 753          return "SELECT $distinct $sql_calc_found_rows $fields FROM $from $index_hint $join $where $group_by $having $order_by $limit";
 754      }
 755  
 756  	function parse_value( $field, $value = '' ) {
 757          if ( !$value && !is_numeric($value) )
 758              return '';
 759  
 760          global $bbdb;
 761  
 762          $op = substr($value, 0, 1);
 763  
 764          // #, =whatever, <#, >#.  Cannot do < and > at same time
 765          if ( in_array($op, array('<', '=', '>')) ) :
 766              $value = substr($value, 1);
 767              $value = is_numeric($value) ? (float) $value : $bbdb->escape( $value );
 768              return " AND $field $op '$value'";
 769          elseif ( false === strpos($value, ',') && 'NULL' !== $value && '-NULL' !== $value ) :
 770              $value = is_numeric($value) ? (float) $value : $bbdb->escape( $value );
 771              return '-' == $op ? " AND $field != '" . substr($value, 1) . "'" : " AND $field = '$value'";
 772          endif;
 773  
 774          $y = $n = array();
 775          foreach ( explode(',', $value) as $v ) {
 776              $v = is_numeric($v) ? (int) $v : $bbdb->escape( $v );
 777              if ( '-' == substr($v, 0, 1) )
 778                  if ( $v === '-NULL' )
 779                      $not_null_flag = true;
 780                  else
 781                      $n[] = substr($v, 1);
 782              else
 783                  if ( $v === 'NULL' )
 784                      $null_flag = true;
 785                  else
 786                      $y[] = $v;
 787          }
 788  
 789          $r = '';
 790          if ( $y ) {
 791              $r .= " AND ";
 792              if ( $null_flag )
 793                  $r .= "(";
 794              $r .= "$field IN ('" . join("','", $y) . "')";
 795              if ( $null_flag )
 796                  $r .= " OR $field IS NULL)";
 797          } elseif ( $null_flag ) {
 798              $r .= " AND $field IS NULL";
 799          }
 800          
 801          if ( $n ) {
 802              $r .= " AND ";
 803              if ( $not_null_flag )
 804                  $r .= "(";
 805              $r .= "$field NOT IN ('" . join("','", $n) . "')";
 806              if ( $not_null_flag )
 807                  $r .= " AND $field IS NOT NULL)";
 808          } elseif ( $not_null_flag ) {
 809              $r .= " AND $field IS NOT NULL";
 810          }
 811  
 812          return $r;
 813      }
 814  
 815  	function date( $field, $date ) {
 816          if ( !$date && !is_int($date) )
 817              return '';
 818  
 819          if ( $is_range = false !== strpos( $date, '--' ) )
 820              $dates = explode( '--', $date, 2 );
 821          else
 822              $dates = array( $date );
 823  
 824          $op = false;
 825          $r = '';
 826          foreach ( $dates as $date ) {
 827              if ( $is_range ) {
 828                  $op = $op ? '<' : '>';
 829                  $date = (int) substr($date, 0, 14);
 830              } else {
 831                  $op = substr($date, 0, 1);
 832                  if ( !in_array($op, array('>', '<')) )
 833                      break;
 834                  $date = (int) substr($date, 1, 14);
 835              }
 836              if ( strlen($date) < 14 )
 837                  $date .= str_repeat('0', 14 - strlen($date));
 838              $r .= " AND $field $op $date";
 839          }
 840          if ( $r )
 841              return $r;
 842  
 843          $date = (int) $date;
 844          $r = " AND YEAR($field) = " . substr($date, 0, 4);
 845          if ( strlen($date) > 5 )
 846              $r .= " AND MONTH($field) = " . substr($date, 4, 2);
 847          if ( strlen($date) > 7 )
 848              $r .= " AND DAYOFMONTH($field) = " . substr($date, 6, 2);
 849          if ( strlen($date) > 9 )
 850              $r .= " AND HOUR($field) = " . substr($date, 8, 2);
 851          if ( strlen($date) > 11 )
 852              $r .= " AND MINUTE($field) = " . substr($date, 10, 2);
 853          if ( strlen($date) > 13 )
 854              $r .= " AND SECOND($field) = " . substr($date, 12, 2);
 855          return $r;
 856      }
 857  
 858  	function error( $code, $message ) {
 859          if ( is_wp_error($this->errors) )
 860              $this->errors->add( $code, $message );
 861          else
 862              $this->errors = new WP_Error( $code, $message );
 863      }
 864  }
 865  
 866  class BB_Query_Form extends BB_Query {
 867      var $defaults;
 868      var $allowed;
 869  
 870      // Can optionally pass unique id string to help out filters
 871  	function BB_Query_Form( $type = 'topic', $defaults = '', $allowed = '', $id = '' ) {
 872          $this->defaults = wp_parse_args( $defaults );
 873          $this->allowed  = wp_parse_args( $allowed );
 874          if ( !empty($defaults) || !empty($allowed) )
 875              $this->query_from_env($type, $defaults, $allowed, $id);
 876      }
 877  
 878  	function form( $args = null ) {
 879          $_post = 'post' == $this->type;
 880  
 881          $defaults = array(
 882              'search' => true,
 883              'forum'  => true,
 884              'tag'    => false,
 885              'open'   => false,
 886              'topic_author' => false,
 887              'post_author'  => false,
 888              'topic_status' => false,
 889              'post_status'  => false,
 890              'topic_title'  => false,
 891              'poster_ip'  => false,
 892  
 893              'method' => 'get',
 894              'submit' => __('Search &#187;'),
 895              'action' => ''
 896          );
 897          $defaults['id'] = $_post ? 'post-search-form' : 'topic-search-form';
 898  
 899          $args = wp_parse_args( $args, $defaults );
 900          extract( $args, EXTR_SKIP );
 901  
 902          $id = esc_attr( $id );
 903          $method = 'get' == strtolower($method) ? 'get' : 'post';
 904          $submit = esc_attr( $submit );
 905          if ( !$action = esc_url( $action ) )
 906              $action = '';
 907  
 908          if ( $this->query_vars )
 909              $query_vars =& $this->query_vars;
 910          else
 911              $query_vars = $this->fill_query_vars( $this->defaults );
 912  
 913          extract($query_vars, EXTR_PREFIX_ALL, 'q');
 914  
 915          $r  = "<form action='$action' method='$method' id='$id' class='search-form'>\n";
 916  
 917          $r .= "\t<fieldset>\n";
 918  
 919          if ( $search ) {
 920              if ( $_post ) {
 921                  $s_value = esc_attr( $q_post_text );
 922                  $s_name = 'post_text';
 923                  $s_id = 'post-text';
 924              } else {
 925                  $s_value = esc_attr( $q_search );
 926                  $s_name = $s_id = 'search';
 927              }
 928              $r .= "\t<div><label for=\"$s_id\">" . __('Search term') . "</label>\n";
 929              $r .= "\t\t<div><input name='$s_name' id='$s_id' type='text' class='text-input' value='$s_value' /></div>\n";
 930              $r .= "\t</div>\n\n";
 931          }
 932  
 933          if ( $forum ) {
 934              $r .= "\t<div><label for=\"forum-id\">" . __('Forum')  . "</label>\n";
 935              $r .= "\t\t<div>" . bb_get_forum_dropdown( array( 'selected' => $q_forum_id, 'none' => __('Any') ) ) . "</div>\n";
 936              $r .= "\t</div>\n\n";
 937          }
 938  
 939          if ( $tag ) {
 940              $q_tag = esc_attr( $q_tag );
 941              $r .= "\t<div><label for=\"topic-tag\">" .  __('Tag') . "</label>\n";
 942              $r .= "\t\t<div><input name='tag' id='topic-tag' type='text' class='text-input' value='$q_tag' /></div>\n";
 943              $r .= "\t</div>\n\n";
 944          }
 945  
 946          if ( $topic_author ) {
 947              $q_topic_author = esc_attr( $q_topic_author );
 948              $r .= "\t<div><label for=\"topic-author\">" . __('Topic author') . "</label>\n";
 949              $r .= "\t\t<div><input name='topic_author' id='topic-author' type='text' class='text-input' value='$q_topic_author' /></div>\n";
 950              $r .= "\t</div>\n\n";
 951          }
 952  
 953          if ( $post_author ) {
 954              $q_post_author = esc_attr( $q_post_author );
 955              $r .= "\t<div><label for=\"post-author\">" . __('Post author') . "</label>\n";
 956              $r .= "\t\t<div><input name='post_author' id='post-author' type='text' class='text-input' value='$q_post_author' /></div>\n";
 957              $r .= "\t</div>\n\n";
 958          }
 959  
 960          $stati = apply_filters( 'bb_query_form_post_status', array( 'all' => _x( 'All', 'post status' ), '0' => __('Normal'), '1' => __('Deleted') ), $this->type );
 961  
 962          if ( $topic_status ) {
 963              $r .= "\t<div><label for=\"topic-status\">" . __('Topic status') . "</label>\n";
 964              $r .= "\t\t<div><select name='topic_status' id='topic-status'>\n";
 965              foreach ( $stati as $status => $label ) {
 966                  $selected = (string) $status == (string) $q_topic_status ? " selected='selected'" : '';
 967                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
 968              }
 969              $r .= "\t\t</select></div>\n";
 970              $r .= "\t</div>\n\n";
 971          }
 972  
 973          if ( $post_status ) {
 974              $r .= "\t<div><label for=\"post-status\">" . __('Post status') . "</label>\n";
 975              $r .= "\t\t<div><select name='post_status' id='post-status'>\n";
 976              foreach ( $stati as $status => $label ) {
 977                  $selected = (string) $status == (string) $q_post_status ? " selected='selected'" : '';
 978                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
 979              }
 980              $r .= "\t\t</select></div>\n";
 981              $r .= "\t</div>\n\n";
 982          }
 983  
 984          if ( $poster_ip ) {
 985              $r .= "\t<div><label for=\"poster-ip\">" . __('Poster IP address') . "</label>\n";
 986              $r .= "\t\t<div><input name='poster_ip' id='poster-ip' type='text' class='text-input' value='$q_poster_ip' /></div>\n";
 987              $r .= "\t</div>\n\n";
 988          }
 989  
 990          if ( $open ) {
 991              $r .= "\t<div><label for=\"topic-open\">" . __('Open?') . "</label>\n";
 992              $r .= "\t\t<div><select name='open' id='topic-open'>\n";
 993              foreach ( array( 'all' => _x( 'All', 'posting status' ), '1' => _x( 'Open', 'posting status' ), '0' => __('Closed') ) as $status => $label ) {
 994                  $label = esc_html( $label );
 995                  $selected = (string) $status == (string) $q_open ? " selected='selected'" : '';
 996                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
 997              }
 998              $r .= "\t\t</select></div>\n";
 999              $r .= "\t</div>\n\n";
1000          }
1001  
1002          if ( $topic_title ) {
1003              $q_topic_title = esc_attr( $q_topic_title );
1004              $r .= "\t<div><label for=\"topic-title\">" . __('Title') . "</label>\n";
1005              $r .= "\t\t<div><input name='topic_title' id='topic-title' type='text' class='text-input' value='$q_topic_title' /></div>\n";
1006              $r .= "\t</div>\n\n";
1007          }
1008  
1009          $r .= apply_filters( 'bb_query_form_inputs', '', $args, $query_vars );
1010  
1011          $r .= "\t<div class=\"submit\"><label for=\"$id-submit\">" . __('Search') . "</label>\n";
1012          $r .= "\t\t<div><input type='submit' class='button submit-input' value='$submit' id='$id-submit' /></div>\n";
1013          $r .= "\t</div>\n";
1014  
1015          $r .= "\t</fieldset>\n\n";
1016  
1017          do_action( 'bb_query_form', $args, $query_vars );
1018  
1019          $r .= "</form>\n\n";
1020  
1021          echo $r;
1022      }
1023  }


Generated: Mon Nov 15 04:45:27 2010 Cross-referenced by PHPXref 0.7