| Conditions | 93 | 
| Paths | > 20000 | 
| Total Lines | 401 | 
| Code Lines | 289 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php | ||
| 366 | public function searchIndividualsAdvanced(array $trees, array $fields, array $modifiers): Collection | ||
| 367 |     { | ||
| 368 | $fields = array_filter($fields); | ||
| 369 | |||
| 370 |         $query = DB::table('individuals') | ||
| 371 | ->select(['individuals.*']) | ||
| 372 | ->distinct(); | ||
| 373 | |||
| 374 | $this->whereTrees($query, 'i_file', $trees); | ||
| 375 | |||
| 376 | // Join the following tables | ||
| 377 | $father_name = false; | ||
| 378 | $mother_name = false; | ||
| 379 | $spouse_family = false; | ||
| 380 | $indi_name = false; | ||
| 381 | $indi_date = false; | ||
| 382 | $fam_date = false; | ||
| 383 | $indi_plac = false; | ||
| 384 | $fam_plac = false; | ||
| 385 | |||
| 386 |         foreach ($fields as $field_name => $field_value) { | ||
| 387 |             if ($field_value !== '') { | ||
| 388 |                 if (substr($field_name, 0, 14) === 'FAMC:HUSB:NAME') { | ||
| 389 | $father_name = true; | ||
| 390 |                 } elseif (substr($field_name, 0, 14) === 'FAMC:WIFE:NAME') { | ||
| 391 | $mother_name = true; | ||
| 392 |                 } elseif (substr($field_name, 0, 4) === 'NAME') { | ||
| 393 | $indi_name = true; | ||
| 394 |                 } elseif (strpos($field_name, ':DATE') !== false) { | ||
| 395 |                     if (substr($field_name, 0, 4) === 'FAMS') { | ||
| 396 | $fam_date = true; | ||
| 397 | $spouse_family = true; | ||
| 398 |                     } else { | ||
| 399 | $indi_date = true; | ||
| 400 | } | ||
| 401 |                 } elseif (strpos($field_name, ':PLAC') !== false) { | ||
| 402 |                     if (substr($field_name, 0, 4) === 'FAMS') { | ||
| 403 | $fam_plac = true; | ||
| 404 | $spouse_family = true; | ||
| 405 |                     } else { | ||
| 406 | $indi_plac = true; | ||
| 407 | } | ||
| 408 |                 } elseif ($field_name === 'FAMS:NOTE') { | ||
| 409 | $spouse_family = true; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 |         if ($father_name || $mother_name) { | ||
| 415 |             $query->join('link AS l1', static function (JoinClause $join): void { | ||
| 416 | $join | ||
| 417 |                     ->on('l1.l_file', '=', 'individuals.i_file') | ||
| 418 |                     ->on('l1.l_from', '=', 'individuals.i_id') | ||
| 419 |                     ->where('l1.l_type', '=', 'FAMC'); | ||
| 420 | }); | ||
| 421 | |||
| 422 |             if ($father_name) { | ||
| 423 |                 $query->join('link AS l2', static function (JoinClause $join): void { | ||
| 424 | $join | ||
| 425 |                         ->on('l2.l_file', '=', 'l1.l_file') | ||
| 426 |                         ->on('l2.l_from', '=', 'l1.l_to') | ||
| 427 |                         ->where('l2.l_type', '=', 'HUSB'); | ||
| 428 | }); | ||
| 429 |                 $query->join('name AS father_name', static function (JoinClause $join): void { | ||
| 430 | $join | ||
| 431 |                         ->on('father_name.n_file', '=', 'l2.l_file') | ||
| 432 |                         ->on('father_name.n_id', '=', 'l2.l_to'); | ||
| 433 | }); | ||
| 434 | } | ||
| 435 | |||
| 436 |             if ($mother_name) { | ||
| 437 |                 $query->join('link AS l3', static function (JoinClause $join): void { | ||
| 438 | $join | ||
| 439 |                         ->on('l3.l_file', '=', 'l1.l_file') | ||
| 440 |                         ->on('l3.l_from', '=', 'l1.l_to') | ||
| 441 |                         ->where('l3.l_type', '=', 'WIFE'); | ||
| 442 | }); | ||
| 443 |                 $query->join('name AS mother_name', static function (JoinClause $join): void { | ||
| 444 | $join | ||
| 445 |                         ->on('mother_name.n_file', '=', 'l3.l_file') | ||
| 446 |                         ->on('mother_name.n_id', '=', 'l3.l_to'); | ||
| 447 | }); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 |         if ($spouse_family) { | ||
| 452 |             $query->join('link AS l4', static function (JoinClause $join): void { | ||
| 453 | $join | ||
| 454 |                     ->on('l4.l_file', '=', 'individuals.i_file') | ||
| 455 |                     ->on('l4.l_from', '=', 'individuals.i_id') | ||
| 456 |                     ->where('l4.l_type', '=', 'FAMS'); | ||
| 457 | }); | ||
| 458 |             $query->join('families AS spouse_families', static function (JoinClause $join): void { | ||
| 459 | $join | ||
| 460 |                     ->on('spouse_families.f_file', '=', 'l4.l_file') | ||
| 461 |                     ->on('spouse_families.f_id', '=', 'l4.l_to'); | ||
| 462 | }); | ||
| 463 | } | ||
| 464 | |||
| 465 |         if ($indi_name) { | ||
| 466 |             $query->join('name AS individual_name', static function (JoinClause $join): void { | ||
| 467 | $join | ||
| 468 |                     ->on('individual_name.n_file', '=', 'individuals.i_file') | ||
| 469 |                     ->on('individual_name.n_id', '=', 'individuals.i_id'); | ||
| 470 | }); | ||
| 471 | } | ||
| 472 | |||
| 473 |         if ($indi_date) { | ||
| 474 |             $query->join('dates AS individual_dates', static function (JoinClause $join): void { | ||
| 475 | $join | ||
| 476 |                     ->on('individual_dates.d_file', '=', 'individuals.i_file') | ||
| 477 |                     ->on('individual_dates.d_gid', '=', 'individuals.i_id'); | ||
| 478 | }); | ||
| 479 | } | ||
| 480 | |||
| 481 |         if ($fam_date) { | ||
| 482 |             $query->join('dates AS family_dates', static function (JoinClause $join): void { | ||
| 483 | $join | ||
| 484 |                     ->on('family_dates.d_file', '=', 'spouse_families.f_file') | ||
| 485 |                     ->on('family_dates.d_gid', '=', 'spouse_families.f_id'); | ||
| 486 | }); | ||
| 487 | } | ||
| 488 | |||
| 489 |         if ($indi_plac) { | ||
| 490 |             $query->join('placelinks AS individual_placelinks', static function (JoinClause $join): void { | ||
| 491 | $join | ||
| 492 |                     ->on('individual_placelinks.pl_file', '=', 'individuals.i_file') | ||
| 493 |                     ->on('individual_placelinks.pl_gid', '=', 'individuals.i_id'); | ||
| 494 | }); | ||
| 495 |             $query->join('places AS individual_places', static function (JoinClause $join): void { | ||
| 496 | $join | ||
| 497 |                     ->on('individual_places.p_file', '=', 'individual_placelinks.pl_file') | ||
| 498 |                     ->on('individual_places.p_id', '=', 'individual_placelinks.pl_p_id'); | ||
| 499 | }); | ||
| 500 | } | ||
| 501 | |||
| 502 |         if ($fam_plac) { | ||
| 503 |             $query->join('placelinks AS familyl_placelinks', static function (JoinClause $join): void { | ||
| 504 | $join | ||
| 505 |                     ->on('familyl_placelinks.pl_file', '=', 'individuals.i_file') | ||
| 506 |                     ->on('familyl_placelinks.pl_gid', '=', 'individuals.i_id'); | ||
| 507 | }); | ||
| 508 |             $query->join('places AS family_places', static function (JoinClause $join): void { | ||
| 509 | $join | ||
| 510 |                     ->on('family_places.p_file', '=', 'familyl_placelinks.pl_file') | ||
| 511 |                     ->on('family_places.p_id', '=', 'familyl_placelinks.pl_p_id'); | ||
| 512 | }); | ||
| 513 | } | ||
| 514 | |||
| 515 |         foreach ($fields as $field_name => $field_value) { | ||
| 516 |             $parts = explode(':', $field_name . '::::'); | ||
| 517 |             if ($parts[0] === 'NAME') { | ||
| 518 | // NAME:* | ||
| 519 |                 switch ($parts[1]) { | ||
| 520 | case 'GIVN': | ||
| 521 |                         switch ($modifiers[$field_name]) { | ||
| 522 | case 'EXACT': | ||
| 523 |                                 $query->where('individual_name.n_givn', '=', $field_value); | ||
| 524 | break; | ||
| 525 | case 'BEGINS': | ||
| 526 |                                 $query->where('individual_name.n_givn', 'LIKE', $field_value . '%'); | ||
| 527 | break; | ||
| 528 | case 'CONTAINS': | ||
| 529 |                                 $query->where('individual_name.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 530 | break; | ||
| 531 | case 'SDX_STD': | ||
| 532 | $sdx = Soundex::russell($field_value); | ||
| 533 |                                 if ($sdx !== '') { | ||
| 534 | $this->wherePhonetic($query, 'individual_name.n_soundex_givn_std', $sdx); | ||
| 535 |                                 } else { | ||
| 536 | // No phonetic content? Use a substring match | ||
| 537 |                                     $query->where('individual_name.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 538 | } | ||
| 539 | break; | ||
| 540 | case 'SDX': // SDX uses DM by default. | ||
| 541 | case 'SDX_DM': | ||
| 542 | $sdx = Soundex::daitchMokotoff($field_value); | ||
| 543 |                                 if ($sdx !== '') { | ||
| 544 | $this->wherePhonetic($query, 'individual_name.n_soundex_givn_dm', $sdx); | ||
| 545 |                                 } else { | ||
| 546 | // No phonetic content? Use a substring match | ||
| 547 |                                     $query->where('individual_name.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 548 | } | ||
| 549 | break; | ||
| 550 | } | ||
| 551 | break; | ||
| 552 | case 'SURN': | ||
| 553 |                         switch ($modifiers[$field_name]) { | ||
| 554 | case 'EXACT': | ||
| 555 |                                 $query->where('individual_name.n_surn', '=', $field_value); | ||
| 556 | break; | ||
| 557 | case 'BEGINS': | ||
| 558 |                                 $query->where('individual_name.n_surn', 'LIKE', $field_value . '%'); | ||
| 559 | break; | ||
| 560 | case 'CONTAINS': | ||
| 561 |                                 $query->where('individual_name.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 562 | break; | ||
| 563 | case 'SDX_STD': | ||
| 564 | $sdx = Soundex::russell($field_value); | ||
| 565 |                                 if ($sdx !== '') { | ||
| 566 | $this->wherePhonetic($query, 'individual_name.n_soundex_surn_std', $sdx); | ||
| 567 |                                 } else { | ||
| 568 | // No phonetic content? Use a substring match | ||
| 569 |                                     $query->where('individual_name.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 570 | } | ||
| 571 | break; | ||
| 572 | case 'SDX': // SDX uses DM by default. | ||
| 573 | case 'SDX_DM': | ||
| 574 | $sdx = Soundex::daitchMokotoff($field_value); | ||
| 575 |                                 if ($sdx !== '') { | ||
| 576 | $this->wherePhonetic($query, 'individual_name.n_soundex_surn_dm', $sdx); | ||
| 577 |                                 } else { | ||
| 578 | // No phonetic content? Use a substring match | ||
| 579 |                                     $query->where('individual_name.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 580 | } | ||
| 581 | break; | ||
| 582 | } | ||
| 583 | break; | ||
| 584 | case 'NICK': | ||
| 585 | case '_MARNM': | ||
| 586 | case '_HEB': | ||
| 587 | case '_AKA': | ||
| 588 | $query | ||
| 589 |                             ->where('individual_name', '=', $parts[1]) | ||
| 590 |                             ->where('individual_name', 'LIKE', '%' . $field_value . '%'); | ||
| 591 | break; | ||
| 592 | } | ||
| 593 | unset($fields[$field_name]); | ||
| 594 |             } elseif ($parts[1] === 'DATE') { | ||
| 595 | // *:DATE | ||
| 596 | $date = new Date($field_value); | ||
| 597 |                 if ($date->isOK()) { | ||
| 598 | $delta = 365 * ($modifiers[$field_name] ?? 0); | ||
| 599 | $query | ||
| 600 |                         ->where('individual_dates.d_fact', '=', $parts[0]) | ||
| 601 |                         ->where('individual_dates.d_julianday1', '>=', $date->minimumJulianDay() - $delta) | ||
| 602 |                         ->where('individual_dates.d_julianday2', '<=', $date->minimumJulianDay() + $delta); | ||
| 603 | } | ||
| 604 | unset($fields[$field_name]); | ||
| 605 |             } elseif ($parts[0] === 'FAMS' && $parts[2] === 'DATE') { | ||
| 606 | // FAMS:*:DATE | ||
| 607 | $date = new Date($field_value); | ||
| 608 |                 if ($date->isOK()) { | ||
| 609 | $delta = 365 * $modifiers[$field_name]; | ||
| 610 | $query | ||
| 611 |                         ->where('family_dates.d_fact', '=', $parts[1]) | ||
| 612 |                         ->where('family_dates.d_julianday1', '>=', $date->minimumJulianDay() - $delta) | ||
| 613 |                         ->where('family_dates.d_julianday2', '<=', $date->minimumJulianDay() + $delta); | ||
| 614 | } | ||
| 615 | unset($fields[$field_name]); | ||
| 616 |             } elseif ($parts[1] === 'PLAC') { | ||
| 617 | // *:PLAC | ||
| 618 | // SQL can only link a place to a person/family, not to an event. | ||
| 619 |                 $query->where('individual_places.p_place', 'LIKE', '%' . $field_value . '%'); | ||
| 620 |             } elseif ($parts[0] === 'FAMS' && $parts[2] === 'PLAC') { | ||
| 621 | // FAMS:*:PLAC | ||
| 622 | // SQL can only link a place to a person/family, not to an event. | ||
| 623 |                 $query->where('family_places.p_place', 'LIKE', '%' . $field_value . '%'); | ||
| 624 |             } elseif ($parts[0] === 'FAMC' && $parts[2] === 'NAME') { | ||
| 625 | $table = $parts[1] === 'HUSB' ? 'father_name' : 'mother_name'; | ||
| 626 | // NAME:* | ||
| 627 |                 switch ($parts[3]) { | ||
| 628 | case 'GIVN': | ||
| 629 |                         switch ($modifiers[$field_name]) { | ||
| 630 | case 'EXACT': | ||
| 631 | $query->where($table . '.n_givn', '=', $field_value); | ||
| 632 | break; | ||
| 633 | case 'BEGINS': | ||
| 634 | $query->where($table . '.n_givn', 'LIKE', $field_value . '%'); | ||
| 635 | break; | ||
| 636 | case 'CONTAINS': | ||
| 637 | $query->where($table . '.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 638 | break; | ||
| 639 | case 'SDX_STD': | ||
| 640 | $sdx = Soundex::russell($field_value); | ||
| 641 |                                 if ($sdx !== '') { | ||
| 642 | $this->wherePhonetic($query, $table . '.n_soundex_givn_std', $sdx); | ||
| 643 |                                 } else { | ||
| 644 | // No phonetic content? Use a substring match | ||
| 645 | $query->where($table . '.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 646 | } | ||
| 647 | break; | ||
| 648 | case 'SDX': // SDX uses DM by default. | ||
| 649 | case 'SDX_DM': | ||
| 650 | $sdx = Soundex::daitchMokotoff($field_value); | ||
| 651 |                                 if ($sdx !== '') { | ||
| 652 | $this->wherePhonetic($query, $table . '.n_soundex_givn_dm', $sdx); | ||
| 653 |                                 } else { | ||
| 654 | // No phonetic content? Use a substring match | ||
| 655 | $query->where($table . '.n_givn', 'LIKE', '%' . $field_value . '%'); | ||
| 656 | } | ||
| 657 | break; | ||
| 658 | } | ||
| 659 | break; | ||
| 660 | case 'SURN': | ||
| 661 |                         switch ($modifiers[$field_name]) { | ||
| 662 | case 'EXACT': | ||
| 663 | $query->where($table . '.n_surn', '=', $field_value); | ||
| 664 | break; | ||
| 665 | case 'BEGINS': | ||
| 666 | $query->where($table . '.n_surn', 'LIKE', $field_value . '%'); | ||
| 667 | break; | ||
| 668 | case 'CONTAINS': | ||
| 669 | $query->where($table . '.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 670 | break; | ||
| 671 | case 'SDX_STD': | ||
| 672 | $sdx = Soundex::russell($field_value); | ||
| 673 |                                 if ($sdx !== '') { | ||
| 674 | $this->wherePhonetic($query, $table . '.n_soundex_surn_std', $sdx); | ||
| 675 |                                 } else { | ||
| 676 | // No phonetic content? Use a substring match | ||
| 677 | $query->where($table . '.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 678 | } | ||
| 679 | break; | ||
| 680 | case 'SDX': // SDX uses DM by default. | ||
| 681 | case 'SDX_DM': | ||
| 682 | $sdx = Soundex::daitchMokotoff($field_value); | ||
| 683 |                                 if ($sdx !== '') { | ||
| 684 | $this->wherePhonetic($query, $table . '.n_soundex_surn_dm', $sdx); | ||
| 685 |                                 } else { | ||
| 686 | // No phonetic content? Use a substring match | ||
| 687 | $query->where($table . '.n_surn', 'LIKE', '%' . $field_value . '%'); | ||
| 688 | } | ||
| 689 | break; | ||
| 690 | } | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | unset($fields[$field_name]); | ||
| 694 |             } elseif ($parts[0] === 'FAMS') { | ||
| 695 | // e.g. searches for occupation, religion, note, etc. | ||
| 696 | // Initial matching only. Need PHP to apply filter. | ||
| 697 |                 $query->where('families.f_gedcom', 'LIKE', "%\n1 " . $parts[1] . ' %' . $field_value . '%'); | ||
| 698 |             } elseif ($parts[1] === 'TYPE') { | ||
| 699 | // e.g. FACT:TYPE or EVEN:TYPE | ||
| 700 | // Initial matching only. Need PHP to apply filter. | ||
| 701 |                 $query->where('individuals.i_gedcom', 'LIKE', "%\n1 " . $parts[0] . '%\n2 TYPE %' . $field_value . '%'); | ||
| 702 |             } else { | ||
| 703 | // e.g. searches for occupation, religion, note, etc. | ||
| 704 | // Initial matching only. Need PHP to apply filter. | ||
| 705 |                 $query->where('individuals.i_gedcom', 'LIKE', "%\n1 " . $parts[0] . '%' . $parts[1] . '%' . $field_value . '%'); | ||
| 706 | } | ||
| 707 | } | ||
| 708 | return $query | ||
| 709 | ->get() | ||
| 710 | ->each($this->rowLimiter()) | ||
| 711 | ->map($this->individualRowMapper()) | ||
| 712 | ->filter(GedcomRecord::accessFilter()) | ||
| 713 |             ->filter(static function (Individual $individual) use ($fields): bool { | ||
| 714 | // Check for searches which were only partially matched by SQL | ||
| 715 |                 foreach ($fields as $field_name => $field_value) { | ||
| 716 | $regex = '/' . preg_quote($field_value, '/') . '/i'; | ||
| 717 | |||
| 718 |                     $parts = explode(':', $field_name . '::::'); | ||
| 719 | |||
| 720 | // *:PLAC | ||
| 721 |                     if ($parts[1] === 'PLAC') { | ||
| 722 |                         foreach ($individual->facts([$parts[0]]) as $fact) { | ||
| 723 |                             if (preg_match($regex, $fact->place()->gedcomName())) { | ||
| 724 | continue 2; | ||
| 725 | } | ||
| 726 | } | ||
| 727 | return false; | ||
| 728 | } | ||
| 729 | |||
| 730 | // FAMS:*:PLAC | ||
| 731 |                     if ($parts[0] === 'FAMS' && $parts[2] === 'PLAC') { | ||
| 732 |                         foreach ($individual->spouseFamilies() as $family) { | ||
| 733 |                             foreach ($family->facts([$parts[1]]) as $fact) { | ||
| 734 |                                 if (preg_match($regex, $fact->place()->gedcomName())) { | ||
| 735 | continue 2; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | } | ||
| 739 | return false; | ||
| 740 | } | ||
| 741 | |||
| 742 | // e.g. searches for occupation, religion, note, etc. | ||
| 743 |                     if ($parts[0] === 'FAMS') { | ||
| 744 |                         foreach ($individual->spouseFamilies() as $family) { | ||
| 745 |                             foreach ($family->facts([$parts[1]]) as $fact) { | ||
| 746 |                                 if (preg_match($regex, $fact->value())) { | ||
| 747 | continue 3; | ||
| 748 | } | ||
| 749 | } | ||
| 750 | } | ||
| 751 | return false; | ||
| 752 | } | ||
| 753 | |||
| 754 | // e.g. FACT:TYPE or EVEN:TYPE | ||
| 755 |                     if ($parts[1] === 'TYPE' || $parts[1] === '_WT_USER') { | ||
| 756 |                         foreach ($individual->facts([$parts[0]]) as $fact) { | ||
| 757 |                             if (preg_match($regex, $fact->attribute($parts[1]))) { | ||
| 758 | continue 2; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 762 | return false; | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | return true; | ||
| 767 | }); | ||
| 1104 |