fetchOne(); } $alphas[$letter] = $count; } // Now fetch initial letters that are not in our alphabet, // including "@" (for "@N.N.") and "" for no surname. $sql = "SELECT SQL_CACHE UPPER(LEFT(n_surn, 1)), COUNT(n_id)" . " FROM `##name` " . ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") . " WHERE n_file={$ged_id} AND n_surn<>''" . ($marnm ? "" : " AND n_type!='_MARNM'"); foreach (self::_getAlphabet(WT_LOCALE) as $letter) { $sql .= " AND n_surn NOT LIKE '" . $letter . "%' COLLATE " . WT_I18N::$collation; } $sql .= " GROUP BY LEFT(n_surn, 1) ORDER BY LEFT(n_surn, 1)='', LEFT(n_surn, 1)='@', LEFT(n_surn, 1)"; foreach (WT_DB::prepare($sql)->fetchAssoc() as $alpha=>$count) { $alphas[$alpha] = $count; } // Names with no surname $sql = "SELECT SQL_CACHE COUNT(n_id)" . " FROM `##name` " . ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") . " WHERE n_file={$ged_id} AND n_surn=''" . ($marnm ? "" : " AND n_type!='_MARNM'"); $num_none = WT_DB::prepare($sql)->fetchOne(); if ($num_none) { // Special code to indicate "no surname" $alphas[','] = $num_none; } return $alphas; } /** * Get a list of initial given name letters for indilist.php and famlist.php * * @param string $surn if set, only consider people with this surname * @param string $salpha if set, only consider surnames starting with this letter * @param bool $marnm if set, include married names * @param bool $fams if set, only consider individuals with FAMS records * @param int $ged_id only consider individuals from this tree * * @return int[] */ public static function givenAlpha($surn, $salpha, $marnm, $fams, $ged_id) { $alphas=array(); $sql = "SELECT SQL_CACHE COUNT(DISTINCT n_id)" . " FROM `##name`" . ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") . " WHERE n_file={$ged_id} " . ($marnm ? "" : " AND n_type!='_MARNM'"); if ($surn) { $sql .= " AND n_surn=" . WT_DB::quote($surn) . " COLLATE '" . WT_I18N::$collation . "'"; } elseif ($salpha==',') { $sql .= " AND n_surn=''"; } elseif ($salpha=='@') { $sql .= " AND n_surn='@N.N.'"; } elseif ($salpha) { $sql .= " AND " . self::_getInitialSql('n_surn', $salpha); } else { // All surnames $sql .= " AND n_surn NOT IN ('', '@N.N.')"; } // Fetch all the letters in our alphabet, whether or not there // are any names beginning with that letter. It looks better to // show the full alphabet, rather than omitting rare letters such as X foreach (self::_getAlphabet(WT_LOCALE) as $letter) { $count=WT_DB::prepare($sql . " AND " . self::_getInitialSql('n_givn', $letter))->fetchOne(); $alphas[$letter] = $count; } // Now fetch initial letters that are not in our alphabet, // including "@" (for "@N.N.") and "" for no surname $sql = "SELECT SQL_CACHE UPPER(LEFT(n_givn, 1)), COUNT(DISTINCT n_id)" . " FROM `##name` " . ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") . " WHERE n_file={$ged_id} " . ($marnm ? "" : " AND n_type!='_MARNM'"); if ($surn) { $sql .= " AND n_surn=" . WT_DB::quote($surn) . " COLLATE '" . WT_I18N::$collation . "'"; } elseif ($salpha==',') { $sql .= " AND n_surn=''"; } elseif ($salpha=='@') { $sql .= " AND n_surn='@N.N.'"; } elseif ($salpha) { $sql .= " AND " . self::_getInitialSql('n_surn', $salpha); } else { // All surnames $sql .= " AND n_surn NOT IN ('', '@N.N.')"; } foreach (self::_getAlphabet(WT_LOCALE) as $letter) { $sql .= " AND n_givn NOT LIKE '" . $letter . "%' COLLATE " . WT_I18N::$collation; } $sql .= " GROUP BY LEFT(n_givn, 1) ORDER BY LEFT(n_givn, 1)='@', LEFT(n_givn, 1)='', LEFT(n_givn, 1)"; foreach (WT_DB::prepare($sql)->fetchAssoc() as $alpha=>$count) { $alphas[$alpha] = $count; } return $alphas; } /** * Get a list of actual surnames and variants, based on a "root" surname. * * @param string $surn if set, only fetch people with this surname * @param string $salpha if set, only consider surnames starting with this letter * @param bool $marnm if set, include married names * @param bool $fams if set, only consider individuals with FAMS records * @param int $ged_id only consider individuals from this gedcom * * @return array */ public static function surnames($surn, $salpha, $marnm, $fams, $ged_id) { $sql= "SELECT SQL_CACHE n2.n_surn, n1.n_surname, n1.n_id". " FROM `##name` n1 ". ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : ""). " JOIN (SELECT n_surn, n_file FROM `##name`". " WHERE n_file={$ged_id}". ($marnm ? "" : " AND n_type!='_MARNM'"); if ($surn) { $sql.=" AND n_surn COLLATE '".WT_I18N::$collation."' =".WT_DB::quote($surn); } elseif ($salpha==',') { $sql.=" AND n_surn=''"; } elseif ($salpha=='@') { $sql.=" AND n_surn='@N.N.'"; } elseif ($salpha) { $sql.=" AND ".self::_getInitialSql('n_surn', $salpha); } else { // All surnames $sql.=" AND n_surn NOT IN ('', '@N.N.')"; } $sql.=" GROUP BY n_surn COLLATE '".WT_I18N::$collation."', n_file) n2 ON (n1.n_surn=n2.n_surn COLLATE '".WT_I18N::$collation."' AND n1.n_file=n2.n_file)"; if (!$marnm) { $sql.=" AND n_type!='_MARNM'"; } $list=array(); foreach (WT_DB::prepare($sql)->fetchAll() as $row) { $list[utf8_strtoupper($row->n_surn)][$row->n_surname][$row->n_id]=true; } return $list; } /** * Fetch a list of individuals with specified names * * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@" * To search for names with no surnames, use $salpha="," * * @param string $surn if set, only fetch people with this surname * @param string $salpha if set, only fetch surnames starting with this letter * @param string $galpha if set, only fetch given names starting with this letter * @param bool $marnm if set, include married names * @param bool $fams if set, only fetch individuals with FAMS records * @param int $ged_id if set, only fetch individuals from this gedcom * * @return WT_Individual[] */ public static function individuals($surn, $salpha, $galpha, $marnm, $fams, $ged_id) { $sql= "SELECT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full " . "FROM `##individuals` " . "JOIN `##name` ON (n_id=i_id AND n_file=i_file) " . ($fams ? "JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") . "WHERE n_file={$ged_id} " . ($marnm ? "" : "AND n_type!='_MARNM'"); if ($surn) { $sql .= " AND n_surn COLLATE '" . WT_I18N::$collation . "'=" . WT_DB::quote($surn); } elseif ($salpha==',') { $sql .= " AND n_surn=''"; } elseif ($salpha=='@') { $sql .= " AND n_surn='@N.N.'"; } elseif ($salpha) { $sql .= " AND ".self::_getInitialSql('n_surn', $salpha); } else { // All surnames $sql .= " AND n_surn NOT IN ('', '@N.N.')"; } if ($galpha) { $sql .= " AND " . self::_getInitialSql('n_givn', $galpha); } $sql .= " ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE '" . WT_I18N::$collation . "', CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE '" . WT_I18N::$collation . "'"; $list = array(); $rows = WT_DB::prepare($sql)->fetchAll(); foreach ($rows as $row) { $person = WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); // The name from the database may be private - check the filtered list... foreach ($person->getAllNames() as $n=>$name) { if ($name['fullNN'] == $row->n_full) { $person->setPrimaryName($n); // We need to clone $person, as we may have multiple references to the // same person in this list, and the "primary name" would otherwise // be shared amongst all of them. $list[] = clone $person; break; } } } return $list; } /** * Fetch a list of families with specified names * * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@" * To search for names with no surnames, use $salpha="," * * @param string $surn if set, only fetch people with this surname * @param string $salpha if set, only fetch surnames starting with this letter * @param string $galpha if set, only fetch given names starting with this letter * @param bool $marnm if set, include married names * @param int $ged_id if set, only fetch individuals from this gedcom * * @return WT_Family[] */ public static function families($surn, $salpha, $galpha, $marnm, $ged_id) { $list=array(); foreach (self::individuals($surn, $salpha, $galpha, $marnm, true, $ged_id) as $indi) { foreach ($indi->getSpouseFamilies() as $family) { $list[$family->getXref()]=$family; } } usort($list, array('WT_GedcomRecord', 'Compare')); return $list; } }