/wp-content/plugins/buddypress/bp-activity/classes/class-bp-activity-query.php

https://github.com/livinglab/openlab · PHP · 247 lines · 103 code · 31 blank · 113 comment · 22 complexity · e0444936d203585ff0da7f497ae4c749 MD5 · raw file

  1. <?php
  2. /**
  3. * BuddyPress Activity Classes
  4. *
  5. * @package BuddyPress
  6. * @subpackage ActivityQuery
  7. * @since 2.2.0
  8. */
  9. // Exit if accessed directly.
  10. defined( 'ABSPATH' ) || exit;
  11. /**
  12. * Class for generating the WHERE SQL clause for advanced activity fetching.
  13. *
  14. * This is notably used in {@link BP_Activity_Activity::get()} with the
  15. * 'filter_query' parameter.
  16. *
  17. * @since 2.2.0
  18. */
  19. class BP_Activity_Query extends BP_Recursive_Query {
  20. /**
  21. * Array of activity queries.
  22. *
  23. * See {@see BP_Activity_Query::__construct()} for information on query arguments.
  24. *
  25. * @since 2.2.0
  26. * @var array
  27. */
  28. public $queries = array();
  29. /**
  30. * Table alias.
  31. *
  32. * @since 2.2.0
  33. * @var string
  34. */
  35. public $table_alias = '';
  36. /**
  37. * Supported DB columns.
  38. *
  39. * See the 'wp_bp_activity' DB table schema.
  40. *
  41. * @since 2.2.0
  42. * @var array
  43. */
  44. public $db_columns = array(
  45. 'id', 'user_id', 'component', 'type', 'action', 'content', 'primary_link',
  46. 'item_id', 'secondary_item_id', 'hide_sitewide', 'is_spam',
  47. );
  48. /**
  49. * Constructor.
  50. *
  51. * @since 2.2.0
  52. *
  53. * @param array $query {
  54. * Array of query clauses.
  55. * @type array {
  56. * @type string $column Required. The column to query against. Basically, any DB column in the main
  57. * 'wp_bp_activity' table.
  58. * @type string $value Required. Value to filter by.
  59. * @type string $compare Optional. The comparison operator. Default '='.
  60. * Accepts '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'LIKE',
  61. * 'NOT LIKE', BETWEEN', 'NOT BETWEEN', 'REGEXP', 'NOT REGEXP', 'RLIKE'.
  62. * @type string $relation Optional. The boolean relationship between the activity queries.
  63. * Accepts 'OR', 'AND'. Default 'AND'.
  64. * @type array {
  65. * Optional. Another fully-formed activity query. See parameters above.
  66. * }
  67. * }
  68. * }
  69. */
  70. public function __construct( $query = array() ) {
  71. if ( ! is_array( $query ) ) {
  72. return;
  73. }
  74. $this->queries = $this->sanitize_query( $query );
  75. }
  76. /**
  77. * Generates WHERE SQL clause to be appended to a main query.
  78. *
  79. * @since 2.2.0
  80. *
  81. * @param string $alias An existing table alias that is compatible with the current query clause.
  82. * Default: 'a'. BP_Activity_Activity::get() uses 'a', so we default to that.
  83. * @return string SQL fragment to append to the main WHERE clause.
  84. */
  85. public function get_sql( $alias = 'a' ) {
  86. if ( ! empty( $alias ) ) {
  87. $this->table_alias = sanitize_title( $alias );
  88. }
  89. $sql = $this->get_sql_clauses();
  90. // We only need the 'where' clause.
  91. //
  92. // Also trim trailing "AND" clause from parent BP_Recursive_Query class
  93. // since it's not necessary for our needs.
  94. return preg_replace( '/^\sAND/', '', $sql['where'] );
  95. }
  96. /**
  97. * Generate WHERE clauses for a first-order clause.
  98. *
  99. * @since 2.2.0
  100. *
  101. * @param array $clause Array of arguments belonging to the clause.
  102. * @param array $parent_query Parent query to which the clause belongs.
  103. * @return array {
  104. * @type array $where Array of subclauses for the WHERE statement.
  105. * @type array $join Empty array. Not used.
  106. * }
  107. */
  108. protected function get_sql_for_clause( $clause, $parent_query ) {
  109. global $wpdb;
  110. $sql_chunks = array(
  111. 'where' => array(),
  112. 'join' => array(),
  113. );
  114. $column = isset( $clause['column'] ) ? $this->validate_column( $clause['column'] ) : '';
  115. $value = isset( $clause['value'] ) ? $clause['value'] : '';
  116. if ( empty( $column ) || ! isset( $clause['value'] ) ) {
  117. return $sql_chunks;
  118. }
  119. if ( isset( $clause['compare'] ) ) {
  120. $clause['compare'] = strtoupper( $clause['compare'] );
  121. } else {
  122. $clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
  123. }
  124. // Default 'compare' to '=' if no valid operator is found.
  125. if ( ! in_array( $clause['compare'], array(
  126. '=', '!=', '>', '>=', '<', '<=',
  127. 'LIKE', 'NOT LIKE',
  128. 'IN', 'NOT IN',
  129. 'BETWEEN', 'NOT BETWEEN',
  130. 'REGEXP', 'NOT REGEXP', 'RLIKE'
  131. ) ) ) {
  132. $clause['compare'] = '=';
  133. }
  134. $compare = $clause['compare'];
  135. $alias = ! empty( $this->table_alias ) ? "{$this->table_alias}." : '';
  136. // Next, Build the WHERE clause.
  137. $where = '';
  138. // Value.
  139. if ( isset( $clause['value'] ) ) {
  140. if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
  141. if ( ! is_array( $value ) ) {
  142. $value = preg_split( '/[,\s]+/', $value );
  143. }
  144. }
  145. // Tinyint.
  146. if ( ! empty( $column ) && true === in_array( $column, array( 'hide_sitewide', 'is_spam' ) ) ) {
  147. $sql_chunks['where'][] = $wpdb->prepare( "{$alias}{$column} = %d", $value );
  148. } else {
  149. switch ( $compare ) {
  150. // IN uses different syntax.
  151. case 'IN' :
  152. case 'NOT IN' :
  153. $in_sql = BP_Activity_Activity::get_in_operator_sql( "{$alias}{$column}", $value );
  154. // 'NOT IN' operator is as easy as a string replace!
  155. if ( 'NOT IN' === $compare ) {
  156. $in_sql = str_replace( 'IN', 'NOT IN', $in_sql );
  157. }
  158. $sql_chunks['where'][] = $in_sql;
  159. break;
  160. case 'BETWEEN' :
  161. case 'NOT BETWEEN' :
  162. $value = array_slice( $value, 0, 2 );
  163. $where = $wpdb->prepare( '%s AND %s', $value );
  164. break;
  165. case 'LIKE' :
  166. case 'NOT LIKE' :
  167. $value = '%' . bp_esc_like( $value ) . '%';
  168. $where = $wpdb->prepare( '%s', $value );
  169. break;
  170. default :
  171. $where = $wpdb->prepare( '%s', $value );
  172. break;
  173. }
  174. }
  175. if ( $where ) {
  176. $sql_chunks['where'][] = "{$alias}{$column} {$compare} {$where}";
  177. }
  178. }
  179. /*
  180. * Multiple WHERE clauses should be joined in parentheses.
  181. */
  182. if ( 1 < count( $sql_chunks['where'] ) ) {
  183. $sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
  184. }
  185. return $sql_chunks;
  186. }
  187. /**
  188. * Determine whether a clause is first-order.
  189. *
  190. * @since 2.2.0
  191. *
  192. * @param array $query Clause to check.
  193. * @return bool
  194. */
  195. protected function is_first_order_clause( $query ) {
  196. return isset( $query['column'] ) || isset( $query['value'] );
  197. }
  198. /**
  199. * Validates a column name parameter.
  200. *
  201. * Column names are checked against a list of known tables.
  202. * See {@link BP_Activity_Query::db_tables}.
  203. *
  204. * @since 2.2.0
  205. *
  206. * @param string $column The user-supplied column name.
  207. * @return string A validated column name value.
  208. */
  209. public function validate_column( $column = '' ) {
  210. if ( in_array( $column, $this->db_columns ) ) {
  211. return $column;
  212. } else {
  213. return '';
  214. }
  215. }
  216. }