Example #1
0
 /**
  * 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[WT_I18N::strtoupper($row->n_surn)][$row->n_surname][$row->n_id] = true;
     }
     return $list;
 }
Example #2
0
/**
 * Get array of common surnames
 *
 * This function returns a simple array of the most common surnames
 * found in the individuals list.
 *
 * @param int $min the number of times a surname must occur before it is added to the array
 *
 * @return array
 */
function get_common_surnames($min)
{
    $COMMON_NAMES_ADD = get_gedcom_setting(WT_GED_ID, 'COMMON_NAMES_ADD');
    $COMMON_NAMES_REMOVE = get_gedcom_setting(WT_GED_ID, 'COMMON_NAMES_REMOVE');
    $topsurns = get_top_surnames(WT_GED_ID, $min, 0);
    foreach (explode(',', $COMMON_NAMES_ADD) as $surname) {
        if ($surname && !array_key_exists($surname, $topsurns)) {
            $topsurns[$surname] = $min;
        }
    }
    foreach (explode(',', $COMMON_NAMES_REMOVE) as $surname) {
        unset($topsurns[WT_I18N::strtoupper($surname)]);
    }
    //-- check if we found some, else recurse
    if (empty($topsurns) && $min > 2) {
        return get_common_surnames($min / 2);
    } else {
        uksort($topsurns, array('WT_I18N', 'strcasecmp'));
        foreach ($topsurns as $key => $value) {
            $topsurns[$key] = array('name' => $key, 'match' => $value);
        }
        return $topsurns;
    }
}
Example #3
0
 private static function DMSoundex($name)
 {
     // Apply special transformation rules to the input string
     $name = WT_I18N::strtoupper($name);
     foreach (self::$transformNameTable as $transformRule) {
         $name = str_replace($transformRule[0], $transformRule[1], $name);
     }
     // Initialize
     $name_script = WT_I18N::textScript($name);
     if ($name_script == 'Hebr' || $name_script == 'Arab') {
         $noVowels = true;
     } else {
         $noVowels = false;
     }
     $lastPos = strlen($name) - 1;
     $currPos = 0;
     $state = 1;
     // 1: start of input string, 2: before vowel, 3: other
     $result = array();
     // accumulate complete 6-digit D-M codes here
     $partialResult = array();
     // accumulate incomplete D-M codes here
     $partialResult[] = array('!');
     // initialize 1st partial result  ('!' stops "duplicate sound" check)
     // Loop through the input string.
     // Stop when the string is exhausted or when no more partial results remain
     while (count($partialResult) != 0 && $currPos <= $lastPos) {
         // Find the DM coding table entry for the chunk at the current position
         $thisEntry = substr($name, $currPos, self::MAXCHAR);
         // Get maximum length chunk
         while ($thisEntry != '') {
             if (isset(self::$dmsounds[$thisEntry])) {
                 break;
             }
             $thisEntry = substr($thisEntry, 0, -1);
             // Not in table: try a shorter chunk
         }
         if ($thisEntry == '') {
             $currPos++;
             // Not in table: advance pointer to next byte
             continue;
             // and try again
         }
         $soundTableEntry = self::$dmsounds[$thisEntry];
         $workingResult = $partialResult;
         $partialResult = array();
         $currPos += strlen($thisEntry);
         if ($state != 1) {
             // Not at beginning of input string
             if ($currPos <= $lastPos) {
                 // Determine whether the next chunk is a vowel
                 $nextEntry = substr($name, $currPos, self::MAXCHAR);
                 // Get maximum length chunk
                 while ($nextEntry != '') {
                     if (isset(self::$dmsounds[$nextEntry])) {
                         break;
                     }
                     $nextEntry = substr($nextEntry, 0, -1);
                     // Not in table: try a shorter chunk
                 }
             } else {
                 $nextEntry = '';
             }
             if ($nextEntry != '' && self::$dmsounds[$nextEntry][0] != '0') {
                 $state = 2;
             } else {
                 $state = 3;
             }
         }
         while ($state < count($soundTableEntry)) {
             if ($soundTableEntry[$state] == '') {
                 // empty means 'ignore this sound in this state'
                 foreach ($workingResult as $workingEntry) {
                     $tempEntry = $workingEntry;
                     $tempEntry[count($tempEntry) - 1] .= '!';
                     // Prevent false 'doubles'
                     $partialResult[] = $tempEntry;
                 }
             } else {
                 foreach ($workingResult as $workingEntry) {
                     if ($soundTableEntry[$state] !== $workingEntry[count($workingEntry) - 1]) {
                         // Incoming sound isn't a duplicate of the previous sound
                         $workingEntry[] = $soundTableEntry[$state];
                     } else {
                         // Incoming sound is a duplicate of the previous sound
                         // For Hebrew and Arabic, we need to create a pair of D-M sound codes,
                         // one of the pair with only a single occurrence of the duplicate sound,
                         // the other with both occurrences
                         if ($noVowels) {
                             //$partialResult[] = $workingEntry;
                             $workingEntry[] = $soundTableEntry[$state];
                         }
                     }
                     if (count($workingEntry) < 7) {
                         $partialResult[] = $workingEntry;
                     } else {
                         // This is the 6th code in the sequence
                         // We're looking for 7 entries because the first is '!' and doesn't count
                         $tempResult = str_replace('!', '', implode('', $workingEntry));
                         // Only return codes from recognisable sounds
                         if ($tempResult) {
                             $result[] = substr($tempResult . '000000', 0, 6);
                         }
                     }
                 }
             }
             $state = $state + 3;
             // Advance to next triplet while keeping the same basic state
         }
     }
     // Zero-fill and copy all remaining partial results
     foreach ($partialResult as $workingEntry) {
         $tempResult = str_replace('!', '', implode('', $workingEntry));
         // Only return codes from recognisable sounds
         if ($tempResult) {
             $result[] = substr($tempResult . '000000', 0, 6);
         }
     }
     return $result;
 }
