/wp-includes/class-wp-list-util.php

  1. <?php 
  2. /** 
  3. * WordPress List utility class 
  4. * 
  5. * @package WordPress 
  6. * @since 4.7.0 
  7. */ 
  8.  
  9. /** 
  10. * List utility. 
  11. * 
  12. * Utility class to handle operations on an array of objects. 
  13. * 
  14. * @since 4.7.0 
  15. */ 
  16. class WP_List_Util { 
  17. /** 
  18. * The input array. 
  19. * 
  20. * @since 4.7.0 
  21. * @access private 
  22. * @var array 
  23. */ 
  24. private $input = array(); 
  25.  
  26. /** 
  27. * The output array. 
  28. * 
  29. * @since 4.7.0 
  30. * @access private 
  31. * @var array 
  32. */ 
  33. private $output = array(); 
  34.  
  35. /** 
  36. * Temporary arguments for sorting. 
  37. * 
  38. * @since 4.7.0 
  39. * @access private 
  40. * @var array 
  41. */ 
  42. private $orderby = array(); 
  43.  
  44. /** 
  45. * Constructor. 
  46. * 
  47. * Sets the input array. 
  48. * 
  49. * @since 4.7.0 
  50. * 
  51. * @param array $input Array to perform operations on. 
  52. */ 
  53. public function __construct( $input ) { 
  54. $this->output = $this->input = $input; 
  55.  
  56. /** 
  57. * Returns the original input array. 
  58. * 
  59. * @since 4.7.0 
  60. * @access public 
  61. * 
  62. * @return array The input array. 
  63. */ 
  64. public function get_input() { 
  65. return $this->input; 
  66.  
  67. /** 
  68. * Returns the output array. 
  69. * 
  70. * @since 4.7.0 
  71. * @access public 
  72. * 
  73. * @return array The output array. 
  74. */ 
  75. public function get_output() { 
  76. return $this->output; 
  77.  
  78. /** 
  79. * Filters the list, based on a set of key => value arguments. 
  80. * 
  81. * @since 4.7.0 
  82. * 
  83. * @param array $args Optional. An array of key => value arguments to match 
  84. * against each object. Default empty array. 
  85. * @param string $operator Optional. The logical operation to perform. 'AND' means 
  86. * all elements from the array must match. 'OR' means only 
  87. * one element needs to match. 'NOT' means no elements may 
  88. * match. Default 'AND'. 
  89. * @return array Array of found values. 
  90. */ 
  91. public function filter( $args = array(), $operator = 'AND' ) { 
  92. if ( empty( $args ) ) { 
  93. return $this->output; 
  94.  
  95. $operator = strtoupper( $operator ); 
  96.  
  97. if ( ! in_array( $operator, array( 'AND', 'OR', 'NOT' ), true ) ) { 
  98. return array(); 
  99.  
  100. $count = count( $args ); 
  101. $filtered = array(); 
  102.  
  103. foreach ( $this->output as $key => $obj ) { 
  104. $to_match = (array) $obj; 
  105.  
  106. $matched = 0; 
  107. foreach ( $args as $m_key => $m_value ) { 
  108. if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) { 
  109. $matched++; 
  110.  
  111. if ( 
  112. ( 'AND' == $operator && $matched == $count ) || 
  113. ( 'OR' == $operator && $matched > 0 ) || 
  114. ( 'NOT' == $operator && 0 == $matched ) 
  115. ) { 
  116. $filtered[$key] = $obj; 
  117.  
  118. $this->output = $filtered; 
  119.  
  120. return $this->output; 
  121.  
  122. /** 
  123. * Plucks a certain field out of each object in the list. 
  124. * 
  125. * This has the same functionality and prototype of 
  126. * array_column() (PHP 5.5) but also supports objects. 
  127. * 
  128. * @since 4.7.0 
  129. * 
  130. * @param int|string $field Field from the object to place instead of the entire object 
  131. * @param int|string $index_key Optional. Field from the object to use as keys for the new array. 
  132. * Default null. 
  133. * @return array Array of found values. If `$index_key` is set, an array of found values with keys 
  134. * corresponding to `$index_key`. If `$index_key` is null, array keys from the original 
  135. * `$list` will be preserved in the results. 
  136. */ 
  137. public function pluck( $field, $index_key = null ) { 
  138. if ( ! $index_key ) { 
  139. /** 
  140. * This is simple. Could at some point wrap array_column() 
  141. * if we knew we had an array of arrays. 
  142. */ 
  143. foreach ( $this->output as $key => $value ) { 
  144. if ( is_object( $value ) ) { 
  145. $this->output[ $key ] = $value->$field; 
  146. } else { 
  147. $this->output[ $key ] = $value[ $field ]; 
  148. return $this->output; 
  149.  
  150. /** 
  151. * When index_key is not set for a particular item, push the value 
  152. * to the end of the stack. This is how array_column() behaves. 
  153. */ 
  154. $newlist = array(); 
  155. foreach ( $this->output as $value ) { 
  156. if ( is_object( $value ) ) { 
  157. if ( isset( $value->$index_key ) ) { 
  158. $newlist[ $value->$index_key ] = $value->$field; 
  159. } else { 
  160. $newlist[] = $value->$field; 
  161. } else { 
  162. if ( isset( $value[ $index_key ] ) ) { 
  163. $newlist[ $value[ $index_key ] ] = $value[ $field ]; 
  164. } else { 
  165. $newlist[] = $value[ $field ]; 
  166.  
  167. $this->output = $newlist; 
  168.  
  169. return $this->output; 
  170.  
  171. /** 
  172. * Sorts the list, based on one or more orderby arguments. 
  173. * 
  174. * @since 4.7.0 
  175. * 
  176. * @param string|array $orderby Optional. Either the field name to order by or an array 
  177. * of multiple orderby fields as $orderby => $order. 
  178. * @param string $order Optional. Either 'ASC' or 'DESC'. Only used if $orderby 
  179. * is a string. 
  180. * @param bool $preserve_keys Optional. Whether to preserve keys. Default false. 
  181. * @return array The sorted array. 
  182. */ 
  183. public function sort( $orderby = array(), $order = 'ASC', $preserve_keys = false ) { 
  184. if ( empty( $orderby ) ) { 
  185. return $this->output; 
  186.  
  187. if ( is_string( $orderby ) ) { 
  188. $orderby = array( $orderby => $order ); 
  189.  
  190. foreach ( $orderby as $field => $direction ) { 
  191. $orderby[ $field ] = 'DESC' === strtoupper( $direction ) ? 'DESC' : 'ASC'; 
  192.  
  193. $this->orderby = $orderby; 
  194.  
  195. if ( $preserve_keys ) { 
  196. uasort( $this->output, array( $this, 'sort_callback' ) ); 
  197. } else { 
  198. usort( $this->output, array( $this, 'sort_callback' ) ); 
  199.  
  200. $this->orderby = array(); 
  201.  
  202. return $this->output; 
  203.  
  204. /** 
  205. * Callback to sort the list by specific fields. 
  206. * 
  207. * @since 4.7.0 
  208. * @access private 
  209. * 
  210. * @see WP_List_Util::sort() 
  211. * 
  212. * @param object|array $a One object to compare. 
  213. * @param object|array $b The other object to compare. 
  214. * @return int 0 if both objects equal. -1 if second object should come first, 1 otherwise. 
  215. */ 
  216. private function sort_callback( $a, $b ) { 
  217. if ( empty( $this->orderby ) ) { 
  218. return 0; 
  219.  
  220. $a = (array) $a; 
  221. $b = (array) $b; 
  222.  
  223. foreach ( $this->orderby as $field => $direction ) { 
  224. if ( ! isset( $a[ $field ] ) || ! isset( $b[ $field ] ) ) { 
  225. continue; 
  226.  
  227. if ( $a[ $field ] == $b[ $field ] ) { 
  228. continue; 
  229.  
  230. $results = 'DESC' === $direction ? array( 1, -1 ) : array( -1, 1 ); 
  231.  
  232. if ( is_numeric( $a[ $field ] ) && is_numeric( $b[ $field ] ) ) { 
  233. return ( $a[ $field ] < $b[ $field ] ) ? $results[0] : $results[1]; 
  234.  
  235. return 0 > strcmp( $a[ $field ], $b[ $field ] ) ? $results[0] : $results[1]; 
  236.  
  237. return 0; 
.