Total Complexity | 111 |
Total Lines | 507 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like QueryName 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 QueryName, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class QueryName { |
||
28 | /** |
||
29 | * Get a list of initial letters, for lists of names. |
||
30 | * |
||
31 | * @param string $locale Return the alphabet for this locale |
||
32 | * |
||
33 | * @return string[] |
||
34 | */ |
||
35 | private static function getAlphabetForLocale($locale) { |
||
36 | switch ($locale) { |
||
37 | case 'ar': |
||
38 | return [ |
||
39 | 'ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی', |
||
40 | ]; |
||
41 | case 'cs': |
||
42 | return [ |
||
43 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'CH', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||
44 | ]; |
||
45 | case 'da': |
||
46 | case 'nb': |
||
47 | case 'nn': |
||
48 | return [ |
||
49 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Æ', 'Ø', 'Å', |
||
50 | ]; |
||
51 | case 'el': |
||
52 | return [ |
||
53 | 'Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω', |
||
54 | ]; |
||
55 | case 'es': |
||
56 | return [ |
||
57 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'Ñ', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||
58 | ]; |
||
59 | case 'et': |
||
60 | return [ |
||
61 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'Z', 'Ž', 'T', 'U', 'V', 'W', 'Õ', 'Ä', 'Ö', 'Ü', 'X', 'Y', |
||
62 | ]; |
||
63 | case 'fi': |
||
64 | case 'sv': |
||
65 | return [ |
||
66 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Å', 'Ä', 'Ö', |
||
67 | ]; |
||
68 | case 'he': |
||
69 | return [ |
||
70 | 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק', 'ר', 'ש', 'ת', |
||
71 | ]; |
||
72 | case 'hu': |
||
73 | return [ |
||
74 | 'A', 'B', 'C', 'CS', 'D', 'DZ', 'DZS', 'E', 'F', 'G', 'GY', 'H', 'I', 'J', 'K', 'L', 'LY', 'M', 'N', 'NY', 'O', 'Ö', 'P', 'Q', 'R', 'S', 'SZ', 'T', 'TY', 'U', 'Ü', 'V', 'W', 'X', 'Y', 'Z', 'ZS', |
||
75 | ]; |
||
76 | case 'lt': |
||
77 | return [ |
||
78 | 'A', 'Ą', 'B', 'C', 'Č', 'D', 'E', 'Ę', 'Ė', 'F', 'G', 'H', 'I', 'Y', 'Į', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'Š', 'T', 'U', 'Ų', 'Ū', 'V', 'Z', 'Ž', |
||
79 | ]; |
||
80 | case 'nl': |
||
81 | return [ |
||
82 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'IJ', |
||
83 | ]; |
||
84 | case 'pl': |
||
85 | return [ |
||
86 | 'A', 'B', 'C', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Ł', 'M', 'N', 'O', 'Ó', 'P', 'Q', 'R', 'S', 'Ś', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ź', 'Ż', |
||
87 | ]; |
||
88 | case 'ro': |
||
89 | return [ |
||
90 | 'A', 'Ă', 'Â', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'Î', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Ş', 'T', 'Ţ', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||
91 | ]; |
||
92 | case 'ru': |
||
93 | return [ |
||
94 | 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я', |
||
95 | ]; |
||
96 | case 'sk': |
||
97 | return [ |
||
98 | 'A', 'Á', 'Ä', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'F', 'G', 'H', 'I', 'Í', 'J', 'K', 'L', 'Ľ', 'Ĺ', 'M', 'N', 'Ň', 'O', 'Ó', 'Ô', 'P', 'Q', 'R', 'Ŕ', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž', |
||
99 | ]; |
||
100 | case 'sl': |
||
101 | return [ |
||
102 | 'A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž', |
||
103 | ]; |
||
104 | case 'sr': |
||
105 | return [ |
||
106 | 'A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž', |
||
107 | ]; |
||
108 | case 'tr': |
||
109 | return [ |
||
110 | 'A', 'B', 'C', 'Ç', 'D', 'E', 'F', 'G', 'Ğ', 'H', 'I', 'İ', 'J', 'K', 'L', 'M', 'N', 'O', 'Ö', 'P', 'R', 'S', 'Ş', 'T', 'U', 'Ü', 'V', 'Y', 'Z', |
||
111 | ]; |
||
112 | default: |
||
113 | return [ |
||
114 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||
115 | ]; |
||
116 | } |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Get the initial letter of a name, taking care of multi-letter sequences and equivalences. |
||
121 | * |
||
122 | * @param string $name |
||
123 | * |
||
124 | * @return string |
||
125 | */ |
||
126 | public static function initialLetter($name) { |
||
127 | $name = I18N::strtoupper($name); |
||
128 | switch (WT_LOCALE) { |
||
129 | case 'cs': |
||
130 | if (substr($name, 0, 2) == 'CH') { |
||
131 | return 'CH'; |
||
132 | } |
||
133 | break; |
||
134 | case 'da': |
||
135 | case 'nb': |
||
136 | case 'nn': |
||
137 | if (substr($name, 0, 2) == 'AA') { |
||
138 | return 'Å'; |
||
139 | } |
||
140 | break; |
||
141 | case 'hu': |
||
142 | if (substr($name, 0, 2) == 'CS') { |
||
143 | return 'CS'; |
||
144 | } elseif (substr($name, 0, 3) == 'DZS') { |
||
145 | return 'DZS'; |
||
146 | } elseif (substr($name, 0, 2) == 'DZ') { |
||
147 | return 'DZ'; |
||
148 | } elseif (substr($name, 0, 2) == 'GY') { |
||
149 | return 'GY'; |
||
150 | } elseif (substr($name, 0, 2) == 'LY') { |
||
151 | return 'LY'; |
||
152 | } elseif (substr($name, 0, 2) == 'NY') { |
||
153 | return 'NY'; |
||
154 | } elseif (substr($name, 0, 2) == 'SZ') { |
||
155 | return 'SZ'; |
||
156 | } elseif (substr($name, 0, 2) == 'TY') { |
||
157 | return 'TY'; |
||
158 | } elseif (substr($name, 0, 2) == 'ZS') { |
||
159 | return 'ZS'; |
||
160 | } |
||
161 | break; |
||
162 | case 'nl': |
||
163 | if (substr($name, 0, 2) == 'IJ') { |
||
164 | return 'IJ'; |
||
165 | } |
||
166 | break; |
||
167 | } |
||
168 | // No special rules - just take the first character |
||
169 | return mb_substr($name, 0, 1); |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * Generate SQL to match a given letter, taking care of cases that |
||
174 | * are not covered by the collation setting. |
||
175 | * |
||
176 | * We must consider: |
||
177 | * potential substrings, such as Czech "CH" and "C" |
||
178 | * equivalent letters, such as Danish "AA" and "Å" |
||
179 | * |
||
180 | * We COULD write something that handles all languages generically, |
||
181 | * but its performance would most likely be poor. |
||
182 | * |
||
183 | * For languages that don't appear in this list, we could write |
||
184 | * simpler versions of the surnameAlpha() and givenAlpha() functions, |
||
185 | * but it gives no noticable improvement in performance. |
||
186 | * |
||
187 | * @param string $field |
||
188 | * @param string $letter |
||
189 | * |
||
190 | * @return string |
||
191 | */ |
||
192 | private static function getInitialSql($field, $letter) { |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Get a list of initial surname letters for indilist.php and famlist.php |
||
234 | * |
||
235 | * @param Tree $tree Find surnames from this tree |
||
236 | * @param bool $marnm if set, include married names |
||
237 | * @param bool $fams if set, only consider individuals with FAMS records |
||
238 | * @param bool $totals if set, count the number of names beginning with each letter |
||
239 | * |
||
240 | * @return int[] |
||
241 | */ |
||
242 | public static function surnameAlpha(Tree $tree, $marnm, $fams, $totals = true) { |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Get a list of initial given name letters for indilist.php and famlist.php |
||
309 | * |
||
310 | * @param Tree $tree Find names in this tree |
||
311 | * @param string $surn if set, only consider people with this surname |
||
312 | * @param string $salpha if set, only consider surnames starting with this letter |
||
313 | * @param bool $marnm if set, include married names |
||
314 | * @param bool $fams if set, only consider individuals with FAMS records |
||
315 | * |
||
316 | * @return int[] |
||
317 | */ |
||
318 | public static function givenAlpha(Tree $tree, $surn, $salpha, $marnm, $fams) { |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Get a list of actual surnames and variants, based on a "root" surname. |
||
391 | * |
||
392 | * @param Tree $tree only fetch individuals from this tree |
||
393 | * @param string $surn if set, only fetch people with this surname |
||
394 | * @param string $salpha if set, only consider surnames starting with this letter |
||
395 | * @param bool $marnm if set, include married names |
||
396 | * @param bool $fams if set, only consider individuals with FAMS records |
||
397 | * |
||
398 | * @return array |
||
399 | */ |
||
400 | public static function surnames(Tree $tree, $surn, $salpha, $marnm, $fams) { |
||
401 | $sql = |
||
402 | "SELECT SQL_CACHE n2.n_surn, n1.n_surname, n1.n_id" . |
||
403 | " FROM `##name` n1 " . |
||
404 | ($fams ? " JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") . |
||
405 | " JOIN (SELECT n_surn COLLATE :collate_0 AS n_surn, n_file FROM `##name`" . |
||
406 | " WHERE n_file = :tree_id" . |
||
407 | ($marnm ? "" : " AND n_type != '_MARNM'"); |
||
408 | |||
409 | $args = [ |
||
410 | 'tree_id' => $tree->getTreeId(), |
||
411 | 'collate_0' => I18N::collation(), |
||
412 | ]; |
||
413 | |||
414 | if ($surn) { |
||
415 | $sql .= " AND n_surn COLLATE :collate_1 = :surn"; |
||
416 | $args['collate_1'] = I18N::collation(); |
||
417 | $args['surn'] = $surn; |
||
418 | } elseif ($salpha === ',') { |
||
419 | $sql .= " AND n_surn = ''"; |
||
420 | } elseif ($salpha === '@') { |
||
421 | $sql .= " AND n_surn = '@N.N.'"; |
||
422 | } elseif ($salpha) { |
||
423 | $sql .= " AND " . self::getInitialSql('n_surn', $salpha); |
||
424 | } else { |
||
425 | // All surnames |
||
426 | $sql .= " AND n_surn NOT IN ('', '@N.N.')"; |
||
427 | } |
||
428 | $sql .= " GROUP BY n_surn COLLATE :collate_2, n_file) AS n2 ON (n1.n_surn = n2.n_surn COLLATE :collate_3 AND n1.n_file = n2.n_file)"; |
||
429 | $args['collate_2'] = I18N::collation(); |
||
430 | $args['collate_3'] = I18N::collation(); |
||
431 | |||
432 | $list = []; |
||
433 | foreach (Database::prepare($sql)->execute($args)->fetchAll() as $row) { |
||
434 | $list[I18N::strtoupper($row->n_surn)][$row->n_surname][$row->n_id] = true; |
||
435 | } |
||
436 | |||
437 | return $list; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Fetch a list of individuals with specified names |
||
442 | * |
||
443 | * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@" |
||
444 | * To search for names with no surnames, use $salpha="," |
||
445 | * |
||
446 | * @param Tree $tree only fetch individuals from this tree |
||
447 | * @param string $surn if set, only fetch people with this surname |
||
448 | * @param string $salpha if set, only fetch surnames starting with this letter |
||
449 | * @param string $galpha if set, only fetch given names starting with this letter |
||
450 | * @param bool $marnm if set, include married names |
||
451 | * @param bool $fams if set, only fetch individuals with FAMS records |
||
452 | * |
||
453 | * @return Individual[] |
||
454 | */ |
||
455 | public static function individuals(Tree $tree, $surn, $salpha, $galpha, $marnm, $fams) { |
||
456 | $sql = |
||
457 | "SELECT i_id AS xref, i_gedcom AS gedcom, n_full " . |
||
458 | "FROM `##individuals` " . |
||
459 | "JOIN `##name` ON n_id = i_id AND n_file = i_file " . |
||
460 | ($fams ? "JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") . |
||
461 | "WHERE n_file = :tree_id " . |
||
462 | ($marnm ? "" : "AND n_type != '_MARNM'"); |
||
463 | |||
464 | $args = [ |
||
465 | 'tree_id' => $tree->getTreeId(), |
||
466 | ]; |
||
467 | |||
468 | if ($surn) { |
||
469 | $sql .= " AND n_surn COLLATE :collate_1 = :surn"; |
||
470 | $args['collate_1'] = I18N::collation(); |
||
471 | $args['surn'] = $surn; |
||
472 | } elseif ($salpha === ',') { |
||
473 | $sql .= " AND n_surn = ''"; |
||
474 | } elseif ($salpha === '@') { |
||
475 | $sql .= " AND n_surn = '@N.N.'"; |
||
476 | } elseif ($salpha) { |
||
477 | $sql .= " AND " . self::getInitialSql('n_surn', $salpha); |
||
478 | } else { |
||
479 | // All surnames |
||
480 | $sql .= " AND n_surn NOT IN ('', '@N.N.')"; |
||
481 | } |
||
482 | if ($galpha) { |
||
483 | $sql .= " AND " . self::getInitialSql('n_givn', $galpha); |
||
484 | } |
||
485 | |||
486 | $sql .= " ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE :collate_2, CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE :collate_3"; |
||
487 | $args['collate_2'] = I18N::collation(); |
||
488 | $args['collate_3'] = I18N::collation(); |
||
489 | |||
490 | $list = []; |
||
491 | $rows = Database::prepare($sql)->execute($args)->fetchAll(); |
||
492 | foreach ($rows as $row) { |
||
493 | $person = Individual::getInstance($row->xref, $tree, $row->gedcom); |
||
494 | // The name from the database may be private - check the filtered list... |
||
495 | foreach ($person->getAllNames() as $n => $name) { |
||
496 | if ($name['fullNN'] == $row->n_full) { |
||
497 | $person->setPrimaryName($n); |
||
498 | // We need to clone $person, as we may have multiple references to the |
||
499 | // same person in this list, and the "primary name" would otherwise |
||
500 | // be shared amongst all of them. |
||
501 | $list[] = clone $person; |
||
502 | break; |
||
503 | } |
||
504 | } |
||
505 | } |
||
506 | |||
507 | return $list; |
||
508 | } |
||
509 | |||
510 | /** |
||
511 | * Fetch a list of families with specified names |
||
512 | * |
||
513 | * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@" |
||
514 | * To search for names with no surnames, use $salpha="," |
||
515 | * |
||
516 | * @param Tree $tree only fetch individuals from this tree |
||
517 | * @param string $surn if set, only fetch people with this surname |
||
518 | * @param string $salpha if set, only fetch surnames starting with this letter |
||
519 | * @param string $galpha if set, only fetch given names starting with this letter |
||
520 | * @param bool $marnm if set, include married names |
||
521 | * |
||
522 | * @return Family[] |
||
523 | */ |
||
524 | public static function families(Tree $tree, $surn, $salpha, $galpha, $marnm) { |
||
534 | } |
||
535 | } |
||
536 |
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.