/wp-content/plugins/badgeos/includes/p2p/p2p-core/query.php

https://github.com/livinglab/openlab · PHP · 222 lines · 148 code · 59 blank · 15 comment · 22 complexity · f30c4042b8073dc816db56071228d79e MD5 · raw file

  1. <?php
  2. class P2P_Query {
  3. protected $ctypes, $items, $query, $meta;
  4. protected $orderby, $order, $order_num;
  5. private static function expand_shortcuts( $q ) {
  6. $shortcuts = array(
  7. 'connected' => 'any',
  8. 'connected_to' => 'to',
  9. 'connected_from' => 'from',
  10. );
  11. foreach ( $shortcuts as $key => $direction ) {
  12. if ( !empty( $q[ $key ] ) ) {
  13. $q['connected_items'] = _p2p_pluck( $q, $key );
  14. $q['connected_direction'] = $direction;
  15. }
  16. }
  17. return $q;
  18. }
  19. private static function expand_ctypes( $item, $directions, $object_type, $ctypes ) {
  20. $p2p_types = array();
  21. foreach ( $ctypes as $i => $p2p_type ) {
  22. $ctype = p2p_type( $p2p_type );
  23. if ( !$ctype )
  24. continue;
  25. if ( isset( $directions[ $i ] ) ) {
  26. $directed = $ctype->set_direction( $directions[ $i ] );
  27. } else {
  28. $directed = $ctype->find_direction( $item, true, $object_type );
  29. }
  30. if ( !$directed )
  31. continue;
  32. $p2p_types[] = $directed;
  33. }
  34. return $p2p_types;
  35. }
  36. private static function finalize_query_vars( $q, $directed, $item ) {
  37. if ( $orderby_key = $directed->get_orderby_key() ) {
  38. $q = wp_parse_args( $q, array(
  39. 'connected_orderby' => $orderby_key,
  40. 'connected_order' => 'ASC',
  41. 'connected_order_num' => true,
  42. ) );
  43. }
  44. $q = array_merge_recursive( $q, array(
  45. 'connected_meta' => $directed->data
  46. ) );
  47. $q = $directed->get_final_qv( $q, 'opposite' );
  48. return apply_filters( 'p2p_connected_args', $q, $directed, $item );
  49. }
  50. /**
  51. * Create instance from mixed query vars; also returns the modified query vars.
  52. *
  53. * @param array Query vars to collect parameters from
  54. * @return:
  55. * - null means ignore current query
  56. * - WP_Error instance if the query is invalid
  57. * - array( P2P_Query, array )
  58. */
  59. public static function create_from_qv( $q, $object_type ) {
  60. $q = self::expand_shortcuts( $q );
  61. if ( !isset( $q['connected_type'] ) ) {
  62. if ( isset( $q['connected_items'] ) ) {
  63. return new WP_Error( 'no_connection_type', "Queries without 'connected_type' are no longer supported." );
  64. }
  65. return;
  66. }
  67. if ( isset( $q['connected_direction'] ) )
  68. $directions = (array) _p2p_pluck( $q, 'connected_direction' );
  69. else
  70. $directions = array();
  71. $item = isset( $q['connected_items'] ) ? $q['connected_items'] : 'any';
  72. $ctypes = (array) _p2p_pluck( $q, 'connected_type' );
  73. $p2p_types = self::expand_ctypes( $item, $directions, $object_type, $ctypes );
  74. if ( empty( $p2p_types ) )
  75. return new WP_Error( 'no_direction', "Could not find direction(s)." );
  76. if ( 1 == count( $p2p_types ) ) {
  77. $q = self::finalize_query_vars( $q, $p2p_types[0], $item );
  78. }
  79. $p2p_q = new P2P_Query;
  80. $p2p_q->ctypes = $p2p_types;
  81. $p2p_q->items = $item;
  82. foreach ( array( 'meta', 'orderby', 'order_num', 'order' ) as $key ) {
  83. $p2p_q->$key = isset( $q["connected_$key"] ) ? $q["connected_$key"] : false;
  84. }
  85. $p2p_q->query = isset( $q['connected_query'] ) ? $q['connected_query'] : array();
  86. return array( $p2p_q, $q );
  87. }
  88. protected function __construct() {}
  89. public function __get( $key ) {
  90. return $this->$key;
  91. }
  92. private function do_other_query( $directed, $which ) {
  93. $side = $directed->get( $which, 'side' );
  94. $qv = array_merge( $this->query, array(
  95. 'fields' => 'ids',
  96. 'p2p:per_page' => -1
  97. ) );
  98. if ( 'any' != $this->items )
  99. $qv['p2p:include'] = _p2p_normalize( $this->items );
  100. $qv = $directed->get_final_qv( $qv, $which );
  101. return $side->capture_query( $qv );
  102. }
  103. /**
  104. * For low-level query modifications
  105. */
  106. public function alter_clauses( &$clauses, $main_id_column ) {
  107. global $wpdb;
  108. $clauses['fields'] .= ", $wpdb->p2p.*";
  109. $clauses['join'] .= " INNER JOIN $wpdb->p2p";
  110. $where_parts = array();
  111. foreach ( $this->ctypes as $directed ) {
  112. if ( null === $directed ) // used by migration script
  113. continue;
  114. $part = $wpdb->prepare( "$wpdb->p2p.p2p_type = %s", $directed->name );
  115. $fields = array( 'p2p_from', 'p2p_to' );
  116. switch ( $directed->get_direction() ) {
  117. case 'from':
  118. $fields = array_reverse( $fields );
  119. // fallthrough
  120. case 'to':
  121. list( $from, $to ) = $fields;
  122. $search = $this->do_other_query( $directed, 'current' );
  123. $part .= " AND $main_id_column = $wpdb->p2p.$from";
  124. $part .= " AND $wpdb->p2p.$to IN ($search)";
  125. break;
  126. default:
  127. $part .= sprintf ( " AND (
  128. ($main_id_column = $wpdb->p2p.p2p_to AND $wpdb->p2p.p2p_from IN (%s)) OR
  129. ($main_id_column = $wpdb->p2p.p2p_from AND $wpdb->p2p.p2p_to IN (%s))
  130. )",
  131. $this->do_other_query( $directed, 'current' ),
  132. $this->do_other_query( $directed, 'opposite' )
  133. );
  134. }
  135. $where_parts[] = '(' . $part . ')';
  136. }
  137. if ( 1 == count( $where_parts ) )
  138. $clauses['where'] .= " AND " . $where_parts[0];
  139. elseif ( !empty( $where_parts ) )
  140. $clauses['where'] .= " AND (" . implode( ' OR ', $where_parts ) . ")";
  141. // Handle custom fields
  142. if ( !empty( $this->meta ) ) {
  143. $meta_clauses = _p2p_meta_sql_helper( $this->meta );
  144. foreach ( $meta_clauses as $key => $value ) {
  145. $clauses[ $key ] .= $value;
  146. }
  147. }
  148. // Handle ordering
  149. if ( $this->orderby ) {
  150. $clauses['join'] .= $wpdb->prepare( "
  151. LEFT JOIN $wpdb->p2pmeta AS p2pm_order ON (
  152. $wpdb->p2p.p2p_id = p2pm_order.p2p_id AND p2pm_order.meta_key = %s
  153. )
  154. ", $this->orderby );
  155. $order = ( 'DESC' == strtoupper( $this->order ) ) ? 'DESC' : 'ASC';
  156. $field = 'meta_value';
  157. if ( $this->order_num )
  158. $field .= '+0';
  159. $clauses['orderby'] = "p2pm_order.$field $order, " . str_replace( 'ORDER BY ', '', $clauses['orderby'] );
  160. }
  161. return $clauses;
  162. }
  163. }