/** * Build all patronymic lineages for the reference surname. * * @return array List of root patronymic lineages */ public function buildLineages() { $indis = \Fisharebest\Webtrees\Query\QueryName::individuals($this->tree, $this->surname, null, null, false, false); if (count($indis) == 0) { return null; } $root_lineages = array(); foreach ($indis as $indi) { $pid = $indi->getXref(); if (!isset($this->used_indis[$pid])) { //Find the root of the lineage /** @var Fisharebest\Webtrees\Individual $indiFirst */ $indiFirst = $this->getLineageRootIndividual($indi); if ($indiFirst) { $this->used_indis[$indiFirst->getXref()] = true; if ($indiFirst->canShow()) { //Check if the root individual has brothers and sisters, without parents $indiChildFamily = $indiFirst->getPrimaryChildFamily(); if ($indiChildFamily !== null) { $root_node = new LineageRootNode(null); $root_node->addFamily($indiChildFamily); } else { $root_node = new LineageRootNode($indiFirst); } $root_node = $this->buildLineage($root_node); if ($root_node) { $root_lineages[] = $root_node; } } } } } return $root_lineages; }
/** * Format a list of individuals. * * @param Tree $tree * @param string $alpha * @param string $surname * * @return string */ private function getSurnameIndis(Tree $tree, $alpha, $surname) { $indis = QueryName::individuals($tree, $surname, $alpha, '', true, false); $out = '<ul>'; foreach ($indis as $person) { if ($person->canShowName()) { $out .= '<li><a href="' . $person->getHtmlUrl() . '">' . $person->getSexImage() . ' ' . $person->getFullName() . ' '; if ($person->canShow()) { $bd = $person->getLifeSpan(); if (!empty($bd)) { $out .= ' (' . $bd . ')'; } } $out .= '</a></li>'; } } $out .= '</ul>'; return $out; }
/** * Create a chart of common surnames. * * @param string[] $params * * @return string */ public function chartCommonSurnames($params = array()) { $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values'); $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values'); $WT_STATS_S_CHART_X = Theme::theme()->parameter('stats-small-chart-x'); $WT_STATS_S_CHART_Y = Theme::theme()->parameter('stats-small-chart-y'); 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 = $this->tree->getPreference('COMMON_NAMES_THRESHOLD'); } if (isset($params[4]) && $params[4] != '') { $maxtoshow = strtolower($params[4]); } else { $maxtoshow = 7; } $sizes = explode('x', $size); $tot_indi = $this->totalIndividualsQuery(); $surnames = FunctionsDb::getCommonSurnames($threshold, $this->tree); if (count($surnames) <= 0) { return ''; } $SURNAME_TRADITION = $this->tree->getPreference('SURNAME_TRADITION'); uasort($surnames, '\\Fisharebest\\Webtrees\\Stats::nameTotalReverseSort'); $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, QueryName::surnames($this->tree, I18N::strtoupper($surname), '', false, false)); } $tot = 0; foreach ($surnames as $surname) { $tot += $surname['match']; } $chd = ''; $chl = array(); foreach ($all_surnames as $surns) { $count_per = 0; $max_name = 0; $top_name = ''; 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 .= $this->arrayToExtendedEncoding(array($per)); $chl[] = $top_name . ' - ' . I18N::number($count_per); } $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0); $chd .= $this->arrayToExtendedEncoding(array($per)); $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot); $chart_title = implode(I18N::$list_separator, $chl); $chl = implode('|', $chl); return '<img src="https://chart.googleapis.com/chart?cht=p3&chd=e:' . $chd . '&chs=' . $size . '&chco=' . $color_from . ',' . $color_to . '&chf=bg,s,ffffff00&chl=' . rawurlencode($chl) . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" alt="' . $chart_title . '" title="' . $chart_title . '" />'; }
break; } if ($count) { if ($show === 'indi' && $givn_initial === $falpha && $show_all_firstnames === 'no') { $list[] = '<a class="warning" href="' . $url . '&falpha=' . rawurlencode($givn_initial) . '" title="' . I18N::number($count) . '">' . $html . '</a>'; } else { $list[] = '<a href="' . $url . '&falpha=' . rawurlencode($givn_initial) . '" title="' . I18N::number($count) . '">' . $html . '</a>'; } } else { $list[] = $html; } } // Search spiders don't get the "show all" option as the other links give them everything. if (!Auth::isSearchEngine()) { if ($show_all_firstnames === 'yes') { $list[] = '<span class="warning">' . I18N::translate('All') . '</span>'; } else { $list[] = '<a href="' . $url . '&show_all_firstnames=yes">' . I18N::translate('All') . '</a>'; } } if ($show_all === 'no') { echo '<h2 class="center">', I18N::translate('Individuals with surname %s', $legend), '</h2>'; } echo '<p class="center alpha_index">', implode(' | ', $list), '</p>'; } } if ($show === 'indi') { echo FunctionsPrintLists::individualTable(QueryName::individuals($WT_TREE, $surname, $alpha, $falpha, $show_marnm === 'yes', false)); } } }
/** * Get the list of initial letters * * @return string[] */ private function getInitialLettersList() { $list = array(); /** @var \Fisharebest\Webtrees\Tree $tree */ $tree = $this->data->get('tree'); $script_base_url = WT_SCRIPT_NAME . '?mod=' . \MyArtJaub\Webtrees\Constants::MODULE_MAJ_PATROLIN_NAME . '&mod_action=Lineage'; foreach (QueryName::surnameAlpha($tree, false, false) as $letter => $count) { switch ($letter) { case '@': $html = I18N::translateContext('Unknown surname', '…'); break; case ',': $html = I18N::translate('None'); break; default: $html = Filter::escapeHtml($letter); break; } if ($count) { if ($letter == $this->data->get('alpha')) { $list[] = '<a href="' . $script_base_url . '&alpha=' . rawurlencode($letter) . '&ged=' . $tree->getNameUrl() . '" class="warning" title="' . I18N::number($count) . '">' . $html . '</a>'; } else { $list[] = '<a href="' . $script_base_url . '&alpha=' . rawurlencode($letter) . '&ged=' . $tree->getNameUrl() . '" title="' . I18N::number($count) . '">' . $html . '</a>'; } } else { $list[] = $html; } } // Search spiders don't get the "show all" option as the other links give them everything. if (!Auth::isSearchEngine()) { if ($this->data->get('show_all') === 'yes') { $list[] = '<span class="warning">' . I18N::translate('All') . '</span>'; } else { $list[] = '<a href="' . $script_base_url . '&show_all=yes' . '&ged=' . $tree->getNameUrl() . '">' . I18N::translate('All') . '</a>'; } } return $list; }
/** * Get a list of surnames. * * @param Tree $tree * @param string $alpha * @param string $surname * * @return string */ public function getSurnameFams(Tree $tree, $alpha, $surname) { $families = QueryName::families($tree, $surname, $alpha, '', true); $out = '<ul>'; foreach ($families as $family) { if ($family->canShowName()) { $out .= '<li><a href="' . $family->getHtmlUrl() . '">' . $family->getFullName() . ' '; if ($family->canShow()) { $marriage_year = $family->getMarriageYear(); if ($marriage_year) { $out .= ' (' . $marriage_year . ')'; } } $out .= '</a></li>'; } } $out .= '</ul>'; return $out; }
break; } if ($count) { if ($show === 'indi' && $givn_initial === $falpha && $show_all_firstnames === 'no') { $list[] = '<a class="warning" href="' . $url . '&falpha=' . rawurlencode($givn_initial) . '" title="' . I18N::number($count) . '">' . $html . '</a>'; } else { $list[] = '<a href="' . $url . '&falpha=' . rawurlencode($givn_initial) . '" title="' . I18N::number($count) . '">' . $html . '</a>'; } } else { $list[] = $html; } } // Search spiders don't get the "show all" option as the other links give them everything. if (!Auth::isSearchEngine()) { if ($show_all_firstnames === 'yes') { $list[] = '<span class="warning">' . I18N::translate('All') . '</span>'; } else { $list[] = '<a href="' . $url . '&show_all_firstnames=yes">' . I18N::translate('All') . '</a>'; } } if ($show_all === 'no') { echo '<h2 class="center">', I18N::translate('Individuals with surname %s', $legend), '</h2>'; } echo '<p class="center alpha_index">', implode(' | ', $list), '</p>'; } } if ($show === 'indi') { echo FunctionsPrintLists::familyTable(QueryName::families($WT_TREE, $surname, $alpha, $falpha, $show_marnm === 'yes')); } } }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $WT_TREE, $ctype; $COMMON_NAMES_REMOVE = $WT_TREE->getPreference('COMMON_NAMES_REMOVE'); $COMMON_NAMES_THRESHOLD = $WT_TREE->getPreference('COMMON_NAMES_THRESHOLD'); $num = $this->getBlockSetting($block_id, 'num', '10'); $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table'); $block = $this->getBlockSetting($block_id, 'block', '0'); 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 = FunctionsDb::getTopSurnames($WT_TREE->getTreeId(), $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[I18N::strtoupper($delname)]); } } $all_surnames = array(); $i = 0; foreach (array_keys($top_surnames) as $top_surname) { $all_surnames = array_merge($all_surnames, QueryName::surnames($WT_TREE, $top_surname, '', false, false)); if (++$i == $num) { break; } } if ($i < $num) { $num = $i; } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } if ($num == 1) { // I18N: i.e. most popular surname. $title .= 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 .= I18N::plural('Top %s surname', 'Top %s surnames', $num, I18N::number($num)); } switch ($infoStyle) { case 'tagcloud': uksort($all_surnames, '\\Fisharebest\\Webtrees\\I18N::strcasecmp'); $content = FunctionsPrintLists::surnameTagCloud($all_surnames, 'indilist.php', true, $WT_TREE); break; case 'list': uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameList($all_surnames, '1', true, 'indilist.php', $WT_TREE); break; case 'array': uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameList($all_surnames, '2', true, 'indilist.php', $WT_TREE); break; case 'table': default: uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameTable($all_surnames, 'indilist.php', $WT_TREE); break; } if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
/** * Get list of surnames, starting with the specified initial * @return array */ protected function getSurnamesList() { global $WT_TREE; return QueryName::surnames($WT_TREE, $this->surname, $this->alpha, false, false); }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $WT_TREE, $ctype; $show_last_update = $this->getBlockSetting($block_id, 'show_last_update', '1'); $show_common_surnames = $this->getBlockSetting($block_id, 'show_common_surnames', '1'); $number_of_surnames = $this->getBlockSetting($block_id, 'number_of_surnames', self::DEFAULT_NUMBER_OF_SURNAMES); $stat_indi = $this->getBlockSetting($block_id, 'stat_indi', '1'); $stat_fam = $this->getBlockSetting($block_id, 'stat_fam', '1'); $stat_sour = $this->getBlockSetting($block_id, 'stat_sour', '1'); $stat_media = $this->getBlockSetting($block_id, 'stat_media', '1'); $stat_repo = $this->getBlockSetting($block_id, 'stat_repo', '1'); $stat_surname = $this->getBlockSetting($block_id, 'stat_surname', '1'); $stat_events = $this->getBlockSetting($block_id, 'stat_events', '1'); $stat_users = $this->getBlockSetting($block_id, 'stat_users', '1'); $stat_first_birth = $this->getBlockSetting($block_id, 'stat_first_birth', '1'); $stat_last_birth = $this->getBlockSetting($block_id, 'stat_last_birth', '1'); $stat_first_death = $this->getBlockSetting($block_id, 'stat_first_death', '1'); $stat_last_death = $this->getBlockSetting($block_id, 'stat_last_death', '1'); $stat_long_life = $this->getBlockSetting($block_id, 'stat_long_life', '1'); $stat_avg_life = $this->getBlockSetting($block_id, 'stat_avg_life', '1'); $stat_most_chil = $this->getBlockSetting($block_id, 'stat_most_chil', '1'); $stat_avg_chil = $this->getBlockSetting($block_id, 'stat_avg_chil', '1'); // This can be overriden when embedding in an HTML block $block = '0'; foreach (array('show_common_surnames', 'number_common_surnames', 'stat_indi', 'stat_fam', 'stat_sour', 'stat_media', 'stat_surname', 'stat_events', 'stat_users', 'stat_first_birth', 'stat_last_birth', 'stat_first_death', 'stat_last_death', 'stat_long_life', 'stat_avg_life', 'stat_most_chil', 'stat_avg_chil', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle() . ' — ' . $WT_TREE->getTitleHtml(); $stats = new Stats($WT_TREE); $content = ''; if ($show_last_update) { $content .= '<p>' . I18N::translate('This family tree was last updated on %s.', strip_tags($stats->gedcomUpdated())) . '</p>'; } /** Responsive Design */ $content .= '<div class="stat-table1">'; if ($stat_indi) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Individuals') . '</div><div class="facts_value stats_value stat-cell"><a href="' . "indilist.php?surname_sublist=no&ged=" . $WT_TREE->getNameUrl() . '">' . $stats->totalIndividuals() . '</a></div></div>'; $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Males') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalSexMales() . '<br>' . $stats->totalSexMalesPercentage() . '</div></div>'; $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Females') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalSexFemales() . '<br>' . $stats->totalSexFemalesPercentage() . '</div></div>'; } if ($stat_surname) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total surnames') . '</div><div class="facts_value stats_value stat-cell"><a href="indilist.php?show_all=yes&surname_sublist=yes&ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalSurnames() . '</a></div></div>'; } if ($stat_fam) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Families') . '</div><div class="facts_value stats_value stat-cell"><a href="famlist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalFamilies() . '</a></div></div>'; } if ($stat_sour) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Sources') . '</div><div class="facts_value stats_value stat-cell"><a href="sourcelist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalSources() . '</a></div></div>'; } if ($stat_media) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Media objects') . '</div><div class="facts_value stats_value stat-cell"><a href="medialist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalMedia() . '</a></div></div>'; } if ($stat_repo) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Repositories') . '</div><div class="facts_value stats_value stat-cell"><a href="repolist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalRepositories() . '</a></div></div>'; } if ($stat_events) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total events') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalEvents() . '</div></div>'; } if ($stat_users) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total users') . '</div><div class="facts_value stats_value stat-cell">'; if (Auth::isManager($WT_TREE)) { $content .= '<a href="admin_users.php">' . $stats->totalUsers() . '</a>'; } else { $content .= $stats->totalUsers(); } $content .= '</div></div>'; } if (!$block) { $content .= '</div><div class="facts_table stat-table2">'; } if ($stat_first_birth) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstBirthYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->firstBirth() . '</div>'; } $content .= '</div>'; } if ($stat_last_birth) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastBirthYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->lastBirth() . '</div>'; } $content .= '</div>'; } if ($stat_first_death) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstDeathYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->firstDeath() . '</div>'; } $content .= '</div>'; } if ($stat_last_death) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastDeathYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->lastDeath() . '</div>'; } $content .= '</div>'; } if ($stat_long_life) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Individual who lived the longest') . '</div><div class="facts_value stats_value stat-cell">' . $stats->longestLifeAge() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->longestLife() . '</div>'; } $content .= '</div>'; } if ($stat_avg_life) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average age at death') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageLifespan() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . I18N::translate('Males') . ': ' . $stats->averageLifespanMale(); $content .= ' ' . I18N::translate('Females') . ': ' . $stats->averageLifespanFemale() . '</div>'; } $content .= '</div>'; } if ($stat_most_chil && !$block) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Family with the most children') . '</div><div class="facts_value stats_value stat-cell">' . $stats->largestFamilySize() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->largestFamily() . '</div>'; } $content .= '</div>'; } if ($stat_avg_chil) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average number of children per family') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageChildren() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left"></div>'; } $content .= '</div>'; } $content .= '</div>'; if ($show_common_surnames) { $surnames = FunctionsDb::getTopSurnames($WT_TREE->getTreeId(), 0, (int) $number_of_surnames); $all_surnames = array(); foreach (array_keys($surnames) as $surname) { $all_surnames = array_merge($all_surnames, QueryName::surnames($WT_TREE, $surname, '', false, false)); } if (!empty($surnames)) { ksort($all_surnames); $content .= '<div class="clearfloat">'; $content .= '<p>'; $content .= '<strong>' . I18N::translate('Most common surnames') . '</strong>'; $content .= '<br>'; $content .= '<span class="common_surnames">' . FunctionsPrintLists::surnameList($all_surnames, 2, false, 'indilist.php', $WT_TREE) . '</span>'; $content .= '</p>'; $content .= '</div>'; } } if ($template) { return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
/** * Create a chart of common surnames. * * @param string[] $params * * @return string */ public function chartCommonSurnames($params = array()) { $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values'); $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values'); $WT_STATS_S_CHART_X = Theme::theme()->parameter('stats-small-chart-x'); $WT_STATS_S_CHART_Y = Theme::theme()->parameter('stats-small-chart-y'); $size = empty($params[0]) ? $WT_STATS_S_CHART_X . "x" . $WT_STATS_S_CHART_Y : strtolower($params[0]); $color_from = empty($params[1]) ? $WT_STATS_CHART_COLOR1 : strtolower($params[1]); $color_to = empty($params[2]) ? $WT_STATS_CHART_COLOR2 : strtolower($params[2]); $number_of_surnames = empty($params[3]) ? 10 : (int) $params[3]; $sizes = explode('x', $size); $tot_indi = $this->totalIndividualsQuery(); $surnames = FunctionsDb::getTopSurnames($this->tree->getTreeId(), 0, $number_of_surnames); if (empty($surnames)) { return ''; } $SURNAME_TRADITION = $this->tree->getPreference('SURNAME_TRADITION'); $all_surnames = array(); $tot = 0; foreach ($surnames as $surname => $num) { $all_surnames = array_merge($all_surnames, QueryName::surnames($this->tree, I18N::strtoupper($surname), '', false, false)); $tot += $num; } $chd = ''; $chl = array(); foreach ($all_surnames as $surns) { $count_per = 0; $max_name = 0; $top_name = ''; 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 .= $this->arrayToExtendedEncoding(array($per)); $chl[] = $top_name . ' - ' . I18N::number($count_per); } $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0); $chd .= $this->arrayToExtendedEncoding(array($per)); $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot); $chart_title = implode(I18N::$list_separator, $chl); $chl = implode('|', $chl); return '<img src="https://chart.googleapis.com/chart?cht=p3&chd=e:' . $chd . '&chs=' . $size . '&chco=' . $color_from . ',' . $color_to . '&chf=bg,s,ffffff00&chl=' . rawurlencode($chl) . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" alt="' . $chart_title . '" title="' . $chart_title . '" />'; }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $WT_TREE, $ctype; $COMMON_NAMES_REMOVE = $WT_TREE->getPreference('COMMON_NAMES_REMOVE'); $COMMON_NAMES_THRESHOLD = $WT_TREE->getPreference('COMMON_NAMES_THRESHOLD'); $num = $this->getBlockSetting($block_id, 'num', '10'); // The “Minimum number of occurrences” input field from Control Panel’s Preferences page // has to be copied here otherwise user doesn't understand why the result is different // than expected (input of add and remove surnames may also be copied to make this module // indenpendent from module statistics; it is not copied yet). The data of original input // field is still used in the bottom of the statistics module $threshold = $this->getBlockSetting($block_id, 'threshold', '5'); $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table'); $block = $this->getBlockSetting($block_id, 'block', '0'); 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 // First defining the upper limit of surname occurrences to get at least one row in // result list if user sets too high number in “Minimum number of occurrences” field. // Without this definition a short message “No data available in table” appears by // webtrees\packages\datatables-1.10.7\js\jquery.dataTables.min.js JavaScript file // without the possibility of translating (and only if presentation style is table; // all other styles result no message at all) $top_surnames_in_DB = FunctionsDb::getCommonSurnames($WT_TREE->getPreference('COMMON_NAMES_THRESHOLD'), $WT_TREE); $max_occurrences = 0; foreach ($top_surnames_in_DB as $array) { if ($array['match'] > $max_occurrences) { $max_occurrences = $array['match']; } } if ($threshold > $max_occurrences) { $threshold = $max_occurrences; } $top_surnames = FunctionsDb::getTopSurnames($WT_TREE->getTreeId(), $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[I18N::strtoupper($delname)]); } } $all_surnames = array(); $i = 0; foreach (array_keys($top_surnames) as $top_surname) { $all_surnames = array_merge($all_surnames, QueryName::surnames($WT_TREE, $top_surname, '', false, false)); if (++$i == $num) { break; } } if ($i < $num) { $num = $i; } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } if ($num == 1) { // I18N: i.e. most popular surname. $title .= 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 .= I18N::plural('Top %s surname', 'Top %s surnames', $num, I18N::number($num)); } switch ($infoStyle) { case 'tagcloud': uksort($all_surnames, '\\Fisharebest\\Webtrees\\I18N::strcasecmp'); $content = FunctionsPrintLists::surnameTagCloud($all_surnames, 'indilist.php', true, $WT_TREE); break; case 'list': uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameList($all_surnames, '1', true, 'indilist.php', $WT_TREE); break; case 'array': uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameList($all_surnames, '2', true, 'indilist.php', $WT_TREE); break; case 'table': default: uasort($all_surnames, '\\Fisharebest\\Webtrees\\Module\\TopSurnamesModule::surnameCountSort'); $content = FunctionsPrintLists::surnameTable($all_surnames, 'indilist.php', $WT_TREE); break; } if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }