| Total Complexity | 73 |
| Total Lines | 619 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like Select2 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Select2, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 27 | class Select2 extends Html { |
||
| 28 | // Send this many results with each request. |
||
| 29 | const RESULTS_PER_PAGE = 20; |
||
| 30 | |||
| 31 | // Don't send queries with fewer than this many characters |
||
| 32 | const MINIMUM_INPUT_LENGTH = '1'; |
||
| 33 | |||
| 34 | // Don't send queries until this many milliseconds. |
||
| 35 | const DELAY = '350'; |
||
| 36 | |||
| 37 | // API endpoints |
||
| 38 | const URL_FAM = 'action.php?action=select2-family'; |
||
| 39 | const URL_INDI = 'action.php?action=select2-individual'; |
||
| 40 | const URL_NOTE = 'action.php?action=select2-note'; |
||
| 41 | const URL_OBJE = 'action.php?action=select2-media'; |
||
| 42 | const URL_PLAC = 'action.php?action=select2-place'; |
||
| 43 | const URL_REPO = 'action.php?action=select2-repository'; |
||
| 44 | const URL_SOUR = 'action.php?action=select2-source'; |
||
| 45 | const URL_SUBM = 'action.php?action=select2-submitter'; |
||
| 46 | const URL_FLAG = 'action.php?action=select2-flag'; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Select2 configuration that is common to all searches. |
||
| 50 | * |
||
| 51 | * @return string[] |
||
| 52 | */ |
||
| 53 | private static function commonConfig() { |
||
| 54 | return [ |
||
| 55 | 'autocomplete' => 'off', |
||
| 56 | 'class' => 'form-control select2', |
||
| 57 | 'data-ajax--delay' => self::DELAY, |
||
| 58 | 'data-ajax--minimum-input-length' => self::MINIMUM_INPUT_LENGTH, |
||
| 59 | 'data-ajax--type' => 'POST', |
||
| 60 | 'data-allow-clear' => 'true', |
||
| 61 | 'data-placeholder' => '', |
||
| 62 | ]; |
||
| 63 | } |
||
| 64 | |||
| 65 | /** |
||
| 66 | * Select2 configuration for a family lookup. |
||
| 67 | * |
||
| 68 | * @return string[] |
||
| 69 | */ |
||
| 70 | public static function familyConfig() { |
||
| 71 | return self::commonConfig() + ['data-ajax--url' => self::URL_FAM]; |
||
| 72 | } |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Look up a family. |
||
| 76 | * |
||
| 77 | * @param Tree $tree Search this tree. |
||
| 78 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 79 | * @param string $query Search terms. |
||
| 80 | * |
||
| 81 | * @return mixed[] |
||
| 82 | */ |
||
| 83 | public static function familySearch(Tree $tree, $page, $query) { |
||
| 84 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 85 | $more = false; |
||
| 86 | $results = []; |
||
| 87 | |||
| 88 | $cursor = Database::prepare("SELECT DISTINCT 'FAM' AS type, f_id AS xref, f_gedcom AS gedcom, husb_name.n_sort, wife_name.n_sort" . |
||
| 89 | " FROM `##families`" . |
||
| 90 | " JOIN `##name` AS husb_name ON f_husb = husb_name.n_id AND f_file = husb_name.n_file" . |
||
| 91 | " JOIN `##name` AS wife_name ON f_wife = wife_name.n_id AND f_file = wife_name.n_file" . |
||
| 92 | " WHERE (CONCAT(husb_name.n_full, ' ', wife_name.n_full) LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR f_id = :xref) AND f_file = :tree_id" . |
||
| 93 | " AND husb_name.n_type <> '_MARNM' AND wife_name.n_type <> '_MARNM'" . |
||
| 94 | " ORDER BY husb_name.n_sort, wife_name.n_sort COLLATE :collation")->execute([ |
||
| 95 | 'query' => $query, |
||
| 96 | 'xref' => $query, |
||
| 97 | 'tree_id' => $tree->getTreeId(), |
||
| 98 | 'collation' => I18N::collation(), |
||
| 99 | ]); |
||
| 100 | |||
| 101 | while (is_object($row = $cursor->fetch())) { |
||
| 102 | $family = Family::getInstance($row->xref, $tree, $row->gedcom); |
||
| 103 | // Filter for privacy |
||
| 104 | if ($family !== null && $family->canShowName()) { |
||
| 105 | if ($offset > 0) { |
||
| 106 | // Skip results |
||
| 107 | $offset--; |
||
| 108 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 109 | // Stop when we have found a page of results |
||
| 110 | $more = true; |
||
| 111 | break; |
||
| 112 | } else { |
||
| 113 | // Add to the results |
||
| 114 | $results[] = [ |
||
| 115 | 'id' => $row->xref, |
||
| 116 | 'text' => view('selects/family', ['family' => $family]), |
||
| 117 | ]; |
||
| 118 | } |
||
| 119 | } |
||
| 120 | } |
||
| 121 | $cursor->closeCursor(); |
||
| 122 | |||
| 123 | return [ |
||
| 124 | 'results' => $results, |
||
| 125 | 'pagination' => [ |
||
| 126 | 'more' => $more, |
||
| 127 | ], |
||
| 128 | ]; |
||
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Select2 configuration for a flag icon lookup. |
||
| 133 | * |
||
| 134 | * @return string[] |
||
| 135 | */ |
||
| 136 | public static function flagConfig() { |
||
| 137 | return self::commonConfig() + ['data-ajax--url' => self::URL_FLAG]; |
||
| 138 | } |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Format a flag icon for display in a Select2 control. |
||
| 142 | * |
||
| 143 | * @param string $flag |
||
| 144 | * |
||
| 145 | * @return string |
||
| 146 | */ |
||
| 147 | public static function flagValue($flag) { |
||
| 148 | return '<img src="' . WT_MODULES_DIR . 'googlemap/places/flags/' . $flag . '"> ' . $flag; |
||
| 149 | } |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Look up a flag icon. |
||
| 153 | * |
||
| 154 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 155 | * @param string $query Search terms. |
||
| 156 | * |
||
| 157 | * @return mixed[] |
||
| 158 | */ |
||
| 159 | public static function flagSearch($page, $query) { |
||
| 160 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 161 | $more = false; |
||
| 162 | $results = []; |
||
| 163 | $directory = WT_ROOT . WT_MODULES_DIR . 'googlemap/places/flags/'; |
||
| 164 | $di = new RecursiveDirectoryIterator($directory); |
||
| 165 | $it = new RecursiveIteratorIterator($di); |
||
| 166 | |||
| 167 | $flag_files = []; |
||
| 168 | foreach ($it as $file) { |
||
| 169 | $file_path = substr($file->getPathname(), strlen($directory)); |
||
| 170 | if ($file->getExtension() === 'png' && stripos($file_path, $query) !== false) { |
||
| 171 | if ($offset > 0) { |
||
| 172 | // Skip results |
||
| 173 | $offset--; |
||
| 174 | } elseif (count($flag_files) >= self::RESULTS_PER_PAGE) { |
||
| 175 | $more = true; |
||
| 176 | break; |
||
| 177 | } else { |
||
| 178 | $flag_files[] = $file_path; |
||
| 179 | } |
||
| 180 | } |
||
| 181 | } |
||
| 182 | |||
| 183 | foreach ($flag_files as $flag_file) { |
||
| 184 | $results[] = [ |
||
| 185 | 'id' => $flag_file, |
||
| 186 | 'text' => self::flagValue($flag_file), |
||
| 187 | ]; |
||
| 188 | } |
||
| 189 | |||
| 190 | return [ |
||
| 191 | 'results' => $results, |
||
| 192 | 'pagination' => [ |
||
| 193 | 'more' => $more, |
||
| 194 | ], |
||
| 195 | ]; |
||
| 196 | } |
||
| 197 | |||
| 198 | /** |
||
| 199 | * Select2 configuration for an individual lookup. |
||
| 200 | * |
||
| 201 | * @return string[] |
||
| 202 | */ |
||
| 203 | public static function individualConfig() { |
||
| 204 | return self::commonConfig() + ['data-ajax--url' => self::URL_INDI]; |
||
| 205 | } |
||
| 206 | |||
| 207 | /** |
||
| 208 | * Look up an individual. |
||
| 209 | * |
||
| 210 | * @param Tree $tree Search this tree. |
||
| 211 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 212 | * @param string $query Search terms. |
||
| 213 | * |
||
| 214 | * @return mixed[] |
||
| 215 | */ |
||
| 216 | public static function individualSearch(Tree $tree, $page, $query) { |
||
| 217 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 218 | $more = false; |
||
| 219 | $results = []; |
||
| 220 | $cursor = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom, n_num" . " FROM `##individuals`" . " JOIN `##name` ON i_id = n_id AND i_file = n_file" . " WHERE (n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR i_id = :xref) AND i_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([ |
||
| 221 | 'query' => $query, |
||
| 222 | 'xref' => $query, |
||
| 223 | 'tree_id' => $tree->getTreeId(), |
||
| 224 | 'collation' => I18N::collation(), |
||
| 225 | ]); |
||
| 226 | |||
| 227 | while (is_object($row = $cursor->fetch())) { |
||
| 228 | $individual = Individual::getInstance($row->xref, $tree, $row->gedcom); |
||
| 229 | $individual->setPrimaryName($row->n_num); |
||
| 230 | // Filter for privacy |
||
| 231 | if ($individual !== null && $individual->canShowName()) { |
||
| 232 | if ($offset > 0) { |
||
| 233 | // Skip results |
||
| 234 | $offset--; |
||
| 235 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 236 | // Stop when we have found a page of results |
||
| 237 | $more = true; |
||
| 238 | break; |
||
| 239 | } else { |
||
| 240 | // Add to the results |
||
| 241 | $results[] = [ |
||
| 242 | 'id' => $row->xref, |
||
| 243 | 'text' => view('selects/individual', ['individual' => $individual]), |
||
| 244 | ]; |
||
| 245 | } |
||
| 246 | } |
||
| 247 | } |
||
| 248 | $cursor->closeCursor(); |
||
| 249 | |||
| 250 | return [ |
||
| 251 | 'results' => $results, |
||
| 252 | 'pagination' => [ |
||
| 253 | 'more' => $more, |
||
| 254 | ], |
||
| 255 | ]; |
||
| 256 | } |
||
| 257 | |||
| 258 | /** |
||
| 259 | * Select2 configuration for a media object lookup. |
||
| 260 | * |
||
| 261 | * @return string[] |
||
| 262 | */ |
||
| 263 | public static function mediaObjectConfig() { |
||
| 264 | return self::commonConfig() + ['data-ajax--url' => self::URL_OBJE]; |
||
| 265 | } |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Look up a media object. |
||
| 269 | * |
||
| 270 | * @param Tree $tree Search this tree. |
||
| 271 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 272 | * @param string $query Search terms. |
||
| 273 | * |
||
| 274 | * @return mixed[] |
||
| 275 | */ |
||
| 276 | public static function mediaObjectSearch(Tree $tree, $page, $query) { |
||
| 277 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 278 | $more = false; |
||
| 279 | $results = []; |
||
| 280 | $cursor = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom, n_full" . " FROM `##media`" . " JOIN `##name` ON m_id = n_id AND m_file = n_file" . " WHERE (n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR m_id = :xref) AND m_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([ |
||
| 281 | 'query' => $query, |
||
| 282 | 'xref' => $query, |
||
| 283 | 'tree_id' => $tree->getTreeId(), |
||
| 284 | 'collation' => I18N::collation(), |
||
| 285 | ]); |
||
| 286 | |||
| 287 | while (is_object($row = $cursor->fetch())) { |
||
| 288 | $media = Media::getInstance($row->xref, $tree, $row->gedcom); |
||
| 289 | // Filter for privacy |
||
| 290 | if ($media !== null && $media->canShow()) { |
||
| 291 | if ($offset > 0) { |
||
| 292 | // Skip results |
||
| 293 | $offset--; |
||
| 294 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 295 | // Stop when we have found a page of results |
||
| 296 | $more = true; |
||
| 297 | break; |
||
| 298 | } else { |
||
| 299 | // Add to the results |
||
| 300 | $results[] = [ |
||
| 301 | 'id' => $row->xref, |
||
| 302 | 'text' => view('selects/media', ['media' => $media]), |
||
| 303 | ]; |
||
| 304 | } |
||
| 305 | } |
||
| 306 | } |
||
| 307 | $cursor->closeCursor(); |
||
| 308 | |||
| 309 | return [ |
||
| 310 | 'results' => $results, |
||
| 311 | 'pagination' => [ |
||
| 312 | 'more' => $more, |
||
| 313 | ], |
||
| 314 | ]; |
||
| 315 | } |
||
| 316 | |||
| 317 | /** |
||
| 318 | * Select2 configuration for a note. |
||
| 319 | * |
||
| 320 | * @return string[] |
||
| 321 | */ |
||
| 322 | public static function noteConfig() { |
||
| 323 | return self::commonConfig() + ['data-ajax--url' => self::URL_NOTE]; |
||
| 324 | } |
||
| 325 | |||
| 326 | /** |
||
| 327 | * Look up a note. |
||
| 328 | * |
||
| 329 | * @param Tree $tree Search this tree. |
||
| 330 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 331 | * @param string $query Search terms. |
||
| 332 | * |
||
| 333 | * @return mixed[] |
||
| 334 | */ |
||
| 335 | public static function noteSearch(Tree $tree, $page, $query) { |
||
| 336 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 337 | $more = false; |
||
| 338 | $results = []; |
||
| 339 | $cursor = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom, n_full" . " FROM `##other`" . " JOIN `##name` ON o_id = n_id AND o_file = n_file" . " WHERE (n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR o_id = :xref) AND o_file = :tree_id AND o_type='NOTE'" . " ORDER BY n_full COLLATE :collation")->execute([ |
||
| 340 | 'query' => $query, |
||
| 341 | 'xref' => $query, |
||
| 342 | 'tree_id' => $tree->getTreeId(), |
||
| 343 | 'collation' => I18N::collation(), |
||
| 344 | ]); |
||
| 345 | |||
| 346 | while (is_object($row = $cursor->fetch())) { |
||
| 347 | $note = Note::getInstance($row->xref, $tree, $row->gedcom); |
||
| 348 | // Filter for privacy |
||
| 349 | if ($note !== null && $note->canShowName()) { |
||
| 350 | if ($offset > 0) { |
||
| 351 | // Skip results |
||
| 352 | $offset--; |
||
| 353 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 354 | // Stop when we have found a page of results |
||
| 355 | $more = true; |
||
| 356 | break; |
||
| 357 | } else { |
||
| 358 | // Add to the results |
||
| 359 | $results[] = [ |
||
| 360 | 'id' => $row->xref, |
||
| 361 | 'text' => view('selects/note', ['note' => $note]), |
||
| 362 | ]; |
||
| 363 | } |
||
| 364 | } |
||
| 365 | } |
||
| 366 | $cursor->closeCursor(); |
||
| 367 | |||
| 368 | return [ |
||
| 369 | 'results' => $results, |
||
| 370 | 'pagination' => [ |
||
| 371 | 'more' => $more, |
||
| 372 | ], |
||
| 373 | ]; |
||
| 374 | } |
||
| 375 | |||
| 376 | /** |
||
| 377 | * Select2 configuration for a note. |
||
| 378 | * |
||
| 379 | * @return string[] |
||
| 380 | */ |
||
| 381 | public static function placeConfig() { |
||
| 382 | return self::commonConfig() + ['data-ajax--url' => self::URL_PLAC]; |
||
| 383 | } |
||
| 384 | |||
| 385 | /** |
||
| 386 | * Look up a place name. |
||
| 387 | * |
||
| 388 | * @param Tree $tree Search this tree. |
||
| 389 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 390 | * @param string $query Search terms. |
||
| 391 | * @param bool $create if true, include the query in the results so it can be created. |
||
| 392 | * |
||
| 393 | * @return mixed[] |
||
| 394 | */ |
||
| 395 | public static function placeSearch(Tree $tree, $page, $query, $create) { |
||
| 396 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 397 | $results = []; |
||
| 398 | $found = false; |
||
| 399 | |||
| 400 | // Do not filter by privacy. Place names on their own do not identify individuals. |
||
| 401 | foreach (Place::findPlaces($query, $tree) as $place) { |
||
| 402 | $place_name = $place->getGedcomName(); |
||
| 403 | if ($place_name === $query) { |
||
| 404 | $found = true; |
||
| 405 | } |
||
| 406 | $results[] = [ |
||
| 407 | 'id' => $place_name, |
||
| 408 | 'text' => $place_name, |
||
| 409 | ]; |
||
| 410 | } |
||
| 411 | |||
| 412 | // No place found? Use an external gazetteer |
||
| 413 | if (empty($results) && $tree->getPreference('GEONAMES_ACCOUNT')) { |
||
| 414 | $url = |
||
| 415 | "http://api.geonames.org/searchJSON" . |
||
| 416 | "?name_startsWith=" . urlencode($query) . |
||
| 417 | "&lang=" . WT_LOCALE . |
||
| 418 | "&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC" . |
||
| 419 | "&style=full" . |
||
| 420 | "&username=" . $tree->getPreference('GEONAMES_ACCOUNT'); |
||
| 421 | // try to use curl when file_get_contents not allowed |
||
| 422 | if (ini_get('allow_url_fopen')) { |
||
| 423 | $json = file_get_contents($url); |
||
| 424 | $places = json_decode($json, true); |
||
| 425 | } elseif (function_exists('curl_init')) { |
||
| 426 | $ch = curl_init(); |
||
| 427 | curl_setopt($ch, CURLOPT_URL, $url); |
||
| 428 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
||
| 429 | $json = curl_exec($ch); |
||
| 430 | $places = json_decode($json, true); |
||
| 431 | curl_close($ch); |
||
| 432 | } else { |
||
| 433 | $places = []; |
||
| 434 | } |
||
| 435 | if (isset($places['geonames']) && is_array($places['geonames'])) { |
||
| 436 | foreach ($places['geonames'] as $k => $place) { |
||
| 437 | $place_name = $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName']; |
||
| 438 | if ($place_name === $query) { |
||
| 439 | $found = true; |
||
| 440 | } |
||
| 441 | $results[] = [ |
||
| 442 | 'id' => $place_name, |
||
| 443 | 'text' => $place_name, |
||
| 444 | ]; |
||
| 445 | } |
||
| 446 | } |
||
| 447 | } |
||
| 448 | |||
| 449 | // Include the query term in the results. This allows the user to select a |
||
| 450 | // place that doesn't already exist in the database. |
||
| 451 | if (!$found && $create) { |
||
| 452 | array_unshift($results, [ |
||
| 453 | 'id' => $query, |
||
| 454 | 'text' => $query, |
||
| 455 | ]); |
||
| 456 | } |
||
| 457 | |||
| 458 | $more = count($results) > $offset + self::RESULTS_PER_PAGE; |
||
| 459 | $results = array_slice($results, $offset, self::RESULTS_PER_PAGE); |
||
| 460 | |||
| 461 | return [ |
||
| 462 | 'results' => $results, |
||
| 463 | 'pagination' => [ |
||
| 464 | 'more' => $more, |
||
| 465 | ], |
||
| 466 | ]; |
||
| 467 | } |
||
| 468 | |||
| 469 | /** |
||
| 470 | * Select2 configuration for a repository lookup. |
||
| 471 | * |
||
| 472 | * @return string[] |
||
| 473 | */ |
||
| 474 | public static function repositoryConfig() { |
||
| 476 | } |
||
| 477 | |||
| 478 | /** |
||
| 479 | * Look up a repository. |
||
| 480 | * |
||
| 481 | * @param Tree $tree Search this tree. |
||
| 482 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 483 | * @param string $query Search terms. |
||
| 484 | * |
||
| 485 | * @return mixed[] |
||
| 486 | */ |
||
| 487 | public static function repositorySearch(Tree $tree, $page, $query) { |
||
| 488 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 489 | $more = false; |
||
| 490 | $results = []; |
||
| 491 | $cursor = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom, n_full" . " FROM `##other`" . " JOIN `##name` ON o_id = n_id AND o_file = n_file" . " WHERE (n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR o_id = :xref) AND o_file = :tree_id AND o_type = 'REPO'" . " ORDER BY n_full COLLATE :collation")->execute([ |
||
| 492 | 'query' => $query, |
||
| 493 | 'xref' => $query, |
||
| 494 | 'tree_id' => $tree->getTreeId(), |
||
| 495 | 'collation' => I18N::collation(), |
||
| 496 | ]); |
||
| 497 | |||
| 498 | while (is_object($row = $cursor->fetch())) { |
||
| 499 | $repository = Repository::getInstance($row->xref, $tree, $row->gedcom); |
||
| 500 | // Filter for privacy |
||
| 501 | if ($repository !== null && $repository->canShow()) { |
||
| 502 | if ($offset > 0) { |
||
| 503 | // Skip results |
||
| 504 | $offset--; |
||
| 505 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 506 | // Stop when we have found a page of results |
||
| 507 | $more = true; |
||
| 508 | break; |
||
| 509 | } else { |
||
| 510 | // Add to the results |
||
| 511 | $results[] = [ |
||
| 512 | 'id' => $row->xref, |
||
| 513 | 'text' => view('selects/repository', ['repository' => $repository]), |
||
| 514 | ]; |
||
| 515 | } |
||
| 516 | } |
||
| 517 | } |
||
| 518 | $cursor->closeCursor(); |
||
| 519 | |||
| 520 | return [ |
||
| 521 | 'results' => $results, |
||
| 522 | 'pagination' => [ |
||
| 523 | 'more' => $more, |
||
| 524 | ], |
||
| 525 | ]; |
||
| 526 | } |
||
| 527 | |||
| 528 | /** |
||
| 529 | * Select2 configuration for a source lookup. |
||
| 530 | * |
||
| 531 | * @return string[] |
||
| 532 | */ |
||
| 533 | public static function sourceConfig() { |
||
| 535 | } |
||
| 536 | |||
| 537 | /** |
||
| 538 | * Look up a source. |
||
| 539 | * |
||
| 540 | * @param Tree $tree Search this tree. |
||
| 541 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 542 | * @param string $query Search terms. |
||
| 543 | * |
||
| 544 | * @return mixed[] |
||
| 545 | */ |
||
| 546 | public static function sourceSearch(Tree $tree, $page, $query) { |
||
| 547 | $offset = $page * self::RESULTS_PER_PAGE; |
||
| 548 | $more = false; |
||
| 549 | $results = []; |
||
| 550 | $cursor = Database::prepare("SELECT s_id AS xref, s_gedcom AS gedcom, n_full" . " FROM `##sources`" . " JOIN `##name` ON s_id = n_id AND s_file = n_file" . " WHERE (n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') OR s_id = :xref) AND s_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([ |
||
| 551 | 'query' => $query, |
||
| 552 | 'xref' => $query, |
||
| 553 | 'tree_id' => $tree->getTreeId(), |
||
| 554 | 'collation' => I18N::collation(), |
||
| 555 | ]); |
||
| 556 | |||
| 557 | while (is_object($row = $cursor->fetch())) { |
||
| 558 | $source = Source::getInstance($row->xref, $tree, $row->gedcom); |
||
| 559 | // Filter for privacy |
||
| 560 | if ($source !== null && $source->canShow()) { |
||
| 561 | if ($offset > 0) { |
||
| 562 | // Skip results |
||
| 563 | $offset--; |
||
| 564 | } elseif (count($results) === self::RESULTS_PER_PAGE) { |
||
| 565 | // Stop when we have found a page of results |
||
| 566 | $more = true; |
||
| 567 | break; |
||
| 568 | } else { |
||
| 569 | // Add to the results |
||
| 570 | $results[] = [ |
||
| 571 | 'id' => $row->xref, |
||
| 572 | 'text' => view('selects/source', ['source' => $source]), |
||
| 573 | ]; |
||
| 574 | } |
||
| 575 | } |
||
| 576 | } |
||
| 577 | $cursor->closeCursor(); |
||
| 578 | |||
| 579 | return [ |
||
| 580 | 'results' => $results, |
||
| 581 | 'pagination' => [ |
||
| 582 | 'more' => $more, |
||
| 583 | ], |
||
| 584 | ]; |
||
| 585 | } |
||
| 586 | |||
| 587 | /** |
||
| 588 | * Select2 configuration for a submitter lookup. |
||
| 589 | * |
||
| 590 | * @return string[] |
||
| 591 | */ |
||
| 592 | public static function submitterConfig() { |
||
| 594 | } |
||
| 595 | |||
| 596 | /** |
||
| 597 | * Look up a submitter. |
||
| 598 | * |
||
| 599 | * @param Tree $tree Search this tree. |
||
| 600 | * @param int $page Skip this number of pages. Starts with zero. |
||
| 601 | * @param string $query Search terms. |
||
| 602 | * |
||
| 603 | * @return mixed[] |
||
| 604 | */ |
||
| 605 | public static function submitterSearch(Tree $tree, $page, $query) { |
||
| 646 | ], |
||
| 647 | ]; |
||
| 648 | } |
||
| 649 | } |
||
| 650 |