function format_surname_list($surnames, $style, $totals, $script)
{
    global $GEDCOM;
    $html = array();
    foreach ($surnames as $surn => $surns) {
        // Each surname links back to the indilist
        if ($surn) {
            $url = $script . '?surname=' . urlencode($surn) . '&amp;ged=' . rawurlencode($GEDCOM);
        } else {
            $url = $script . '?alpha=,&amp;ged=' . rawurlencode($GEDCOM);
        }
        // If all the surnames are just case variants, then merge them into one
        // Comment out this block if you want SMITH listed separately from Smith
        $first_spfxsurn = null;
        foreach ($surns as $spfxsurn => $indis) {
            if ($first_spfxsurn) {
                if (WT_I18N::strtoupper($spfxsurn) == WT_I18N::strtoupper($first_spfxsurn)) {
                    $surns[$first_spfxsurn] = array_merge($surns[$first_spfxsurn], $surns[$spfxsurn]);
                    unset($surns[$spfxsurn]);
                }
            } else {
                $first_spfxsurn = $spfxsurn;
            }
        }
        $subhtml = '<a href="' . $url . '" dir="auto">' . WT_Filter::escapeHtml(implode(WT_I18N::$list_separator, array_keys($surns))) . '</a>';
        if ($totals) {
            $subtotal = 0;
            foreach ($surns as $indis) {
                $subtotal += count($indis);
            }
            $subhtml .= '&nbsp;(' . WT_I18N::number($subtotal) . ')';
        }
        $html[] = $subhtml;
    }
    switch ($style) {
        case 1:
            return '<ul><li>' . implode('</li><li>', $html) . '</li></ul>';
        case 2:
            return implode(WT_I18N::$list_separator, $html);
        case 3:
            $i = 0;
            $count = count($html);
            $col = 1;
            if ($count > 36) {
                $col = 4;
            } else {
                if ($count > 18) {
                    $col = 3;
                } else {
                    if ($count > 6) {
                        $col = 2;
                    }
                }
            }
            $newcol = ceil($count / $col);
            $html2 = '<table class="list_table"><tr>';
            $html2 .= '<td class="list_value" style="padding: 14px;">';
            foreach ($html as $surns) {
                $html2 .= $surns . '<br>';
                $i++;
                if ($i == $newcol && $i < $count) {
                    $html2 .= '</td><td class="list_value" style="padding: 14px;">';
                    $newcol = $i + ceil($count / $col);
                }
            }
            $html2 .= '</td></tr></table>';
            return $html2;
    }
}
Example #5
0
 public function getBlock($block_id, $template = true, $cfg = null)
 {
     global $ctype, $SURNAME_LIST_STYLE;
     require_once WT_ROOT . 'includes/functions/functions_print_lists.php';
     $COMMON_NAMES_REMOVE = get_gedcom_setting(WT_GED_ID, 'COMMON_NAMES_REMOVE');
     $COMMON_NAMES_THRESHOLD = get_gedcom_setting(WT_GED_ID, 'COMMON_NAMES_THRESHOLD');
     $num = get_block_setting($block_id, 'num', 10);
     $infoStyle = get_block_setting($block_id, 'infoStyle', 'table');
     $block = get_block_setting($block_id, 'block', false);
     if ($cfg) {
         foreach (array('num', 'infoStyle', 'block') as $name) {
             if (array_key_exists($name, $cfg)) {
                 ${$name} = $cfg[$name];
             }
         }
     }
     // This next function is a bit out of date, and doesn't cope well with surname variants
     $top_surnames = get_top_surnames(WT_GED_ID, $COMMON_NAMES_THRESHOLD, $num);
     // Remove names found in the "Remove Names" list
     if ($COMMON_NAMES_REMOVE) {
         foreach (preg_split("/[,; ]+/", $COMMON_NAMES_REMOVE) as $delname) {
             unset($top_surnames[$delname]);
             unset($top_surnames[WT_I18N::strtoupper($delname)]);
         }
     }
     $all_surnames = array();
     $i = 0;
     foreach (array_keys($top_surnames) as $top_surname) {
         $all_surnames = array_merge($all_surnames, WT_Query_Name::surnames($top_surname, '', false, false, WT_GED_ID));
         if (++$i == $num) {
             break;
         }
     }
     if ($i < $num) {
         $num = $i;
     }
     $id = $this->getName() . $block_id;
     $class = $this->getName() . '_block';
     if ($ctype == 'gedcom' && WT_USER_GEDCOM_ADMIN || $ctype == 'user' && WT_USER_ID) {
         $title = '<i class="icon-admin" title="' . WT_I18N::translate('Configure') . '" onclick="modalDialog(\'block_edit.php?block_id=' . $block_id . '\', \'' . $this->getTitle() . '\');"></i>';
     } else {
         $title = '';
     }
     if ($num == 1) {
         // I18N: i.e. most popular surname.
         $title .= WT_I18N::translate('Top surname');
     } else {
         // I18N: Title for a list of the most common surnames, %s is a number.  Note that a separate translation exists when %s is 1
         $title .= WT_I18N::plural('Top %s surname', 'Top %s surnames', $num, WT_I18N::number($num));
     }
     switch ($infoStyle) {
         case 'tagcloud':
             uksort($all_surnames, array('WT_I18N', 'strcasecmp'));
             $content = format_surname_tagcloud($all_surnames, 'indilist.php', true);
             break;
         case 'list':
             uasort($all_surnames, array('top10_surnames_WT_Module', 'top_surname_sort'));
             $content = format_surname_list($all_surnames, '1', true, 'indilist.php');
             break;
         case 'array':
             uasort($all_surnames, array('top10_surnames_WT_Module', 'top_surname_sort'));
             $content = format_surname_list($all_surnames, '2', true, 'indilist.php');
             break;
         case 'table':
         default:
             uasort($all_surnames, array('top10_surnames_WT_Module', 'top_surname_sort'));
             $content = format_surname_table($all_surnames, 'indilist.php');
             break;
     }
     if ($template) {
         if ($block) {
             require WT_THEME_DIR . 'templates/block_small_temp.php';
         } else {
             require WT_THEME_DIR . 'templates/block_main_temp.php';
         }
     } else {
         return $content;
     }
 }
