surname = WT_Filter::get('surname'); $this->soundex_std = WT_Filter::getBool('soundex_std'); $this->soundex_dm = WT_Filter::getBool('soundex_dm'); if ($this->surname) { $this->setPageTitle(/* I18N: %s is a surname */ WT_I18N::translate('Branches of the %s family', WT_Filter::escapeHtml($this->surname))); $this->loadIndividuals(); $self = WT_Individual::getInstance(WT_USER_GEDCOM_ID); if ($self) { $this->loadAncestors(WT_Individual::getInstance(WT_USER_GEDCOM_ID), 1); } } else { $this->setPageTitle(/* I18N: Branches of a family tree */ WT_I18N::translate('Branches')); } } // Page parameters public function getSurname() { return $this->surname; } public function getSoundexStd() { return $this->soundex_std; } public function getSoundexDm() { return $this->soundex_dm; } // Fetch all individuals with a matching surname private function loadIndividuals() { $sql= "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, 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=array(WT_GED_ID, '_MARNM', $this->surname, $this->surname); if ($this->soundex_std) { $sdx = WT_Soundex::soundex_std($this->surname); if ($sdx) { foreach (explode(':', $sdx) as $value) { $sql .= " OR n_soundex_surn_std LIKE CONCAT('%', ?, '%')"; $args[] = $value; } } } if ($this->soundex_dm) { $sdx = WT_Soundex::soundex_dm($this->surname); if ($sdx) { foreach (explode(':', $sdx) as $value) { $sql .= " OR n_soundex_surn_dm LIKE CONCAT('%', ?, '%')"; $args[] = $value; } } } $sql .= ')'; $rows = WT_DB::prepare($sql)->execute($args)->fetchAll(); $this->individuals = array(); foreach ($rows as $row) { $this->individuals[] = WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); } // Sort by birth date, oldest first usort($this->individuals, array('WT_Individual', 'CompareBirtDate')); } private function loadAncestors(WT_Individual $ancestor, $sosa) { if ($ancestor) { $this->ancestors[$sosa] = $ancestor; foreach ($ancestor->getChildFamilies() as $family) { foreach ($family->getSpouses() as $parent) { $this->loadAncestors($parent, $sosa * 2 + ($parent->getSex() == 'F')); } } } } // List individuals without an ancestor (with the same surname) public function getPatriarchsHtml() { $html = ''; foreach ($this->individuals as $individual) { foreach ($individual->getChildFamilies() as $family) { foreach ($family->getSpouses() as $parent) { if (in_array($parent, $this->individuals, true)) { continue 3; } } } $html .= $this->getDescendantsHtml($individual); } return $html; } // Generate a recursive list of descendants of an individual. // If parents are specified, we can also show the pedigree (adopted, etc.). private function getDescendantsHtml(WT_Individual $individual, WT_Family $parents=null) { // A person has many names. Select the one that matches the searched surname $person_name = ''; foreach ($individual->getAllNames() as $n=>$name) { list($surn1) = explode(",", $name['sort']); if ( // one name is a substring of the other stripos($surn1, $this->surname) !== false || stripos($this->surname, $surn1) !== false || // one name sounds like the other $this->soundex_std && WT_Soundex::compare(WT_Soundex::soundex_std($surn1), WT_Soundex::soundex_std($this->surname)) || $this->soundex_dm && WT_Soundex::compare(WT_Soundex::soundex_dm ($surn1), WT_Soundex::soundex_dm ($this->surname)) ) { $person_name = $name['full']; break; } } // No matching name? Typically children with a different surname. The tree stops here. if (!$person_name) { return '
  • ' . $individual->getSexImage() . '…
  • '; } // Is this individual one of our ancestors? $sosa = array_search($individual, $this->ancestors); if ($sosa) { $sosa_class = 'search_hit'; $sosa_html = ' ' . $sosa . '' . self::sosaGeneration($sosa); } else { $sosa_class = ''; $sosa_html = ''; } // Generate HTML for this individual, and all their descendants $indi_html = $individual->getSexImage() . '' . $person_name . ' ' . $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 = ''.WT_Gedcom_Code_Pedi::getValue($pedi, $individual).' ' . $indi_html; } } // spouses and children $spouse_families = $individual->getSpouseFamilies(); if ($spouse_families) { $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, $this->ancestors); if ($sosa) { $sosa_class = 'search_hit'; $sosa_html = ' '.$sosa.' ' . self::sosaGeneration($sosa); } else { $sosa_class = ''; $sosa_html = ''; } $marriage_year = $family->getMarriageYear(); if ($marriage_year) { $fam_html .= ' ' . $marriage_year . ''; } elseif ($family->getFirstFact('MARR')) { $fam_html .= ' '; } elseif ($family->getFirstFact('_NMR')) { $fam_html .= ' '; } $fam_html .= ' ' . $spouse->getSexImage() . '' . $spouse->getFullName() . ' ' . $spouse->getLifeSpan() . ' ' . $sosa_html; } $fam_html .= '
      '; foreach ($family->getChildren() as $child) { $fam_html .= $this->getDescendantsHtml($child, $family); } $fam_html .= '
    '; } return '
  • ' . $fam_html . '
  • '; } else { // No spouses - just show the individual return '
  • ' . $indi_html . '
  • '; } } private static function sosaGeneration($sosa) { $generation = (int)log($sosa, 2) + 1; return '' . $generation . ''; } }