diff options
Diffstat (limited to 'app/Http/Controllers/BranchesController.php')
| -rw-r--r-- | app/Http/Controllers/BranchesController.php | 532 |
1 files changed, 270 insertions, 262 deletions
diff --git a/app/Http/Controllers/BranchesController.php b/app/Http/Controllers/BranchesController.php index df352e1372..cadc5cdfe9 100644 --- a/app/Http/Controllers/BranchesController.php +++ b/app/Http/Controllers/BranchesController.php @@ -31,83 +31,87 @@ use Symfony\Component\HttpFoundation\Response; /** * Find all branches of families with a given surname. */ -class BranchesController extends AbstractBaseController { - /** - * A form to request the page parameters. - * - * @param Request $request - * - * @return Response - */ - public function page(Request $request): Response { - $surname = $request->get('surname', ''); - $soundex_std = (bool) $request->get('soundex_std'); - $soundex_dm = (bool) $request->get('soundex_dm'); +class BranchesController extends AbstractBaseController +{ + /** + * A form to request the page parameters. + * + * @param Request $request + * + * @return Response + */ + public function page(Request $request): Response + { + $surname = $request->get('surname', ''); + $soundex_std = (bool)$request->get('soundex_std'); + $soundex_dm = (bool)$request->get('soundex_dm'); - if ($surname !== '') { - $title = /* I18N: %s is a surname */ - I18N::translate('Branches of the %s family', e($surname)); - } else { - $title = /* I18N: Branches of a family tree */ - I18N::translate('Branches'); - } + if ($surname !== '') { + $title = /* I18N: %s is a surname */ + I18N::translate('Branches of the %s family', e($surname)); + } else { + $title = /* I18N: Branches of a family tree */ + I18N::translate('Branches'); + } - return $this->viewResponse('branches-page', [ - 'soundex_dm' => $soundex_dm, - 'soundex_std' => $soundex_std, - 'surname' => $surname, - 'title' => $title, - ]); - } + return $this->viewResponse('branches-page', [ + 'soundex_dm' => $soundex_dm, + 'soundex_std' => $soundex_std, + 'surname' => $surname, + 'title' => $title, + ]); + } - /** - * @param Request $request - * - * @return Response - */ - public function list(Request $request): Response { - /** @var Tree $tree */ - $tree = $request->attributes->get('tree'); + /** + * @param Request $request + * + * @return Response + */ + public function list(Request $request): Response + { + /** @var Tree $tree */ + $tree = $request->attributes->get('tree'); - /** @var User $user */ - $user = $request->attributes->get('user'); + /** @var User $user */ + $user = $request->attributes->get('user'); - $soundex_dm = (bool) $request->get('soundex_dm'); - $soundex_std = (bool) $request->get('soundex_std'); - $surname = $request->get('surname', ''); + $soundex_dm = (bool)$request->get('soundex_dm'); + $soundex_std = (bool)$request->get('soundex_std'); + $surname = $request->get('surname', ''); - // Highlight direct-line ancestors of this individual. - $self = Individual::getInstance($tree->getUserPreference($user, 'gedcomid'), $tree); + // Highlight direct-line ancestors of this individual. + $self = Individual::getInstance($tree->getUserPreference($user, 'gedcomid'), $tree); - if ($surname !== '') { - $individuals = $this->loadIndividuals($tree, $surname, $soundex_dm, $soundex_std); - } else { - $individuals = []; - } + if ($surname !== '') { + $individuals = $this->loadIndividuals($tree, $surname, $soundex_dm, $soundex_std); + } else { + $individuals = []; + } - if ($self !== null) { - $ancestors = $this->allAncestors($self); - } else { - $ancestors = []; - } + if ($self !== null) { + $ancestors = $this->allAncestors($self); + } else { + $ancestors = []; + } - // @TODO - convert this to use views - $html = view('branches-list', [ - 'branches' => $this->getPatriarchsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std), - ]); + // @TODO - convert this to use views + $html = view('branches-list', [ + 'branches' => $this->getPatriarchsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std), + ]); - return new Response($html); - } + return new Response($html); + } - /** - * Find all ancestors of an individual, indexed by the Sosa-Stradonitz number. - * - * @param Individual $individual - * - * @return Individual[] - */ - protected function allAncestors(Individual $individual): array { - /** @var Individual[] $ancestors */ + /** + * Find all ancestors of an individual, indexed by the Sosa-Stradonitz number. + * + * @param Individual $individual + * + * @return Individual[] + */ + protected function allAncestors(Individual $individual): array + { + /** @var Individual[] $ancestors */ $ancestors = [ 1 => $individual, ]; @@ -115,9 +119,9 @@ class BranchesController extends AbstractBaseController { do { $sosa = key($ancestors); - $family = $ancestors[$sosa]->getPrimaryChildFamily(); + $family = $ancestors[$sosa]->getPrimaryChildFamily(); - if ($family !== null) { + if ($family !== null) { if ($family->getHusband() !== null) { $ancestors[$sosa * 2] = $family->getHusband(); } @@ -125,219 +129,223 @@ class BranchesController extends AbstractBaseController { $ancestors[$sosa * 2 + 1] = $family->getWife(); } } - } while (next($ancestors)); + } while (next($ancestors)); - return $ancestors; - } + return $ancestors; + } - /** - * Fetch all individuals with a matching surname - * - * @param Tree $tree - * @param string $surname - * @param bool $soundex_dm - * @param bool $soundex_std - * - * @return Individual[] - */ - private function loadIndividuals(Tree $tree, string $surname, bool $soundex_dm, bool $soundex_std): array { - $sql = - "SELECT DISTINCT i_id AS xref, i_gedcom AS gedcom" . - " FROM `##individuals`" . - " JOIN `##name` ON (i_id=n_id AND i_file=n_file)" . - " WHERE n_file = ?" . - " AND n_type != ?" . - " AND (n_surn = ? OR n_surname = ?"; + /** + * Fetch all individuals with a matching surname + * + * @param Tree $tree + * @param string $surname + * @param bool $soundex_dm + * @param bool $soundex_std + * + * @return Individual[] + */ + private function loadIndividuals(Tree $tree, string $surname, bool $soundex_dm, bool $soundex_std): array + { + $sql = + "SELECT DISTINCT i_id AS xref, i_gedcom AS gedcom" . + " FROM `##individuals`" . + " JOIN `##name` ON (i_id=n_id AND i_file=n_file)" . + " WHERE n_file = ?" . + " AND n_type != ?" . + " AND (n_surn = ? OR n_surname = ?"; - $args = [ - $tree->getTreeId(), - '_MARNM', - $surname, - $surname, - ]; - if ($soundex_std) { - $sdx = Soundex::russell($surname); - if ($sdx !== '') { - foreach (explode(':', $sdx) as $value) { - $sql .= " OR n_soundex_surn_std LIKE CONCAT('%', ?, '%')"; - $args[] = $value; - } - } - } + $args = [ + $tree->getTreeId(), + '_MARNM', + $surname, + $surname, + ]; + if ($soundex_std) { + $sdx = Soundex::russell($surname); + if ($sdx !== '') { + foreach (explode(':', $sdx) as $value) { + $sql .= " OR n_soundex_surn_std LIKE CONCAT('%', ?, '%')"; + $args[] = $value; + } + } + } - if ($soundex_dm) { - $sdx = Soundex::daitchMokotoff($surname); - if ($sdx !== '') { - foreach (explode(':', $sdx) as $value) { - $sql .= " OR n_soundex_surn_dm LIKE CONCAT('%', ?, '%')"; - $args[] = $value; - } - } - } - $sql .= ')'; + if ($soundex_dm) { + $sdx = Soundex::daitchMokotoff($surname); + if ($sdx !== '') { + foreach (explode(':', $sdx) as $value) { + $sql .= " OR n_soundex_surn_dm LIKE CONCAT('%', ?, '%')"; + $args[] = $value; + } + } + } + $sql .= ')'; - $rows = Database::prepare($sql)->execute($args)->fetchAll(); + $rows = Database::prepare($sql)->execute($args)->fetchAll(); - $individuals = []; - foreach ($rows as $row) { - $individuals[] = Individual::getInstance($row->xref, $tree, $row->gedcom); - } + $individuals = []; + foreach ($rows as $row) { + $individuals[] = Individual::getInstance($row->xref, $tree, $row->gedcom); + } - usort($individuals, '\Fisharebest\Webtrees\Individual::compareBirthDate'); + usort($individuals, '\Fisharebest\Webtrees\Individual::compareBirthDate'); - return $individuals; - } + return $individuals; + } - /** - * For each individual with no ancestors, list their descendants. - * - * @param Individual[] $individuals - * @param Individual[] $ancestors - * @param string $surname - * @param bool $soundex_dm - * @param bool $soundex_std - * - * @return string - */ - public function getPatriarchsHtml(array $individuals, array $ancestors, string $surname, bool $soundex_dm, bool $soundex_std): string { - $html = ''; - foreach ($individuals as $individual) { - foreach ($individual->getChildFamilies() as $family) { - foreach ($family->getSpouses() as $parent) { - if (in_array($parent, $individuals, true)) { - continue 3; - } - } - } - $html .= $this->getDescendantsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std, $individual, null); - } + /** + * For each individual with no ancestors, list their descendants. + * + * @param Individual[] $individuals + * @param Individual[] $ancestors + * @param string $surname + * @param bool $soundex_dm + * @param bool $soundex_std + * + * @return string + */ + public function getPatriarchsHtml(array $individuals, array $ancestors, string $surname, bool $soundex_dm, bool $soundex_std): string + { + $html = ''; + foreach ($individuals as $individual) { + foreach ($individual->getChildFamilies() as $family) { + foreach ($family->getSpouses() as $parent) { + if (in_array($parent, $individuals, true)) { + continue 3; + } + } + } + $html .= $this->getDescendantsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std, $individual, null); + } - return $html; - } + return $html; + } - /** - * Generate a recursive list of descendants of an individual. - * If parents are specified, we can also show the pedigree (adopted, etc.). - * - * @param array $individuals - * @param array $ancestors - * @param string $surname - * @param bool $soundex_dm - * @param bool $soundex_std - * @param Individual $individual - * @param Family|null $parents - * - * @return string - */ - private function getDescendantsHtml(array $individuals, array $ancestors, string $surname, bool $soundex_dm, bool $soundex_std, Individual $individual, Family $parents = null) { - // A person has many names. Select the one that matches the searched surname - $person_name = ''; - foreach ($individual->getAllNames() as $name) { - list($surn1) = explode(',', $name['sort']); - if (// one name is a substring of the other - stripos($surn1, $surname) !== false || - stripos($surname, $surn1) !== false || - // one name sounds like the other - $soundex_std && Soundex::compare(Soundex::russell($surn1), Soundex::russell($surname)) || - $soundex_dm && Soundex::compare(Soundex::daitchMokotoff($surn1), Soundex::daitchMokotoff($surname)) - ) { - $person_name = $name['full']; - break; - } - } + /** + * Generate a recursive list of descendants of an individual. + * If parents are specified, we can also show the pedigree (adopted, etc.). + * + * @param array $individuals + * @param array $ancestors + * @param string $surname + * @param bool $soundex_dm + * @param bool $soundex_std + * @param Individual $individual + * @param Family|null $parents + * + * @return string + */ + private function getDescendantsHtml(array $individuals, array $ancestors, string $surname, bool $soundex_dm, bool $soundex_std, Individual $individual, Family $parents = null) + { + // A person has many names. Select the one that matches the searched surname + $person_name = ''; + foreach ($individual->getAllNames() as $name) { + list($surn1) = explode(',', $name['sort']); + if (// one name is a substring of the other + stripos($surn1, $surname) !== false || + stripos($surname, $surn1) !== false || + // one name sounds like the other + $soundex_std && Soundex::compare(Soundex::russell($surn1), Soundex::russell($surname)) || + $soundex_dm && Soundex::compare(Soundex::daitchMokotoff($surn1), Soundex::daitchMokotoff($surname)) + ) { + $person_name = $name['full']; + break; + } + } - // No matching name? Typically children with a different surname. The branch stops here. - if (!$person_name) { - return '<li title="' . strip_tags($individual->getFullName()) . '">' . $individual->getSexImage() . '…</li>'; - } + // No matching name? Typically children with a different surname. The branch stops here. + if (!$person_name) { + return '<li title="' . strip_tags($individual->getFullName()) . '">' . $individual->getSexImage() . '…</li>'; + } - // Is this individual one of our ancestors? - $sosa = array_search($individual, $ancestors, true); - if ($sosa !== false) { - $sosa_class = 'search_hit'; - $sosa_html = ' <a class="details1 ' . $individual->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="' . e(route('relationships', [ - 'xref1' => $individual->getXref(), - 'xref2' => $ancestors[1]->getXref(), - 'ged' => $individual->getTree()->getName(), - ])) . '" rel="nofollow">' . $sosa . '</a>' . self::sosaGeneration($sosa); - } else { - $sosa_class = ''; - $sosa_html = ''; - } + // Is this individual one of our ancestors? + $sosa = array_search($individual, $ancestors, true); + if ($sosa !== false) { + $sosa_class = 'search_hit'; + $sosa_html = ' <a class="details1 ' . $individual->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="' . e(route('relationships', [ + 'xref1' => $individual->getXref(), + 'xref2' => $ancestors[1]->getXref(), + 'ged' => $individual->getTree()->getName(), + ])) . '" rel="nofollow">' . $sosa . '</a>' . self::sosaGeneration($sosa); + } else { + $sosa_class = ''; + $sosa_html = ''; + } - // Generate HTML for this individual, and all their descendants - $indi_html = $individual->getSexImage() . '<a class="' . $sosa_class . '" href="' . e($individual->url()) . '">' . $person_name . '</a> ' . $individual->getLifeSpan() . $sosa_html; + // Generate HTML for this individual, and all their descendants + $indi_html = $individual->getSexImage() . '<a class="' . $sosa_class . '" href="' . e($individual->url()) . '">' . $person_name . '</a> ' . $individual->getLifeSpan() . $sosa_html; - // If this is not a birth pedigree (e.g. an adoption), highlight it - if ($parents) { - $pedi = ''; - foreach ($individual->getFacts('FAMC') as $fact) { - if ($fact->getTarget() === $parents) { - $pedi = $fact->getAttribute('PEDI'); - break; - } - } - if ($pedi !== '' && $pedi !== 'birth') { - $indi_html = '<span class="red">' . GedcomCodePedi::getValue($pedi, $individual) . '</span> ' . $indi_html; - } - } + // If this is not a birth pedigree (e.g. an adoption), highlight it + if ($parents) { + $pedi = ''; + foreach ($individual->getFacts('FAMC') as $fact) { + if ($fact->getTarget() === $parents) { + $pedi = $fact->getAttribute('PEDI'); + break; + } + } + if ($pedi !== '' && $pedi !== 'birth') { + $indi_html = '<span class="red">' . GedcomCodePedi::getValue($pedi, $individual) . '</span> ' . $indi_html; + } + } - // spouses and children - $spouse_families = $individual->getSpouseFamilies(); - if ($spouse_families) { - usort($spouse_families, '\Fisharebest\Webtrees\Family::compareMarrDate'); - $fam_html = ''; - foreach ($spouse_families as $family) { - $fam_html .= $indi_html; // Repeat the individual details for each spouse. + // spouses and children + $spouse_families = $individual->getSpouseFamilies(); + if ($spouse_families) { + usort($spouse_families, '\Fisharebest\Webtrees\Family::compareMarrDate'); + $fam_html = ''; + foreach ($spouse_families as $family) { + $fam_html .= $indi_html; // Repeat the individual details for each spouse. - $spouse = $family->getSpouse($individual); - if ($spouse) { - $sosa = array_search($spouse, $ancestors, true); - if ($sosa) { - $sosa_class = 'search_hit'; - $sosa_html = ' <a class="details1 ' . $spouse->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="' . e(route('relationships', [ - 'xref2' => $ancestors[1]->getXref(), - 'ged' => $individual->getTree()->getName(), - ])) . '" rel="nofollow"> ' . $sosa . ' </a>' . self::sosaGeneration($sosa); - } else { - $sosa_class = ''; - $sosa_html = ''; - } - $marriage_year = $family->getMarriageYear(); - if ($marriage_year) { - $fam_html .= ' <a href="' . e($family->url()) . '" title="' . strip_tags($family->getMarriageDate()->display()) . '"><i class="icon-rings"></i>' . $marriage_year . '</a>'; - } elseif ($family->getFirstFact('MARR')) { - $fam_html .= ' <a href="' . e($family->url()) . '" title="' . I18N::translate('Marriage') . '"><i class="icon-rings"></i></a>'; - } else { - $fam_html .= ' <a href="' . e($family->url()) . '" title="' . I18N::translate('Not married') . '"><i class="icon-rings"></i></a>'; - } - $fam_html .= ' ' . $spouse->getSexImage() . '<a class="' . $sosa_class . '" href="' . e($spouse->url()) . '">' . $spouse->getFullName() . '</a> ' . $spouse->getLifeSpan() . ' ' . $sosa_html; - } + $spouse = $family->getSpouse($individual); + if ($spouse) { + $sosa = array_search($spouse, $ancestors, true); + if ($sosa) { + $sosa_class = 'search_hit'; + $sosa_html = ' <a class="details1 ' . $spouse->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="' . e(route('relationships', [ + 'xref2' => $ancestors[1]->getXref(), + 'ged' => $individual->getTree()->getName(), + ])) . '" rel="nofollow"> ' . $sosa . ' </a>' . self::sosaGeneration($sosa); + } else { + $sosa_class = ''; + $sosa_html = ''; + } + $marriage_year = $family->getMarriageYear(); + if ($marriage_year) { + $fam_html .= ' <a href="' . e($family->url()) . '" title="' . strip_tags($family->getMarriageDate()->display()) . '"><i class="icon-rings"></i>' . $marriage_year . '</a>'; + } elseif ($family->getFirstFact('MARR')) { + $fam_html .= ' <a href="' . e($family->url()) . '" title="' . I18N::translate('Marriage') . '"><i class="icon-rings"></i></a>'; + } else { + $fam_html .= ' <a href="' . e($family->url()) . '" title="' . I18N::translate('Not married') . '"><i class="icon-rings"></i></a>'; + } + $fam_html .= ' ' . $spouse->getSexImage() . '<a class="' . $sosa_class . '" href="' . e($spouse->url()) . '">' . $spouse->getFullName() . '</a> ' . $spouse->getLifeSpan() . ' ' . $sosa_html; + } - $fam_html .= '<ol>'; - foreach ($family->getChildren() as $child) { - $fam_html .= $this->getDescendantsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std, $child, $family); - } - $fam_html .= '</ol>'; - } + $fam_html .= '<ol>'; + foreach ($family->getChildren() as $child) { + $fam_html .= $this->getDescendantsHtml($individuals, $ancestors, $surname, $soundex_dm, $soundex_std, $child, $family); + } + $fam_html .= '</ol>'; + } - return '<li>' . $fam_html . '</li>'; - } else { - // No spouses - just show the individual - return '<li>' . $indi_html . '</li>'; - } - } + return '<li>' . $fam_html . '</li>'; + } else { + // No spouses - just show the individual + return '<li>' . $indi_html . '</li>'; + } + } - /** - * Convert a SOSA number into a generation number. e.g. 8 = great-grandfather = 3 generations - * - * @param int $sosa - * - * @return string - */ - private static function sosaGeneration($sosa) { - $generation = (int) log($sosa, 2) + 1; + /** + * Convert a SOSA number into a generation number. e.g. 8 = great-grandfather = 3 generations + * + * @param int $sosa + * + * @return string + */ + private static function sosaGeneration($sosa) + { + $generation = (int)log($sosa, 2) + 1; - return '<sup title="' . I18N::translate('Generation') . '">' . $generation . '</sup>'; - } + return '<sup title="' . I18N::translate('Generation') . '">' . $generation . '</sup>'; + } } |