Example #6
0
 function chartCommonSurnames($params = null)
 {
     global $WT_STATS_CHART_COLOR1, $WT_STATS_CHART_COLOR2, $WT_STATS_S_CHART_X, $WT_STATS_S_CHART_Y;
     if ($params === null) {
         $params = array();
     }
     if (isset($params[0]) && $params[0] != '') {
         $size = strtolower($params[0]);
     } else {
         $size = $WT_STATS_S_CHART_X . "x" . $WT_STATS_S_CHART_Y;
     }
     if (isset($params[1]) && $params[1] != '') {
         $color_from = strtolower($params[1]);
     } else {
         $color_from = $WT_STATS_CHART_COLOR1;
     }
     if (isset($params[2]) && $params[2] != '') {
         $color_to = strtolower($params[2]);
     } else {
         $color_to = $WT_STATS_CHART_COLOR2;
     }
     if (isset($params[3]) && $params[3] != '') {
         $threshold = strtolower($params[3]);
     } else {
         $threshold = get_gedcom_setting($this->_ged_id, 'COMMON_NAMES_THRESHOLD');
     }
     if (isset($params[4]) && $params[4] != '') {
         $maxtoshow = strtolower($params[4]);
     } else {
         $maxtoshow = 7;
     }
     $sizes = explode('x', $size);
     $tot_indi = $this->_totalIndividuals();
     $surnames = get_common_surnames($threshold);
     if (count($surnames) <= 0) {
         return '';
     }
     $SURNAME_TRADITION = get_gedcom_setting(WT_GED_ID, 'SURNAME_TRADITION');
     uasort($surnames, array('WT_Stats', '_name_total_rsort'));
     $surnames = array_slice($surnames, 0, $maxtoshow);
     $all_surnames = array();
     foreach (array_keys($surnames) as $n => $surname) {
         if ($n >= $maxtoshow) {
             break;
         }
         $all_surnames = array_merge($all_surnames, WT_Query_Name::surnames(WT_I18N::strtoupper($surname), '', false, false, WT_GED_ID));
     }
     $tot = 0;
     foreach ($surnames as $surname) {
         $tot += $surname['match'];
     }
     $chd = '';
     $chl = array();
     foreach ($all_surnames as $surns) {
         $count_per = 0;
         $max_name = 0;
         foreach ($surns as $spfxsurn => $indis) {
             $per = count($indis);
             $count_per += $per;
             // select most common surname from all variants
             if ($per > $max_name) {
                 $max_name = $per;
                 $top_name = $spfxsurn;
             }
         }
         switch ($SURNAME_TRADITION) {
             case 'polish':
                 // most common surname should be in male variant (Kowalski, not Kowalska)
                 $top_name = preg_replace(array('/ska$/', '/cka$/', '/dzka$/', '/żka$/'), array('ski', 'cki', 'dzki', 'żki'), $top_name);
         }
         $per = round(100 * $count_per / $tot_indi, 0);
         $chd .= self::_array_to_extended_encoding($per);
         //ToDo: RTL names are often printed LTR when also LTR names are present
         $chl[] = $top_name . ' - ' . WT_I18N::number($count_per);
     }
     $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0);
     $chd .= self::_array_to_extended_encoding($per);
     $chl[] = WT_I18N::translate('Other') . ' - ' . WT_I18N::number($tot_indi - $tot);
     $chart_title = implode(WT_I18N::$list_separator, $chl);
     $chl = implode('|', $chl);
     return '<img src="https://chart.googleapis.com/chart?cht=p3&amp;chd=e:' . $chd . '&amp;chs=' . $size . '&amp;chco=' . $color_from . ',' . $color_to . '&amp;chf=bg,s,ffffff00&amp;chl=' . rawurlencode($chl) . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" alt="' . $chart_title . '" title="' . $chart_title . '" />';
 }