Textpattern | PHP Cross Reference | Content Management Systems |
Description: Admin-side search method.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * https://textpattern.com/ 6 * 7 * Copyright (C) 2020 The Textpattern Development Team 8 * 9 * This file is part of Textpattern. 10 * 11 * Textpattern is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation, version 2. 14 * 15 * Textpattern is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with Textpattern. If not, see <https://www.gnu.org/licenses/>. 22 */ 23 24 /** 25 * Admin-side search method. 26 * 27 * A container for packaging search criteria into a cohesive set of SQL 28 * statements suitable for the WHERE clause of a query. 29 * 30 * Supports aliasing of criteria so many user input values equates to a single 31 * value to be compared in the DB (e.g. 'true', 'yes', or '1' can all be used to 32 * check for a '1' in a boolean field). 33 * 34 * @since 4.6.0 35 * @package Search 36 */ 37 38 namespace Textpattern\Search; 39 40 class Method 41 { 42 /** 43 * The method's unique reference -- usually the form-submitted variable name. 44 * 45 * @var string 46 */ 47 48 protected $id; 49 50 /** 51 * The database column names against which a search should be performed. 52 * 53 * @var array 54 */ 55 56 protected $columns; 57 58 /** 59 * The method's human friendly name. 60 * 61 * @var string 62 */ 63 64 protected $label; 65 66 /** 67 * The method's data type. 68 * 69 * Determines if the method is compared as string, integer, etc. 70 * 71 * @var string 72 */ 73 74 protected $type; 75 76 /** 77 * The method's options. 78 * 79 * @var array 80 */ 81 82 protected $options; 83 84 /** 85 * Criteria aliases: values that are equivalent to the actual DB value. 86 * 87 * @var array 88 */ 89 90 protected $aliases; 91 92 /** 93 * General constructor for search methods. 94 * 95 * @param string $key The unique reference to this Method 96 * @param array $atts Attributes such as the DB column(s) to which the method applies, its label or data type 97 */ 98 99 public function __construct($key, $atts) 100 { 101 $this->id = $key; 102 $options = array(); 103 104 foreach ($atts as $attribute => $value) { 105 switch ($attribute) { 106 case 'column': 107 $this->columns = (array) $value; 108 break; 109 case 'label': 110 $this->label = (string) $value; 111 break; 112 case 'type': 113 $this->type = (string) $value; 114 break; 115 case 'options': 116 $options = (array) $value; 117 break; 118 } 119 } 120 121 $this->setOptions($options); 122 } 123 124 /** 125 * Sets method's options. 126 * 127 * Valid options are: 128 * -> always_like: treat the criteria as SQL LIKE, regardless if it is "in quotes". 129 * -> can_list: the criteria can be a comma-separated list of values to retrieve. 130 * -> case_sensitive: the criteria is case sensitive. 131 * 132 * @param array $options Array of options 133 */ 134 135 public function setOptions($options = array()) 136 { 137 $this->options = lAtts(array( 138 'always_like' => false, 139 'can_list' => false, 140 'case_sensitive' => false, 141 ), (array) $options); 142 } 143 144 /** 145 * Gets methods options. 146 * 147 * @param array $options Array of options 148 */ 149 150 public function getOptions($keys = array()) 151 { 152 $out = array(); 153 154 if (empty($keys)) { 155 $keys = array_keys($this->options); 156 } 157 158 foreach ((array) $keys as $key) { 159 if (isset($this->options[$key])) { 160 $out[] = $this->options[$key]; 161 } 162 } 163 164 return $out; 165 } 166 167 /** 168 * Sets method aliases. 169 * 170 * An alias' key is the literal value that is passed to the database as search criteria 171 * if the user-supplied criteria matches any of the aliases. Useful for computed, 172 * define()d or boolean fields. For example, allowing anyone to use the (localised) 173 * words 'draft', 'hidden' or 'live' in a search box as aliases for the numeric 174 * values 1, 2, and 4 respectively. 175 * 176 * @param string $column DB column to which the aliases should be applied. 177 * @param string $key DB value that is returned if the criteria matches. 178 * @param array $aliases Criteria values that are equivalent to the key. 179 */ 180 181 public function setAlias($column, $key, $aliases) 182 { 183 $this->aliases[$column][$key] = $aliases; 184 } 185 186 /** 187 * Searches aliases for a partial match. 188 * 189 * @param string $needle The thing to look for 190 * @param array $haystack The place to look in 191 * @param string $type $needle's type, which affects the way the alias is interpreted 192 */ 193 194 private function findAlias($needle, $haystack, $type = '') 195 { 196 foreach ($haystack as $key => $value) { 197 if ($type === 'numeric') { 198 if ($value == $needle) { 199 return $key; 200 } 201 } else { 202 if (strpos($value, $needle) !== false) { 203 return $key; 204 } 205 } 206 } 207 208 return false; 209 } 210 211 /** 212 * Gets an item from the object. 213 * 214 * @param string $item The thing to retrieve 215 */ 216 217 public function getInfo($item) 218 { 219 $out = null; 220 221 switch ($item) { 222 case 'column': 223 $out = $this->columns; 224 break; 225 case 'label': 226 $out = $this->label; 227 break; 228 case 'type': 229 $out = $this->type; 230 break; 231 } 232 233 return $out; 234 } 235 236 /** 237 * Gets an SQL clause for this method based on the criteria. 238 * 239 * @todo Case-sensitive searches 240 * 241 * @param string $search_term The value to search for 242 * @param int $verbatim Whether the search term is in quotes (1) or not (0) 243 */ 244 245 public function getCriteria($search_term, $verbatim) 246 { 247 $clause = array(); 248 249 foreach ($this->columns as $column) { 250 if (isset($this->aliases[$column])) { 251 foreach ($this->aliases[$column] as $dbval => $aliases) { 252 $terms = do_list($search_term); 253 254 foreach ($terms as $idx => $term) { 255 if ($this->findAlias($term, $aliases, $this->type) !== false) { 256 $terms[$idx] = $dbval; 257 } 258 } 259 260 $search_term = join(',', $terms); 261 } 262 } 263 264 if ($this->options['case_sensitive']) { 265 $column = 'BINARY '.$column; 266 } 267 268 if ($this->options['can_list']) { 269 $operator = ' in '; 270 $value = '('.join(',', quote_list(do_list($search_term))).')'; 271 } elseif ($this->type === 'boolean') { 272 $clause[] = "convert(".$column.", char) = '".$search_term."'"; 273 continue; 274 } elseif ($verbatim && !$this->options['always_like']) { 275 $operator = ' = '; 276 $value = doQuote($search_term); 277 } elseif ($this->type === 'find_in_set') { 278 $clause[] = "find_in_set('".$search_term."', ".$column." )"; 279 continue; 280 } elseif ($this->type === 'numeric') { 281 $clause[] = "convert(".$column.", char) = '".$search_term."'"; 282 continue; 283 } else { 284 $operator = ' like '; 285 $value = doQuote("%$search_term%"); 286 } 287 288 $clause[] = join($operator, array($column, $value)); 289 } 290 291 return $clause; 292 } 293 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title