summaryrefslogtreecommitdiff
path: root/app/Stats.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/Stats.php')
-rw-r--r--app/Stats.php13935
1 files changed, 7490 insertions, 6445 deletions
diff --git a/app/Stats.php b/app/Stats.php
index 82271cf933..907e28b42a 100644
--- a/app/Stats.php
+++ b/app/Stats.php
@@ -32,6910 +32,7955 @@ use PDOException;
* These are primarily used for embedded keywords on HTML blocks, but
* are also used elsewhere in the code.
*/
-class Stats {
- // Used in Google charts
- const GOOGLE_CHART_ENCODING = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
-
- /** @var Tree Generate statistics for a specified tree. */
- private $tree;
+class Stats
+{
+ // Used in Google charts
+ const GOOGLE_CHART_ENCODING = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
- /** @var string[] All public functions are available as keywords - except these ones */
- private $public_but_not_allowed = [
- '__construct', 'embedTags', 'iso3166', 'getAllCountries', 'getAllTagsTable', 'getAllTagsText', 'statsPlaces', 'statsBirthQuery', 'statsDeathQuery', 'statsMarrQuery', 'statsAgeQuery', 'monthFirstChildQuery', 'statsChildrenQuery', 'statsMarrAgeQuery',
- ];
+ /** @var Tree Generate statistics for a specified tree. */
+ private $tree;
- /** @var string[] List of GEDCOM media types */
- private $_media_types = ['audio', 'book', 'card', 'certificate', 'coat', 'document', 'electronic', 'magazine', 'manuscript', 'map', 'fiche', 'film', 'newspaper', 'painting', 'photo', 'tombstone', 'video', 'other'];
+ /** @var string[] All public functions are available as keywords - except these ones */
+ private $public_but_not_allowed = [
+ '__construct',
+ 'embedTags',
+ 'iso3166',
+ 'getAllCountries',
+ 'getAllTagsTable',
+ 'getAllTagsText',
+ 'statsPlaces',
+ 'statsBirthQuery',
+ 'statsDeathQuery',
+ 'statsMarrQuery',
+ 'statsAgeQuery',
+ 'monthFirstChildQuery',
+ 'statsChildrenQuery',
+ 'statsMarrAgeQuery',
+ ];
- /**
- * Create the statistics for a tree.
- *
- * @param Tree $tree Generate statistics for this tree
- */
- public function __construct(Tree $tree) {
- $this->tree = $tree;
- }
+ /** @var string[] List of GEDCOM media types */
+ private $_media_types = [
+ 'audio',
+ 'book',
+ 'card',
+ 'certificate',
+ 'coat',
+ 'document',
+ 'electronic',
+ 'magazine',
+ 'manuscript',
+ 'map',
+ 'fiche',
+ 'film',
+ 'newspaper',
+ 'painting',
+ 'photo',
+ 'tombstone',
+ 'video',
+ 'other',
+ ];
- /**
- * Return a string of all supported tags and an example of its output in table row form.
- *
- * @return string
- */
- public function getAllTagsTable() {
- $examples = [];
- foreach (get_class_methods($this) as $method) {
- $reflection = new \ReflectionMethod($this, $method);
- if ($reflection->isPublic() && !in_array($method, $this->public_but_not_allowed)) {
- $examples[$method] = $this->$method();
- }
- }
- ksort($examples);
+ /**
+ * Create the statistics for a tree.
+ *
+ * @param Tree $tree Generate statistics for this tree
+ */
+ public function __construct(Tree $tree)
+ {
+ $this->tree = $tree;
+ }
- $html = '';
- foreach ($examples as $tag => $value) {
- $html .= '<tr>';
- $html .= '<td class="list_value_wrap">' . $tag . '</td>';
- $html .= '<td class="list_value_wrap">' . $value . '</td>';
- $html .= '</tr>';
- }
+ /**
+ * Return a string of all supported tags and an example of its output in table row form.
+ *
+ * @return string
+ */
+ public function getAllTagsTable()
+ {
+ $examples = [];
+ foreach (get_class_methods($this) as $method) {
+ $reflection = new \ReflectionMethod($this, $method);
+ if ($reflection->isPublic() && !in_array($method, $this->public_but_not_allowed)) {
+ $examples[$method] = $this->$method();
+ }
+ }
+ ksort($examples);
- return
- '<table id="keywords" style="width:100%; table-layout:fixed"><thead>' .
- '<tr>' .
- '<th class="list_label_wrap width25">' .
- I18N::translate('Embedded variable') .
- '</th>' .
- '<th class="list_label_wrap width75">' .
- I18N::translate('Resulting value') .
- '</th>' .
- '</tr>' .
- '</thead><tbody>' .
- $html .
- '</tbody></table>';
- }
+ $html = '';
+ foreach ($examples as $tag => $value) {
+ $html .= '<tr>';
+ $html .= '<td class="list_value_wrap">' . $tag . '</td>';
+ $html .= '<td class="list_value_wrap">' . $value . '</td>';
+ $html .= '</tr>';
+ }
- /**
- * Return a string of all supported tags in plain text.
- *
- * @return string
- */
- public function getAllTagsText() {
- $examples = [];
- foreach (get_class_methods($this) as $method) {
- $reflection = new \ReflectionMethod($this, $method);
- if ($reflection->isPublic() && !in_array($method, $this->public_but_not_allowed)) {
- $examples[$method] = $method;
- }
- }
- ksort($examples);
+ return
+ '<table id="keywords" style="width:100%; table-layout:fixed"><thead>' .
+ '<tr>' .
+ '<th class="list_label_wrap width25">' .
+ I18N::translate('Embedded variable') .
+ '</th>' .
+ '<th class="list_label_wrap width75">' .
+ I18N::translate('Resulting value') .
+ '</th>' .
+ '</tr>' .
+ '</thead><tbody>' .
+ $html .
+ '</tbody></table>';
+ }
- return implode('<br>', $examples);
- }
+ /**
+ * Return a string of all supported tags in plain text.
+ *
+ * @return string
+ */
+ public function getAllTagsText()
+ {
+ $examples = [];
+ foreach (get_class_methods($this) as $method) {
+ $reflection = new \ReflectionMethod($this, $method);
+ if ($reflection->isPublic() && !in_array($method, $this->public_but_not_allowed)) {
+ $examples[$method] = $method;
+ }
+ }
+ ksort($examples);
- /**
- * Get tags and their parsed results.
- *
- * @param string $text
- *
- * @return string[][]
- */
- private function getTags($text) {
- // Extract all tags from the provided text
- preg_match_all('/#([^#]+)(?=#)/', (string) $text, $match);
- $tags = $match[1];
- $c = count($tags);
- $new_tags = []; // tag to replace
- $new_values = []; // value to replace it with
+ return implode('<br>', $examples);
+ }
- /*
+ /**
+ * Get tags and their parsed results.
+ *
+ * @param string $text
+ *
+ * @return string[][]
+ */
+ private function getTags($text)
+ {
+ // Extract all tags from the provided text
+ preg_match_all('/#([^#]+)(?=#)/', (string)$text, $match);
+ $tags = $match[1];
+ $c = count($tags);
+ $new_tags = []; // tag to replace
+ $new_values = []; // value to replace it with
+
+ /*
* Parse block tags.
*/
- for ($i = 0; $i < $c; $i++) {
- $full_tag = $tags[$i];
- // Added for new parameter support
- $params = explode(':', $tags[$i]);
- if (count($params) > 1) {
- $tags[$i] = array_shift($params);
- } else {
- $params = [];
- }
+ for ($i = 0; $i < $c; $i++) {
+ $full_tag = $tags[$i];
+ // Added for new parameter support
+ $params = explode(':', $tags[$i]);
+ if (count($params) > 1) {
+ $tags[$i] = array_shift($params);
+ } else {
+ $params = [];
+ }
- // Generate the replacement value for the tag
- if (method_exists($this, $tags[$i])) {
- $new_tags[] = "#{$full_tag}#";
- $new_values[] = call_user_func_array([$this, $tags[$i]], [$params]);
- }
- }
+ // Generate the replacement value for the tag
+ if (method_exists($this, $tags[$i])) {
+ $new_tags[] = "#{$full_tag}#";
+ $new_values[] = call_user_func_array([
+ $this,
+ $tags[$i],
+ ], [$params]);
+ }
+ }
- return [$new_tags, $new_values];
- }
+ return [
+ $new_tags,
+ $new_values,
+ ];
+ }
- /**
- * Embed tags in text
- *
- * @param string $text
- *
- * @return string
- */
- public function embedTags($text) {
- if (strpos($text, '#') !== false) {
- list($new_tags, $new_values) = $this->getTags($text);
- $text = str_replace($new_tags, $new_values, $text);
- }
+ /**
+ * Embed tags in text
+ *
+ * @param string $text
+ *
+ * @return string
+ */
+ public function embedTags($text)
+ {
+ if (strpos($text, '#') !== false) {
+ list($new_tags, $new_values) = $this->getTags($text);
+ $text = str_replace($new_tags, $new_values, $text);
+ }
- return $text;
- }
+ return $text;
+ }
- /**
- * Get the name used for GEDCOM files and URLs.
- *
- * @return string
- */
- public function gedcomFilename() {
- return $this->tree->getName();
- }
+ /**
+ * Get the name used for GEDCOM files and URLs.
+ *
+ * @return string
+ */
+ public function gedcomFilename()
+ {
+ return $this->tree->getName();
+ }
- /**
- * Get the internal ID number of the tree.
- *
- * @return int
- */
- public function gedcomId() {
- return $this->tree->getTreeId();
- }
+ /**
+ * Get the internal ID number of the tree.
+ *
+ * @return int
+ */
+ public function gedcomId()
+ {
+ return $this->tree->getTreeId();
+ }
- /**
- * Get the descriptive title of the tree.
- *
- * @return string
- */
- public function gedcomTitle() {
- return e($this->tree->getTitle());
- }
+ /**
+ * Get the descriptive title of the tree.
+ *
+ * @return string
+ */
+ public function gedcomTitle()
+ {
+ return e($this->tree->getTitle());
+ }
- /**
- * Get information from the GEDCOM's HEAD record.
- *
- * @return string[]
- */
- private function gedcomHead() {
- $title = '';
- $version = '';
- $source = '';
+ /**
+ * Get information from the GEDCOM's HEAD record.
+ *
+ * @return string[]
+ */
+ private function gedcomHead()
+ {
+ $title = '';
+ $version = '';
+ $source = '';
- $head = GedcomRecord::getInstance('HEAD', $this->tree);
- $sour = $head->getFirstFact('SOUR');
- if ($sour !== null) {
- $source = $sour->getValue();
- $title = $sour->getAttribute('NAME');
- $version = $sour->getAttribute('VERS');
- }
+ $head = GedcomRecord::getInstance('HEAD', $this->tree);
+ $sour = $head->getFirstFact('SOUR');
+ if ($sour !== null) {
+ $source = $sour->getValue();
+ $title = $sour->getAttribute('NAME');
+ $version = $sour->getAttribute('VERS');
+ }
- return [$title, $version, $source];
- }
+ return [
+ $title,
+ $version,
+ $source,
+ ];
+ }
- /**
- * Get the software originally used to create the GEDCOM file.
- *
- * @return string
- */
- public function gedcomCreatedSoftware() {
- $head = $this->gedcomHead();
+ /**
+ * Get the software originally used to create the GEDCOM file.
+ *
+ * @return string
+ */
+ public function gedcomCreatedSoftware()
+ {
+ $head = $this->gedcomHead();
- return $head[0];
- }
+ return $head[0];
+ }
- /**
- * Get the version of software which created the GEDCOM file.
- *
- * @return string
- */
- public function gedcomCreatedVersion() {
- $head = $this->gedcomHead();
- // fix broken version string in Family Tree Maker
- if (strstr($head[1], 'Family Tree Maker ')) {
- $p = strpos($head[1], '(') + 1;
- $p2 = strpos($head[1], ')');
- $head[1] = substr($head[1], $p, ($p2 - $p));
- }
- // Fix EasyTree version
- if ($head[2] == 'EasyTree') {
- $head[1] = substr($head[1], 1);
- }
+ /**
+ * Get the version of software which created the GEDCOM file.
+ *
+ * @return string
+ */
+ public function gedcomCreatedVersion()
+ {
+ $head = $this->gedcomHead();
+ // fix broken version string in Family Tree Maker
+ if (strstr($head[1], 'Family Tree Maker ')) {
+ $p = strpos($head[1], '(') + 1;
+ $p2 = strpos($head[1], ')');
+ $head[1] = substr($head[1], $p, ($p2 - $p));
+ }
+ // Fix EasyTree version
+ if ($head[2] == 'EasyTree') {
+ $head[1] = substr($head[1], 1);
+ }
- return $head[1];
- }
+ return $head[1];
+ }
- /**
- * Get the date the GEDCOM file was created.
- *
- * @return string
- */
- public function gedcomDate() {
- $head = GedcomRecord::getInstance('HEAD', $this->tree);
- $fact = $head->getFirstFact('DATE');
- if ($fact) {
- $date = new Date($fact->getValue());
+ /**
+ * Get the date the GEDCOM file was created.
+ *
+ * @return string
+ */
+ public function gedcomDate()
+ {
+ $head = GedcomRecord::getInstance('HEAD', $this->tree);
+ $fact = $head->getFirstFact('DATE');
+ if ($fact) {
+ $date = new Date($fact->getValue());
- return $date->display();
- }
+ return $date->display();
+ }
- return '';
- }
+ return '';
+ }
- /**
- * When was this tree last updated?
- *
- * @return string
- */
- public function gedcomUpdated() {
- $row = Database::prepare(
- "SELECT d_year, d_month, d_day FROM `##dates` WHERE d_julianday1 = (SELECT MAX(d_julianday1) FROM `##dates` WHERE d_file =? AND d_fact='CHAN') LIMIT 1"
- )->execute([$this->tree->getTreeId()])->fetchOneRow();
- if ($row) {
- $date = new Date("{$row->d_day} {$row->d_month} {$row->d_year}");
+ /**
+ * When was this tree last updated?
+ *
+ * @return string
+ */
+ public function gedcomUpdated()
+ {
+ $row = Database::prepare(
+ "SELECT d_year, d_month, d_day FROM `##dates` WHERE d_julianday1 = (SELECT MAX(d_julianday1) FROM `##dates` WHERE d_file =? AND d_fact='CHAN') LIMIT 1"
+ )->execute([$this->tree->getTreeId()])->fetchOneRow();
+ if ($row) {
+ $date = new Date("{$row->d_day} {$row->d_month} {$row->d_year}");
- return $date->display();
- } else {
- return $this->gedcomDate();
- }
- }
+ return $date->display();
+ } else {
+ return $this->gedcomDate();
+ }
+ }
- /**
- * What is the significant individual from this tree?
- *
- * @return string
- */
- public function gedcomRootId() {
- return $this->tree->getPreference('PEDIGREE_ROOT_ID');
- }
+ /**
+ * What is the significant individual from this tree?
+ *
+ * @return string
+ */
+ public function gedcomRootId()
+ {
+ return $this->tree->getPreference('PEDIGREE_ROOT_ID');
+ }
- /**
- * Convert totals into percentages.
- *
- * @param string $total
- * @param string $type
- *
- * @return string
- */
- private function getPercentage($total, $type) {
- switch ($type) {
- case 'individual':
- $type = $this->totalIndividualsQuery();
- break;
- case 'family':
- $type = $this->totalFamiliesQuery();
- break;
- case 'source':
- $type = $this->totalSourcesQuery();
- break;
- case 'note':
- $type = $this->totalNotesQuery();
- break;
- case 'all':
- default:
- $type = $this->totalIndividualsQuery() + $this->totalFamiliesQuery() + $this->totalSourcesQuery();
- break;
- }
- if ($type == 0) {
- return I18N::percentage(0, 1);
- } else {
- return I18N::percentage($total / $type, 1);
- }
- }
+ /**
+ * Convert totals into percentages.
+ *
+ * @param string $total
+ * @param string $type
+ *
+ * @return string
+ */
+ private function getPercentage($total, $type)
+ {
+ switch ($type) {
+ case 'individual':
+ $type = $this->totalIndividualsQuery();
+ break;
+ case 'family':
+ $type = $this->totalFamiliesQuery();
+ break;
+ case 'source':
+ $type = $this->totalSourcesQuery();
+ break;
+ case 'note':
+ $type = $this->totalNotesQuery();
+ break;
+ case 'all':
+ default:
+ $type = $this->totalIndividualsQuery() + $this->totalFamiliesQuery() + $this->totalSourcesQuery();
+ break;
+ }
+ if ($type == 0) {
+ return I18N::percentage(0, 1);
+ } else {
+ return I18N::percentage($total / $type, 1);
+ }
+ }
- /**
- * How many GEDCOM records exist in the tree.
- *
- * @return string
- */
- public function totalRecords() {
- return I18N::number($this->totalIndividualsQuery() + $this->totalFamiliesQuery() + $this->totalSourcesQuery());
- }
+ /**
+ * How many GEDCOM records exist in the tree.
+ *
+ * @return string
+ */
+ public function totalRecords()
+ {
+ return I18N::number($this->totalIndividualsQuery() + $this->totalFamiliesQuery() + $this->totalSourcesQuery());
+ }
- /**
- * How many individuals exist in the tree.
- *
- * @return int
- */
- private function totalIndividualsQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * How many individuals exist in the tree.
+ *
+ * @return int
+ */
+ private function totalIndividualsQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * How many individuals exist in the tree.
- *
- * @return string
- */
- public function totalIndividuals() {
- return I18N::number($this->totalIndividualsQuery());
- }
+ /**
+ * How many individuals exist in the tree.
+ *
+ * @return string
+ */
+ public function totalIndividuals()
+ {
+ return I18N::number($this->totalIndividualsQuery());
+ }
- /**
- * How many individuals have one or more sources.
- *
- * @return int
- */
- private function totalIndisWithSourcesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(DISTINCT i_id)" .
- " FROM `##individuals` JOIN `##link` ON i_id = l_from AND i_file = l_file" .
- " WHERE l_file = :tree_id AND l_type = 'SOUR'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * How many individuals have one or more sources.
+ *
+ * @return int
+ */
+ private function totalIndisWithSourcesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(DISTINCT i_id)" .
+ " FROM `##individuals` JOIN `##link` ON i_id = l_from AND i_file = l_file" .
+ " WHERE l_file = :tree_id AND l_type = 'SOUR'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * How many individuals have one or more sources.
- *
- * @return string
- */
- public function totalIndisWithSources() {
- return I18N::number($this->totalIndisWithSourcesQuery());
- }
+ /**
+ * How many individuals have one or more sources.
+ *
+ * @return string
+ */
+ public function totalIndisWithSources()
+ {
+ return I18N::number($this->totalIndisWithSourcesQuery());
+ }
- /**
- * Create a chart showing individuals with/without sources.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartIndisWithSources($params = []) {
- $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');
+ /**
+ * Create a chart showing individuals with/without sources.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartIndisWithSources($params = [])
+ {
+ $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;
- }
- $sizes = explode('x', $size);
- $tot_indi = $this->totalIndividualsQuery();
- if ($tot_indi == 0) {
- return '';
- } else {
- $tot_sindi_per = round($this->totalIndisWithSourcesQuery() / $tot_indi, 3);
- $chd = $this->arrayToExtendedEncoding([100 - 100 * $tot_sindi_per, 100 * $tot_sindi_per]);
- $chl = I18N::translate('Without sources') . ' - ' . I18N::percentage(1 - $tot_sindi_per, 1) . '|' .
- I18N::translate('With sources') . ' - ' . I18N::percentage($tot_sindi_per, 1);
- $chart_title = I18N::translate('Individuals with sources');
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot_indi = $this->totalIndividualsQuery();
+ if ($tot_indi == 0) {
+ return '';
+ } else {
+ $tot_sindi_per = round($this->totalIndisWithSourcesQuery() / $tot_indi, 3);
+ $chd = $this->arrayToExtendedEncoding([
+ 100 - 100 * $tot_sindi_per,
+ 100 * $tot_sindi_per,
+ ]);
+ $chl = I18N::translate('Without sources') . ' - ' . I18N::percentage(1 - $tot_sindi_per, 1) . '|' .
+ I18N::translate('With sources') . ' - ' . I18N::percentage($tot_sindi_per, 1);
+ $chart_title = I18N::translate('Individuals with sources');
- 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 . '">';
- }
- }
+ 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 . '">';
+ }
+ }
- /**
- * Show the total individuals as a percentage.
- *
- * @return string
- */
- public function totalIndividualsPercentage() {
- return $this->getPercentage($this->totalIndividualsQuery(), 'all');
- }
+ /**
+ * Show the total individuals as a percentage.
+ *
+ * @return string
+ */
+ public function totalIndividualsPercentage()
+ {
+ return $this->getPercentage($this->totalIndividualsQuery(), 'all');
+ }
- /**
- * Count the total families.
- *
- * @return int
- */
- private function totalFamiliesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##families` WHERE f_file = :tree_id"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the total families.
+ *
+ * @return int
+ */
+ private function totalFamiliesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##families` WHERE f_file = :tree_id"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the total families.
- *
- * @return string
- */
- public function totalFamilies() {
- return I18N::number($this->totalFamiliesQuery());
- }
+ /**
+ * Count the total families.
+ *
+ * @return string
+ */
+ public function totalFamilies()
+ {
+ return I18N::number($this->totalFamiliesQuery());
+ }
- /**
- * Count the families with source records.
- *
- * @return int
- */
- private function totalFamsWithSourcesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(DISTINCT f_id)" .
- " FROM `##families` JOIN `##link` ON f_id = l_from AND f_file = l_file" .
- " WHERE l_file = :tree_id AND l_type = 'SOUR'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the families with source records.
+ *
+ * @return int
+ */
+ private function totalFamsWithSourcesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(DISTINCT f_id)" .
+ " FROM `##families` JOIN `##link` ON f_id = l_from AND f_file = l_file" .
+ " WHERE l_file = :tree_id AND l_type = 'SOUR'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the families with with source records.
- *
- * @return string
- */
- public function totalFamsWithSources() {
- return I18N::number($this->totalFamsWithSourcesQuery());
- }
+ /**
+ * Count the families with with source records.
+ *
+ * @return string
+ */
+ public function totalFamsWithSources()
+ {
+ return I18N::number($this->totalFamsWithSourcesQuery());
+ }
- /**
- * Create a chart of individuals with/without sources.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartFamsWithSources($params = []) {
- $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');
+ /**
+ * Create a chart of individuals with/without sources.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartFamsWithSources($params = [])
+ {
+ $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;
- }
- $sizes = explode('x', $size);
- $tot_fam = $this->totalFamiliesQuery();
- if ($tot_fam == 0) {
- return '';
- } else {
- $tot_sfam_per = round($this->totalFamsWithSourcesQuery() / $tot_fam, 3);
- $chd = $this->arrayToExtendedEncoding([100 - 100 * $tot_sfam_per, 100 * $tot_sfam_per]);
- $chl = I18N::translate('Without sources') . ' - ' . I18N::percentage(1 - $tot_sfam_per, 1) . '|' .
- I18N::translate('With sources') . ' - ' . I18N::percentage($tot_sfam_per, 1);
- $chart_title = I18N::translate('Families with sources');
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot_fam = $this->totalFamiliesQuery();
+ if ($tot_fam == 0) {
+ return '';
+ } else {
+ $tot_sfam_per = round($this->totalFamsWithSourcesQuery() / $tot_fam, 3);
+ $chd = $this->arrayToExtendedEncoding([
+ 100 - 100 * $tot_sfam_per,
+ 100 * $tot_sfam_per,
+ ]);
+ $chl = I18N::translate('Without sources') . ' - ' . I18N::percentage(1 - $tot_sfam_per, 1) . '|' .
+ I18N::translate('With sources') . ' - ' . I18N::percentage($tot_sfam_per, 1);
+ $chart_title = I18N::translate('Families with sources');
- return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&chs={$size}&amp;chco={$color_from},{$color_to}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
- }
- }
+ return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&chs={$size}&amp;chco={$color_from},{$color_to}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
+ }
+ }
- /**
- * Show the total families as a percentage.
- *
- * @return string
- */
- public function totalFamiliesPercentage() {
- return $this->getPercentage($this->totalFamiliesQuery(), 'all');
- }
+ /**
+ * Show the total families as a percentage.
+ *
+ * @return string
+ */
+ public function totalFamiliesPercentage()
+ {
+ return $this->getPercentage($this->totalFamiliesQuery(), 'all');
+ }
- /**
- * Count the total number of sources.
- *
- * @return int
- */
- private function totalSourcesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##sources` WHERE s_file = :tree_id"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the total number of sources.
+ *
+ * @return int
+ */
+ private function totalSourcesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##sources` WHERE s_file = :tree_id"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the total number of sources.
- *
- * @return string
- */
- public function totalSources() {
- return I18N::number($this->totalSourcesQuery());
- }
+ /**
+ * Count the total number of sources.
+ *
+ * @return string
+ */
+ public function totalSources()
+ {
+ return I18N::number($this->totalSourcesQuery());
+ }
- /**
- * Show the number of sources as a percentage.
- *
- * @return string
- */
- public function totalSourcesPercentage() {
- return $this->getPercentage($this->totalSourcesQuery(), 'all');
- }
+ /**
+ * Show the number of sources as a percentage.
+ *
+ * @return string
+ */
+ public function totalSourcesPercentage()
+ {
+ return $this->getPercentage($this->totalSourcesQuery(), 'all');
+ }
- /**
- * Count the number of notes.
- *
- * @return int
- */
- private function totalNotesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##other` WHERE o_type='NOTE' AND o_file = :tree_id"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of notes.
+ *
+ * @return int
+ */
+ private function totalNotesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##other` WHERE o_type='NOTE' AND o_file = :tree_id"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of notes.
- *
- * @return string
- */
- public function totalNotes() {
- return I18N::number($this->totalNotesQuery());
- }
+ /**
+ * Count the number of notes.
+ *
+ * @return string
+ */
+ public function totalNotes()
+ {
+ return I18N::number($this->totalNotesQuery());
+ }
- /**
- * Show the number of notes as a percentage.
- *
- * @return string
- */
- public function totalNotesPercentage() {
- return $this->getPercentage($this->totalNotesQuery(), 'all');
- }
+ /**
+ * Show the number of notes as a percentage.
+ *
+ * @return string
+ */
+ public function totalNotesPercentage()
+ {
+ return $this->getPercentage($this->totalNotesQuery(), 'all');
+ }
- /**
- * Count the number of repositories.
- *
- * @return int
- */
- private function totalRepositoriesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##other` WHERE o_type='REPO' AND o_file = :tree_id"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of repositories.
+ *
+ * @return int
+ */
+ private function totalRepositoriesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##other` WHERE o_type='REPO' AND o_file = :tree_id"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of repositories
- *
- * @return string
- */
- public function totalRepositories() {
- return I18N::number($this->totalRepositoriesQuery());
- }
+ /**
+ * Count the number of repositories
+ *
+ * @return string
+ */
+ public function totalRepositories()
+ {
+ return I18N::number($this->totalRepositoriesQuery());
+ }
- /**
- * Show the total number of repositories as a percentage.
- *
- * @return string
- */
- public function totalRepositoriesPercentage() {
- return $this->getPercentage($this->totalRepositoriesQuery(), 'all');
- }
+ /**
+ * Show the total number of repositories as a percentage.
+ *
+ * @return string
+ */
+ public function totalRepositoriesPercentage()
+ {
+ return $this->getPercentage($this->totalRepositoriesQuery(), 'all');
+ }
- /**
- * Count the surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function totalSurnames($params = []) {
- if ($params) {
- $opt = 'IN (' . implode(',', array_fill(0, count($params), '?')) . ')';
- $distinct = '';
- } else {
- $opt = "IS NOT NULL";
- $distinct = 'DISTINCT';
- }
- $params[] = $this->tree->getTreeId();
- $total =
- Database::prepare(
- "SELECT COUNT({$distinct} n_surn COLLATE '" . I18N::collation() . "')" .
- " FROM `##name`" .
- " WHERE n_surn COLLATE '" . I18N::collation() . "' {$opt} AND n_file=?"
- )->execute(
- $params
- )->fetchOne();
+ /**
+ * Count the surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function totalSurnames($params = [])
+ {
+ if ($params) {
+ $opt = 'IN (' . implode(',', array_fill(0, count($params), '?')) . ')';
+ $distinct = '';
+ } else {
+ $opt = "IS NOT NULL";
+ $distinct = 'DISTINCT';
+ }
+ $params[] = $this->tree->getTreeId();
+ $total =
+ Database::prepare(
+ "SELECT COUNT({$distinct} n_surn COLLATE '" . I18N::collation() . "')" .
+ " FROM `##name`" .
+ " WHERE n_surn COLLATE '" . I18N::collation() . "' {$opt} AND n_file=?"
+ )->execute(
+ $params
+ )->fetchOne();
- return I18N::number($total);
- }
+ return I18N::number($total);
+ }
- /**
- * Count the number of distinct given names, or count the number of
- * occurrences of a specific name or names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function totalGivennames($params = []) {
- if ($params) {
- $qs = implode(',', array_fill(0, count($params), '?'));
- $params[] = $this->tree->getTreeId();
- $total =
- Database::prepare("SELECT COUNT( n_givn) FROM `##name` WHERE n_givn IN ({$qs}) AND n_file=?")
- ->execute($params)
- ->fetchOne();
- } else {
- $total =
- Database::prepare("SELECT COUNT(DISTINCT n_givn) FROM `##name` WHERE n_givn IS NOT NULL AND n_file=?")
- ->execute([$this->tree->getTreeId()])
- ->fetchOne();
- }
+ /**
+ * Count the number of distinct given names, or count the number of
+ * occurrences of a specific name or names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function totalGivennames($params = [])
+ {
+ if ($params) {
+ $qs = implode(',', array_fill(0, count($params), '?'));
+ $params[] = $this->tree->getTreeId();
+ $total =
+ Database::prepare("SELECT COUNT( n_givn) FROM `##name` WHERE n_givn IN ({$qs}) AND n_file=?")
+ ->execute($params)
+ ->fetchOne();
+ } else {
+ $total =
+ Database::prepare("SELECT COUNT(DISTINCT n_givn) FROM `##name` WHERE n_givn IS NOT NULL AND n_file=?")
+ ->execute([$this->tree->getTreeId()])
+ ->fetchOne();
+ }
- return I18N::number($total);
- }
+ return I18N::number($total);
+ }
- /**
- * Count the number of events (with dates).
- *
- * @param string[] $params
- *
- * @return string
- */
- public function totalEvents($params = []) {
- $sql = "SELECT COUNT(*) AS tot FROM `##dates` WHERE d_file=?";
- $vars = [$this->tree->getTreeId()];
+ /**
+ * Count the number of events (with dates).
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function totalEvents($params = [])
+ {
+ $sql = "SELECT COUNT(*) AS tot FROM `##dates` WHERE d_file=?";
+ $vars = [$this->tree->getTreeId()];
- $no_types = ['HEAD', 'CHAN'];
- if ($params) {
- $types = [];
- foreach ($params as $type) {
- if (substr($type, 0, 1) == '!') {
- $no_types[] = substr($type, 1);
- } else {
- $types[] = $type;
- }
- }
- if ($types) {
- $sql .= ' AND d_fact IN (' . implode(', ', array_fill(0, count($types), '?')) . ')';
- $vars = array_merge($vars, $types);
- }
- }
- $sql .= ' AND d_fact NOT IN (' . implode(', ', array_fill(0, count($no_types), '?')) . ')';
- $vars = array_merge($vars, $no_types);
+ $no_types = [
+ 'HEAD',
+ 'CHAN',
+ ];
+ if ($params) {
+ $types = [];
+ foreach ($params as $type) {
+ if (substr($type, 0, 1) == '!') {
+ $no_types[] = substr($type, 1);
+ } else {
+ $types[] = $type;
+ }
+ }
+ if ($types) {
+ $sql .= ' AND d_fact IN (' . implode(', ', array_fill(0, count($types), '?')) . ')';
+ $vars = array_merge($vars, $types);
+ }
+ }
+ $sql .= ' AND d_fact NOT IN (' . implode(', ', array_fill(0, count($no_types), '?')) . ')';
+ $vars = array_merge($vars, $no_types);
- return I18N::number(Database::prepare($sql)->execute($vars)->fetchOne());
- }
+ return I18N::number(Database::prepare($sql)->execute($vars)->fetchOne());
+ }
- /**
- * Count the number of births.
- *
- * @return string
- */
- public function totalEventsBirth() {
- return $this->totalEvents(explode('|', WT_EVENTS_BIRT));
- }
+ /**
+ * Count the number of births.
+ *
+ * @return string
+ */
+ public function totalEventsBirth()
+ {
+ return $this->totalEvents(explode('|', WT_EVENTS_BIRT));
+ }
- /**
- * Count the number of births.
- *
- * @return string
- */
- public function totalBirths() {
- return $this->totalEvents(['BIRT']);
- }
+ /**
+ * Count the number of births.
+ *
+ * @return string
+ */
+ public function totalBirths()
+ {
+ return $this->totalEvents(['BIRT']);
+ }
- /**
- * Count the number of deaths.
- *
- * @return string
- */
- public function totalEventsDeath() {
- return $this->totalEvents(explode('|', WT_EVENTS_DEAT));
- }
+ /**
+ * Count the number of deaths.
+ *
+ * @return string
+ */
+ public function totalEventsDeath()
+ {
+ return $this->totalEvents(explode('|', WT_EVENTS_DEAT));
+ }
- /**
- * Count the number of deaths.
- *
- * @return string
- */
- public function totalDeaths() {
- return $this->totalEvents(['DEAT']);
- }
+ /**
+ * Count the number of deaths.
+ *
+ * @return string
+ */
+ public function totalDeaths()
+ {
+ return $this->totalEvents(['DEAT']);
+ }
- /**
- * Count the number of marriages.
- *
- * @return string
- */
- public function totalEventsMarriage() {
- return $this->totalEvents(explode('|', WT_EVENTS_MARR));
- }
+ /**
+ * Count the number of marriages.
+ *
+ * @return string
+ */
+ public function totalEventsMarriage()
+ {
+ return $this->totalEvents(explode('|', WT_EVENTS_MARR));
+ }
- /**
- * Count the number of marriages.
- *
- * @return string
- */
- public function totalMarriages() {
- return $this->totalEvents(['MARR']);
- }
+ /**
+ * Count the number of marriages.
+ *
+ * @return string
+ */
+ public function totalMarriages()
+ {
+ return $this->totalEvents(['MARR']);
+ }
- /**
- * Count the number of divorces.
- *
- * @return string
- */
- public function totalEventsDivorce() {
- return $this->totalEvents(explode('|', WT_EVENTS_DIV));
- }
+ /**
+ * Count the number of divorces.
+ *
+ * @return string
+ */
+ public function totalEventsDivorce()
+ {
+ return $this->totalEvents(explode('|', WT_EVENTS_DIV));
+ }
- /**
- * Count the number of divorces.
- *
- * @return string
- */
- public function totalDivorces() {
- return $this->totalEvents(['DIV']);
- }
+ /**
+ * Count the number of divorces.
+ *
+ * @return string
+ */
+ public function totalDivorces()
+ {
+ return $this->totalEvents(['DIV']);
+ }
- /**
- * Count the number of other events.
- *
- * @return string
- */
- public function totalEventsOther() {
- $facts = array_merge(explode('|', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT));
- $no_facts = [];
- foreach ($facts as $fact) {
- $fact = '!' . str_replace('\'', '', $fact);
- $no_facts[] = $fact;
- }
+ /**
+ * Count the number of other events.
+ *
+ * @return string
+ */
+ public function totalEventsOther()
+ {
+ $facts = array_merge(explode('|', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT));
+ $no_facts = [];
+ foreach ($facts as $fact) {
+ $fact = '!' . str_replace('\'', '', $fact);
+ $no_facts[] = $fact;
+ }
- return $this->totalEvents($no_facts);
- }
+ return $this->totalEvents($no_facts);
+ }
- /**
- * Count the number of males.
- *
- * @return int
- */
- private function totalSexMalesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'M'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of males.
+ *
+ * @return int
+ */
+ private function totalSexMalesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'M'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of males.
- *
- * @return string
- */
- public function totalSexMales() {
- return I18N::number($this->totalSexMalesQuery());
- }
+ /**
+ * Count the number of males.
+ *
+ * @return string
+ */
+ public function totalSexMales()
+ {
+ return I18N::number($this->totalSexMalesQuery());
+ }
- /**
- * Count the number of males
- *
- * @return string
- */
- public function totalSexMalesPercentage() {
- return $this->getPercentage($this->totalSexMalesQuery(), 'individual');
- }
+ /**
+ * Count the number of males
+ *
+ * @return string
+ */
+ public function totalSexMalesPercentage()
+ {
+ return $this->getPercentage($this->totalSexMalesQuery(), 'individual');
+ }
- /**
- * Count the number of females.
- *
- * @return int
- */
- private function totalSexFemalesQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'F'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of females.
+ *
+ * @return int
+ */
+ private function totalSexFemalesQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'F'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of females.
- *
- * @return string
- */
- public function totalSexFemales() {
- return I18N::number($this->totalSexFemalesQuery());
- }
+ /**
+ * Count the number of females.
+ *
+ * @return string
+ */
+ public function totalSexFemales()
+ {
+ return I18N::number($this->totalSexFemalesQuery());
+ }
- /**
- * Count the number of females.
- *
- * @return string
- */
- public function totalSexFemalesPercentage() {
- return $this->getPercentage($this->totalSexFemalesQuery(), 'individual');
- }
+ /**
+ * Count the number of females.
+ *
+ * @return string
+ */
+ public function totalSexFemalesPercentage()
+ {
+ return $this->getPercentage($this->totalSexFemalesQuery(), 'individual');
+ }
- /**
- * Count the number of individuals with unknown sex.
- *
- * @return int
- */
- private function totalSexUnknownQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'U'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of individuals with unknown sex.
+ *
+ * @return int
+ */
+ private function totalSexUnknownQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_sex = 'U'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of individuals with unknown sex.
- *
- * @return string
- */
- public function totalSexUnknown() {
- return I18N::number($this->totalSexUnknownQuery());
- }
+ /**
+ * Count the number of individuals with unknown sex.
+ *
+ * @return string
+ */
+ public function totalSexUnknown()
+ {
+ return I18N::number($this->totalSexUnknownQuery());
+ }
- /**
- * Count the number of individuals with unknown sex.
- *
- * @return string
- */
- public function totalSexUnknownPercentage() {
- return $this->getPercentage($this->totalSexUnknownQuery(), 'individual');
- }
+ /**
+ * Count the number of individuals with unknown sex.
+ *
+ * @return string
+ */
+ public function totalSexUnknownPercentage()
+ {
+ return $this->getPercentage($this->totalSexUnknownQuery(), 'individual');
+ }
- /**
- * Generate a chart showing sex distribution.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartSex($params = []) {
- $WT_STATS_S_CHART_X = Theme::theme()->parameter('stats-small-chart-x');
- $WT_STATS_S_CHART_Y = Theme::theme()->parameter('stats-small-chart-y');
+ /**
+ * Generate a chart showing sex distribution.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartSex($params = [])
+ {
+ $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_female = strtolower($params[1]);
- } else {
- $color_female = 'ffd1dc';
- }
- if (isset($params[2]) && $params[2] != '') {
- $color_male = strtolower($params[2]);
- } else {
- $color_male = '84beff';
- }
- if (isset($params[3]) && $params[3] != '') {
- $color_unknown = strtolower($params[3]);
- } else {
- $color_unknown = '777777';
- }
- $sizes = explode('x', $size);
- // Raw data - for calculation
- $tot_f = $this->totalSexFemalesQuery();
- $tot_m = $this->totalSexMalesQuery();
- $tot_u = $this->totalSexUnknownQuery();
- $tot = $tot_f + $tot_m + $tot_u;
- // I18N data - for display
- $per_f = $this->totalSexFemalesPercentage();
- $per_m = $this->totalSexMalesPercentage();
- $per_u = $this->totalSexUnknownPercentage();
- if ($tot == 0) {
- return '';
- } elseif ($tot_u > 0) {
- $chd = $this->arrayToExtendedEncoding([4095 * $tot_u / $tot, 4095 * $tot_f / $tot, 4095 * $tot_m / $tot]);
- $chl =
- I18N::translateContext('unknown people', 'Unknown') . ' - ' . $per_u . '|' .
- I18N::translate('Females') . ' - ' . $per_f . '|' .
- I18N::translate('Males') . ' - ' . $per_m;
- $chart_title =
- I18N::translate('Males') . ' - ' . $per_m . I18N::$list_separator .
- I18N::translate('Females') . ' - ' . $per_f . I18N::$list_separator .
- I18N::translateContext('unknown people', 'Unknown') . ' - ' . $per_u;
+ 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_female = strtolower($params[1]);
+ } else {
+ $color_female = 'ffd1dc';
+ }
+ if (isset($params[2]) && $params[2] != '') {
+ $color_male = strtolower($params[2]);
+ } else {
+ $color_male = '84beff';
+ }
+ if (isset($params[3]) && $params[3] != '') {
+ $color_unknown = strtolower($params[3]);
+ } else {
+ $color_unknown = '777777';
+ }
+ $sizes = explode('x', $size);
+ // Raw data - for calculation
+ $tot_f = $this->totalSexFemalesQuery();
+ $tot_m = $this->totalSexMalesQuery();
+ $tot_u = $this->totalSexUnknownQuery();
+ $tot = $tot_f + $tot_m + $tot_u;
+ // I18N data - for display
+ $per_f = $this->totalSexFemalesPercentage();
+ $per_m = $this->totalSexMalesPercentage();
+ $per_u = $this->totalSexUnknownPercentage();
+ if ($tot == 0) {
+ return '';
+ } elseif ($tot_u > 0) {
+ $chd = $this->arrayToExtendedEncoding([
+ 4095 * $tot_u / $tot,
+ 4095 * $tot_f / $tot,
+ 4095 * $tot_m / $tot,
+ ]);
+ $chl =
+ I18N::translateContext('unknown people', 'Unknown') . ' - ' . $per_u . '|' .
+ I18N::translate('Females') . ' - ' . $per_f . '|' .
+ I18N::translate('Males') . ' - ' . $per_m;
+ $chart_title =
+ I18N::translate('Males') . ' - ' . $per_m . I18N::$list_separator .
+ I18N::translate('Females') . ' - ' . $per_f . I18N::$list_separator .
+ I18N::translateContext('unknown people', 'Unknown') . ' - ' . $per_u;
- return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_unknown},{$color_female},{$color_male}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
- } else {
- $chd = $this->arrayToExtendedEncoding([4095 * $tot_f / $tot, 4095 * $tot_m / $tot]);
- $chl =
- I18N::translate('Females') . ' - ' . $per_f . '|' .
- I18N::translate('Males') . ' - ' . $per_m;
- $chart_title = I18N::translate('Males') . ' - ' . $per_m . I18N::$list_separator .
- I18N::translate('Females') . ' - ' . $per_f;
+ return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_unknown},{$color_female},{$color_male}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
+ } else {
+ $chd = $this->arrayToExtendedEncoding([
+ 4095 * $tot_f / $tot,
+ 4095 * $tot_m / $tot,
+ ]);
+ $chl =
+ I18N::translate('Females') . ' - ' . $per_f . '|' .
+ I18N::translate('Males') . ' - ' . $per_m;
+ $chart_title = I18N::translate('Males') . ' - ' . $per_m . I18N::$list_separator .
+ I18N::translate('Females') . ' - ' . $per_f;
- return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_female},{$color_male}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
- }
- }
+ return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_female},{$color_male}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
+ }
+ }
- /**
- * Count the number of living individuals.
- *
- * The totalLiving/totalDeceased queries assume that every dead person will
- * have a DEAT record. It will not include individuals who were born more
- * than MAX_ALIVE_AGE years ago, and who have no DEAT record.
- * A good reason to run the “Add missing DEAT records” batch-update!
- *
- * @return int
- */
- private function totalLivingQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom NOT REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of living individuals.
+ *
+ * The totalLiving/totalDeceased queries assume that every dead person will
+ * have a DEAT record. It will not include individuals who were born more
+ * than MAX_ALIVE_AGE years ago, and who have no DEAT record.
+ * A good reason to run the “Add missing DEAT records” batch-update!
+ *
+ * @return int
+ */
+ private function totalLivingQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom NOT REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of living individuals.
- *
- * @return string
- */
- public function totalLiving() {
- return I18N::number($this->totalLivingQuery());
- }
+ /**
+ * Count the number of living individuals.
+ *
+ * @return string
+ */
+ public function totalLiving()
+ {
+ return I18N::number($this->totalLivingQuery());
+ }
- /**
- * Count the number of living individuals.
- *
- * @return string
- */
- public function totalLivingPercentage() {
- return $this->getPercentage($this->totalLivingQuery(), 'individual');
- }
+ /**
+ * Count the number of living individuals.
+ *
+ * @return string
+ */
+ public function totalLivingPercentage()
+ {
+ return $this->getPercentage($this->totalLivingQuery(), 'individual');
+ }
- /**
- * Count the number of dead individuals.
- *
- * @return int
- */
- private function totalDeceasedQuery() {
- return (int) Database::prepare(
- "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchOne();
- }
+ /**
+ * Count the number of dead individuals.
+ *
+ * @return int
+ */
+ private function totalDeceasedQuery()
+ {
+ return (int)Database::prepare(
+ "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchOne();
+ }
- /**
- * Count the number of dead individuals.
- *
- * @return string
- */
- public function totalDeceased() {
- return I18N::number($this->totalDeceasedQuery());
- }
+ /**
+ * Count the number of dead individuals.
+ *
+ * @return string
+ */
+ public function totalDeceased()
+ {
+ return I18N::number($this->totalDeceasedQuery());
+ }
- /**
- * Count the number of dead individuals.
- *
- * @return string
- */
- public function totalDeceasedPercentage() {
- return $this->getPercentage($this->totalDeceasedQuery(), 'individual');
- }
+ /**
+ * Count the number of dead individuals.
+ *
+ * @return string
+ */
+ public function totalDeceasedPercentage()
+ {
+ return $this->getPercentage($this->totalDeceasedQuery(), 'individual');
+ }
- /**
- * Create a chart showing mortality.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartMortality($params = []) {
- $WT_STATS_S_CHART_X = Theme::theme()->parameter('stats-small-chart-x');
- $WT_STATS_S_CHART_Y = Theme::theme()->parameter('stats-small-chart-y');
+ /**
+ * Create a chart showing mortality.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartMortality($params = [])
+ {
+ $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_living = strtolower($params[1]);
- } else {
- $color_living = 'ffffff';
- }
- if (isset($params[2]) && $params[2] != '') {
- $color_dead = strtolower($params[2]);
- } else {
- $color_dead = 'cccccc';
- }
- $sizes = explode('x', $size);
- // Raw data - for calculation
- $tot_l = $this->totalLivingQuery();
- $tot_d = $this->totalDeceasedQuery();
- $tot = $tot_l + $tot_d;
- // I18N data - for display
- $per_l = $this->totalLivingPercentage();
- $per_d = $this->totalDeceasedPercentage();
- if ($tot == 0) {
- return '';
- } else {
- $chd = $this->arrayToExtendedEncoding([4095 * $tot_l / $tot, 4095 * $tot_d / $tot]);
- $chl =
- I18N::translate('Living') . ' - ' . $per_l . '|' .
- I18N::translate('Dead') . ' - ' . $per_d . '|';
- $chart_title = I18N::translate('Living') . ' - ' . $per_l . I18N::$list_separator .
- I18N::translate('Dead') . ' - ' . $per_d;
+ 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_living = strtolower($params[1]);
+ } else {
+ $color_living = 'ffffff';
+ }
+ if (isset($params[2]) && $params[2] != '') {
+ $color_dead = strtolower($params[2]);
+ } else {
+ $color_dead = 'cccccc';
+ }
+ $sizes = explode('x', $size);
+ // Raw data - for calculation
+ $tot_l = $this->totalLivingQuery();
+ $tot_d = $this->totalDeceasedQuery();
+ $tot = $tot_l + $tot_d;
+ // I18N data - for display
+ $per_l = $this->totalLivingPercentage();
+ $per_d = $this->totalDeceasedPercentage();
+ if ($tot == 0) {
+ return '';
+ } else {
+ $chd = $this->arrayToExtendedEncoding([
+ 4095 * $tot_l / $tot,
+ 4095 * $tot_d / $tot,
+ ]);
+ $chl =
+ I18N::translate('Living') . ' - ' . $per_l . '|' .
+ I18N::translate('Dead') . ' - ' . $per_d . '|';
+ $chart_title = I18N::translate('Living') . ' - ' . $per_l . I18N::$list_separator .
+ I18N::translate('Dead') . ' - ' . $per_d;
- return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_living},{$color_dead}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
- }
- }
+ return "<img src=\"https://chart.googleapis.com/chart?cht=p3&amp;chd=e:{$chd}&amp;chs={$size}&amp;chco={$color_living},{$color_dead}&amp;chf=bg,s,ffffff00&amp;chl={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
+ }
+ }
- /**
- * Count the number of users.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function totalUsers($params = []) {
- if (isset($params[0])) {
- $total = count(User::all()) + (int) $params[0];
- } else {
- $total = count(User::all());
- }
+ /**
+ * Count the number of users.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function totalUsers($params = [])
+ {
+ if (isset($params[0])) {
+ $total = count(User::all()) + (int)$params[0];
+ } else {
+ $total = count(User::all());
+ }
- return I18N::number($total);
- }
+ return I18N::number($total);
+ }
- /**
- * Count the number of administrators.
- *
- * @return string
- */
- public function totalAdmins() {
- return I18N::number(count(User::administrators()));
- }
+ /**
+ * Count the number of administrators.
+ *
+ * @return string
+ */
+ public function totalAdmins()
+ {
+ return I18N::number(count(User::administrators()));
+ }
- /**
- * Count the number of administrators.
- *
- * @return string
- */
- public function totalNonAdmins() {
- return I18N::number(count(User::all()) - count(User::administrators()));
- }
+ /**
+ * Count the number of administrators.
+ *
+ * @return string
+ */
+ public function totalNonAdmins()
+ {
+ return I18N::number(count(User::all()) - count(User::administrators()));
+ }
- /**
- * Count the number of media records with a given type.
- *
- * @param string $type
- *
- * @return int
- */
- private function totalMediaType($type = 'all') {
- if (!in_array($type, $this->_media_types) && $type != 'all' && $type != 'unknown') {
- return 0;
- }
- $sql = "SELECT COUNT(*) AS tot FROM `##media` WHERE m_file=?";
- $vars = [$this->tree->getTreeId()];
+ /**
+ * Count the number of media records with a given type.
+ *
+ * @param string $type
+ *
+ * @return int
+ */
+ private function totalMediaType($type = 'all')
+ {
+ if (!in_array($type, $this->_media_types) && $type != 'all' && $type != 'unknown') {
+ return 0;
+ }
+ $sql = "SELECT COUNT(*) AS tot FROM `##media` WHERE m_file=?";
+ $vars = [$this->tree->getTreeId()];
- if ($type != 'all') {
- if ($type == 'unknown') {
- // There has to be a better way then this :(
- foreach ($this->_media_types as $t) {
- $sql .= " AND (m_gedcom NOT LIKE ? AND m_gedcom NOT LIKE ?)";
- $vars[] = "%3 TYPE {$t}%";
- $vars[] = "%1 _TYPE {$t}%";
- }
- } else {
- $sql .= " AND (m_gedcom LIKE ? OR m_gedcom LIKE ?)";
- $vars[] = "%3 TYPE {$type}%";
- $vars[] = "%1 _TYPE {$type}%";
- }
- }
+ if ($type != 'all') {
+ if ($type == 'unknown') {
+ // There has to be a better way then this :(
+ foreach ($this->_media_types as $t) {
+ $sql .= " AND (m_gedcom NOT LIKE ? AND m_gedcom NOT LIKE ?)";
+ $vars[] = "%3 TYPE {$t}%";
+ $vars[] = "%1 _TYPE {$t}%";
+ }
+ } else {
+ $sql .= " AND (m_gedcom LIKE ? OR m_gedcom LIKE ?)";
+ $vars[] = "%3 TYPE {$type}%";
+ $vars[] = "%1 _TYPE {$type}%";
+ }
+ }
- return (int) Database::prepare($sql)->execute($vars)->fetchOne();
- }
+ return (int)Database::prepare($sql)->execute($vars)->fetchOne();
+ }
- /**
- * Count the number of media records.
- *
- * @return string
- */
- public function totalMedia() {
- return I18N::number($this->totalMediaType('all'));
- }
+ /**
+ * Count the number of media records.
+ *
+ * @return string
+ */
+ public function totalMedia()
+ {
+ return I18N::number($this->totalMediaType('all'));
+ }
- /**
- * Count the number of media records with type "audio".
- *
- * @return string
- */
- public function totalMediaAudio() {
- return I18N::number($this->totalMediaType('audio'));
- }
+ /**
+ * Count the number of media records with type "audio".
+ *
+ * @return string
+ */
+ public function totalMediaAudio()
+ {
+ return I18N::number($this->totalMediaType('audio'));
+ }
- /**
- * Count the number of media records with type "book".
- *
- * @return string
- */
- public function totalMediaBook() {
- return I18N::number($this->totalMediaType('book'));
- }
+ /**
+ * Count the number of media records with type "book".
+ *
+ * @return string
+ */
+ public function totalMediaBook()
+ {
+ return I18N::number($this->totalMediaType('book'));
+ }
- /**
- * Count the number of media records with type "card".
- *
- * @return string
- */
- public function totalMediaCard() {
- return I18N::number($this->totalMediaType('card'));
- }
+ /**
+ * Count the number of media records with type "card".
+ *
+ * @return string
+ */
+ public function totalMediaCard()
+ {
+ return I18N::number($this->totalMediaType('card'));
+ }
- /**
- * Count the number of media records with type "certificate".
- *
- * @return string
- */
- public function totalMediaCertificate() {
- return I18N::number($this->totalMediaType('certificate'));
- }
+ /**
+ * Count the number of media records with type "certificate".
+ *
+ * @return string
+ */
+ public function totalMediaCertificate()
+ {
+ return I18N::number($this->totalMediaType('certificate'));
+ }
- /**
- * Count the number of media records with type "coat of arms".
- *
- * @return string
- */
- public function totalMediaCoatOfArms() {
- return I18N::number($this->totalMediaType('coat'));
- }
+ /**
+ * Count the number of media records with type "coat of arms".
+ *
+ * @return string
+ */
+ public function totalMediaCoatOfArms()
+ {
+ return I18N::number($this->totalMediaType('coat'));
+ }
- /**
- * Count the number of media records with type "document".
- *
- * @return string
- */
- public function totalMediaDocument() {
- return I18N::number($this->totalMediaType('document'));
- }
+ /**
+ * Count the number of media records with type "document".
+ *
+ * @return string
+ */
+ public function totalMediaDocument()
+ {
+ return I18N::number($this->totalMediaType('document'));
+ }
- /**
- * Count the number of media records with type "electronic".
- *
- * @return string
- */
- public function totalMediaElectronic() {
- return I18N::number($this->totalMediaType('electronic'));
- }
+ /**
+ * Count the number of media records with type "electronic".
+ *
+ * @return string
+ */
+ public function totalMediaElectronic()
+ {
+ return I18N::number($this->totalMediaType('electronic'));
+ }
- /**
- * Count the number of media records with type "magazine".
- *
- * @return string
- */
- public function totalMediaMagazine() {
- return I18N::number($this->totalMediaType('magazine'));
- }
+ /**
+ * Count the number of media records with type "magazine".
+ *
+ * @return string
+ */
+ public function totalMediaMagazine()
+ {
+ return I18N::number($this->totalMediaType('magazine'));
+ }
- /**
- * Count the number of media records with type "manuscript".
- *
- * @return string
- */
- public function totalMediaManuscript() {
- return I18N::number($this->totalMediaType('manuscript'));
- }
+ /**
+ * Count the number of media records with type "manuscript".
+ *
+ * @return string
+ */
+ public function totalMediaManuscript()
+ {
+ return I18N::number($this->totalMediaType('manuscript'));
+ }
- /**
- * Count the number of media records with type "map".
- *
- * @return string
- */
- public function totalMediaMap() {
- return I18N::number($this->totalMediaType('map'));
- }
+ /**
+ * Count the number of media records with type "map".
+ *
+ * @return string
+ */
+ public function totalMediaMap()
+ {
+ return I18N::number($this->totalMediaType('map'));
+ }
- /**
- * Count the number of media records with type "microfiche".
- *
- * @return string
- */
- public function totalMediaFiche() {
- return I18N::number($this->totalMediaType('fiche'));
- }
+ /**
+ * Count the number of media records with type "microfiche".
+ *
+ * @return string
+ */
+ public function totalMediaFiche()
+ {
+ return I18N::number($this->totalMediaType('fiche'));
+ }
- /**
- * Count the number of media records with type "microfilm".
- *
- * @return string
- */
- public function totalMediaFilm() {
- return I18N::number($this->totalMediaType('film'));
- }
+ /**
+ * Count the number of media records with type "microfilm".
+ *
+ * @return string
+ */
+ public function totalMediaFilm()
+ {
+ return I18N::number($this->totalMediaType('film'));
+ }
- /**
- * Count the number of media records with type "newspaper".
- *
- * @return string
- */
- public function totalMediaNewspaper() {
- return I18N::number($this->totalMediaType('newspaper'));
- }
+ /**
+ * Count the number of media records with type "newspaper".
+ *
+ * @return string
+ */
+ public function totalMediaNewspaper()
+ {
+ return I18N::number($this->totalMediaType('newspaper'));
+ }
- /**
- * Count the number of media records with type "painting".
- *
- * @return string
- */
- public function totalMediaPainting() {
- return I18N::number($this->totalMediaType('painting'));
- }
+ /**
+ * Count the number of media records with type "painting".
+ *
+ * @return string
+ */
+ public function totalMediaPainting()
+ {
+ return I18N::number($this->totalMediaType('painting'));
+ }
- /**
- * Count the number of media records with type "photograph".
- *
- * @return string
- */
- public function totalMediaPhoto() {
- return I18N::number($this->totalMediaType('photo'));
- }
+ /**
+ * Count the number of media records with type "photograph".
+ *
+ * @return string
+ */
+ public function totalMediaPhoto()
+ {
+ return I18N::number($this->totalMediaType('photo'));
+ }
- /**
- * Count the number of media records with type "tombstone".
- *
- * @return string
- */
- public function totalMediaTombstone() {
- return I18N::number($this->totalMediaType('tombstone'));
- }
+ /**
+ * Count the number of media records with type "tombstone".
+ *
+ * @return string
+ */
+ public function totalMediaTombstone()
+ {
+ return I18N::number($this->totalMediaType('tombstone'));
+ }
- /**
- * Count the number of media records with type "video".
- *
- * @return string
- */
- public function totalMediaVideo() {
- return I18N::number($this->totalMediaType('video'));
- }
+ /**
+ * Count the number of media records with type "video".
+ *
+ * @return string
+ */
+ public function totalMediaVideo()
+ {
+ return I18N::number($this->totalMediaType('video'));
+ }
- /**
- * Count the number of media records with type "other".
- *
- * @return string
- */
- public function totalMediaOther() {
- return I18N::number($this->totalMediaType('other'));
- }
+ /**
+ * Count the number of media records with type "other".
+ *
+ * @return string
+ */
+ public function totalMediaOther()
+ {
+ return I18N::number($this->totalMediaType('other'));
+ }
- /**
- * Count the number of media records with type "unknown".
- *
- * @return string
- */
- public function totalMediaUnknown() {
- return I18N::number($this->totalMediaType('unknown'));
- }
+ /**
+ * Count the number of media records with type "unknown".
+ *
+ * @return string
+ */
+ public function totalMediaUnknown()
+ {
+ return I18N::number($this->totalMediaType('unknown'));
+ }
- /**
- * Create a chart of media types.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartMedia($params = []) {
- $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');
+ /**
+ * Create a chart of media types.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartMedia($params = [])
+ {
+ $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;
- }
- $sizes = explode('x', $size);
- $tot = $this->totalMediaType('all');
- // Beware divide by zero
- if ($tot == 0) {
- return I18N::translate('None');
- }
- // Build a table listing only the media types actually present in the GEDCOM
- $mediaCounts = [];
- $mediaTypes = '';
- $chart_title = '';
- $c = 0;
- $max = 0;
- $media = [];
- foreach ($this->_media_types as $type) {
- $count = $this->totalMediaType($type);
- if ($count > 0) {
- $media[$type] = $count;
- if ($count > $max) {
- $max = $count;
- }
- $c += $count;
- }
- }
- $count = $this->totalMediaType('unknown');
- if ($count > 0) {
- $media['unknown'] = $tot - $c;
- if ($tot - $c > $max) {
- $max = $count;
- }
- }
- if (($max / $tot) > 0.6 && count($media) > 10) {
- arsort($media);
- $media = array_slice($media, 0, 10);
- $c = $tot;
- foreach ($media as $cm) {
- $c -= $cm;
- }
- if (isset($media['other'])) {
- $media['other'] += $c;
- } else {
- $media['other'] = $c;
- }
- }
- asort($media);
- foreach ($media as $type => $count) {
- $mediaCounts[] = round(100 * $count / $tot, 0);
- $mediaTypes .= GedcomTag::getFileFormTypeValue($type) . ' - ' . I18N::number($count) . '|';
- $chart_title .= GedcomTag::getFileFormTypeValue($type) . ' (' . $count . '), ';
- }
- $chart_title = substr($chart_title, 0, -2);
- $chd = $this->arrayToExtendedEncoding($mediaCounts);
- $chl = substr($mediaTypes, 0, -1);
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = $this->totalMediaType('all');
+ // Beware divide by zero
+ if ($tot == 0) {
+ return I18N::translate('None');
+ }
+ // Build a table listing only the media types actually present in the GEDCOM
+ $mediaCounts = [];
+ $mediaTypes = '';
+ $chart_title = '';
+ $c = 0;
+ $max = 0;
+ $media = [];
+ foreach ($this->_media_types as $type) {
+ $count = $this->totalMediaType($type);
+ if ($count > 0) {
+ $media[$type] = $count;
+ if ($count > $max) {
+ $max = $count;
+ }
+ $c += $count;
+ }
+ }
+ $count = $this->totalMediaType('unknown');
+ if ($count > 0) {
+ $media['unknown'] = $tot - $c;
+ if ($tot - $c > $max) {
+ $max = $count;
+ }
+ }
+ if (($max / $tot) > 0.6 && count($media) > 10) {
+ arsort($media);
+ $media = array_slice($media, 0, 10);
+ $c = $tot;
+ foreach ($media as $cm) {
+ $c -= $cm;
+ }
+ if (isset($media['other'])) {
+ $media['other'] += $c;
+ } else {
+ $media['other'] = $c;
+ }
+ }
+ asort($media);
+ foreach ($media as $type => $count) {
+ $mediaCounts[] = round(100 * $count / $tot, 0);
+ $mediaTypes .= GedcomTag::getFileFormTypeValue($type) . ' - ' . I18N::number($count) . '|';
+ $chart_title .= GedcomTag::getFileFormTypeValue($type) . ' (' . $count . '), ';
+ }
+ $chart_title = substr($chart_title, 0, -2);
+ $chd = $this->arrayToExtendedEncoding($mediaCounts);
+ $chl = substr($mediaTypes, 0, -1);
- 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . $chart_title . '" title="' . $chart_title . '" />';
+ }
- /**
- * Birth and Death
- *
- * @param string $type
- * @param string $life_dir
- * @param string $birth_death
- *
- * @return string
- */
- private function mortalityQuery($type = 'full', $life_dir = 'ASC', $birth_death = 'BIRT') {
- if ($birth_death == 'MARR') {
- $query_field = "'MARR'";
- } elseif ($birth_death == 'DIV') {
- $query_field = "'DIV'";
- } elseif ($birth_death == 'BIRT') {
- $query_field = "'BIRT'";
- } else {
- $query_field = "'DEAT'";
- }
- if ($life_dir == 'ASC') {
- $dmod = 'MIN';
- } else {
- $dmod = 'MAX';
- }
- $rows = $this->runSql(
- "SELECT d_year, d_type, d_fact, d_gid" .
- " FROM `##dates`" .
- " WHERE d_file={$this->tree->getTreeId()} AND d_fact IN ({$query_field}) AND d_julianday1=(" .
- " SELECT {$dmod}( d_julianday1 )" .
- " FROM `##dates`" .
- " WHERE d_file={$this->tree->getTreeId()} AND d_fact IN ({$query_field}) AND d_julianday1<>0 )" .
- " LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- $record = GedcomRecord::getInstance($row['d_gid'], $this->tree);
- switch ($type) {
- default:
- case 'full':
- if ($record->canShow()) {
- $result = $record->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'year':
- if ($row['d_year'] < 0) {
- $row['d_year'] = abs($row['d_year']) . ' B.C.';
- }
- $date = new Date($row['d_type'] . ' ' . $row['d_year']);
- $result = $date->display();
- break;
- case 'name':
- $result = '<a href="' . e($record->url()) . '">' . $record->getFullName() . '</a>';
- break;
- case 'place':
- $fact = GedcomRecord::getInstance($row['d_gid'], $this->tree)->getFirstFact($row['d_fact']);
- if ($fact) {
- $result = FunctionsPrint::formatFactPlace($fact, true, true, true);
- } else {
- $result = I18N::translate('Private');
- }
- break;
- }
+ /**
+ * Birth and Death
+ *
+ * @param string $type
+ * @param string $life_dir
+ * @param string $birth_death
+ *
+ * @return string
+ */
+ private function mortalityQuery($type = 'full', $life_dir = 'ASC', $birth_death = 'BIRT')
+ {
+ if ($birth_death == 'MARR') {
+ $query_field = "'MARR'";
+ } elseif ($birth_death == 'DIV') {
+ $query_field = "'DIV'";
+ } elseif ($birth_death == 'BIRT') {
+ $query_field = "'BIRT'";
+ } else {
+ $query_field = "'DEAT'";
+ }
+ if ($life_dir == 'ASC') {
+ $dmod = 'MIN';
+ } else {
+ $dmod = 'MAX';
+ }
+ $rows = $this->runSql(
+ "SELECT d_year, d_type, d_fact, d_gid" .
+ " FROM `##dates`" .
+ " WHERE d_file={$this->tree->getTreeId()} AND d_fact IN ({$query_field}) AND d_julianday1=(" .
+ " SELECT {$dmod}( d_julianday1 )" .
+ " FROM `##dates`" .
+ " WHERE d_file={$this->tree->getTreeId()} AND d_fact IN ({$query_field}) AND d_julianday1<>0 )" .
+ " LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ $record = GedcomRecord::getInstance($row['d_gid'], $this->tree);
+ switch ($type) {
+ default:
+ case 'full':
+ if ($record->canShow()) {
+ $result = $record->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'year':
+ if ($row['d_year'] < 0) {
+ $row['d_year'] = abs($row['d_year']) . ' B.C.';
+ }
+ $date = new Date($row['d_type'] . ' ' . $row['d_year']);
+ $result = $date->display();
+ break;
+ case 'name':
+ $result = '<a href="' . e($record->url()) . '">' . $record->getFullName() . '</a>';
+ break;
+ case 'place':
+ $fact = GedcomRecord::getInstance($row['d_gid'], $this->tree)->getFirstFact($row['d_fact']);
+ if ($fact) {
+ $result = FunctionsPrint::formatFactPlace($fact, true, true, true);
+ } else {
+ $result = I18N::translate('Private');
+ }
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * Places
- *
- * @param string $what
- * @param string $fact
- * @param int $parent
- * @param bool $country
- *
- * @return int[]|string[][]
- */
- public function statsPlaces($what = 'ALL', $fact = '', $parent = 0, $country = false) {
- if ($fact) {
- if ($what == 'INDI') {
- $rows = Database::prepare(
- "SELECT i_gedcom AS ged FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom LIKE '%\n2 PLAC %'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchAll();
- } elseif ($what == 'FAM') {
- $rows = Database::prepare(
- "SELECT f_gedcom AS ged FROM `##families` WHERE f_file = :tree_id AND f_gedcom LIKE '%\n2 PLAC %'"
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- ])->fetchAll();
- }
- $placelist = [];
- foreach ($rows as $row) {
- if (preg_match('/\n1 ' . $fact . '(?:\n[2-9].*)*\n2 PLAC (.+)/', $row->ged, $match)) {
- if ($country) {
- $tmp = explode(Place::GEDCOM_SEPARATOR, $match[1]);
- $place = end($tmp);
- } else {
- $place = $match[1];
- }
- if (!isset($placelist[$place])) {
- $placelist[$place] = 1;
- } else {
- $placelist[$place]++;
- }
- }
- }
+ /**
+ * Places
+ *
+ * @param string $what
+ * @param string $fact
+ * @param int $parent
+ * @param bool $country
+ *
+ * @return int[]|string[][]
+ */
+ public function statsPlaces($what = 'ALL', $fact = '', $parent = 0, $country = false)
+ {
+ if ($fact) {
+ if ($what == 'INDI') {
+ $rows = Database::prepare(
+ "SELECT i_gedcom AS ged FROM `##individuals` WHERE i_file = :tree_id AND i_gedcom LIKE '%\n2 PLAC %'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchAll();
+ } elseif ($what == 'FAM') {
+ $rows = Database::prepare(
+ "SELECT f_gedcom AS ged FROM `##families` WHERE f_file = :tree_id AND f_gedcom LIKE '%\n2 PLAC %'"
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ ])->fetchAll();
+ }
+ $placelist = [];
+ foreach ($rows as $row) {
+ if (preg_match('/\n1 ' . $fact . '(?:\n[2-9].*)*\n2 PLAC (.+)/', $row->ged, $match)) {
+ if ($country) {
+ $tmp = explode(Place::GEDCOM_SEPARATOR, $match[1]);
+ $place = end($tmp);
+ } else {
+ $place = $match[1];
+ }
+ if (!isset($placelist[$place])) {
+ $placelist[$place] = 1;
+ } else {
+ $placelist[$place]++;
+ }
+ }
+ }
- return $placelist;
- } elseif ($parent > 0) {
- // used by placehierarchy googlemap module
- if ($what == 'INDI') {
- $join = " JOIN `##individuals` ON pl_file = i_file AND pl_gid = i_id";
- } elseif ($what == 'FAM') {
- $join = " JOIN `##families` ON pl_file = f_file AND pl_gid = f_id";
- } else {
- $join = "";
- }
- $rows = $this->runSql(
- " SELECT" .
- " p_place AS place," .
- " COUNT(*) AS tot" .
- " FROM" .
- " `##places`" .
- " JOIN `##placelinks` ON pl_file=p_file AND p_id=pl_p_id" .
- $join .
- " WHERE" .
- " p_id={$parent} AND" .
- " p_file={$this->tree->getTreeId()}" .
- " GROUP BY place"
- );
+ return $placelist;
+ } elseif ($parent > 0) {
+ // used by placehierarchy googlemap module
+ if ($what == 'INDI') {
+ $join = " JOIN `##individuals` ON pl_file = i_file AND pl_gid = i_id";
+ } elseif ($what == 'FAM') {
+ $join = " JOIN `##families` ON pl_file = f_file AND pl_gid = f_id";
+ } else {
+ $join = "";
+ }
+ $rows = $this->runSql(
+ " SELECT" .
+ " p_place AS place," .
+ " COUNT(*) AS tot" .
+ " FROM" .
+ " `##places`" .
+ " JOIN `##placelinks` ON pl_file=p_file AND p_id=pl_p_id" .
+ $join .
+ " WHERE" .
+ " p_id={$parent} AND" .
+ " p_file={$this->tree->getTreeId()}" .
+ " GROUP BY place"
+ );
- return $rows;
- } else {
- if ($what == 'INDI') {
- $join = " JOIN `##individuals` ON pl_file = i_file AND pl_gid = i_id";
- } elseif ($what == 'FAM') {
- $join = " JOIN `##families` ON pl_file = f_file AND pl_gid = f_id";
- } else {
- $join = "";
- }
- $rows = $this->runSql(
- " SELECT" .
- " p_place AS country," .
- " COUNT(*) AS tot" .
- " FROM" .
- " `##places`" .
- " JOIN `##placelinks` ON pl_file=p_file AND p_id=pl_p_id" .
- $join .
- " WHERE" .
- " p_file={$this->tree->getTreeId()}" .
- " AND p_parent_id='0'" .
- " GROUP BY country ORDER BY tot DESC, country ASC"
- );
+ return $rows;
+ } else {
+ if ($what == 'INDI') {
+ $join = " JOIN `##individuals` ON pl_file = i_file AND pl_gid = i_id";
+ } elseif ($what == 'FAM') {
+ $join = " JOIN `##families` ON pl_file = f_file AND pl_gid = f_id";
+ } else {
+ $join = "";
+ }
+ $rows = $this->runSql(
+ " SELECT" .
+ " p_place AS country," .
+ " COUNT(*) AS tot" .
+ " FROM" .
+ " `##places`" .
+ " JOIN `##placelinks` ON pl_file=p_file AND p_id=pl_p_id" .
+ $join .
+ " WHERE" .
+ " p_file={$this->tree->getTreeId()}" .
+ " AND p_parent_id='0'" .
+ " GROUP BY country ORDER BY tot DESC, country ASC"
+ );
- return $rows;
- }
- }
+ return $rows;
+ }
+ }
- /**
- * Count total places.
- *
- * @return int
- */
- private function totalPlacesQuery() {
- return
- (int) Database::prepare("SELECT COUNT(*) FROM `##places` WHERE p_file=?")
- ->execute([$this->tree->getTreeId()])
- ->fetchOne();
- }
+ /**
+ * Count total places.
+ *
+ * @return int
+ */
+ private function totalPlacesQuery()
+ {
+ return
+ (int)Database::prepare("SELECT COUNT(*) FROM `##places` WHERE p_file=?")
+ ->execute([$this->tree->getTreeId()])
+ ->fetchOne();
+ }
- /**
- * Count total places.
- *
- * @return string
- */
- public function totalPlaces() {
- return I18N::number($this->totalPlacesQuery());
- }
+ /**
+ * Count total places.
+ *
+ * @return string
+ */
+ public function totalPlaces()
+ {
+ return I18N::number($this->totalPlacesQuery());
+ }
- /**
- * Create a chart showing where events occurred.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartDistribution($params = []) {
- $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values');
- $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values');
- $WT_STATS_CHART_COLOR3 = Theme::theme()->parameter('distribution-chart-low-values');
- $WT_STATS_MAP_X = Theme::theme()->parameter('distribution-chart-x');
- $WT_STATS_MAP_Y = Theme::theme()->parameter('distribution-chart-y');
+ /**
+ * Create a chart showing where events occurred.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartDistribution($params = [])
+ {
+ $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values');
+ $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values');
+ $WT_STATS_CHART_COLOR3 = Theme::theme()->parameter('distribution-chart-low-values');
+ $WT_STATS_MAP_X = Theme::theme()->parameter('distribution-chart-x');
+ $WT_STATS_MAP_Y = Theme::theme()->parameter('distribution-chart-y');
- if (isset($params[0])) {
- $chart_shows = $params[0];
- } else {
- $chart_shows = 'world';
- }
- if (isset($params[1])) {
- $chart_type = $params[1];
- } else {
- $chart_type = '';
- }
- if (isset($params[2])) {
- $surname = $params[2];
- } else {
- $surname = '';
- }
+ if (isset($params[0])) {
+ $chart_shows = $params[0];
+ } else {
+ $chart_shows = 'world';
+ }
+ if (isset($params[1])) {
+ $chart_type = $params[1];
+ } else {
+ $chart_type = '';
+ }
+ if (isset($params[2])) {
+ $surname = $params[2];
+ } else {
+ $surname = '';
+ }
- if ($this->totalPlacesQuery() == 0) {
- return '';
- }
- // Get the country names for each language
- $country_to_iso3166 = [];
- foreach (I18N::activeLocales() as $locale) {
- I18N::init($locale->languageTag());
- $countries = $this->getAllCountries();
- foreach ($this->iso3166() as $three => $two) {
- $country_to_iso3166[$three] = $two;
- $country_to_iso3166[$countries[$three]] = $two;
- }
- }
- I18N::init(WT_LOCALE);
- switch ($chart_type) {
- case 'surname_distribution_chart':
- if ($surname == '') {
- $surname = $this->getCommonSurname();
- }
- $chart_title = I18N::translate('Surname distribution chart') . ': ' . $surname;
- // Count how many people are events in each country
- $surn_countries = [];
- $indis = QueryName::individuals($this->tree, I18N::strtoupper($surname), '', '', false, false);
- foreach ($indis as $person) {
- if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcom(), $matches)) {
- // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
- foreach ($matches[1] as $country) {
- if (array_key_exists($country, $country_to_iso3166)) {
- if (array_key_exists($country_to_iso3166[$country], $surn_countries)) {
- $surn_countries[$country_to_iso3166[$country]]++;
- } else {
- $surn_countries[$country_to_iso3166[$country]] = 1;
- }
- }
- }
- }
- }
- break;
- case 'birth_distribution_chart':
- $chart_title = I18N::translate('Birth by country');
- // Count how many people were born in each country
- $surn_countries = [];
- $b_countries = $this->statsPlaces('INDI', 'BIRT', 0, true);
- foreach ($b_countries as $place => $count) {
- $country = $place;
- if (array_key_exists($country, $country_to_iso3166)) {
- if (!isset($surn_countries[$country_to_iso3166[$country]])) {
- $surn_countries[$country_to_iso3166[$country]] = $count;
- } else {
- $surn_countries[$country_to_iso3166[$country]] += $count;
- }
- }
- }
- break;
- case 'death_distribution_chart':
- $chart_title = I18N::translate('Death by country');
- // Count how many people were death in each country
- $surn_countries = [];
- $d_countries = $this->statsPlaces('INDI', 'DEAT', 0, true);
- foreach ($d_countries as $place => $count) {
- $country = $place;
- if (array_key_exists($country, $country_to_iso3166)) {
- if (!isset($surn_countries[$country_to_iso3166[$country]])) {
- $surn_countries[$country_to_iso3166[$country]] = $count;
- } else {
- $surn_countries[$country_to_iso3166[$country]] += $count;
- }
- }
- }
- break;
- case 'marriage_distribution_chart':
- $chart_title = I18N::translate('Marriage by country');
- // Count how many families got marriage in each country
- $surn_countries = [];
- $m_countries = $this->statsPlaces('FAM');
- // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
- foreach ($m_countries as $place) {
- $country = $place['country'];
- if (array_key_exists($country, $country_to_iso3166)) {
- if (!isset($surn_countries[$country_to_iso3166[$country]])) {
- $surn_countries[$country_to_iso3166[$country]] = $place['tot'];
- } else {
- $surn_countries[$country_to_iso3166[$country]] += $place['tot'];
- }
- }
- }
- break;
- case 'indi_distribution_chart':
- default:
- $chart_title = I18N::translate('Individual distribution chart');
- // Count how many people have events in each country
- $surn_countries = [];
- $a_countries = $this->statsPlaces('INDI');
- // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
- foreach ($a_countries as $place) {
- $country = $place['country'];
- if (array_key_exists($country, $country_to_iso3166)) {
- if (!isset($surn_countries[$country_to_iso3166[$country]])) {
- $surn_countries[$country_to_iso3166[$country]] = $place['tot'];
- } else {
- $surn_countries[$country_to_iso3166[$country]] += $place['tot'];
- }
- }
- }
- break;
- }
- $chart_url = 'https://chart.googleapis.com/chart?cht=t&amp;chtm=' . $chart_shows;
- $chart_url .= '&amp;chco=' . $WT_STATS_CHART_COLOR1 . ',' . $WT_STATS_CHART_COLOR3 . ',' . $WT_STATS_CHART_COLOR2; // country colours
- $chart_url .= '&amp;chf=bg,s,ECF5FF'; // sea colour
- $chart_url .= '&amp;chs=' . $WT_STATS_MAP_X . 'x' . $WT_STATS_MAP_Y;
- $chart_url .= '&amp;chld=' . implode('', array_keys($surn_countries)) . '&amp;chd=s:';
- foreach ($surn_countries as $count) {
- $chart_url .= substr(self::GOOGLE_CHART_ENCODING, (int) ($count / max($surn_countries) * 61), 1);
- }
- $chart = '<div id="google_charts" class="center">';
- $chart .= '<p>' . $chart_title . '</p>';
- $chart .= '<div><img src="' . $chart_url . '" alt="' . $chart_title . '" title="' . $chart_title . '" class="gchart" /><br>';
- $chart .= '<table class="center"><tr>';
- $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR2 . '" width="12"></td><td>' . I18N::translate('Highest population') . '</td>';
- $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR3 . '" width="12"></td><td>' . I18N::translate('Lowest population') . '</td>';
- $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR1 . '" width="12"></td><td>' . I18N::translate('Nobody at all') . '</td>';
- $chart .= '</tr></table></div></div>';
+ if ($this->totalPlacesQuery() == 0) {
+ return '';
+ }
+ // Get the country names for each language
+ $country_to_iso3166 = [];
+ foreach (I18N::activeLocales() as $locale) {
+ I18N::init($locale->languageTag());
+ $countries = $this->getAllCountries();
+ foreach ($this->iso3166() as $three => $two) {
+ $country_to_iso3166[$three] = $two;
+ $country_to_iso3166[$countries[$three]] = $two;
+ }
+ }
+ I18N::init(WT_LOCALE);
+ switch ($chart_type) {
+ case 'surname_distribution_chart':
+ if ($surname == '') {
+ $surname = $this->getCommonSurname();
+ }
+ $chart_title = I18N::translate('Surname distribution chart') . ': ' . $surname;
+ // Count how many people are events in each country
+ $surn_countries = [];
+ $indis = QueryName::individuals($this->tree, I18N::strtoupper($surname), '', '', false, false);
+ foreach ($indis as $person) {
+ if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcom(), $matches)) {
+ // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
+ foreach ($matches[1] as $country) {
+ if (array_key_exists($country, $country_to_iso3166)) {
+ if (array_key_exists($country_to_iso3166[$country], $surn_countries)) {
+ $surn_countries[$country_to_iso3166[$country]]++;
+ } else {
+ $surn_countries[$country_to_iso3166[$country]] = 1;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 'birth_distribution_chart':
+ $chart_title = I18N::translate('Birth by country');
+ // Count how many people were born in each country
+ $surn_countries = [];
+ $b_countries = $this->statsPlaces('INDI', 'BIRT', 0, true);
+ foreach ($b_countries as $place => $count) {
+ $country = $place;
+ if (array_key_exists($country, $country_to_iso3166)) {
+ if (!isset($surn_countries[$country_to_iso3166[$country]])) {
+ $surn_countries[$country_to_iso3166[$country]] = $count;
+ } else {
+ $surn_countries[$country_to_iso3166[$country]] += $count;
+ }
+ }
+ }
+ break;
+ case 'death_distribution_chart':
+ $chart_title = I18N::translate('Death by country');
+ // Count how many people were death in each country
+ $surn_countries = [];
+ $d_countries = $this->statsPlaces('INDI', 'DEAT', 0, true);
+ foreach ($d_countries as $place => $count) {
+ $country = $place;
+ if (array_key_exists($country, $country_to_iso3166)) {
+ if (!isset($surn_countries[$country_to_iso3166[$country]])) {
+ $surn_countries[$country_to_iso3166[$country]] = $count;
+ } else {
+ $surn_countries[$country_to_iso3166[$country]] += $count;
+ }
+ }
+ }
+ break;
+ case 'marriage_distribution_chart':
+ $chart_title = I18N::translate('Marriage by country');
+ // Count how many families got marriage in each country
+ $surn_countries = [];
+ $m_countries = $this->statsPlaces('FAM');
+ // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
+ foreach ($m_countries as $place) {
+ $country = $place['country'];
+ if (array_key_exists($country, $country_to_iso3166)) {
+ if (!isset($surn_countries[$country_to_iso3166[$country]])) {
+ $surn_countries[$country_to_iso3166[$country]] = $place['tot'];
+ } else {
+ $surn_countries[$country_to_iso3166[$country]] += $place['tot'];
+ }
+ }
+ }
+ break;
+ case 'indi_distribution_chart':
+ default:
+ $chart_title = I18N::translate('Individual distribution chart');
+ // Count how many people have events in each country
+ $surn_countries = [];
+ $a_countries = $this->statsPlaces('INDI');
+ // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
+ foreach ($a_countries as $place) {
+ $country = $place['country'];
+ if (array_key_exists($country, $country_to_iso3166)) {
+ if (!isset($surn_countries[$country_to_iso3166[$country]])) {
+ $surn_countries[$country_to_iso3166[$country]] = $place['tot'];
+ } else {
+ $surn_countries[$country_to_iso3166[$country]] += $place['tot'];
+ }
+ }
+ }
+ break;
+ }
+ $chart_url = 'https://chart.googleapis.com/chart?cht=t&amp;chtm=' . $chart_shows;
+ $chart_url .= '&amp;chco=' . $WT_STATS_CHART_COLOR1 . ',' . $WT_STATS_CHART_COLOR3 . ',' . $WT_STATS_CHART_COLOR2; // country colours
+ $chart_url .= '&amp;chf=bg,s,ECF5FF'; // sea colour
+ $chart_url .= '&amp;chs=' . $WT_STATS_MAP_X . 'x' . $WT_STATS_MAP_Y;
+ $chart_url .= '&amp;chld=' . implode('', array_keys($surn_countries)) . '&amp;chd=s:';
+ foreach ($surn_countries as $count) {
+ $chart_url .= substr(self::GOOGLE_CHART_ENCODING, (int)($count / max($surn_countries) * 61), 1);
+ }
+ $chart = '<div id="google_charts" class="center">';
+ $chart .= '<p>' . $chart_title . '</p>';
+ $chart .= '<div><img src="' . $chart_url . '" alt="' . $chart_title . '" title="' . $chart_title . '" class="gchart" /><br>';
+ $chart .= '<table class="center"><tr>';
+ $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR2 . '" width="12"></td><td>' . I18N::translate('Highest population') . '</td>';
+ $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR3 . '" width="12"></td><td>' . I18N::translate('Lowest population') . '</td>';
+ $chart .= '<td bgcolor="#' . $WT_STATS_CHART_COLOR1 . '" width="12"></td><td>' . I18N::translate('Nobody at all') . '</td>';
+ $chart .= '</tr></table></div></div>';
- return $chart;
- }
+ return $chart;
+ }
- /**
- * A list of common countries.
- *
- * @return string
- */
- public function commonCountriesList() {
- $countries = $this->statsPlaces();
- if (empty($countries)) {
- return '';
- }
- $top10 = [];
- $i = 1;
- // Get the country names for each language
- $country_names = [];
- foreach (I18N::activeLocales() as $locale) {
- I18N::init($locale->languageTag());
- $all_countries = $this->getAllCountries();
- foreach ($all_countries as $country_code => $country_name) {
- $country_names[$country_name] = $country_code;
- }
- }
- I18N::init(WT_LOCALE);
- $all_db_countries = [];
- foreach ($countries as $place) {
- $country = trim($place['country']);
- if (array_key_exists($country, $country_names)) {
- if (!isset($all_db_countries[$country_names[$country]][$country])) {
- $all_db_countries[$country_names[$country]][$country] = (int) $place['tot'];
- } else {
- $all_db_countries[$country_names[$country]][$country] += (int) $place['tot'];
- }
- }
- }
- // get all the user’s countries names
- $all_countries = $this->getAllCountries();
- foreach ($all_db_countries as $country_code => $country) {
- $top10[] = '<li>';
- foreach ($country as $country_name => $tot) {
- $tmp = new Place($country_name, $this->tree);
- $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $all_countries[$country_code] . '</a>';
- $top10[] .= $place . ' - ' . I18N::number($tot);
- }
- $top10[] .= '</li>';
- if ($i++ == 10) {
- break;
- }
- }
- $top10 = implode('', $top10);
+ /**
+ * A list of common countries.
+ *
+ * @return string
+ */
+ public function commonCountriesList()
+ {
+ $countries = $this->statsPlaces();
+ if (empty($countries)) {
+ return '';
+ }
+ $top10 = [];
+ $i = 1;
+ // Get the country names for each language
+ $country_names = [];
+ foreach (I18N::activeLocales() as $locale) {
+ I18N::init($locale->languageTag());
+ $all_countries = $this->getAllCountries();
+ foreach ($all_countries as $country_code => $country_name) {
+ $country_names[$country_name] = $country_code;
+ }
+ }
+ I18N::init(WT_LOCALE);
+ $all_db_countries = [];
+ foreach ($countries as $place) {
+ $country = trim($place['country']);
+ if (array_key_exists($country, $country_names)) {
+ if (!isset($all_db_countries[$country_names[$country]][$country])) {
+ $all_db_countries[$country_names[$country]][$country] = (int)$place['tot'];
+ } else {
+ $all_db_countries[$country_names[$country]][$country] += (int)$place['tot'];
+ }
+ }
+ }
+ // get all the user’s countries names
+ $all_countries = $this->getAllCountries();
+ foreach ($all_db_countries as $country_code => $country) {
+ $top10[] = '<li>';
+ foreach ($country as $country_name => $tot) {
+ $tmp = new Place($country_name, $this->tree);
+ $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $all_countries[$country_code] . '</a>';
+ $top10[] .= $place . ' - ' . I18N::number($tot);
+ }
+ $top10[] .= '</li>';
+ if ($i++ == 10) {
+ break;
+ }
+ }
+ $top10 = implode('', $top10);
- return '<ul>' . $top10 . '</ul>';
- }
+ return '<ul>' . $top10 . '</ul>';
+ }
- /**
- * A list of common birth places.
- *
- * @return string
- */
- public function commonBirthPlacesList() {
- $places = $this->statsPlaces('INDI', 'BIRT');
- $top10 = [];
- $i = 1;
- arsort($places);
- foreach ($places as $place => $count) {
- $tmp = new Place($place, $this->tree);
- $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
- $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
- if ($i++ == 10) {
- break;
- }
- }
- $top10 = implode('', $top10);
+ /**
+ * A list of common birth places.
+ *
+ * @return string
+ */
+ public function commonBirthPlacesList()
+ {
+ $places = $this->statsPlaces('INDI', 'BIRT');
+ $top10 = [];
+ $i = 1;
+ arsort($places);
+ foreach ($places as $place => $count) {
+ $tmp = new Place($place, $this->tree);
+ $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
+ $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
+ if ($i++ == 10) {
+ break;
+ }
+ }
+ $top10 = implode('', $top10);
- return '<ul>' . $top10 . '</ul>';
- }
+ return '<ul>' . $top10 . '</ul>';
+ }
- /**
- * A list of common death places.
- *
- * @return string
- */
- public function commonDeathPlacesList() {
- $places = $this->statsPlaces('INDI', 'DEAT');
- $top10 = [];
- $i = 1;
- arsort($places);
- foreach ($places as $place => $count) {
- $tmp = new Place($place, $this->tree);
- $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
- $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
- if ($i++ == 10) {
- break;
- }
- }
- $top10 = implode('', $top10);
+ /**
+ * A list of common death places.
+ *
+ * @return string
+ */
+ public function commonDeathPlacesList()
+ {
+ $places = $this->statsPlaces('INDI', 'DEAT');
+ $top10 = [];
+ $i = 1;
+ arsort($places);
+ foreach ($places as $place => $count) {
+ $tmp = new Place($place, $this->tree);
+ $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
+ $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
+ if ($i++ == 10) {
+ break;
+ }
+ }
+ $top10 = implode('', $top10);
- return '<ul>' . $top10 . '</ul>';
- }
+ return '<ul>' . $top10 . '</ul>';
+ }
- /**
- * A list of common marriage places.
- *
- * @return string
- */
- public function commonMarriagePlacesList() {
- $places = $this->statsPlaces('FAM', 'MARR');
- $top10 = [];
- $i = 1;
- arsort($places);
- foreach ($places as $place => $count) {
- $tmp = new Place($place, $this->tree);
- $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
- $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
- if ($i++ == 10) {
- break;
- }
- }
- $top10 = implode('', $top10);
+ /**
+ * A list of common marriage places.
+ *
+ * @return string
+ */
+ public function commonMarriagePlacesList()
+ {
+ $places = $this->statsPlaces('FAM', 'MARR');
+ $top10 = [];
+ $i = 1;
+ arsort($places);
+ foreach ($places as $place => $count) {
+ $tmp = new Place($place, $this->tree);
+ $place = '<a href="' . $tmp->getURL() . '" class="list_item">' . $tmp->getFullName() . '</a>';
+ $top10[] = '<li>' . $place . ' - ' . I18N::number($count) . '</li>';
+ if ($i++ == 10) {
+ break;
+ }
+ }
+ $top10 = implode('', $top10);
- return '<ul>' . $top10 . '</ul>';
- }
+ return '<ul>' . $top10 . '</ul>';
+ }
- /**
- * Create a chart of birth places.
- *
- * @param bool $simple
- * @param bool $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return array|string
- */
- public function statsBirthQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = []) {
- $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');
+ /**
+ * Create a chart of birth places.
+ *
+ * @param bool $simple
+ * @param bool $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return array|string
+ */
+ public function statsBirthQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = [])
+ {
+ $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 ($simple) {
- $sql =
- "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total FROM `##dates` " .
- "WHERE " .
- "d_file = {$this->tree->getTreeId()} AND " .
- "d_year <> 0 AND " .
- "d_fact='BIRT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- } elseif ($sex) {
- $sql =
- "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " .
- "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " .
- "WHERE " .
- "d_file={$this->tree->getTreeId()} AND " .
- "d_fact='BIRT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- } else {
- $sql =
- "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
- "WHERE " .
- "d_file={$this->tree->getTreeId()} AND " .
- "d_fact='BIRT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- }
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- if ($simple) {
- $sql .= " GROUP BY century ORDER BY century";
- } else {
- $sql .= " GROUP BY d_month";
- if ($sex) {
- $sql .= ", i_sex";
- }
- }
- $rows = $this->runSql($sql);
- if ($simple) {
- 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;
- }
- $sizes = explode('x', $size);
- $tot = 0;
- foreach ($rows as $values) {
- $tot += $values['total'];
- }
- // Beware divide by zero
- if ($tot == 0) {
- return '';
- }
- $centuries = '';
- $counts = [];
- foreach ($rows as $values) {
- $counts[] = round(100 * $values['total'] / $tot, 0);
- $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chl = rawurlencode(substr($centuries, 0, -1));
+ if ($simple) {
+ $sql =
+ "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total FROM `##dates` " .
+ "WHERE " .
+ "d_file = {$this->tree->getTreeId()} AND " .
+ "d_year <> 0 AND " .
+ "d_fact='BIRT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ } elseif ($sex) {
+ $sql =
+ "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " .
+ "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " .
+ "WHERE " .
+ "d_file={$this->tree->getTreeId()} AND " .
+ "d_fact='BIRT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ } else {
+ $sql =
+ "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
+ "WHERE " .
+ "d_file={$this->tree->getTreeId()} AND " .
+ "d_fact='BIRT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ }
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ if ($simple) {
+ $sql .= " GROUP BY century ORDER BY century";
+ } else {
+ $sql .= " GROUP BY d_month";
+ if ($sex) {
+ $sql .= ", i_sex";
+ }
+ }
+ $rows = $this->runSql($sql);
+ if ($simple) {
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = 0;
+ foreach ($rows as $values) {
+ $tot += $values['total'];
+ }
+ // Beware divide by zero
+ if ($tot == 0) {
+ return '';
+ }
+ $centuries = '';
+ $counts = [];
+ foreach ($rows as $values) {
+ $counts[] = round(100 * $values['total'] / $tot, 0);
+ $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chl = rawurlencode(substr($centuries, 0, -1));
- 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Births by century') . '" title="' . I18N::translate('Births by century') . '" />';
- } else {
- return $rows;
- }
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Births by century') . '" title="' . I18N::translate('Births by century') . '" />';
+ } else {
+ return $rows;
+ }
+ }
- /**
- * Create a chart of death places.
- *
- * @param bool $simple
- * @param bool $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return array|string
- */
- public function statsDeathQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = []) {
- $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');
+ /**
+ * Create a chart of death places.
+ *
+ * @param bool $simple
+ * @param bool $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return array|string
+ */
+ public function statsDeathQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = [])
+ {
+ $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 ($simple) {
- $sql =
- "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total FROM `##dates` " .
- "WHERE " .
- "d_file={$this->tree->getTreeId()} AND " .
- 'd_year<>0 AND ' .
- "d_fact='DEAT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- } elseif ($sex) {
- $sql =
- "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " .
- "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " .
- "WHERE " .
- "d_file={$this->tree->getTreeId()} AND " .
- "d_fact='DEAT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- } else {
- $sql =
- "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
- "WHERE " .
- "d_file={$this->tree->getTreeId()} AND " .
- "d_fact='DEAT' AND " .
- "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- }
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- if ($simple) {
- $sql .= " GROUP BY century ORDER BY century";
- } else {
- $sql .= " GROUP BY d_month";
- if ($sex) {
- $sql .= ", i_sex";
- }
- }
- $rows = $this->runSql($sql);
- if ($simple) {
- 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;
- }
- $sizes = explode('x', $size);
- $tot = 0;
- foreach ($rows as $values) {
- $tot += $values['total'];
- }
- // Beware divide by zero
- if ($tot == 0) {
- return '';
- }
- $centuries = '';
- $counts = [];
- foreach ($rows as $values) {
- $counts[] = round(100 * $values['total'] / $tot, 0);
- $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chl = rawurlencode(substr($centuries, 0, -1));
+ if ($simple) {
+ $sql =
+ "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total FROM `##dates` " .
+ "WHERE " .
+ "d_file={$this->tree->getTreeId()} AND " .
+ 'd_year<>0 AND ' .
+ "d_fact='DEAT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ } elseif ($sex) {
+ $sql =
+ "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " .
+ "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " .
+ "WHERE " .
+ "d_file={$this->tree->getTreeId()} AND " .
+ "d_fact='DEAT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ } else {
+ $sql =
+ "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
+ "WHERE " .
+ "d_file={$this->tree->getTreeId()} AND " .
+ "d_fact='DEAT' AND " .
+ "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ }
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ if ($simple) {
+ $sql .= " GROUP BY century ORDER BY century";
+ } else {
+ $sql .= " GROUP BY d_month";
+ if ($sex) {
+ $sql .= ", i_sex";
+ }
+ }
+ $rows = $this->runSql($sql);
+ if ($simple) {
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = 0;
+ foreach ($rows as $values) {
+ $tot += $values['total'];
+ }
+ // Beware divide by zero
+ if ($tot == 0) {
+ return '';
+ }
+ $centuries = '';
+ $counts = [];
+ foreach ($rows as $values) {
+ $counts[] = round(100 * $values['total'] / $tot, 0);
+ $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chl = rawurlencode(substr($centuries, 0, -1));
- 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Deaths by century') . '" title="' . I18N::translate('Deaths by century') . '" />';
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Deaths by century') . '" title="' . I18N::translate('Deaths by century') . '" />';
+ }
- return $rows;
- }
+ return $rows;
+ }
- /**
- * Find the earliest birth.
- *
- * @return string
- */
- public function firstBirth() {
- return $this->mortalityQuery('full', 'ASC', 'BIRT');
- }
+ /**
+ * Find the earliest birth.
+ *
+ * @return string
+ */
+ public function firstBirth()
+ {
+ return $this->mortalityQuery('full', 'ASC', 'BIRT');
+ }
- /**
- * Find the earliest birth year.
- *
- * @return string
- */
- public function firstBirthYear() {
- return $this->mortalityQuery('year', 'ASC', 'BIRT');
- }
+ /**
+ * Find the earliest birth year.
+ *
+ * @return string
+ */
+ public function firstBirthYear()
+ {
+ return $this->mortalityQuery('year', 'ASC', 'BIRT');
+ }
- /**
- * Find the name of the earliest birth.
- *
- * @return string
- */
- public function firstBirthName() {
- return $this->mortalityQuery('name', 'ASC', 'BIRT');
- }
+ /**
+ * Find the name of the earliest birth.
+ *
+ * @return string
+ */
+ public function firstBirthName()
+ {
+ return $this->mortalityQuery('name', 'ASC', 'BIRT');
+ }
- /**
- * Find the earliest birth place.
- *
- * @return string
- */
- public function firstBirthPlace() {
- return $this->mortalityQuery('place', 'ASC', 'BIRT');
- }
+ /**
+ * Find the earliest birth place.
+ *
+ * @return string
+ */
+ public function firstBirthPlace()
+ {
+ return $this->mortalityQuery('place', 'ASC', 'BIRT');
+ }
- /**
- * Find the latest birth.
- *
- * @return string
- */
- public function lastBirth() {
- return $this->mortalityQuery('full', 'DESC', 'BIRT');
- }
+ /**
+ * Find the latest birth.
+ *
+ * @return string
+ */
+ public function lastBirth()
+ {
+ return $this->mortalityQuery('full', 'DESC', 'BIRT');
+ }
- /**
- * Find the latest birth year.
- *
- * @return string
- */
- public function lastBirthYear() {
- return $this->mortalityQuery('year', 'DESC', 'BIRT');
- }
+ /**
+ * Find the latest birth year.
+ *
+ * @return string
+ */
+ public function lastBirthYear()
+ {
+ return $this->mortalityQuery('year', 'DESC', 'BIRT');
+ }
- /**
- * Find the latest birth name.
- *
- * @return string
- */
- public function lastBirthName() {
- return $this->mortalityQuery('name', 'DESC', 'BIRT');
- }
+ /**
+ * Find the latest birth name.
+ *
+ * @return string
+ */
+ public function lastBirthName()
+ {
+ return $this->mortalityQuery('name', 'DESC', 'BIRT');
+ }
- /**
- * Find the latest birth place.
- *
- * @return string
- */
- public function lastBirthPlace() {
- return $this->mortalityQuery('place', 'DESC', 'BIRT');
- }
+ /**
+ * Find the latest birth place.
+ *
+ * @return string
+ */
+ public function lastBirthPlace()
+ {
+ return $this->mortalityQuery('place', 'DESC', 'BIRT');
+ }
- /**
- * General query on births.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsBirth($params = []) {
- return $this->statsBirthQuery(true, false, -1, -1, $params);
- }
+ /**
+ * General query on births.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsBirth($params = [])
+ {
+ return $this->statsBirthQuery(true, false, -1, -1, $params);
+ }
- /**
- * Find the earliest death.
- *
- * @return string
- */
- public function firstDeath() {
- return $this->mortalityQuery('full', 'ASC', 'DEAT');
- }
+ /**
+ * Find the earliest death.
+ *
+ * @return string
+ */
+ public function firstDeath()
+ {
+ return $this->mortalityQuery('full', 'ASC', 'DEAT');
+ }
- /**
- * Find the earliest death year.
- *
- * @return string
- */
- public function firstDeathYear() {
- return $this->mortalityQuery('year', 'ASC', 'DEAT');
- }
+ /**
+ * Find the earliest death year.
+ *
+ * @return string
+ */
+ public function firstDeathYear()
+ {
+ return $this->mortalityQuery('year', 'ASC', 'DEAT');
+ }
- /**
- * Find the earliest death name.
- *
- * @return string
- */
- public function firstDeathName() {
- return $this->mortalityQuery('name', 'ASC', 'DEAT');
- }
+ /**
+ * Find the earliest death name.
+ *
+ * @return string
+ */
+ public function firstDeathName()
+ {
+ return $this->mortalityQuery('name', 'ASC', 'DEAT');
+ }
- /**
- * Find the earliest death place.
- *
- * @return string
- */
- public function firstDeathPlace() {
- return $this->mortalityQuery('place', 'ASC', 'DEAT');
- }
+ /**
+ * Find the earliest death place.
+ *
+ * @return string
+ */
+ public function firstDeathPlace()
+ {
+ return $this->mortalityQuery('place', 'ASC', 'DEAT');
+ }
- /**
- * Find the latest death.
- *
- * @return string
- */
- public function lastDeath() {
- return $this->mortalityQuery('full', 'DESC', 'DEAT');
- }
+ /**
+ * Find the latest death.
+ *
+ * @return string
+ */
+ public function lastDeath()
+ {
+ return $this->mortalityQuery('full', 'DESC', 'DEAT');
+ }
- /**
- * Find the latest death year.
- *
- * @return string
- */
- public function lastDeathYear() {
- return $this->mortalityQuery('year', 'DESC', 'DEAT');
- }
+ /**
+ * Find the latest death year.
+ *
+ * @return string
+ */
+ public function lastDeathYear()
+ {
+ return $this->mortalityQuery('year', 'DESC', 'DEAT');
+ }
- /**
- * Find the latest death name.
- *
- * @return string
- */
- public function lastDeathName() {
- return $this->mortalityQuery('name', 'DESC', 'DEAT');
- }
+ /**
+ * Find the latest death name.
+ *
+ * @return string
+ */
+ public function lastDeathName()
+ {
+ return $this->mortalityQuery('name', 'DESC', 'DEAT');
+ }
- /**
- * Find the place of the latest death.
- *
- * @return string
- */
- public function lastDeathPlace() {
- return $this->mortalityQuery('place', 'DESC', 'DEAT');
- }
+ /**
+ * Find the place of the latest death.
+ *
+ * @return string
+ */
+ public function lastDeathPlace()
+ {
+ return $this->mortalityQuery('place', 'DESC', 'DEAT');
+ }
- /**
- * General query on deaths.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsDeath($params = []) {
- return $this->statsDeathQuery(true, false, -1, -1, $params);
- }
+ /**
+ * General query on deaths.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsDeath($params = [])
+ {
+ return $this->statsDeathQuery(true, false, -1, -1, $params);
+ }
- /**
- * Lifespan
- *
- * @param string $type
- * @param string $sex
- *
- * @return string
- */
- private function longlifeQuery($type = 'full', $sex = 'F') {
- $sex_search = ' 1=1';
- if ($sex == 'F') {
- $sex_search = " i_sex='F'";
- } elseif ($sex == 'M') {
- $sex_search = " i_sex='M'";
- }
+ /**
+ * Lifespan
+ *
+ * @param string $type
+ * @param string $sex
+ *
+ * @return string
+ */
+ private function longlifeQuery($type = 'full', $sex = 'F')
+ {
+ $sex_search = ' 1=1';
+ if ($sex == 'F') {
+ $sex_search = " i_sex='F'";
+ } elseif ($sex == 'M') {
+ $sex_search = " i_sex='M'";
+ }
- $rows = $this->runSql(
- " SELECT" .
- " death.d_gid AS id," .
- " death.d_julianday2-birth.d_julianday1 AS age" .
- " FROM" .
- " `##dates` AS death," .
- " `##dates` AS birth," .
- " `##individuals` AS indi" .
- " WHERE" .
- " indi.i_id=birth.d_gid AND" .
- " birth.d_gid=death.d_gid AND" .
- " death.d_file={$this->tree->getTreeId()} AND" .
- " birth.d_file=death.d_file AND" .
- " birth.d_file=indi.i_file AND" .
- " birth.d_fact='BIRT' AND" .
- " death.d_fact='DEAT' AND" .
- " birth.d_julianday1<>0 AND" .
- " death.d_julianday1>birth.d_julianday2 AND" .
- $sex_search .
- " ORDER BY" .
- " age DESC LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- $person = Individual::getInstance($row['id'], $this->tree);
- switch ($type) {
- default:
- case 'full':
- if ($person->canShowName()) {
- $result = $person->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'age':
- $result = I18N::number((int) ($row['age'] / 365.25));
- break;
- case 'name':
- $result = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a>';
- break;
- }
+ $rows = $this->runSql(
+ " SELECT" .
+ " death.d_gid AS id," .
+ " death.d_julianday2-birth.d_julianday1 AS age" .
+ " FROM" .
+ " `##dates` AS death," .
+ " `##dates` AS birth," .
+ " `##individuals` AS indi" .
+ " WHERE" .
+ " indi.i_id=birth.d_gid AND" .
+ " birth.d_gid=death.d_gid AND" .
+ " death.d_file={$this->tree->getTreeId()} AND" .
+ " birth.d_file=death.d_file AND" .
+ " birth.d_file=indi.i_file AND" .
+ " birth.d_fact='BIRT' AND" .
+ " death.d_fact='DEAT' AND" .
+ " birth.d_julianday1<>0 AND" .
+ " death.d_julianday1>birth.d_julianday2 AND" .
+ $sex_search .
+ " ORDER BY" .
+ " age DESC LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ $person = Individual::getInstance($row['id'], $this->tree);
+ switch ($type) {
+ default:
+ case 'full':
+ if ($person->canShowName()) {
+ $result = $person->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'age':
+ $result = I18N::number((int)($row['age'] / 365.25));
+ break;
+ case 'name':
+ $result = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a>';
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * Find the oldest individuals.
- *
- * @param string $type
- * @param string $sex
- * @param string[] $params
- *
- * @return string
- */
- private function topTenOldestQuery($type = 'list', $sex = 'BOTH', $params = []) {
- if ($sex === 'F') {
- $sex_search = " AND i_sex='F' ";
- } elseif ($sex === 'M') {
- $sex_search = " AND i_sex='M' ";
- } else {
- $sex_search = '';
- }
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- $rows = $this->runSql(
- "SELECT " .
- " MAX(death.d_julianday2-birth.d_julianday1) AS age, " .
- " death.d_gid AS deathdate " .
- "FROM " .
- " `##dates` AS death, " .
- " `##dates` AS birth, " .
- " `##individuals` AS indi " .
- "WHERE " .
- " indi.i_id=birth.d_gid AND " .
- " birth.d_gid=death.d_gid AND " .
- " death.d_file={$this->tree->getTreeId()} AND " .
- " birth.d_file=death.d_file AND " .
- " birth.d_file=indi.i_file AND " .
- " birth.d_fact='BIRT' AND " .
- " death.d_fact='DEAT' AND " .
- " birth.d_julianday1<>0 AND " .
- " death.d_julianday1>birth.d_julianday2 " .
- $sex_search .
- "GROUP BY deathdate " .
- "ORDER BY age DESC " .
- "LIMIT " . $total
- );
- if (!isset($rows[0])) {
- return '';
- }
- $top10 = [];
- foreach ($rows as $row) {
- $person = Individual::getInstance($row['deathdate'], $this->tree);
- $age = $row['age'];
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $age = FunctionsDate::getAgeAtEvent($age);
- if ($person->canShow()) {
- if ($type == 'list') {
- $top10[] = '<li><a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')' . '</li>';
- } else {
- $top10[] = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')';
- }
- }
- }
- if ($type == 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode(' ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type == 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * Find the oldest individuals.
+ *
+ * @param string $type
+ * @param string $sex
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function topTenOldestQuery($type = 'list', $sex = 'BOTH', $params = [])
+ {
+ if ($sex === 'F') {
+ $sex_search = " AND i_sex='F' ";
+ } elseif ($sex === 'M') {
+ $sex_search = " AND i_sex='M' ";
+ } else {
+ $sex_search = '';
+ }
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ $rows = $this->runSql(
+ "SELECT " .
+ " MAX(death.d_julianday2-birth.d_julianday1) AS age, " .
+ " death.d_gid AS deathdate " .
+ "FROM " .
+ " `##dates` AS death, " .
+ " `##dates` AS birth, " .
+ " `##individuals` AS indi " .
+ "WHERE " .
+ " indi.i_id=birth.d_gid AND " .
+ " birth.d_gid=death.d_gid AND " .
+ " death.d_file={$this->tree->getTreeId()} AND " .
+ " birth.d_file=death.d_file AND " .
+ " birth.d_file=indi.i_file AND " .
+ " birth.d_fact='BIRT' AND " .
+ " death.d_fact='DEAT' AND " .
+ " birth.d_julianday1<>0 AND " .
+ " death.d_julianday1>birth.d_julianday2 " .
+ $sex_search .
+ "GROUP BY deathdate " .
+ "ORDER BY age DESC " .
+ "LIMIT " . $total
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $top10 = [];
+ foreach ($rows as $row) {
+ $person = Individual::getInstance($row['deathdate'], $this->tree);
+ $age = $row['age'];
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $age = FunctionsDate::getAgeAtEvent($age);
+ if ($person->canShow()) {
+ if ($type == 'list') {
+ $top10[] = '<li><a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')' . '</li>';
+ } else {
+ $top10[] = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')';
+ }
+ }
+ }
+ if ($type == 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode(' ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type == 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the oldest living individuals.
- *
- * @param string $type
- * @param string $sex
- * @param string[] $params
- *
- * @return string
- */
- private function topTenOldestAliveQuery($type = 'list', $sex = 'BOTH', $params = []) {
- if (!Auth::isMember($this->tree)) {
- return I18N::translate('This information is private and cannot be shown.');
- }
- if ($sex == 'F') {
- $sex_search = " AND i_sex='F'";
- } elseif ($sex == 'M') {
- $sex_search = " AND i_sex='M'";
- } else {
- $sex_search = '';
- }
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- $rows = $this->runSql(
- "SELECT" .
- " birth.d_gid AS id," .
- " MIN(birth.d_julianday1) AS age" .
- " FROM" .
- " `##dates` AS birth," .
- " `##individuals` AS indi" .
- " WHERE" .
- " indi.i_id=birth.d_gid AND" .
- " indi.i_gedcom NOT REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")' AND" .
- " birth.d_file={$this->tree->getTreeId()} AND" .
- " birth.d_fact='BIRT' AND" .
- " birth.d_file=indi.i_file AND" .
- " birth.d_julianday1<>0" .
- $sex_search .
- " GROUP BY id" .
- " ORDER BY age" .
- " ASC LIMIT " . $total
- );
- $top10 = [];
- foreach ($rows as $row) {
- $person = Individual::getInstance($row['id'], $this->tree);
- $age = (WT_CLIENT_JD - $row['age']);
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $age = FunctionsDate::getAgeAtEvent($age);
- if ($type === 'list') {
- $top10[] = '<li><a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')' . '</li>';
- } else {
- $top10[] = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')';
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode('; ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * Find the oldest living individuals.
+ *
+ * @param string $type
+ * @param string $sex
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function topTenOldestAliveQuery($type = 'list', $sex = 'BOTH', $params = [])
+ {
+ if (!Auth::isMember($this->tree)) {
+ return I18N::translate('This information is private and cannot be shown.');
+ }
+ if ($sex == 'F') {
+ $sex_search = " AND i_sex='F'";
+ } elseif ($sex == 'M') {
+ $sex_search = " AND i_sex='M'";
+ } else {
+ $sex_search = '';
+ }
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ $rows = $this->runSql(
+ "SELECT" .
+ " birth.d_gid AS id," .
+ " MIN(birth.d_julianday1) AS age" .
+ " FROM" .
+ " `##dates` AS birth," .
+ " `##individuals` AS indi" .
+ " WHERE" .
+ " indi.i_id=birth.d_gid AND" .
+ " indi.i_gedcom NOT REGEXP '\\n1 (" . WT_EVENTS_DEAT . ")' AND" .
+ " birth.d_file={$this->tree->getTreeId()} AND" .
+ " birth.d_fact='BIRT' AND" .
+ " birth.d_file=indi.i_file AND" .
+ " birth.d_julianday1<>0" .
+ $sex_search .
+ " GROUP BY id" .
+ " ORDER BY age" .
+ " ASC LIMIT " . $total
+ );
+ $top10 = [];
+ foreach ($rows as $row) {
+ $person = Individual::getInstance($row['id'], $this->tree);
+ $age = (WT_CLIENT_JD - $row['age']);
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $age = FunctionsDate::getAgeAtEvent($age);
+ if ($type === 'list') {
+ $top10[] = '<li><a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')' . '</li>';
+ } else {
+ $top10[] = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a> (' . $age . ')';
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode('; ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the average lifespan.
- *
- * @param string $sex
- * @param bool $show_years
- *
- * @return string
- */
- private function averageLifespanQuery($sex = 'BOTH', $show_years = false) {
- if ($sex === 'F') {
- $sex_search = " AND i_sex='F' ";
- } elseif ($sex === 'M') {
- $sex_search = " AND i_sex='M' ";
- } else {
- $sex_search = '';
- }
- $rows = $this->runSql(
- "SELECT " .
- " AVG(death.d_julianday2-birth.d_julianday1) AS age " .
- "FROM " .
- " `##dates` AS death, " .
- " `##dates` AS birth, " .
- " `##individuals` AS indi " .
- "WHERE " .
- " indi.i_id=birth.d_gid AND " .
- " birth.d_gid=death.d_gid AND " .
- " death.d_file=" . $this->tree->getTreeId() . " AND " .
- " birth.d_file=death.d_file AND " .
- " birth.d_file=indi.i_file AND " .
- " birth.d_fact='BIRT' AND " .
- " death.d_fact='DEAT' AND " .
- " birth.d_julianday1<>0 AND " .
- " death.d_julianday1>birth.d_julianday2 " .
- $sex_search
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- $age = $row['age'];
- if ($show_years) {
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } elseif (!empty($age)) {
- $age = $age . 'd';
- }
+ /**
+ * Find the average lifespan.
+ *
+ * @param string $sex
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ private function averageLifespanQuery($sex = 'BOTH', $show_years = false)
+ {
+ if ($sex === 'F') {
+ $sex_search = " AND i_sex='F' ";
+ } elseif ($sex === 'M') {
+ $sex_search = " AND i_sex='M' ";
+ } else {
+ $sex_search = '';
+ }
+ $rows = $this->runSql(
+ "SELECT " .
+ " AVG(death.d_julianday2-birth.d_julianday1) AS age " .
+ "FROM " .
+ " `##dates` AS death, " .
+ " `##dates` AS birth, " .
+ " `##individuals` AS indi " .
+ "WHERE " .
+ " indi.i_id=birth.d_gid AND " .
+ " birth.d_gid=death.d_gid AND " .
+ " death.d_file=" . $this->tree->getTreeId() . " AND " .
+ " birth.d_file=death.d_file AND " .
+ " birth.d_file=indi.i_file AND " .
+ " birth.d_fact='BIRT' AND " .
+ " death.d_fact='DEAT' AND " .
+ " birth.d_julianday1<>0 AND " .
+ " death.d_julianday1>birth.d_julianday2 " .
+ $sex_search
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ $age = $row['age'];
+ if ($show_years) {
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } elseif (!empty($age)) {
+ $age = $age . 'd';
+ }
- return FunctionsDate::getAgeAtEvent($age);
- } else {
- return I18N::number($age / 365.25);
- }
- }
+ return FunctionsDate::getAgeAtEvent($age);
+ } else {
+ return I18N::number($age / 365.25);
+ }
+ }
- /**
- * General query on ages.
- *
- * @param bool $simple
- * @param string $related
- * @param string $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return array|string
- */
- public function statsAgeQuery($simple = true, $related = 'BIRT', $sex = 'BOTH', $year1 = -1, $year2 = -1, $params = []) {
- if ($simple) {
- if (isset($params[0]) && $params[0] != '') {
- $size = strtolower($params[0]);
- } else {
- $size = '230x250';
- }
- $sizes = explode('x', $size);
- $rows = $this->runSql(
- "SELECT" .
- " ROUND(AVG(death.d_julianday2-birth.d_julianday1)/365.25,1) AS age," .
- " FLOOR(death.d_year/100+1) AS century," .
- " i_sex AS sex" .
- " FROM" .
- " `##dates` AS death," .
- " `##dates` AS birth," .
- " `##individuals` AS indi" .
- " WHERE" .
- " indi.i_id=birth.d_gid AND" .
- " birth.d_gid=death.d_gid AND" .
- " death.d_file={$this->tree->getTreeId()} AND" .
- " birth.d_file=death.d_file AND" .
- " birth.d_file=indi.i_file AND" .
- " birth.d_fact='BIRT' AND" .
- " death.d_fact='DEAT' AND" .
- " birth.d_julianday1<>0 AND" .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
- " death.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
- " death.d_julianday1>birth.d_julianday2" .
- " GROUP BY century, sex ORDER BY century, sex");
- if (empty($rows)) {
- return '';
- }
- $chxl = '0:|';
- $countsm = '';
- $countsf = '';
- $countsa = '';
- $out = [];
- foreach ($rows as $values) {
- $out[$values['century']][$values['sex']] = $values['age'];
- }
- foreach ($out as $century => $values) {
- if ($sizes[0] < 980) {
- $sizes[0] += 50;
- }
- $chxl .= $this->centuryName($century) . '|';
- $average = 0;
- if (isset($values['F'])) {
- $countsf .= $values['F'] . ',';
- $average = $values['F'];
- } else {
- $countsf .= '0,';
- }
- if (isset($values['M'])) {
- $countsm .= $values['M'] . ',';
- if ($average == 0) {
- $countsa .= $values['M'] . ',';
- } else {
- $countsa .= (($values['M'] + $average) / 2) . ',';
- }
- } else {
- $countsm .= '0,';
- if ($average == 0) {
- $countsa .= '0,';
- } else {
- $countsa .= $values['F'] . ',';
- }
- }
- }
- $countsm = substr($countsm, 0, -1);
- $countsf = substr($countsf, 0, -1);
- $countsa = substr($countsa, 0, -1);
- $chd = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
- $decades = '';
- for ($i = 0; $i <= 100; $i += 10) {
- $decades .= '|' . I18N::number($i);
- }
- $chxl .= '1:||' . I18N::translate('century') . '|2:' . $decades . '|3:||' . I18N::translate('Age') . '|';
- $title = I18N::translate('Average age related to death century');
- if (count($rows) > 6 || mb_strlen($title) < 30) {
- $chtt = $title;
- } else {
- $offset = 0;
- $counter = [];
- while ($offset = strpos($title, ' ', $offset + 1)) {
- $counter[] = $offset;
- }
- $half = (int) (count($counter) / 2);
- $chtt = substr_replace($title, '|', $counter[$half], 1);
- }
+ /**
+ * General query on ages.
+ *
+ * @param bool $simple
+ * @param string $related
+ * @param string $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return array|string
+ */
+ public function statsAgeQuery($simple = true, $related = 'BIRT', $sex = 'BOTH', $year1 = -1, $year2 = -1, $params = [])
+ {
+ if ($simple) {
+ if (isset($params[0]) && $params[0] != '') {
+ $size = strtolower($params[0]);
+ } else {
+ $size = '230x250';
+ }
+ $sizes = explode('x', $size);
+ $rows = $this->runSql(
+ "SELECT" .
+ " ROUND(AVG(death.d_julianday2-birth.d_julianday1)/365.25,1) AS age," .
+ " FLOOR(death.d_year/100+1) AS century," .
+ " i_sex AS sex" .
+ " FROM" .
+ " `##dates` AS death," .
+ " `##dates` AS birth," .
+ " `##individuals` AS indi" .
+ " WHERE" .
+ " indi.i_id=birth.d_gid AND" .
+ " birth.d_gid=death.d_gid AND" .
+ " death.d_file={$this->tree->getTreeId()} AND" .
+ " birth.d_file=death.d_file AND" .
+ " birth.d_file=indi.i_file AND" .
+ " birth.d_fact='BIRT' AND" .
+ " death.d_fact='DEAT' AND" .
+ " birth.d_julianday1<>0 AND" .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
+ " death.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
+ " death.d_julianday1>birth.d_julianday2" .
+ " GROUP BY century, sex ORDER BY century, sex");
+ if (empty($rows)) {
+ return '';
+ }
+ $chxl = '0:|';
+ $countsm = '';
+ $countsf = '';
+ $countsa = '';
+ $out = [];
+ foreach ($rows as $values) {
+ $out[$values['century']][$values['sex']] = $values['age'];
+ }
+ foreach ($out as $century => $values) {
+ if ($sizes[0] < 980) {
+ $sizes[0] += 50;
+ }
+ $chxl .= $this->centuryName($century) . '|';
+ $average = 0;
+ if (isset($values['F'])) {
+ $countsf .= $values['F'] . ',';
+ $average = $values['F'];
+ } else {
+ $countsf .= '0,';
+ }
+ if (isset($values['M'])) {
+ $countsm .= $values['M'] . ',';
+ if ($average == 0) {
+ $countsa .= $values['M'] . ',';
+ } else {
+ $countsa .= (($values['M'] + $average) / 2) . ',';
+ }
+ } else {
+ $countsm .= '0,';
+ if ($average == 0) {
+ $countsa .= '0,';
+ } else {
+ $countsa .= $values['F'] . ',';
+ }
+ }
+ }
+ $countsm = substr($countsm, 0, -1);
+ $countsf = substr($countsf, 0, -1);
+ $countsa = substr($countsa, 0, -1);
+ $chd = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
+ $decades = '';
+ for ($i = 0; $i <= 100; $i += 10) {
+ $decades .= '|' . I18N::number($i);
+ }
+ $chxl .= '1:||' . I18N::translate('century') . '|2:' . $decades . '|3:||' . I18N::translate('Age') . '|';
+ $title = I18N::translate('Average age related to death century');
+ if (count($rows) > 6 || mb_strlen($title) < 30) {
+ $chtt = $title;
+ } else {
+ $offset = 0;
+ $counter = [];
+ while ($offset = strpos($title, ' ', $offset + 1)) {
+ $counter[] = $offset;
+ }
+ $half = (int)(count($counter) / 2);
+ $chtt = substr_replace($title, '|', $counter[$half], 1);
+ }
- return '<img src="' . "https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chm=D,FF0000,2,0,3,1|N*f1*,000000,0,-1,11,1|N*f1*,000000,1,-1,11,1&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chtt=" . rawurlencode($chtt) . "&amp;chd={$chd}&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . '&amp;chdl=' . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age at death')) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average age related to death century') . '" title="' . I18N::translate('Average age related to death century') . '" />';
- } else {
- $sex_search = '';
- $years = '';
- if ($sex == 'F') {
- $sex_search = " AND i_sex='F'";
- } elseif ($sex == 'M') {
- $sex_search = " AND i_sex='M'";
- }
- if ($year1 >= 0 && $year2 >= 0) {
- if ($related == 'BIRT') {
- $years = " AND birth.d_year BETWEEN '{$year1}' AND '{$year2}'";
- } elseif ($related == 'DEAT') {
- $years = " AND death.d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- }
- $rows = $this->runSql(
- "SELECT" .
- " death.d_julianday2-birth.d_julianday1 AS age" .
- " FROM" .
- " `##dates` AS death," .
- " `##dates` AS birth," .
- " `##individuals` AS indi" .
- " WHERE" .
- " indi.i_id=birth.d_gid AND" .
- " birth.d_gid=death.d_gid AND" .
- " death.d_file={$this->tree->getTreeId()} AND" .
- " birth.d_file=death.d_file AND" .
- " birth.d_file=indi.i_file AND" .
- " birth.d_fact='BIRT' AND" .
- " death.d_fact='DEAT' AND" .
- " birth.d_julianday1 <> 0 AND" .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
- " death.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
- " death.d_julianday1>birth.d_julianday2" .
- $years .
- $sex_search .
- " ORDER BY age DESC");
+ return '<img src="' . "https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chm=D,FF0000,2,0,3,1|N*f1*,000000,0,-1,11,1|N*f1*,000000,1,-1,11,1&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chtt=" . rawurlencode($chtt) . "&amp;chd={$chd}&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . '&amp;chdl=' . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age at death')) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average age related to death century') . '" title="' . I18N::translate('Average age related to death century') . '" />';
+ } else {
+ $sex_search = '';
+ $years = '';
+ if ($sex == 'F') {
+ $sex_search = " AND i_sex='F'";
+ } elseif ($sex == 'M') {
+ $sex_search = " AND i_sex='M'";
+ }
+ if ($year1 >= 0 && $year2 >= 0) {
+ if ($related == 'BIRT') {
+ $years = " AND birth.d_year BETWEEN '{$year1}' AND '{$year2}'";
+ } elseif ($related == 'DEAT') {
+ $years = " AND death.d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ }
+ $rows = $this->runSql(
+ "SELECT" .
+ " death.d_julianday2-birth.d_julianday1 AS age" .
+ " FROM" .
+ " `##dates` AS death," .
+ " `##dates` AS birth," .
+ " `##individuals` AS indi" .
+ " WHERE" .
+ " indi.i_id=birth.d_gid AND" .
+ " birth.d_gid=death.d_gid AND" .
+ " death.d_file={$this->tree->getTreeId()} AND" .
+ " birth.d_file=death.d_file AND" .
+ " birth.d_file=indi.i_file AND" .
+ " birth.d_fact='BIRT' AND" .
+ " death.d_fact='DEAT' AND" .
+ " birth.d_julianday1 <> 0 AND" .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
+ " death.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND" .
+ " death.d_julianday1>birth.d_julianday2" .
+ $years .
+ $sex_search .
+ " ORDER BY age DESC");
- return $rows;
- }
- }
+ return $rows;
+ }
+ }
- /**
- * General query on ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsAge($params = []) {
- return $this->statsAgeQuery(true, 'BIRT', 'BOTH', -1, -1, $params);
- }
+ /**
+ * General query on ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsAge($params = [])
+ {
+ return $this->statsAgeQuery(true, 'BIRT', 'BOTH', -1, -1, $params);
+ }
- /**
- * Find the lognest lived individual.
- *
- * @return string
- */
- public function longestLife() {
- return $this->longlifeQuery('full', 'BOTH');
- }
+ /**
+ * Find the lognest lived individual.
+ *
+ * @return string
+ */
+ public function longestLife()
+ {
+ return $this->longlifeQuery('full', 'BOTH');
+ }
- /**
- * Find the age of the longest lived individual.
- *
- * @return string
- */
- public function longestLifeAge() {
- return $this->longlifeQuery('age', 'BOTH');
- }
+ /**
+ * Find the age of the longest lived individual.
+ *
+ * @return string
+ */
+ public function longestLifeAge()
+ {
+ return $this->longlifeQuery('age', 'BOTH');
+ }
- /**
- * Find the name of the longest lived individual.
- *
- * @return string
- */
- public function longestLifeName() {
- return $this->longlifeQuery('name', 'BOTH');
- }
+ /**
+ * Find the name of the longest lived individual.
+ *
+ * @return string
+ */
+ public function longestLifeName()
+ {
+ return $this->longlifeQuery('name', 'BOTH');
+ }
- /**
- * Find the oldest individuals.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldest($params = []) {
- return $this->topTenOldestQuery('nolist', 'BOTH', $params);
- }
+ /**
+ * Find the oldest individuals.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldest($params = [])
+ {
+ return $this->topTenOldestQuery('nolist', 'BOTH', $params);
+ }
- /**
- * Find the oldest living individuals.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestList($params = []) {
- return $this->topTenOldestQuery('list', 'BOTH', $params);
- }
+ /**
+ * Find the oldest living individuals.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestList($params = [])
+ {
+ return $this->topTenOldestQuery('list', 'BOTH', $params);
+ }
- /**
- * Find the oldest living individuals.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestAlive($params = []) {
- return $this->topTenOldestAliveQuery('nolist', 'BOTH', $params);
- }
+ /**
+ * Find the oldest living individuals.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('nolist', 'BOTH', $params);
+ }
- /**
- * Find the oldest living individuals.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestListAlive($params = []) {
- return $this->topTenOldestAliveQuery('list', 'BOTH', $params);
- }
+ /**
+ * Find the oldest living individuals.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestListAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('list', 'BOTH', $params);
+ }
- /**
- * Find the average lifespan.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function averageLifespan($show_years = false) {
- return $this->averageLifespanQuery('BOTH', $show_years);
- }
+ /**
+ * Find the average lifespan.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function averageLifespan($show_years = false)
+ {
+ return $this->averageLifespanQuery('BOTH', $show_years);
+ }
- /**
- * Find the longest lived female.
- *
- * @return string
- */
- public function longestLifeFemale() {
- return $this->longlifeQuery('full', 'F');
- }
+ /**
+ * Find the longest lived female.
+ *
+ * @return string
+ */
+ public function longestLifeFemale()
+ {
+ return $this->longlifeQuery('full', 'F');
+ }
- /**
- * Find the age of the longest lived female.
- *
- * @return string
- */
- public function longestLifeFemaleAge() {
- return $this->longlifeQuery('age', 'F');
- }
+ /**
+ * Find the age of the longest lived female.
+ *
+ * @return string
+ */
+ public function longestLifeFemaleAge()
+ {
+ return $this->longlifeQuery('age', 'F');
+ }
- /**
- * Find the name of the longest lived female.
- *
- * @return string
- */
- public function longestLifeFemaleName() {
- return $this->longlifeQuery('name', 'F');
- }
+ /**
+ * Find the name of the longest lived female.
+ *
+ * @return string
+ */
+ public function longestLifeFemaleName()
+ {
+ return $this->longlifeQuery('name', 'F');
+ }
- /**
- * Find the oldest females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestFemale($params = []) {
- return $this->topTenOldestQuery('nolist', 'F', $params);
- }
+ /**
+ * Find the oldest females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestFemale($params = [])
+ {
+ return $this->topTenOldestQuery('nolist', 'F', $params);
+ }
- /**
- * Find the oldest living females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestFemaleList($params = []) {
- return $this->topTenOldestQuery('list', 'F', $params);
- }
+ /**
+ * Find the oldest living females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestFemaleList($params = [])
+ {
+ return $this->topTenOldestQuery('list', 'F', $params);
+ }
- /**
- * Find the oldest living females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestFemaleAlive($params = []) {
- return $this->topTenOldestAliveQuery('nolist', 'F', $params);
- }
+ /**
+ * Find the oldest living females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestFemaleAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('nolist', 'F', $params);
+ }
- /**
- * Find the oldest living females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestFemaleListAlive($params = []) {
- return $this->topTenOldestAliveQuery('list', 'F', $params);
- }
+ /**
+ * Find the oldest living females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestFemaleListAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('list', 'F', $params);
+ }
- /**
- * Find the average lifespan of females.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function averageLifespanFemale($show_years = false) {
- return $this->averageLifespanQuery('F', $show_years);
- }
+ /**
+ * Find the average lifespan of females.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function averageLifespanFemale($show_years = false)
+ {
+ return $this->averageLifespanQuery('F', $show_years);
+ }
- /**
- * Find the longest lived male.
- *
- * @return string
- */
- public function longestLifeMale() {
- return $this->longlifeQuery('full', 'M');
- }
+ /**
+ * Find the longest lived male.
+ *
+ * @return string
+ */
+ public function longestLifeMale()
+ {
+ return $this->longlifeQuery('full', 'M');
+ }
- /**
- * Find the age of the longest lived male.
- *
- * @return string
- */
- public function longestLifeMaleAge() {
- return $this->longlifeQuery('age', 'M');
- }
+ /**
+ * Find the age of the longest lived male.
+ *
+ * @return string
+ */
+ public function longestLifeMaleAge()
+ {
+ return $this->longlifeQuery('age', 'M');
+ }
- /**
- * Find the name of the longest lived male.
- *
- * @return string
- */
- public function longestLifeMaleName() {
- return $this->longlifeQuery('name', 'M');
- }
+ /**
+ * Find the name of the longest lived male.
+ *
+ * @return string
+ */
+ public function longestLifeMaleName()
+ {
+ return $this->longlifeQuery('name', 'M');
+ }
- /**
- * Find the longest lived males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestMale($params = []) {
- return $this->topTenOldestQuery('nolist', 'M', $params);
- }
+ /**
+ * Find the longest lived males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestMale($params = [])
+ {
+ return $this->topTenOldestQuery('nolist', 'M', $params);
+ }
- /**
- * Find the longest lived males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestMaleList($params = []) {
- return $this->topTenOldestQuery('list', 'M', $params);
- }
+ /**
+ * Find the longest lived males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestMaleList($params = [])
+ {
+ return $this->topTenOldestQuery('list', 'M', $params);
+ }
- /**
- * Find the longest lived living males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestMaleAlive($params = []) {
- return $this->topTenOldestAliveQuery('nolist', 'M', $params);
- }
+ /**
+ * Find the longest lived living males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestMaleAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('nolist', 'M', $params);
+ }
- /**
- * Find the longest lived living males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenOldestMaleListAlive($params = []) {
- return $this->topTenOldestAliveQuery('list', 'M', $params);
- }
+ /**
+ * Find the longest lived living males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenOldestMaleListAlive($params = [])
+ {
+ return $this->topTenOldestAliveQuery('list', 'M', $params);
+ }
- /**
- * Find the average male lifespan.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function averageLifespanMale($show_years = false) {
- return $this->averageLifespanQuery('M', $show_years);
- }
+ /**
+ * Find the average male lifespan.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function averageLifespanMale($show_years = false)
+ {
+ return $this->averageLifespanQuery('M', $show_years);
+ }
- /**
- * Events
- *
- * @param string $type
- * @param string $direction
- * @param string $facts
- *
- * @return string
- */
- private function eventQuery($type, $direction, $facts) {
- $eventTypes = [
- 'BIRT' => I18N::translate('birth'),
- 'DEAT' => I18N::translate('death'),
- 'MARR' => I18N::translate('marriage'),
- 'ADOP' => I18N::translate('adoption'),
- 'BURI' => I18N::translate('burial'),
- 'CENS' => I18N::translate('census added'),
- ];
+ /**
+ * Events
+ *
+ * @param string $type
+ * @param string $direction
+ * @param string $facts
+ *
+ * @return string
+ */
+ private function eventQuery($type, $direction, $facts)
+ {
+ $eventTypes = [
+ 'BIRT' => I18N::translate('birth'),
+ 'DEAT' => I18N::translate('death'),
+ 'MARR' => I18N::translate('marriage'),
+ 'ADOP' => I18N::translate('adoption'),
+ 'BURI' => I18N::translate('burial'),
+ 'CENS' => I18N::translate('census added'),
+ ];
- $fact_query = "IN ('" . str_replace('|', "','", $facts) . "')";
+ $fact_query = "IN ('" . str_replace('|', "','", $facts) . "')";
- if ($direction != 'ASC') {
- $direction = 'DESC';
- }
- $rows = $this->runSql(''
- . ' SELECT'
- . ' d_gid AS id,'
- . ' d_year AS year,'
- . ' d_fact AS fact,'
- . ' d_type AS type'
- . ' FROM'
- . " `##dates`"
- . ' WHERE'
- . " d_file={$this->tree->getTreeId()} AND"
- . " d_gid<>'HEAD' AND"
- . " d_fact {$fact_query} AND"
- . ' d_julianday1<>0'
- . ' ORDER BY'
- . " d_julianday1 {$direction}, d_type LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- $record = GedcomRecord::getInstance($row['id'], $this->tree);
- switch ($type) {
- default:
- case 'full':
- if ($record->canShow()) {
- $result = $record->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'year':
- $date = new Date($row['type'] . ' ' . $row['year']);
- $result = $date->display();
- break;
- case 'type':
- if (isset($eventTypes[$row['fact']])) {
- $result = $eventTypes[$row['fact']];
- } else {
- $result = GedcomTag::getLabel($row['fact']);
- }
- break;
- case 'name':
- $result = '<a href="' . e($record->url()) . '">' . $record->getFullName() . '</a>';
- break;
- case 'place':
- $fact = $record->getFirstFact($row['fact']);
- if ($fact) {
- $result = FunctionsPrint::formatFactPlace($fact, true, true, true);
- } else {
- $result = I18N::translate('Private');
- }
- break;
- }
+ if ($direction != 'ASC') {
+ $direction = 'DESC';
+ }
+ $rows = $this->runSql(''
+ . ' SELECT'
+ . ' d_gid AS id,'
+ . ' d_year AS year,'
+ . ' d_fact AS fact,'
+ . ' d_type AS type'
+ . ' FROM'
+ . " `##dates`"
+ . ' WHERE'
+ . " d_file={$this->tree->getTreeId()} AND"
+ . " d_gid<>'HEAD' AND"
+ . " d_fact {$fact_query} AND"
+ . ' d_julianday1<>0'
+ . ' ORDER BY'
+ . " d_julianday1 {$direction}, d_type LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ $record = GedcomRecord::getInstance($row['id'], $this->tree);
+ switch ($type) {
+ default:
+ case 'full':
+ if ($record->canShow()) {
+ $result = $record->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'year':
+ $date = new Date($row['type'] . ' ' . $row['year']);
+ $result = $date->display();
+ break;
+ case 'type':
+ if (isset($eventTypes[$row['fact']])) {
+ $result = $eventTypes[$row['fact']];
+ } else {
+ $result = GedcomTag::getLabel($row['fact']);
+ }
+ break;
+ case 'name':
+ $result = '<a href="' . e($record->url()) . '">' . $record->getFullName() . '</a>';
+ break;
+ case 'place':
+ $fact = $record->getFirstFact($row['fact']);
+ if ($fact) {
+ $result = FunctionsPrint::formatFactPlace($fact, true, true, true);
+ } else {
+ $result = I18N::translate('Private');
+ }
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * Find the earliest event.
- *
- * @return string
- */
- public function firstEvent() {
- return $this->eventQuery('full', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the earliest event.
+ *
+ * @return string
+ */
+ public function firstEvent()
+ {
+ return $this->eventQuery('full', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the year of the earliest event.
- *
- * @return string
- */
- public function firstEventYear() {
- return $this->eventQuery('year', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the year of the earliest event.
+ *
+ * @return string
+ */
+ public function firstEventYear()
+ {
+ return $this->eventQuery('year', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the type of the earliest event.
- *
- * @return string
- */
- public function firstEventType() {
- return $this->eventQuery('type', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the type of the earliest event.
+ *
+ * @return string
+ */
+ public function firstEventType()
+ {
+ return $this->eventQuery('type', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the name of the individual with the earliest event.
- *
- * @return string
- */
- public function firstEventName() {
- return $this->eventQuery('name', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the name of the individual with the earliest event.
+ *
+ * @return string
+ */
+ public function firstEventName()
+ {
+ return $this->eventQuery('name', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the location of the earliest event.
- *
- * @return string
- */
- public function firstEventPlace() {
- return $this->eventQuery('place', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the location of the earliest event.
+ *
+ * @return string
+ */
+ public function firstEventPlace()
+ {
+ return $this->eventQuery('place', 'ASC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the latest event.
- *
- * @return string
- */
- public function lastEvent() {
- return $this->eventQuery('full', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the latest event.
+ *
+ * @return string
+ */
+ public function lastEvent()
+ {
+ return $this->eventQuery('full', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the year of the latest event.
- *
- * @return string
- */
- public function lastEventYear() {
- return $this->eventQuery('year', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the year of the latest event.
+ *
+ * @return string
+ */
+ public function lastEventYear()
+ {
+ return $this->eventQuery('year', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the type of the latest event.
- *
- * @return string
- */
- public function lastEventType() {
- return $this->eventQuery('type', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the type of the latest event.
+ *
+ * @return string
+ */
+ public function lastEventType()
+ {
+ return $this->eventQuery('type', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Find the name of the individual with the latest event.
- *
- * @return string
- */
- public function lastEventName() {
- return $this->eventQuery('name', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * Find the name of the individual with the latest event.
+ *
+ * @return string
+ */
+ public function lastEventName()
+ {
+ return $this->eventQuery('name', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * FInd the location of the latest event.
- *
- * @return string
- */
- public function lastEventPlace() {
- return $this->eventQuery('place', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
- }
+ /**
+ * FInd the location of the latest event.
+ *
+ * @return string
+ */
+ public function lastEventPlace()
+ {
+ return $this->eventQuery('place', 'DESC', WT_EVENTS_BIRT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV . '|' . WT_EVENTS_DEAT);
+ }
- /**
- * Query the database for marriage tags.
- *
- * @param string $type
- * @param string $age_dir
- * @param string $sex
- * @param bool $show_years
- *
- * @return string
- */
- private function marriageQuery($type = 'full', $age_dir = 'ASC', $sex = 'F', $show_years = false) {
- if ($sex == 'F') {
- $sex_field = 'f_wife';
- } else {
- $sex_field = 'f_husb';
- }
- if ($age_dir != 'ASC') {
- $age_dir = 'DESC';
- }
- $rows = $this->runSql(
- " SELECT fam.f_id AS famid, fam.{$sex_field}, married.d_julianday2-birth.d_julianday1 AS age, indi.i_id AS i_id" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS birth ON birth.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " birth.d_gid = indi.i_id AND" .
- " married.d_gid = fam.f_id AND" .
- " indi.i_id = fam.{$sex_field} AND" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " birth.d_fact = 'BIRT' AND" .
- " married.d_fact = 'MARR' AND" .
- " birth.d_julianday1 <> 0 AND" .
- " married.d_julianday2 > birth.d_julianday1 AND" .
- " i_sex='{$sex}'" .
- " ORDER BY" .
- " married.d_julianday2-birth.d_julianday1 {$age_dir} LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- if (isset($row['famid'])) {
- $family = Family::getInstance($row['famid'], $this->tree);
- }
- if (isset($row['i_id'])) {
- $person = Individual::getInstance($row['i_id'], $this->tree);
- }
- switch ($type) {
- default:
- case 'full':
- if ($family->canShow()) {
- $result = $family->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'name':
- $result = '<a href="' . e($family->url()) . '">' . $person->getFullName() . '</a>';
- break;
- case 'age':
- $age = $row['age'];
- if ($show_years) {
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $result = FunctionsDate::getAgeAtEvent($age);
- } else {
- $result = I18N::number((int) ($age / 365.25));
- }
- break;
- }
+ /**
+ * Query the database for marriage tags.
+ *
+ * @param string $type
+ * @param string $age_dir
+ * @param string $sex
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ private function marriageQuery($type = 'full', $age_dir = 'ASC', $sex = 'F', $show_years = false)
+ {
+ if ($sex == 'F') {
+ $sex_field = 'f_wife';
+ } else {
+ $sex_field = 'f_husb';
+ }
+ if ($age_dir != 'ASC') {
+ $age_dir = 'DESC';
+ }
+ $rows = $this->runSql(
+ " SELECT fam.f_id AS famid, fam.{$sex_field}, married.d_julianday2-birth.d_julianday1 AS age, indi.i_id AS i_id" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS birth ON birth.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " birth.d_gid = indi.i_id AND" .
+ " married.d_gid = fam.f_id AND" .
+ " indi.i_id = fam.{$sex_field} AND" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " birth.d_fact = 'BIRT' AND" .
+ " married.d_fact = 'MARR' AND" .
+ " birth.d_julianday1 <> 0 AND" .
+ " married.d_julianday2 > birth.d_julianday1 AND" .
+ " i_sex='{$sex}'" .
+ " ORDER BY" .
+ " married.d_julianday2-birth.d_julianday1 {$age_dir} LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ if (isset($row['famid'])) {
+ $family = Family::getInstance($row['famid'], $this->tree);
+ }
+ if (isset($row['i_id'])) {
+ $person = Individual::getInstance($row['i_id'], $this->tree);
+ }
+ switch ($type) {
+ default:
+ case 'full':
+ if ($family->canShow()) {
+ $result = $family->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'name':
+ $result = '<a href="' . e($family->url()) . '">' . $person->getFullName() . '</a>';
+ break;
+ case 'age':
+ $age = $row['age'];
+ if ($show_years) {
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $result = FunctionsDate::getAgeAtEvent($age);
+ } else {
+ $result = I18N::number((int)($age / 365.25));
+ }
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * General query on age at marriage.
- *
- * @param string $type
- * @param string $age_dir
- * @param string[] $params
- *
- * @return string
- */
- private function ageOfMarriageQuery($type = 'list', $age_dir = 'ASC', $params = []) {
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- if ($age_dir != 'ASC') {
- $age_dir = 'DESC';
- }
- $hrows = $this->runSql(
- " SELECT DISTINCT fam.f_id AS family, MIN(husbdeath.d_julianday2-married.d_julianday1) AS age" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##dates` AS husbdeath ON husbdeath.d_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " husbdeath.d_gid = fam.f_husb AND" .
- " husbdeath.d_fact = 'DEAT' AND" .
- " married.d_gid = fam.f_id AND" .
- " married.d_fact = 'MARR' AND" .
- " married.d_julianday1 < husbdeath.d_julianday2 AND" .
- " married.d_julianday1 <> 0" .
- " GROUP BY family" .
- " ORDER BY age {$age_dir}");
- $wrows = $this->runSql(
- " SELECT DISTINCT fam.f_id AS family, MIN(wifedeath.d_julianday2-married.d_julianday1) AS age" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##dates` AS wifedeath ON wifedeath.d_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " wifedeath.d_gid = fam.f_wife AND" .
- " wifedeath.d_fact = 'DEAT' AND" .
- " married.d_gid = fam.f_id AND" .
- " married.d_fact = 'MARR' AND" .
- " married.d_julianday1 < wifedeath.d_julianday2 AND" .
- " married.d_julianday1 <> 0" .
- " GROUP BY family" .
- " ORDER BY age {$age_dir}");
- $drows = $this->runSql(
- " SELECT DISTINCT fam.f_id AS family, MIN(divorced.d_julianday2-married.d_julianday1) AS age" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##dates` AS divorced ON divorced.d_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " married.d_gid = fam.f_id AND" .
- " married.d_fact = 'MARR' AND" .
- " divorced.d_gid = fam.f_id AND" .
- " divorced.d_fact IN ('DIV', 'ANUL', '_SEPR', '_DETS') AND" .
- " married.d_julianday1 < divorced.d_julianday2 AND" .
- " married.d_julianday1 <> 0" .
- " GROUP BY family" .
- " ORDER BY age {$age_dir}");
- if (!isset($hrows) && !isset($wrows) && !isset($drows)) {
- return '';
- }
- $rows = [];
- foreach ($drows as $family) {
- $rows[$family['family']] = $family['age'];
- }
- foreach ($hrows as $family) {
- if (!isset($rows[$family['family']])) {
- $rows[$family['family']] = $family['age'];
- }
- }
- foreach ($wrows as $family) {
- if (!isset($rows[$family['family']])) {
- $rows[$family['family']] = $family['age'];
- } elseif ($rows[$family['family']] > $family['age']) {
- $rows[$family['family']] = $family['age'];
- }
- }
- if ($age_dir === 'DESC') {
- arsort($rows);
- } else {
- asort($rows);
- }
- $top10 = [];
- $i = 0;
- foreach ($rows as $fam => $age) {
- $family = Family::getInstance($fam, $this->tree);
- if ($type === 'name') {
- return $family->formatList();
- }
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $age = FunctionsDate::getAgeAtEvent($age);
- if ($type === 'age') {
- return $age;
- }
- $husb = $family->getHusband();
- $wife = $family->getWife();
- if ($husb && $wife && ($husb->getAllDeathDates() && $wife->getAllDeathDates() || !$husb->isDead() || !$wife->isDead())) {
- if ($family->canShow()) {
- if ($type === 'list') {
- $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')' . '</li>';
- } else {
- $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')';
- }
- }
- if (++$i === $total) {
- break;
- }
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode('; ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * General query on age at marriage.
+ *
+ * @param string $type
+ * @param string $age_dir
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function ageOfMarriageQuery($type = 'list', $age_dir = 'ASC', $params = [])
+ {
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ if ($age_dir != 'ASC') {
+ $age_dir = 'DESC';
+ }
+ $hrows = $this->runSql(
+ " SELECT DISTINCT fam.f_id AS family, MIN(husbdeath.d_julianday2-married.d_julianday1) AS age" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##dates` AS husbdeath ON husbdeath.d_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " husbdeath.d_gid = fam.f_husb AND" .
+ " husbdeath.d_fact = 'DEAT' AND" .
+ " married.d_gid = fam.f_id AND" .
+ " married.d_fact = 'MARR' AND" .
+ " married.d_julianday1 < husbdeath.d_julianday2 AND" .
+ " married.d_julianday1 <> 0" .
+ " GROUP BY family" .
+ " ORDER BY age {$age_dir}");
+ $wrows = $this->runSql(
+ " SELECT DISTINCT fam.f_id AS family, MIN(wifedeath.d_julianday2-married.d_julianday1) AS age" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##dates` AS wifedeath ON wifedeath.d_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " wifedeath.d_gid = fam.f_wife AND" .
+ " wifedeath.d_fact = 'DEAT' AND" .
+ " married.d_gid = fam.f_id AND" .
+ " married.d_fact = 'MARR' AND" .
+ " married.d_julianday1 < wifedeath.d_julianday2 AND" .
+ " married.d_julianday1 <> 0" .
+ " GROUP BY family" .
+ " ORDER BY age {$age_dir}");
+ $drows = $this->runSql(
+ " SELECT DISTINCT fam.f_id AS family, MIN(divorced.d_julianday2-married.d_julianday1) AS age" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##dates` AS divorced ON divorced.d_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " married.d_gid = fam.f_id AND" .
+ " married.d_fact = 'MARR' AND" .
+ " divorced.d_gid = fam.f_id AND" .
+ " divorced.d_fact IN ('DIV', 'ANUL', '_SEPR', '_DETS') AND" .
+ " married.d_julianday1 < divorced.d_julianday2 AND" .
+ " married.d_julianday1 <> 0" .
+ " GROUP BY family" .
+ " ORDER BY age {$age_dir}");
+ if (!isset($hrows) && !isset($wrows) && !isset($drows)) {
+ return '';
+ }
+ $rows = [];
+ foreach ($drows as $family) {
+ $rows[$family['family']] = $family['age'];
+ }
+ foreach ($hrows as $family) {
+ if (!isset($rows[$family['family']])) {
+ $rows[$family['family']] = $family['age'];
+ }
+ }
+ foreach ($wrows as $family) {
+ if (!isset($rows[$family['family']])) {
+ $rows[$family['family']] = $family['age'];
+ } elseif ($rows[$family['family']] > $family['age']) {
+ $rows[$family['family']] = $family['age'];
+ }
+ }
+ if ($age_dir === 'DESC') {
+ arsort($rows);
+ } else {
+ asort($rows);
+ }
+ $top10 = [];
+ $i = 0;
+ foreach ($rows as $fam => $age) {
+ $family = Family::getInstance($fam, $this->tree);
+ if ($type === 'name') {
+ return $family->formatList();
+ }
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $age = FunctionsDate::getAgeAtEvent($age);
+ if ($type === 'age') {
+ return $age;
+ }
+ $husb = $family->getHusband();
+ $wife = $family->getWife();
+ if ($husb && $wife && ($husb->getAllDeathDates() && $wife->getAllDeathDates() || !$husb->isDead() || !$wife->isDead())) {
+ if ($family->canShow()) {
+ if ($type === 'list') {
+ $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')' . '</li>';
+ } else {
+ $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')';
+ }
+ }
+ if (++$i === $total) {
+ break;
+ }
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode('; ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the ages between spouses.
- *
- * @param string $type
- * @param string $age_dir
- * @param string[] $params
- *
- * @return string
- */
- private function ageBetweenSpousesQuery($type = 'list', $age_dir = 'DESC', $params = []) {
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- if ($age_dir === 'DESC') {
- $sql =
- "SELECT f_id AS xref, MIN(wife.d_julianday2-husb.d_julianday1) AS age" .
- " FROM `##families`" .
- " JOIN `##dates` AS wife ON wife.d_gid = f_wife AND wife.d_file = f_file" .
- " JOIN `##dates` AS husb ON husb.d_gid = f_husb AND husb.d_file = f_file" .
- " WHERE f_file = :tree_id" .
- " AND husb.d_fact = 'BIRT'" .
- " AND wife.d_fact = 'BIRT'" .
- " AND wife.d_julianday2 >= husb.d_julianday1 AND husb.d_julianday1 <> 0" .
- " GROUP BY xref" .
- " ORDER BY age DESC" .
- " LIMIT :limit";
- } else {
- $sql =
- "SELECT f_id AS xref, MIN(husb.d_julianday2-wife.d_julianday1) AS age" .
- " FROM `##families`" .
- " JOIN `##dates` AS wife ON wife.d_gid = f_wife AND wife.d_file = f_file" .
- " JOIN `##dates` AS husb ON husb.d_gid = f_husb AND husb.d_file = f_file" .
- " WHERE f_file = :tree_id" .
- " AND husb.d_fact = 'BIRT'" .
- " AND wife.d_fact = 'BIRT'" .
- " AND husb.d_julianday2 >= wife.d_julianday1 AND wife.d_julianday1 <> 0" .
- " GROUP BY xref" .
- " ORDER BY age DESC" .
- " LIMIT :limit";
- }
- $rows = Database::prepare(
- $sql
- )->execute([
- 'tree_id' => $this->tree->getTreeId(),
- 'limit' => $total,
- ])->fetchAll();
+ /**
+ * Find the ages between spouses.
+ *
+ * @param string $type
+ * @param string $age_dir
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function ageBetweenSpousesQuery($type = 'list', $age_dir = 'DESC', $params = [])
+ {
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ if ($age_dir === 'DESC') {
+ $sql =
+ "SELECT f_id AS xref, MIN(wife.d_julianday2-husb.d_julianday1) AS age" .
+ " FROM `##families`" .
+ " JOIN `##dates` AS wife ON wife.d_gid = f_wife AND wife.d_file = f_file" .
+ " JOIN `##dates` AS husb ON husb.d_gid = f_husb AND husb.d_file = f_file" .
+ " WHERE f_file = :tree_id" .
+ " AND husb.d_fact = 'BIRT'" .
+ " AND wife.d_fact = 'BIRT'" .
+ " AND wife.d_julianday2 >= husb.d_julianday1 AND husb.d_julianday1 <> 0" .
+ " GROUP BY xref" .
+ " ORDER BY age DESC" .
+ " LIMIT :limit";
+ } else {
+ $sql =
+ "SELECT f_id AS xref, MIN(husb.d_julianday2-wife.d_julianday1) AS age" .
+ " FROM `##families`" .
+ " JOIN `##dates` AS wife ON wife.d_gid = f_wife AND wife.d_file = f_file" .
+ " JOIN `##dates` AS husb ON husb.d_gid = f_husb AND husb.d_file = f_file" .
+ " WHERE f_file = :tree_id" .
+ " AND husb.d_fact = 'BIRT'" .
+ " AND wife.d_fact = 'BIRT'" .
+ " AND husb.d_julianday2 >= wife.d_julianday1 AND wife.d_julianday1 <> 0" .
+ " GROUP BY xref" .
+ " ORDER BY age DESC" .
+ " LIMIT :limit";
+ }
+ $rows = Database::prepare(
+ $sql
+ )->execute([
+ 'tree_id' => $this->tree->getTreeId(),
+ 'limit' => $total,
+ ])->fetchAll();
- $top10 = [];
- foreach ($rows as $fam) {
- $family = Family::getInstance($fam->xref, $this->tree);
- if ($fam->age < 0) {
- break;
- }
- $age = $fam->age;
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $age = FunctionsDate::getAgeAtEvent($age);
- if ($family->canShow()) {
- if ($type === 'list') {
- $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')' . '</li>';
- } else {
- $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')';
- }
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- if ($top10) {
- $top10 = '<ul>' . $top10 . '</ul>';
- }
- } else {
- $top10 = implode(' ', $top10);
- }
+ $top10 = [];
+ foreach ($rows as $fam) {
+ $family = Family::getInstance($fam->xref, $this->tree);
+ if ($fam->age < 0) {
+ break;
+ }
+ $age = $fam->age;
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $age = FunctionsDate::getAgeAtEvent($age);
+ if ($family->canShow()) {
+ if ($type === 'list') {
+ $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')' . '</li>';
+ } else {
+ $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> (' . $age . ')';
+ }
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ if ($top10) {
+ $top10 = '<ul>' . $top10 . '</ul>';
+ }
+ } else {
+ $top10 = implode(' ', $top10);
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * General query on parents.
- *
- * @param string $type
- * @param string $age_dir
- * @param string $sex
- * @param bool $show_years
- *
- * @return string
- */
- private function parentsQuery($type = 'full', $age_dir = 'ASC', $sex = 'F', $show_years = false) {
- if ($sex == 'F') {
- $sex_field = 'WIFE';
- } else {
- $sex_field = 'HUSB';
- }
- if ($age_dir != 'ASC') {
- $age_dir = 'DESC';
- }
- $rows = $this->runSql(
- " SELECT" .
- " parentfamily.l_to AS id," .
- " childbirth.d_julianday2-birth.d_julianday1 AS age" .
- " FROM `##link` AS parentfamily" .
- " JOIN `##link` AS childfamily ON childfamily.l_file = {$this->tree->getTreeId()}" .
- " JOIN `##dates` AS birth ON birth.d_file = {$this->tree->getTreeId()}" .
- " JOIN `##dates` AS childbirth ON childbirth.d_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " birth.d_gid = parentfamily.l_to AND" .
- " childfamily.l_to = childbirth.d_gid AND" .
- " childfamily.l_type = 'CHIL' AND" .
- " parentfamily.l_type = '{$sex_field}' AND" .
- " childfamily.l_from = parentfamily.l_from AND" .
- " parentfamily.l_file = {$this->tree->getTreeId()} AND" .
- " birth.d_fact = 'BIRT' AND" .
- " childbirth.d_fact = 'BIRT' AND" .
- " birth.d_julianday1 <> 0 AND" .
- " childbirth.d_julianday2 > birth.d_julianday1" .
- " ORDER BY age {$age_dir} LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- if (isset($row['id'])) {
- $person = Individual::getInstance($row['id'], $this->tree);
- }
- switch ($type) {
- default:
- case 'full':
- if ($person->canShow()) {
- $result = $person->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'name':
- $result = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a>';
- break;
- case 'age':
- $age = $row['age'];
- if ($show_years) {
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $result = FunctionsDate::getAgeAtEvent($age);
- } else {
- $result = (int) ($age / 365.25);
- }
- break;
- }
+ /**
+ * General query on parents.
+ *
+ * @param string $type
+ * @param string $age_dir
+ * @param string $sex
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ private function parentsQuery($type = 'full', $age_dir = 'ASC', $sex = 'F', $show_years = false)
+ {
+ if ($sex == 'F') {
+ $sex_field = 'WIFE';
+ } else {
+ $sex_field = 'HUSB';
+ }
+ if ($age_dir != 'ASC') {
+ $age_dir = 'DESC';
+ }
+ $rows = $this->runSql(
+ " SELECT" .
+ " parentfamily.l_to AS id," .
+ " childbirth.d_julianday2-birth.d_julianday1 AS age" .
+ " FROM `##link` AS parentfamily" .
+ " JOIN `##link` AS childfamily ON childfamily.l_file = {$this->tree->getTreeId()}" .
+ " JOIN `##dates` AS birth ON birth.d_file = {$this->tree->getTreeId()}" .
+ " JOIN `##dates` AS childbirth ON childbirth.d_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " birth.d_gid = parentfamily.l_to AND" .
+ " childfamily.l_to = childbirth.d_gid AND" .
+ " childfamily.l_type = 'CHIL' AND" .
+ " parentfamily.l_type = '{$sex_field}' AND" .
+ " childfamily.l_from = parentfamily.l_from AND" .
+ " parentfamily.l_file = {$this->tree->getTreeId()} AND" .
+ " birth.d_fact = 'BIRT' AND" .
+ " childbirth.d_fact = 'BIRT' AND" .
+ " birth.d_julianday1 <> 0 AND" .
+ " childbirth.d_julianday2 > birth.d_julianday1" .
+ " ORDER BY age {$age_dir} LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ if (isset($row['id'])) {
+ $person = Individual::getInstance($row['id'], $this->tree);
+ }
+ switch ($type) {
+ default:
+ case 'full':
+ if ($person->canShow()) {
+ $result = $person->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'name':
+ $result = '<a href="' . e($person->url()) . '">' . $person->getFullName() . '</a>';
+ break;
+ case 'age':
+ $age = $row['age'];
+ if ($show_years) {
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $result = FunctionsDate::getAgeAtEvent($age);
+ } else {
+ $result = (int)($age / 365.25);
+ }
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * General query on marriages.
- *
- * @param bool $simple
- * @param bool $first
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return string|array
- */
- public function statsMarrQuery($simple = true, $first = false, $year1 = -1, $year2 = -1, $params = []) {
- $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');
+ /**
+ * General query on marriages.
+ *
+ * @param bool $simple
+ * @param bool $first
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return string|array
+ */
+ public function statsMarrQuery($simple = true, $first = false, $year1 = -1, $year2 = -1, $params = [])
+ {
+ $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 ($simple) {
- $sql =
- "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total" .
- " FROM `##dates`" .
- " WHERE d_file={$this->tree->getTreeId()} AND d_year<>0 AND d_fact='MARR' AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- $sql .= " GROUP BY century ORDER BY century";
- } elseif ($first) {
- $years = '';
- if ($year1 >= 0 && $year2 >= 0) {
- $years = " married.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
- }
- $sql =
- " SELECT fam.f_id AS fams, fam.f_husb, fam.f_wife, married.d_julianday2 AS age, married.d_month AS month, indi.i_id AS indi" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " married.d_gid = fam.f_id AND" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " married.d_fact = 'MARR' AND" .
- " married.d_julianday2 <> 0 AND" .
- $years .
- " (indi.i_id = fam.f_husb OR indi.i_id = fam.f_wife)" .
- " ORDER BY fams, indi, age ASC";
- } else {
- $sql =
- "SELECT d_month, COUNT(*) AS total" .
- " FROM `##dates`" .
- " WHERE d_file={$this->tree->getTreeId()} AND d_fact='MARR'";
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- $sql .= " GROUP BY d_month";
- }
- $rows = $this->runSql($sql);
- if (!isset($rows)) {
- return '';
- }
- if ($simple) {
- 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;
- }
- $sizes = explode('x', $size);
- $tot = 0;
- foreach ($rows as $values) {
- $tot += (int) $values['total'];
- }
- // Beware divide by zero
- if ($tot === 0) {
- return '';
- }
- $centuries = '';
- $counts = [];
- foreach ($rows as $values) {
- $counts[] = round(100 * $values['total'] / $tot, 0);
- $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chl = substr($centuries, 0, -1);
+ if ($simple) {
+ $sql =
+ "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total" .
+ " FROM `##dates`" .
+ " WHERE d_file={$this->tree->getTreeId()} AND d_year<>0 AND d_fact='MARR' AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ $sql .= " GROUP BY century ORDER BY century";
+ } elseif ($first) {
+ $years = '';
+ if ($year1 >= 0 && $year2 >= 0) {
+ $years = " married.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
+ }
+ $sql =
+ " SELECT fam.f_id AS fams, fam.f_husb, fam.f_wife, married.d_julianday2 AS age, married.d_month AS month, indi.i_id AS indi" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " married.d_gid = fam.f_id AND" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " married.d_fact = 'MARR' AND" .
+ " married.d_julianday2 <> 0 AND" .
+ $years .
+ " (indi.i_id = fam.f_husb OR indi.i_id = fam.f_wife)" .
+ " ORDER BY fams, indi, age ASC";
+ } else {
+ $sql =
+ "SELECT d_month, COUNT(*) AS total" .
+ " FROM `##dates`" .
+ " WHERE d_file={$this->tree->getTreeId()} AND d_fact='MARR'";
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ $sql .= " GROUP BY d_month";
+ }
+ $rows = $this->runSql($sql);
+ if (!isset($rows)) {
+ return '';
+ }
+ if ($simple) {
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = 0;
+ foreach ($rows as $values) {
+ $tot += (int)$values['total'];
+ }
+ // Beware divide by zero
+ if ($tot === 0) {
+ return '';
+ }
+ $centuries = '';
+ $counts = [];
+ foreach ($rows as $values) {
+ $counts[] = round(100 * $values['total'] / $tot, 0);
+ $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chl = substr($centuries, 0, -1);
- 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Marriages by century') . '" title="' . I18N::translate('Marriages by century') . '" />';
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Marriages by century') . '" title="' . I18N::translate('Marriages by century') . '" />';
+ }
- return $rows;
- }
+ return $rows;
+ }
- /**
- * General query on divorces.
- *
- * @param bool $simple
- * @param bool $first
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return string|array
- */
- private function statsDivQuery($simple = true, $first = false, $year1 = -1, $year2 = -1, $params = []) {
- $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');
+ /**
+ * General query on divorces.
+ *
+ * @param bool $simple
+ * @param bool $first
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return string|array
+ */
+ private function statsDivQuery($simple = true, $first = false, $year1 = -1, $year2 = -1, $params = [])
+ {
+ $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 ($simple) {
- $sql =
- "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total" .
- " FROM `##dates`" .
- " WHERE d_file={$this->tree->getTreeId()} AND d_year<>0 AND d_fact = 'DIV' AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- $sql .= " GROUP BY century ORDER BY century";
- } elseif ($first) {
- $years = '';
- if ($year1 >= 0 && $year2 >= 0) {
- $years = " divorced.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
- }
- $sql =
- " SELECT fam.f_id AS fams, fam.f_husb, fam.f_wife, divorced.d_julianday2 AS age, divorced.d_month AS month, indi.i_id AS indi" .
- " FROM `##families` AS fam" .
- " LEFT JOIN `##dates` AS divorced ON divorced.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " divorced.d_gid = fam.f_id AND" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- " divorced.d_fact = 'DIV' AND" .
- " divorced.d_julianday2 <> 0 AND" .
- $years .
- " (indi.i_id = fam.f_husb OR indi.i_id = fam.f_wife)" .
- " ORDER BY fams, indi, age ASC";
- } else {
- $sql =
- "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
- "WHERE d_file={$this->tree->getTreeId()} AND d_fact = 'DIV'";
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
- }
- $sql .= " GROUP BY d_month";
- }
- $rows = $this->runSql($sql);
- if (!isset($rows)) {
- return '';
- }
- if ($simple) {
- 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;
- }
- $sizes = explode('x', $size);
- $tot = 0;
- foreach ($rows as $values) {
- $tot += (int) $values['total'];
- }
- // Beware divide by zero
- if ($tot === 0) {
- return '';
- }
- $centuries = '';
- $counts = [];
- foreach ($rows as $values) {
- $counts[] = round(100 * $values['total'] / $tot, 0);
- $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chl = substr($centuries, 0, -1);
+ if ($simple) {
+ $sql =
+ "SELECT FLOOR(d_year/100+1) AS century, COUNT(*) AS total" .
+ " FROM `##dates`" .
+ " WHERE d_file={$this->tree->getTreeId()} AND d_year<>0 AND d_fact = 'DIV' AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')";
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ $sql .= " GROUP BY century ORDER BY century";
+ } elseif ($first) {
+ $years = '';
+ if ($year1 >= 0 && $year2 >= 0) {
+ $years = " divorced.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
+ }
+ $sql =
+ " SELECT fam.f_id AS fams, fam.f_husb, fam.f_wife, divorced.d_julianday2 AS age, divorced.d_month AS month, indi.i_id AS indi" .
+ " FROM `##families` AS fam" .
+ " LEFT JOIN `##dates` AS divorced ON divorced.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##individuals` AS indi ON indi.i_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " divorced.d_gid = fam.f_id AND" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ " divorced.d_fact = 'DIV' AND" .
+ " divorced.d_julianday2 <> 0 AND" .
+ $years .
+ " (indi.i_id = fam.f_husb OR indi.i_id = fam.f_wife)" .
+ " ORDER BY fams, indi, age ASC";
+ } else {
+ $sql =
+ "SELECT d_month, COUNT(*) AS total FROM `##dates` " .
+ "WHERE d_file={$this->tree->getTreeId()} AND d_fact = 'DIV'";
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'";
+ }
+ $sql .= " GROUP BY d_month";
+ }
+ $rows = $this->runSql($sql);
+ if (!isset($rows)) {
+ return '';
+ }
+ if ($simple) {
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = 0;
+ foreach ($rows as $values) {
+ $tot += (int)$values['total'];
+ }
+ // Beware divide by zero
+ if ($tot === 0) {
+ return '';
+ }
+ $centuries = '';
+ $counts = [];
+ foreach ($rows as $values) {
+ $counts[] = round(100 * $values['total'] / $tot, 0);
+ $centuries .= $this->centuryName($values['century']) . ' - ' . I18N::number($values['total']) . '|';
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chl = substr($centuries, 0, -1);
- 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Divorces by century') . '" title="' . I18N::translate('Divorces by century') . '" />';
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Divorces by century') . '" title="' . I18N::translate('Divorces by century') . '" />';
+ }
- return $rows;
- }
+ return $rows;
+ }
- /**
- * Find the earliest marriage.
- *
- * @return string
- */
- public function firstMarriage() {
- return $this->mortalityQuery('full', 'ASC', 'MARR');
- }
+ /**
+ * Find the earliest marriage.
+ *
+ * @return string
+ */
+ public function firstMarriage()
+ {
+ return $this->mortalityQuery('full', 'ASC', 'MARR');
+ }
- /**
- * Find the year of the earliest marriage.
- *
- * @return string
- */
- public function firstMarriageYear() {
- return $this->mortalityQuery('year', 'ASC', 'MARR');
- }
+ /**
+ * Find the year of the earliest marriage.
+ *
+ * @return string
+ */
+ public function firstMarriageYear()
+ {
+ return $this->mortalityQuery('year', 'ASC', 'MARR');
+ }
- /**
- * Find the names of spouses of the earliest marriage.
- *
- * @return string
- */
- public function firstMarriageName() {
- return $this->mortalityQuery('name', 'ASC', 'MARR');
- }
+ /**
+ * Find the names of spouses of the earliest marriage.
+ *
+ * @return string
+ */
+ public function firstMarriageName()
+ {
+ return $this->mortalityQuery('name', 'ASC', 'MARR');
+ }
- /**
- * Find the place of the earliest marriage.
- *
- * @return string
- */
- public function firstMarriagePlace() {
- return $this->mortalityQuery('place', 'ASC', 'MARR');
- }
+ /**
+ * Find the place of the earliest marriage.
+ *
+ * @return string
+ */
+ public function firstMarriagePlace()
+ {
+ return $this->mortalityQuery('place', 'ASC', 'MARR');
+ }
- /**
- * Find the latest marriage.
- *
- * @return string
- */
- public function lastMarriage() {
- return $this->mortalityQuery('full', 'DESC', 'MARR');
- }
+ /**
+ * Find the latest marriage.
+ *
+ * @return string
+ */
+ public function lastMarriage()
+ {
+ return $this->mortalityQuery('full', 'DESC', 'MARR');
+ }
- /**
- * Find the year of the latest marriage.
- *
- * @return string
- */
- public function lastMarriageYear() {
- return $this->mortalityQuery('year', 'DESC', 'MARR');
- }
+ /**
+ * Find the year of the latest marriage.
+ *
+ * @return string
+ */
+ public function lastMarriageYear()
+ {
+ return $this->mortalityQuery('year', 'DESC', 'MARR');
+ }
- /**
- * Find the names of spouses of the latest marriage.
- *
- * @return string
- */
- public function lastMarriageName() {
- return $this->mortalityQuery('name', 'DESC', 'MARR');
- }
+ /**
+ * Find the names of spouses of the latest marriage.
+ *
+ * @return string
+ */
+ public function lastMarriageName()
+ {
+ return $this->mortalityQuery('name', 'DESC', 'MARR');
+ }
- /**
- * Find the location of the latest marriage.
- *
- * @return string
- */
- public function lastMarriagePlace() {
- return $this->mortalityQuery('place', 'DESC', 'MARR');
- }
+ /**
+ * Find the location of the latest marriage.
+ *
+ * @return string
+ */
+ public function lastMarriagePlace()
+ {
+ return $this->mortalityQuery('place', 'DESC', 'MARR');
+ }
- /**
- * General query on marriages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsMarr($params = []) {
- return $this->statsMarrQuery(true, false, -1, -1, $params);
- }
+ /**
+ * General query on marriages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsMarr($params = [])
+ {
+ return $this->statsMarrQuery(true, false, -1, -1, $params);
+ }
- /**
- * Find the earliest divorce.
- *
- * @return string
- */
- public function firstDivorce() {
- return $this->mortalityQuery('full', 'ASC', 'DIV');
- }
+ /**
+ * Find the earliest divorce.
+ *
+ * @return string
+ */
+ public function firstDivorce()
+ {
+ return $this->mortalityQuery('full', 'ASC', 'DIV');
+ }
- /**
- * Find the year of the earliest divorce.
- *
- * @return string
- */
- public function firstDivorceYear() {
- return $this->mortalityQuery('year', 'ASC', 'DIV');
- }
+ /**
+ * Find the year of the earliest divorce.
+ *
+ * @return string
+ */
+ public function firstDivorceYear()
+ {
+ return $this->mortalityQuery('year', 'ASC', 'DIV');
+ }
- /**
- * Find the names of individuals in the earliest divorce.
- *
- * @return string
- */
- public function firstDivorceName() {
- return $this->mortalityQuery('name', 'ASC', 'DIV');
- }
+ /**
+ * Find the names of individuals in the earliest divorce.
+ *
+ * @return string
+ */
+ public function firstDivorceName()
+ {
+ return $this->mortalityQuery('name', 'ASC', 'DIV');
+ }
- /**
- * Find the location of the earliest divorce.
- *
- * @return string
- */
- public function firstDivorcePlace() {
- return $this->mortalityQuery('place', 'ASC', 'DIV');
- }
+ /**
+ * Find the location of the earliest divorce.
+ *
+ * @return string
+ */
+ public function firstDivorcePlace()
+ {
+ return $this->mortalityQuery('place', 'ASC', 'DIV');
+ }
- /**
- * Find the latest divorce.
- *
- * @return string
- */
- public function lastDivorce() {
- return $this->mortalityQuery('full', 'DESC', 'DIV');
- }
+ /**
+ * Find the latest divorce.
+ *
+ * @return string
+ */
+ public function lastDivorce()
+ {
+ return $this->mortalityQuery('full', 'DESC', 'DIV');
+ }
- /**
- * Find the year of the latest divorce.
- *
- * @return string
- */
- public function lastDivorceYear() {
- return $this->mortalityQuery('year', 'DESC', 'DIV');
- }
+ /**
+ * Find the year of the latest divorce.
+ *
+ * @return string
+ */
+ public function lastDivorceYear()
+ {
+ return $this->mortalityQuery('year', 'DESC', 'DIV');
+ }
- /**
- * Find the names of the individuals in the latest divorce.
- *
- * @return string
- */
- public function lastDivorceName() {
- return $this->mortalityQuery('name', 'DESC', 'DIV');
- }
+ /**
+ * Find the names of the individuals in the latest divorce.
+ *
+ * @return string
+ */
+ public function lastDivorceName()
+ {
+ return $this->mortalityQuery('name', 'DESC', 'DIV');
+ }
- /**
- * Find the location of the latest divorce.
- *
- * @return string
- */
- public function lastDivorcePlace() {
- return $this->mortalityQuery('place', 'DESC', 'DIV');
- }
+ /**
+ * Find the location of the latest divorce.
+ *
+ * @return string
+ */
+ public function lastDivorcePlace()
+ {
+ return $this->mortalityQuery('place', 'DESC', 'DIV');
+ }
- /**
- * General divorce query.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsDiv($params = []) {
- return $this->statsDivQuery(true, false, -1, -1, $params);
- }
+ /**
+ * General divorce query.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsDiv($params = [])
+ {
+ return $this->statsDivQuery(true, false, -1, -1, $params);
+ }
- /**
- * General query on ages at marriage.
- *
- * @param bool $simple
- * @param string $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return array|string
- */
- public function statsMarrAgeQuery($simple = true, $sex = 'M', $year1 = -1, $year2 = -1, $params = []) {
- if ($simple) {
- if (isset($params[0]) && $params[0] != '') {
- $size = strtolower($params[0]);
- } else {
- $size = '200x250';
- }
- $sizes = explode('x', $size);
- $rows = $this->runSql(
- "SELECT " .
- " ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, " .
- " FLOOR(married.d_year/100+1) AS century, " .
- " 'M' AS sex " .
- "FROM `##dates` AS married " .
- "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
- "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_husb AND birth.d_file=fam.f_file) " .
- "WHERE " .
- " '{$sex}' IN ('M', 'BOTH') AND " .
- " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
- " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
- "GROUP BY century, sex " .
- "UNION ALL " .
- "SELECT " .
- " ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, " .
- " FLOOR(married.d_year/100+1) AS century, " .
- " 'F' AS sex " .
- "FROM `##dates` AS married " .
- "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
- "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_wife AND birth.d_file=fam.f_file) " .
- "WHERE " .
- " '{$sex}' IN ('F', 'BOTH') AND " .
- " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
- " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
- " GROUP BY century, sex ORDER BY century"
- );
- if (empty($rows)) {
- return '';
- }
- $max = 0;
- foreach ($rows as $values) {
- if ($max < $values['age']) {
- $max = $values['age'];
- }
- }
- $chxl = '0:|';
- $chmm = '';
- $chmf = '';
- $i = 0;
- $countsm = '';
- $countsf = '';
- $countsa = '';
- $out = [];
- foreach ($rows as $values) {
- $out[$values['century']][$values['sex']] = $values['age'];
- }
- foreach ($out as $century => $values) {
- if ($sizes[0] < 1000) {
- $sizes[0] += 50;
- }
- $chxl .= $this->centuryName($century) . '|';
- $average = 0;
- if (isset($values['F'])) {
- if ($max <= 50) {
- $value = $values['F'] * 2;
- } else {
- $value = $values['F'];
- }
- $countsf .= $value . ',';
- $average = $value;
- $chmf .= 't' . $values['F'] . ',000000,1,' . $i . ',11,1|';
- } else {
- $countsf .= '0,';
- $chmf .= 't0,000000,1,' . $i . ',11,1|';
- }
- if (isset($values['M'])) {
- if ($max <= 50) {
- $value = $values['M'] * 2;
- } else {
- $value = $values['M'];
- }
- $countsm .= $value . ',';
- if ($average == 0) {
- $countsa .= $value . ',';
- } else {
- $countsa .= (($value + $average) / 2) . ',';
- }
- $chmm .= 't' . $values['M'] . ',000000,0,' . $i . ',11,1|';
- } else {
- $countsm .= '0,';
- if ($average == 0) {
- $countsa .= '0,';
- } else {
- $countsa .= $value . ',';
- }
- $chmm .= 't0,000000,0,' . $i . ',11,1|';
- }
- $i++;
- }
- $countsm = substr($countsm, 0, -1);
- $countsf = substr($countsf, 0, -1);
- $countsa = substr($countsa, 0, -1);
- $chmf = substr($chmf, 0, -1);
- $chd = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
- if ($max <= 50) {
- $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|3:||' . I18N::translate('Age') . '|';
- } else {
- $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|60|70|80|90|100|3:||' . I18N::translate('Age') . '|';
- }
- if (count($rows) > 4 || mb_strlen(I18N::translate('Average age in century of marriage')) < 30) {
- $chtt = I18N::translate('Average age in century of marriage');
- } else {
- $offset = 0;
- $counter = [];
- while ($offset = strpos(I18N::translate('Average age in century of marriage'), ' ', $offset + 1)) {
- $counter[] = $offset;
- }
- $half = (int) (count($counter) / 2);
- $chtt = substr_replace(I18N::translate('Average age in century of marriage'), '|', $counter[$half], 1);
- }
+ /**
+ * General query on ages at marriage.
+ *
+ * @param bool $simple
+ * @param string $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return array|string
+ */
+ public function statsMarrAgeQuery($simple = true, $sex = 'M', $year1 = -1, $year2 = -1, $params = [])
+ {
+ if ($simple) {
+ if (isset($params[0]) && $params[0] != '') {
+ $size = strtolower($params[0]);
+ } else {
+ $size = '200x250';
+ }
+ $sizes = explode('x', $size);
+ $rows = $this->runSql(
+ "SELECT " .
+ " ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, " .
+ " FLOOR(married.d_year/100+1) AS century, " .
+ " 'M' AS sex " .
+ "FROM `##dates` AS married " .
+ "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
+ "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_husb AND birth.d_file=fam.f_file) " .
+ "WHERE " .
+ " '{$sex}' IN ('M', 'BOTH') AND " .
+ " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
+ " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
+ "GROUP BY century, sex " .
+ "UNION ALL " .
+ "SELECT " .
+ " ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, " .
+ " FLOOR(married.d_year/100+1) AS century, " .
+ " 'F' AS sex " .
+ "FROM `##dates` AS married " .
+ "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
+ "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_wife AND birth.d_file=fam.f_file) " .
+ "WHERE " .
+ " '{$sex}' IN ('F', 'BOTH') AND " .
+ " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
+ " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
+ " GROUP BY century, sex ORDER BY century"
+ );
+ if (empty($rows)) {
+ return '';
+ }
+ $max = 0;
+ foreach ($rows as $values) {
+ if ($max < $values['age']) {
+ $max = $values['age'];
+ }
+ }
+ $chxl = '0:|';
+ $chmm = '';
+ $chmf = '';
+ $i = 0;
+ $countsm = '';
+ $countsf = '';
+ $countsa = '';
+ $out = [];
+ foreach ($rows as $values) {
+ $out[$values['century']][$values['sex']] = $values['age'];
+ }
+ foreach ($out as $century => $values) {
+ if ($sizes[0] < 1000) {
+ $sizes[0] += 50;
+ }
+ $chxl .= $this->centuryName($century) . '|';
+ $average = 0;
+ if (isset($values['F'])) {
+ if ($max <= 50) {
+ $value = $values['F'] * 2;
+ } else {
+ $value = $values['F'];
+ }
+ $countsf .= $value . ',';
+ $average = $value;
+ $chmf .= 't' . $values['F'] . ',000000,1,' . $i . ',11,1|';
+ } else {
+ $countsf .= '0,';
+ $chmf .= 't0,000000,1,' . $i . ',11,1|';
+ }
+ if (isset($values['M'])) {
+ if ($max <= 50) {
+ $value = $values['M'] * 2;
+ } else {
+ $value = $values['M'];
+ }
+ $countsm .= $value . ',';
+ if ($average == 0) {
+ $countsa .= $value . ',';
+ } else {
+ $countsa .= (($value + $average) / 2) . ',';
+ }
+ $chmm .= 't' . $values['M'] . ',000000,0,' . $i . ',11,1|';
+ } else {
+ $countsm .= '0,';
+ if ($average == 0) {
+ $countsa .= '0,';
+ } else {
+ $countsa .= $value . ',';
+ }
+ $chmm .= 't0,000000,0,' . $i . ',11,1|';
+ }
+ $i++;
+ }
+ $countsm = substr($countsm, 0, -1);
+ $countsf = substr($countsf, 0, -1);
+ $countsa = substr($countsa, 0, -1);
+ $chmf = substr($chmf, 0, -1);
+ $chd = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
+ if ($max <= 50) {
+ $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|3:||' . I18N::translate('Age') . '|';
+ } else {
+ $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|60|70|80|90|100|3:||' . I18N::translate('Age') . '|';
+ }
+ if (count($rows) > 4 || mb_strlen(I18N::translate('Average age in century of marriage')) < 30) {
+ $chtt = I18N::translate('Average age in century of marriage');
+ } else {
+ $offset = 0;
+ $counter = [];
+ while ($offset = strpos(I18N::translate('Average age in century of marriage'), ' ', $offset + 1)) {
+ $counter[] = $offset;
+ }
+ $half = (int)(count($counter) / 2);
+ $chtt = substr_replace(I18N::translate('Average age in century of marriage'), '|', $counter[$half], 1);
+ }
- return '<img src="' . "https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chm=D,FF0000,2,0,3,1|{$chmm}{$chmf}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chtt=" . rawurlencode($chtt) . "&amp;chd={$chd}&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . '&amp;chdl=' . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age')) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average age in century of marriage') . '" title="' . I18N::translate('Average age in century of marriage') . '" />';
- } else {
- if ($year1 >= 0 && $year2 >= 0) {
- $years = " married.d_year BETWEEN {$year1} AND {$year2} AND ";
- } else {
- $years = '';
- }
- $rows = $this->runSql(
- "SELECT " .
- " fam.f_id, " .
- " birth.d_gid, " .
- " married.d_julianday2-birth.d_julianday1 AS age " .
- "FROM `##dates` AS married " .
- "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
- "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_husb AND birth.d_file=fam.f_file) " .
- "WHERE " .
- " '{$sex}' IN ('M', 'BOTH') AND {$years} " .
- " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
- " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
- "UNION ALL " .
- "SELECT " .
- " fam.f_id, " .
- " birth.d_gid, " .
- " married.d_julianday2-birth.d_julianday1 AS age " .
- "FROM `##dates` AS married " .
- "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
- "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_wife AND birth.d_file=fam.f_file) " .
- "WHERE " .
- " '{$sex}' IN ('F', 'BOTH') AND {$years} " .
- " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
- " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
- " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 "
- );
+ return '<img src="' . "https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chm=D,FF0000,2,0,3,1|{$chmm}{$chmf}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chtt=" . rawurlencode($chtt) . "&amp;chd={$chd}&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . '&amp;chdl=' . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age')) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average age in century of marriage') . '" title="' . I18N::translate('Average age in century of marriage') . '" />';
+ } else {
+ if ($year1 >= 0 && $year2 >= 0) {
+ $years = " married.d_year BETWEEN {$year1} AND {$year2} AND ";
+ } else {
+ $years = '';
+ }
+ $rows = $this->runSql(
+ "SELECT " .
+ " fam.f_id, " .
+ " birth.d_gid, " .
+ " married.d_julianday2-birth.d_julianday1 AS age " .
+ "FROM `##dates` AS married " .
+ "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
+ "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_husb AND birth.d_file=fam.f_file) " .
+ "WHERE " .
+ " '{$sex}' IN ('M', 'BOTH') AND {$years} " .
+ " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
+ " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 " .
+ "UNION ALL " .
+ "SELECT " .
+ " fam.f_id, " .
+ " birth.d_gid, " .
+ " married.d_julianday2-birth.d_julianday1 AS age " .
+ "FROM `##dates` AS married " .
+ "JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) " .
+ "JOIN `##dates` AS birth ON (birth.d_gid=fam.f_wife AND birth.d_file=fam.f_file) " .
+ "WHERE " .
+ " '{$sex}' IN ('F', 'BOTH') AND {$years} " .
+ " married.d_file={$this->tree->getTreeId()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " .
+ " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " .
+ " married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 "
+ );
- return $rows;
- }
- }
+ return $rows;
+ }
+ }
- /**
- * Find the youngest wife.
- *
- * @return string
- */
- public function youngestMarriageFemale() {
- return $this->marriageQuery('full', 'ASC', 'F', false);
- }
+ /**
+ * Find the youngest wife.
+ *
+ * @return string
+ */
+ public function youngestMarriageFemale()
+ {
+ return $this->marriageQuery('full', 'ASC', 'F', false);
+ }
- /**
- * Find the name of the youngest wife.
- *
- * @return string
- */
- public function youngestMarriageFemaleName() {
- return $this->marriageQuery('name', 'ASC', 'F', false);
- }
+ /**
+ * Find the name of the youngest wife.
+ *
+ * @return string
+ */
+ public function youngestMarriageFemaleName()
+ {
+ return $this->marriageQuery('name', 'ASC', 'F', false);
+ }
- /**
- * Find the age of the youngest wife.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function youngestMarriageFemaleAge($show_years = false) {
- return $this->marriageQuery('age', 'ASC', 'F', $show_years);
- }
+ /**
+ * Find the age of the youngest wife.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function youngestMarriageFemaleAge($show_years = false)
+ {
+ return $this->marriageQuery('age', 'ASC', 'F', $show_years);
+ }
- /**
- * Find the oldest wife.
- *
- * @return string
- */
- public function oldestMarriageFemale() {
- return $this->marriageQuery('full', 'DESC', 'F', false);
- }
+ /**
+ * Find the oldest wife.
+ *
+ * @return string
+ */
+ public function oldestMarriageFemale()
+ {
+ return $this->marriageQuery('full', 'DESC', 'F', false);
+ }
- /**
- * Find the name of the oldest wife.
- *
- * @return string
- */
- public function oldestMarriageFemaleName() {
- return $this->marriageQuery('name', 'DESC', 'F', false);
- }
+ /**
+ * Find the name of the oldest wife.
+ *
+ * @return string
+ */
+ public function oldestMarriageFemaleName()
+ {
+ return $this->marriageQuery('name', 'DESC', 'F', false);
+ }
- /**
- * Find the age of the oldest wife.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function oldestMarriageFemaleAge($show_years = false) {
- return $this->marriageQuery('age', 'DESC', 'F', $show_years);
- }
+ /**
+ * Find the age of the oldest wife.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function oldestMarriageFemaleAge($show_years = false)
+ {
+ return $this->marriageQuery('age', 'DESC', 'F', $show_years);
+ }
- /**
- * Find the youngest husband.
- *
- * @return string
- */
- public function youngestMarriageMale() {
- return $this->marriageQuery('full', 'ASC', 'M', false);
- }
+ /**
+ * Find the youngest husband.
+ *
+ * @return string
+ */
+ public function youngestMarriageMale()
+ {
+ return $this->marriageQuery('full', 'ASC', 'M', false);
+ }
- /**
- * Find the name of the youngest husband.
- *
- * @return string
- */
- public function youngestMarriageMaleName() {
- return $this->marriageQuery('name', 'ASC', 'M', false);
- }
+ /**
+ * Find the name of the youngest husband.
+ *
+ * @return string
+ */
+ public function youngestMarriageMaleName()
+ {
+ return $this->marriageQuery('name', 'ASC', 'M', false);
+ }
- /**
- * Find the age of the youngest husband.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function youngestMarriageMaleAge($show_years = false) {
- return $this->marriageQuery('age', 'ASC', 'M', $show_years);
- }
+ /**
+ * Find the age of the youngest husband.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function youngestMarriageMaleAge($show_years = false)
+ {
+ return $this->marriageQuery('age', 'ASC', 'M', $show_years);
+ }
- /**
- * Find the oldest husband.
- *
- * @return string
- */
- public function oldestMarriageMale() {
- return $this->marriageQuery('full', 'DESC', 'M', false);
- }
+ /**
+ * Find the oldest husband.
+ *
+ * @return string
+ */
+ public function oldestMarriageMale()
+ {
+ return $this->marriageQuery('full', 'DESC', 'M', false);
+ }
- /**
- * Find the name of the oldest husband.
- *
- * @return string
- */
- public function oldestMarriageMaleName() {
- return $this->marriageQuery('name', 'DESC', 'M', false);
- }
+ /**
+ * Find the name of the oldest husband.
+ *
+ * @return string
+ */
+ public function oldestMarriageMaleName()
+ {
+ return $this->marriageQuery('name', 'DESC', 'M', false);
+ }
- /**
- * Find the age of the oldest husband.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function oldestMarriageMaleAge($show_years = false) {
- return $this->marriageQuery('age', 'DESC', 'M', $show_years);
- }
+ /**
+ * Find the age of the oldest husband.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function oldestMarriageMaleAge($show_years = false)
+ {
+ return $this->marriageQuery('age', 'DESC', 'M', $show_years);
+ }
- /**
- * General query on marriage ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsMarrAge($params = []) {
- return $this->statsMarrAgeQuery(true, 'BOTH', -1, -1, $params);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsMarrAge($params = [])
+ {
+ return $this->statsMarrAgeQuery(true, 'BOTH', -1, -1, $params);
+ }
- /**
- * Find the age between husband and wife.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function ageBetweenSpousesMF($params = []) {
- return $this->ageBetweenSpousesQuery('nolist', 'DESC', $params);
- }
+ /**
+ * Find the age between husband and wife.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function ageBetweenSpousesMF($params = [])
+ {
+ return $this->ageBetweenSpousesQuery('nolist', 'DESC', $params);
+ }
- /**
- * Find the age between husband and wife.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function ageBetweenSpousesMFList($params = []) {
- return $this->ageBetweenSpousesQuery('list', 'DESC', $params);
- }
+ /**
+ * Find the age between husband and wife.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function ageBetweenSpousesMFList($params = [])
+ {
+ return $this->ageBetweenSpousesQuery('list', 'DESC', $params);
+ }
- /**
- * Find the age between wife and husband..
- *
- * @param string[] $params
- *
- * @return string
- */
- public function ageBetweenSpousesFM($params = []) {
- return $this->ageBetweenSpousesQuery('nolist', 'ASC', $params);
- }
+ /**
+ * Find the age between wife and husband..
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function ageBetweenSpousesFM($params = [])
+ {
+ return $this->ageBetweenSpousesQuery('nolist', 'ASC', $params);
+ }
- /**
- * Find the age between wife and husband..
- *
- * @param string[] $params
- *
- * @return string
- */
- public function ageBetweenSpousesFMList($params = []) {
- return $this->ageBetweenSpousesQuery('list', 'ASC', $params);
- }
+ /**
+ * Find the age between wife and husband..
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function ageBetweenSpousesFMList($params = [])
+ {
+ return $this->ageBetweenSpousesQuery('list', 'ASC', $params);
+ }
- /**
- * General query on marriage ages.
- *
- * @return string
- */
- public function topAgeOfMarriageFamily() {
- return $this->ageOfMarriageQuery('name', 'DESC', ['1']);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @return string
+ */
+ public function topAgeOfMarriageFamily()
+ {
+ return $this->ageOfMarriageQuery('name', 'DESC', ['1']);
+ }
- /**
- * General query on marriage ages.
- *
- * @return string
- */
- public function topAgeOfMarriage() {
- return $this->ageOfMarriageQuery('age', 'DESC', ['1']);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @return string
+ */
+ public function topAgeOfMarriage()
+ {
+ return $this->ageOfMarriageQuery('age', 'DESC', ['1']);
+ }
- /**
- * General query on marriage ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeOfMarriageFamilies($params = []) {
- return $this->ageOfMarriageQuery('nolist', 'DESC', $params);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeOfMarriageFamilies($params = [])
+ {
+ return $this->ageOfMarriageQuery('nolist', 'DESC', $params);
+ }
- /**
- * General query on marriage ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeOfMarriageFamiliesList($params = []) {
- return $this->ageOfMarriageQuery('list', 'DESC', $params);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeOfMarriageFamiliesList($params = [])
+ {
+ return $this->ageOfMarriageQuery('list', 'DESC', $params);
+ }
- /**
- * General query on marriage ages.
- *
- * @return string
- */
- public function minAgeOfMarriageFamily() {
- return $this->ageOfMarriageQuery('name', 'ASC', ['1']);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @return string
+ */
+ public function minAgeOfMarriageFamily()
+ {
+ return $this->ageOfMarriageQuery('name', 'ASC', ['1']);
+ }
- /**
- * General query on marriage ages.
- *
- * @return string
- */
- public function minAgeOfMarriage() {
- return $this->ageOfMarriageQuery('age', 'ASC', ['1']);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @return string
+ */
+ public function minAgeOfMarriage()
+ {
+ return $this->ageOfMarriageQuery('age', 'ASC', ['1']);
+ }
- /**
- * General query on marriage ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function minAgeOfMarriageFamilies($params = []) {
- return $this->ageOfMarriageQuery('nolist', 'ASC', $params);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function minAgeOfMarriageFamilies($params = [])
+ {
+ return $this->ageOfMarriageQuery('nolist', 'ASC', $params);
+ }
- /**
- * General query on marriage ages.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function minAgeOfMarriageFamiliesList($params = []) {
- return $this->ageOfMarriageQuery('list', 'ASC', $params);
- }
+ /**
+ * General query on marriage ages.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function minAgeOfMarriageFamiliesList($params = [])
+ {
+ return $this->ageOfMarriageQuery('list', 'ASC', $params);
+ }
- /**
- * Find the youngest mother
- *
- * @return string
- */
- public function youngestMother() {
- return $this->parentsQuery('full', 'ASC', 'F');
- }
+ /**
+ * Find the youngest mother
+ *
+ * @return string
+ */
+ public function youngestMother()
+ {
+ return $this->parentsQuery('full', 'ASC', 'F');
+ }
- /**
- * Find the name of the youngest mother.
- *
- * @return string
- */
- public function youngestMotherName() {
- return $this->parentsQuery('name', 'ASC', 'F');
- }
+ /**
+ * Find the name of the youngest mother.
+ *
+ * @return string
+ */
+ public function youngestMotherName()
+ {
+ return $this->parentsQuery('name', 'ASC', 'F');
+ }
- /**
- * Find the age of the youngest mother.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function youngestMotherAge($show_years = false) {
- return $this->parentsQuery('age', 'ASC', 'F', $show_years);
- }
+ /**
+ * Find the age of the youngest mother.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function youngestMotherAge($show_years = false)
+ {
+ return $this->parentsQuery('age', 'ASC', 'F', $show_years);
+ }
- /**
- * Find the oldest mother.
- *
- * @return string
- */
- public function oldestMother() {
- return $this->parentsQuery('full', 'DESC', 'F');
- }
+ /**
+ * Find the oldest mother.
+ *
+ * @return string
+ */
+ public function oldestMother()
+ {
+ return $this->parentsQuery('full', 'DESC', 'F');
+ }
- /**
- * Find the name of the oldest mother.
- *
- * @return string
- */
- public function oldestMotherName() {
- return $this->parentsQuery('name', 'DESC', 'F');
- }
+ /**
+ * Find the name of the oldest mother.
+ *
+ * @return string
+ */
+ public function oldestMotherName()
+ {
+ return $this->parentsQuery('name', 'DESC', 'F');
+ }
- /**
- * Find the age of the oldest mother.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function oldestMotherAge($show_years = false) {
- return $this->parentsQuery('age', 'DESC', 'F', $show_years);
- }
+ /**
+ * Find the age of the oldest mother.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function oldestMotherAge($show_years = false)
+ {
+ return $this->parentsQuery('age', 'DESC', 'F', $show_years);
+ }
- /**
- * Find the youngest father.
- *
- * @return string
- */
- public function youngestFather() {
- return $this->parentsQuery('full', 'ASC', 'M');
- }
+ /**
+ * Find the youngest father.
+ *
+ * @return string
+ */
+ public function youngestFather()
+ {
+ return $this->parentsQuery('full', 'ASC', 'M');
+ }
- /**
- * Find the name of the youngest father.
- *
- * @return string
- */
- public function youngestFatherName() {
- return $this->parentsQuery('name', 'ASC', 'M');
- }
+ /**
+ * Find the name of the youngest father.
+ *
+ * @return string
+ */
+ public function youngestFatherName()
+ {
+ return $this->parentsQuery('name', 'ASC', 'M');
+ }
- /**
- * Find the age of the youngest father.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function youngestFatherAge($show_years = false) {
- return $this->parentsQuery('age', 'ASC', 'M', $show_years);
- }
+ /**
+ * Find the age of the youngest father.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function youngestFatherAge($show_years = false)
+ {
+ return $this->parentsQuery('age', 'ASC', 'M', $show_years);
+ }
- /**
- * Find the oldest father.
- *
- * @return string
- */
- public function oldestFather() {
- return $this->parentsQuery('full', 'DESC', 'M');
- }
+ /**
+ * Find the oldest father.
+ *
+ * @return string
+ */
+ public function oldestFather()
+ {
+ return $this->parentsQuery('full', 'DESC', 'M');
+ }
- /**
- * Find the name of the oldest father.
- *
- * @return string
- */
- public function oldestFatherName() {
- return $this->parentsQuery('name', 'DESC', 'M');
- }
+ /**
+ * Find the name of the oldest father.
+ *
+ * @return string
+ */
+ public function oldestFatherName()
+ {
+ return $this->parentsQuery('name', 'DESC', 'M');
+ }
- /**
- * Find the age of the oldest father.
- *
- * @param bool $show_years
- *
- * @return string
- */
- public function oldestFatherAge($show_years = false) {
- return $this->parentsQuery('age', 'DESC', 'M', $show_years);
- }
+ /**
+ * Find the age of the oldest father.
+ *
+ * @param bool $show_years
+ *
+ * @return string
+ */
+ public function oldestFatherAge($show_years = false)
+ {
+ return $this->parentsQuery('age', 'DESC', 'M', $show_years);
+ }
- /**
- * Number of husbands.
- *
- * @return string
- */
- public function totalMarriedMales() {
- $n = Database::prepare("SELECT COUNT(DISTINCT f_husb) FROM `##families` WHERE f_file=? AND f_gedcom LIKE '%\\n1 MARR%'")
- ->execute([$this->tree->getTreeId()])
- ->fetchOne();
+ /**
+ * Number of husbands.
+ *
+ * @return string
+ */
+ public function totalMarriedMales()
+ {
+ $n = Database::prepare("SELECT COUNT(DISTINCT f_husb) FROM `##families` WHERE f_file=? AND f_gedcom LIKE '%\\n1 MARR%'")
+ ->execute([$this->tree->getTreeId()])
+ ->fetchOne();
- return I18N::number($n);
- }
+ return I18N::number($n);
+ }
- /**
- * Number of wives.
- *
- * @return string
- */
- public function totalMarriedFemales() {
- $n = Database::prepare("SELECT COUNT(DISTINCT f_wife) FROM `##families` WHERE f_file=? AND f_gedcom LIKE '%\\n1 MARR%'")
- ->execute([$this->tree->getTreeId()])
- ->fetchOne();
+ /**
+ * Number of wives.
+ *
+ * @return string
+ */
+ public function totalMarriedFemales()
+ {
+ $n = Database::prepare("SELECT COUNT(DISTINCT f_wife) FROM `##families` WHERE f_file=? AND f_gedcom LIKE '%\\n1 MARR%'")
+ ->execute([$this->tree->getTreeId()])
+ ->fetchOne();
- return I18N::number($n);
- }
+ return I18N::number($n);
+ }
- /**
- * General query on family.
- *
- * @param string $type
- *
- * @return string
- */
- private function familyQuery($type = 'full') {
- $rows = $this->runSql(
- " SELECT f_numchil AS tot, f_id AS id" .
- " FROM `##families`" .
- " WHERE" .
- " f_file={$this->tree->getTreeId()}" .
- " AND f_numchil = (" .
- " SELECT max( f_numchil )" .
- " FROM `##families`" .
- " WHERE f_file ={$this->tree->getTreeId()}" .
- " )" .
- " LIMIT 1"
- );
- if (!isset($rows[0])) {
- return '';
- }
- $row = $rows[0];
- $family = Family::getInstance($row['id'], $this->tree);
- switch ($type) {
- default:
- case 'full':
- if ($family->canShow()) {
- $result = $family->formatList();
- } else {
- $result = I18N::translate('This information is private and cannot be shown.');
- }
- break;
- case 'size':
- $result = I18N::number($row['tot']);
- break;
- case 'name':
- $result = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a>';
- break;
- }
+ /**
+ * General query on family.
+ *
+ * @param string $type
+ *
+ * @return string
+ */
+ private function familyQuery($type = 'full')
+ {
+ $rows = $this->runSql(
+ " SELECT f_numchil AS tot, f_id AS id" .
+ " FROM `##families`" .
+ " WHERE" .
+ " f_file={$this->tree->getTreeId()}" .
+ " AND f_numchil = (" .
+ " SELECT max( f_numchil )" .
+ " FROM `##families`" .
+ " WHERE f_file ={$this->tree->getTreeId()}" .
+ " )" .
+ " LIMIT 1"
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $row = $rows[0];
+ $family = Family::getInstance($row['id'], $this->tree);
+ switch ($type) {
+ default:
+ case 'full':
+ if ($family->canShow()) {
+ $result = $family->formatList();
+ } else {
+ $result = I18N::translate('This information is private and cannot be shown.');
+ }
+ break;
+ case 'size':
+ $result = I18N::number($row['tot']);
+ break;
+ case 'name':
+ $result = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a>';
+ break;
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * General query on families.
- *
- * @param string $type
- * @param string[] $params
- *
- * @return string
- */
- private function topTenFamilyQuery($type = 'list', $params = []) {
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- $rows = $this->runSql(
- "SELECT f_numchil AS tot, f_id AS id" .
- " FROM `##families`" .
- " WHERE" .
- " f_file={$this->tree->getTreeId()}" .
- " ORDER BY tot DESC" .
- " LIMIT " . $total
- );
- if (!isset($rows[0])) {
- return '';
- }
- if (count($rows) < $total) {
- $total = count($rows);
- }
- $top10 = [];
- for ($c = 0; $c < $total; $c++) {
- $family = Family::getInstance($rows[$c]['id'], $this->tree);
- if ($family->canShow()) {
- if ($type === 'list') {
- $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s child', '%s children', $rows[$c]['tot'], I18N::number($rows[$c]['tot']));
- } else {
- $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s child', '%s children', $rows[$c]['tot'], I18N::number($rows[$c]['tot']));
- }
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode('; ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * General query on families.
+ *
+ * @param string $type
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function topTenFamilyQuery($type = 'list', $params = [])
+ {
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ $rows = $this->runSql(
+ "SELECT f_numchil AS tot, f_id AS id" .
+ " FROM `##families`" .
+ " WHERE" .
+ " f_file={$this->tree->getTreeId()}" .
+ " ORDER BY tot DESC" .
+ " LIMIT " . $total
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ if (count($rows) < $total) {
+ $total = count($rows);
+ }
+ $top10 = [];
+ for ($c = 0; $c < $total; $c++) {
+ $family = Family::getInstance($rows[$c]['id'], $this->tree);
+ if ($family->canShow()) {
+ if ($type === 'list') {
+ $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s child', '%s children', $rows[$c]['tot'], I18N::number($rows[$c]['tot']));
+ } else {
+ $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s child', '%s children', $rows[$c]['tot'], I18N::number($rows[$c]['tot']));
+ }
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode('; ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the ages between siblings.
- *
- * @param string $type
- * @param string[] $params
- *
- * @return string
- */
- private function ageBetweenSiblingsQuery($type = 'list', $params = []) {
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- if (isset($params[1])) {
- $one = $params[1];
- } else {
- $one = false;
- } // each family only once if true
- $rows = $this->runSql(
- " SELECT DISTINCT" .
- " link1.l_from AS family," .
- " link1.l_to AS ch1," .
- " link2.l_to AS ch2," .
- " child1.d_julianday2-child2.d_julianday2 AS age" .
- " FROM `##link` AS link1" .
- " LEFT JOIN `##dates` AS child1 ON child1.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##dates` AS child2 ON child2.d_file = {$this->tree->getTreeId()}" .
- " LEFT JOIN `##link` AS link2 ON link2.l_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " link1.l_file = {$this->tree->getTreeId()} AND" .
- " link1.l_from = link2.l_from AND" .
- " link1.l_type = 'CHIL' AND" .
- " child1.d_gid = link1.l_to AND" .
- " child1.d_fact = 'BIRT' AND" .
- " link2.l_type = 'CHIL' AND" .
- " child2.d_gid = link2.l_to AND" .
- " child2.d_fact = 'BIRT' AND" .
- " child1.d_julianday2 > child2.d_julianday2 AND" .
- " child2.d_julianday2 <> 0 AND" .
- " child1.d_gid <> child2.d_gid" .
- " ORDER BY age DESC" .
- " LIMIT " . $total
- );
- if (!isset($rows[0])) {
- return '';
- }
- $top10 = [];
- $dist = [];
- foreach ($rows as $fam) {
- $family = Family::getInstance($fam['family'], $this->tree);
- $child1 = Individual::getInstance($fam['ch1'], $this->tree);
- $child2 = Individual::getInstance($fam['ch2'], $this->tree);
- if ($type == 'name') {
- if ($child1->canShow() && $child2->canShow()) {
- $return = '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
- $return .= I18N::translate('and') . ' ';
- $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
- $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
- } else {
- $return = I18N::translate('This information is private and cannot be shown.');
- }
+ /**
+ * Find the ages between siblings.
+ *
+ * @param string $type
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function ageBetweenSiblingsQuery($type = 'list', $params = [])
+ {
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ if (isset($params[1])) {
+ $one = $params[1];
+ } else {
+ $one = false;
+ } // each family only once if true
+ $rows = $this->runSql(
+ " SELECT DISTINCT" .
+ " link1.l_from AS family," .
+ " link1.l_to AS ch1," .
+ " link2.l_to AS ch2," .
+ " child1.d_julianday2-child2.d_julianday2 AS age" .
+ " FROM `##link` AS link1" .
+ " LEFT JOIN `##dates` AS child1 ON child1.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##dates` AS child2 ON child2.d_file = {$this->tree->getTreeId()}" .
+ " LEFT JOIN `##link` AS link2 ON link2.l_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " link1.l_file = {$this->tree->getTreeId()} AND" .
+ " link1.l_from = link2.l_from AND" .
+ " link1.l_type = 'CHIL' AND" .
+ " child1.d_gid = link1.l_to AND" .
+ " child1.d_fact = 'BIRT' AND" .
+ " link2.l_type = 'CHIL' AND" .
+ " child2.d_gid = link2.l_to AND" .
+ " child2.d_fact = 'BIRT' AND" .
+ " child1.d_julianday2 > child2.d_julianday2 AND" .
+ " child2.d_julianday2 <> 0 AND" .
+ " child1.d_gid <> child2.d_gid" .
+ " ORDER BY age DESC" .
+ " LIMIT " . $total
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $top10 = [];
+ $dist = [];
+ foreach ($rows as $fam) {
+ $family = Family::getInstance($fam['family'], $this->tree);
+ $child1 = Individual::getInstance($fam['ch1'], $this->tree);
+ $child2 = Individual::getInstance($fam['ch2'], $this->tree);
+ if ($type == 'name') {
+ if ($child1->canShow() && $child2->canShow()) {
+ $return = '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
+ $return .= I18N::translate('and') . ' ';
+ $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
+ $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
+ } else {
+ $return = I18N::translate('This information is private and cannot be shown.');
+ }
- return $return;
- }
- $age = $fam['age'];
- if ((int) ($age / 365.25) > 0) {
- $age = (int) ($age / 365.25) . 'y';
- } elseif ((int) ($age / 30.4375) > 0) {
- $age = (int) ($age / 30.4375) . 'm';
- } else {
- $age = $age . 'd';
- }
- $age = FunctionsDate::getAgeAtEvent($age);
- if ($type == 'age') {
- return $age;
- }
- if ($type == 'list') {
- if ($one && !in_array($fam['family'], $dist)) {
- if ($child1->canShow() && $child2->canShow()) {
- $return = '<li>';
- $return .= '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
- $return .= I18N::translate('and') . ' ';
- $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
- $return .= ' (' . $age . ')';
- $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
- $return .= '</li>';
- $top10[] = $return;
- $dist[] = $fam['family'];
- }
- } elseif (!$one && $child1->canShow() && $child2->canShow()) {
- $return = '<li>';
- $return .= '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
- $return .= I18N::translate('and') . ' ';
- $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
- $return .= ' (' . $age . ')';
- $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
- $return .= '</li>';
- $top10[] = $return;
- }
- } else {
- if ($child1->canShow() && $child2->canShow()) {
- $return = $child2->formatList();
- $return .= '<br>' . I18N::translate('and') . '<br>';
- $return .= $child1->formatList();
- $return .= '<br><a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
+ return $return;
+ }
+ $age = $fam['age'];
+ if ((int)($age / 365.25) > 0) {
+ $age = (int)($age / 365.25) . 'y';
+ } elseif ((int)($age / 30.4375) > 0) {
+ $age = (int)($age / 30.4375) . 'm';
+ } else {
+ $age = $age . 'd';
+ }
+ $age = FunctionsDate::getAgeAtEvent($age);
+ if ($type == 'age') {
+ return $age;
+ }
+ if ($type == 'list') {
+ if ($one && !in_array($fam['family'], $dist)) {
+ if ($child1->canShow() && $child2->canShow()) {
+ $return = '<li>';
+ $return .= '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
+ $return .= I18N::translate('and') . ' ';
+ $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
+ $return .= ' (' . $age . ')';
+ $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
+ $return .= '</li>';
+ $top10[] = $return;
+ $dist[] = $fam['family'];
+ }
+ } elseif (!$one && $child1->canShow() && $child2->canShow()) {
+ $return = '<li>';
+ $return .= '<a href="' . e($child2->url()) . '">' . $child2->getFullName() . '</a> ';
+ $return .= I18N::translate('and') . ' ';
+ $return .= '<a href="' . e($child1->url()) . '">' . $child1->getFullName() . '</a>';
+ $return .= ' (' . $age . ')';
+ $return .= ' <a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
+ $return .= '</li>';
+ $top10[] = $return;
+ }
+ } else {
+ if ($child1->canShow() && $child2->canShow()) {
+ $return = $child2->formatList();
+ $return .= '<br>' . I18N::translate('and') . '<br>';
+ $return .= $child1->formatList();
+ $return .= '<br><a href="' . e($family->url()) . '">[' . I18N::translate('View this family') . ']</a>';
- return $return;
- } else {
- return I18N::translate('This information is private and cannot be shown.');
- }
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ return $return;
+ } else {
+ return I18N::translate('This information is private and cannot be shown.');
+ }
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the month in the year of the birth of the first child.
- *
- * @param bool $simple
- * @param bool $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return string|string[][]
- */
- public function monthFirstChildQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = []) {
- $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');
+ /**
+ * Find the month in the year of the birth of the first child.
+ *
+ * @param bool $simple
+ * @param bool $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return string|string[][]
+ */
+ public function monthFirstChildQuery($simple = true, $sex = false, $year1 = -1, $year2 = -1, $params = [])
+ {
+ $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 ($year1 >= 0 && $year2 >= 0) {
- $sql_years = " AND (d_year BETWEEN '{$year1}' AND '{$year2}')";
- } else {
- $sql_years = '';
- }
- if ($sex) {
- $sql_sex1 = ', i_sex';
- $sql_sex2 = " JOIN `##individuals` AS child ON child1.d_file = i_file AND child1.d_gid = child.i_id ";
- } else {
- $sql_sex1 = '';
- $sql_sex2 = '';
- }
- $sql =
- "SELECT d_month{$sql_sex1}, COUNT(*) AS total " .
- "FROM (" .
- " SELECT family{$sql_sex1}, MIN(date) AS d_date, d_month" .
- " FROM (" .
- " SELECT" .
- " link1.l_from AS family," .
- " link1.l_to AS child," .
- " child1.d_julianday2 AS date," .
- " child1.d_month as d_month" .
- $sql_sex1 .
- " FROM `##link` AS link1" .
- " LEFT JOIN `##dates` AS child1 ON child1.d_file = {$this->tree->getTreeId()}" .
- $sql_sex2 .
- " WHERE" .
- " link1.l_file = {$this->tree->getTreeId()} AND" .
- " link1.l_type = 'CHIL' AND" .
- " child1.d_gid = link1.l_to AND" .
- " child1.d_fact = 'BIRT' AND" .
- " child1.d_month IN ('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC')" .
- $sql_years .
- " ORDER BY date" .
- " ) AS children" .
- " GROUP BY family, d_month{$sql_sex1}" .
- ") AS first_child " .
- "GROUP BY d_month";
- if ($sex) {
- $sql .= ', i_sex';
- }
- $rows = $this->runSql($sql);
- if ($simple) {
- 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;
- }
- $sizes = explode('x', $size);
- $tot = 0;
- foreach ($rows as $values) {
- $tot += $values['total'];
- }
- // Beware divide by zero
- if ($tot == 0) {
- return '';
- }
- $text = '';
- $counts = [];
- foreach ($rows as $values) {
- $counts[] = round(100 * $values['total'] / $tot, 0);
- switch ($values['d_month']) {
- default:
- case 'JAN':
- $values['d_month'] = 1;
- break;
- case 'FEB':
- $values['d_month'] = 2;
- break;
- case 'MAR':
- $values['d_month'] = 3;
- break;
- case 'APR':
- $values['d_month'] = 4;
- break;
- case 'MAY':
- $values['d_month'] = 5;
- break;
- case 'JUN':
- $values['d_month'] = 6;
- break;
- case 'JUL':
- $values['d_month'] = 7;
- break;
- case 'AUG':
- $values['d_month'] = 8;
- break;
- case 'SEP':
- $values['d_month'] = 9;
- break;
- case 'OCT':
- $values['d_month'] = 10;
- break;
- case 'NOV':
- $values['d_month'] = 11;
- break;
- case 'DEC':
- $values['d_month'] = 12;
- break;
- }
- $text .= I18N::translate(ucfirst(strtolower(($values['d_month'])))) . ' - ' . $values['total'] . '|';
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chl = substr($text, 0, -1);
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql_years = " AND (d_year BETWEEN '{$year1}' AND '{$year2}')";
+ } else {
+ $sql_years = '';
+ }
+ if ($sex) {
+ $sql_sex1 = ', i_sex';
+ $sql_sex2 = " JOIN `##individuals` AS child ON child1.d_file = i_file AND child1.d_gid = child.i_id ";
+ } else {
+ $sql_sex1 = '';
+ $sql_sex2 = '';
+ }
+ $sql =
+ "SELECT d_month{$sql_sex1}, COUNT(*) AS total " .
+ "FROM (" .
+ " SELECT family{$sql_sex1}, MIN(date) AS d_date, d_month" .
+ " FROM (" .
+ " SELECT" .
+ " link1.l_from AS family," .
+ " link1.l_to AS child," .
+ " child1.d_julianday2 AS date," .
+ " child1.d_month as d_month" .
+ $sql_sex1 .
+ " FROM `##link` AS link1" .
+ " LEFT JOIN `##dates` AS child1 ON child1.d_file = {$this->tree->getTreeId()}" .
+ $sql_sex2 .
+ " WHERE" .
+ " link1.l_file = {$this->tree->getTreeId()} AND" .
+ " link1.l_type = 'CHIL' AND" .
+ " child1.d_gid = link1.l_to AND" .
+ " child1.d_fact = 'BIRT' AND" .
+ " child1.d_month IN ('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC')" .
+ $sql_years .
+ " ORDER BY date" .
+ " ) AS children" .
+ " GROUP BY family, d_month{$sql_sex1}" .
+ ") AS first_child " .
+ "GROUP BY d_month";
+ if ($sex) {
+ $sql .= ', i_sex';
+ }
+ $rows = $this->runSql($sql);
+ if ($simple) {
+ 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;
+ }
+ $sizes = explode('x', $size);
+ $tot = 0;
+ foreach ($rows as $values) {
+ $tot += $values['total'];
+ }
+ // Beware divide by zero
+ if ($tot == 0) {
+ return '';
+ }
+ $text = '';
+ $counts = [];
+ foreach ($rows as $values) {
+ $counts[] = round(100 * $values['total'] / $tot, 0);
+ switch ($values['d_month']) {
+ default:
+ case 'JAN':
+ $values['d_month'] = 1;
+ break;
+ case 'FEB':
+ $values['d_month'] = 2;
+ break;
+ case 'MAR':
+ $values['d_month'] = 3;
+ break;
+ case 'APR':
+ $values['d_month'] = 4;
+ break;
+ case 'MAY':
+ $values['d_month'] = 5;
+ break;
+ case 'JUN':
+ $values['d_month'] = 6;
+ break;
+ case 'JUL':
+ $values['d_month'] = 7;
+ break;
+ case 'AUG':
+ $values['d_month'] = 8;
+ break;
+ case 'SEP':
+ $values['d_month'] = 9;
+ break;
+ case 'OCT':
+ $values['d_month'] = 10;
+ break;
+ case 'NOV':
+ $values['d_month'] = 11;
+ break;
+ case 'DEC':
+ $values['d_month'] = 12;
+ break;
+ }
+ $text .= I18N::translate(ucfirst(strtolower(($values['d_month'])))) . ' - ' . $values['total'] . '|';
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chl = substr($text, 0, -1);
- 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=' . $chl . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" alt="' . I18N::translate('Month of birth of first child in a relation') . '" title="' . I18N::translate('Month of birth of first child in a relation') . '" />';
- }
+ 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=' . $chl . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" alt="' . I18N::translate('Month of birth of first child in a relation') . '" title="' . I18N::translate('Month of birth of first child in a relation') . '" />';
+ }
- return $rows;
- }
+ return $rows;
+ }
- /**
- * Find the family with the most children.
- *
- * @return string
- */
- public function largestFamily() {
- return $this->familyQuery('full');
- }
+ /**
+ * Find the family with the most children.
+ *
+ * @return string
+ */
+ public function largestFamily()
+ {
+ return $this->familyQuery('full');
+ }
- /**
- * Find the number of children in the largest family.
- *
- * @return string
- */
- public function largestFamilySize() {
- return $this->familyQuery('size');
- }
+ /**
+ * Find the number of children in the largest family.
+ *
+ * @return string
+ */
+ public function largestFamilySize()
+ {
+ return $this->familyQuery('size');
+ }
- /**
- * Find the family with the most children.
- *
- * @return string
- */
- public function largestFamilyName() {
- return $this->familyQuery('name');
- }
+ /**
+ * Find the family with the most children.
+ *
+ * @return string
+ */
+ public function largestFamilyName()
+ {
+ return $this->familyQuery('name');
+ }
- /**
- * The the families with the most children.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenLargestFamily($params = []) {
- return $this->topTenFamilyQuery('nolist', $params);
- }
+ /**
+ * The the families with the most children.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenLargestFamily($params = [])
+ {
+ return $this->topTenFamilyQuery('nolist', $params);
+ }
- /**
- * Find the families with the most children.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenLargestFamilyList($params = []) {
- return $this->topTenFamilyQuery('list', $params);
- }
+ /**
+ * Find the families with the most children.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenLargestFamilyList($params = [])
+ {
+ return $this->topTenFamilyQuery('list', $params);
+ }
- /**
- * Create a chart of the largest families.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartLargestFamilies($params = []) {
- $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values');
- $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values');
- $WT_STATS_L_CHART_X = Theme::theme()->parameter('stats-large-chart-x');
- $WT_STATS_S_CHART_Y = Theme::theme()->parameter('stats-small-chart-y');
+ /**
+ * Create a chart of the largest families.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartLargestFamilies($params = [])
+ {
+ $WT_STATS_CHART_COLOR1 = Theme::theme()->parameter('distribution-chart-no-values');
+ $WT_STATS_CHART_COLOR2 = Theme::theme()->parameter('distribution-chart-high-values');
+ $WT_STATS_L_CHART_X = Theme::theme()->parameter('stats-large-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_L_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] != '') {
- $total = strtolower($params[3]);
- } else {
- $total = 10;
- }
- $sizes = explode('x', $size);
- $total = (int) $total;
- $rows = $this->runSql(
- " SELECT f_numchil AS tot, f_id AS id" .
- " FROM `##families`" .
- " WHERE f_file={$this->tree->getTreeId()}" .
- " ORDER BY tot DESC" .
- " LIMIT " . $total
- );
- if (!isset($rows[0])) {
- return '';
- }
- $tot = 0;
- foreach ($rows as $row) {
- $tot += (int) $row['tot'];
- }
- $chd = '';
- $chl = [];
- foreach ($rows as $row) {
- $family = Family::getInstance($row['id'], $this->tree);
- if ($family->canShow()) {
- if ($tot == 0) {
- $per = 0;
- } else {
- $per = round(100 * $row['tot'] / $tot, 0);
- }
- $chd .= $this->arrayToExtendedEncoding([$per]);
- $chl[] = htmlspecialchars_decode(strip_tags($family->getFullName())) . ' - ' . I18N::number($row['tot']);
- }
- }
- $chl = rawurlencode(implode('|', $chl));
+ if (isset($params[0]) && $params[0] != '') {
+ $size = strtolower($params[0]);
+ } else {
+ $size = $WT_STATS_L_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] != '') {
+ $total = strtolower($params[3]);
+ } else {
+ $total = 10;
+ }
+ $sizes = explode('x', $size);
+ $total = (int)$total;
+ $rows = $this->runSql(
+ " SELECT f_numchil AS tot, f_id AS id" .
+ " FROM `##families`" .
+ " WHERE f_file={$this->tree->getTreeId()}" .
+ " ORDER BY tot DESC" .
+ " LIMIT " . $total
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $tot = 0;
+ foreach ($rows as $row) {
+ $tot += (int)$row['tot'];
+ }
+ $chd = '';
+ $chl = [];
+ foreach ($rows as $row) {
+ $family = Family::getInstance($row['id'], $this->tree);
+ if ($family->canShow()) {
+ if ($tot == 0) {
+ $per = 0;
+ } else {
+ $per = round(100 * $row['tot'] / $tot, 0);
+ }
+ $chd .= $this->arrayToExtendedEncoding([$per]);
+ $chl[] = htmlspecialchars_decode(strip_tags($family->getFullName())) . ' - ' . I18N::number($row['tot']);
+ }
+ }
+ $chl = rawurlencode(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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Largest families') . '" title="' . I18N::translate('Largest families') . '" />';
- }
+ 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={$chl}\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Largest families') . '" title="' . I18N::translate('Largest families') . '" />';
+ }
- /**
- * Count the total children.
- *
- * @return string
- */
- public function totalChildren() {
- $rows = $this->runSql("SELECT SUM(f_numchil) AS tot FROM `##families` WHERE f_file={$this->tree->getTreeId()}");
+ /**
+ * Count the total children.
+ *
+ * @return string
+ */
+ public function totalChildren()
+ {
+ $rows = $this->runSql("SELECT SUM(f_numchil) AS tot FROM `##families` WHERE f_file={$this->tree->getTreeId()}");
- return I18N::number($rows[0]['tot']);
- }
+ return I18N::number($rows[0]['tot']);
+ }
- /**
- * Find the average number of children in families.
- *
- * @return string
- */
- public function averageChildren() {
- $rows = $this->runSql("SELECT AVG(f_numchil) AS tot FROM `##families` WHERE f_file={$this->tree->getTreeId()}");
+ /**
+ * Find the average number of children in families.
+ *
+ * @return string
+ */
+ public function averageChildren()
+ {
+ $rows = $this->runSql("SELECT AVG(f_numchil) AS tot FROM `##families` WHERE f_file={$this->tree->getTreeId()}");
- return I18N::number($rows[0]['tot'], 2);
- }
+ return I18N::number($rows[0]['tot'], 2);
+ }
- /**
- * General query on familes/children.
- *
- * @param bool $simple
- * @param string $sex
- * @param int $year1
- * @param int $year2
- * @param string[] $params
- *
- * @return string|string[][]
- */
- public function statsChildrenQuery($simple = true, $sex = 'BOTH', $year1 = -1, $year2 = -1, $params = []) {
- if ($simple) {
- if (isset($params[0]) && $params[0] != '') {
- $size = strtolower($params[0]);
- } else {
- $size = '220x200';
- }
- $sizes = explode('x', $size);
- $max = 0;
- $rows = $this->runSql(
- " SELECT ROUND(AVG(f_numchil),2) AS num, FLOOR(d_year/100+1) AS century" .
- " FROM `##families`" .
- " JOIN `##dates` ON (d_file = f_file AND d_gid=f_id)" .
- " WHERE f_file = {$this->tree->getTreeId()}" .
- " AND d_julianday1<>0" .
- " AND d_fact = 'MARR'" .
- " AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')" .
- " GROUP BY century" .
- " ORDER BY century");
- if (empty($rows)) {
- return '';
- }
- foreach ($rows as $values) {
- if ($max < $values['num']) {
- $max = $values['num'];
- }
- }
- $chm = '';
- $chxl = '0:|';
- $i = 0;
- $counts = [];
- foreach ($rows as $values) {
- if ($sizes[0] < 980) {
- $sizes[0] += 38;
- }
- $chxl .= $this->centuryName($values['century']) . '|';
- if ($max <= 5) {
- $counts[] = round($values['num'] * 819.2 - 1, 1);
- } elseif ($max <= 10) {
- $counts[] = round($values['num'] * 409.6, 1);
- } else {
- $counts[] = round($values['num'] * 204.8, 1);
- }
- $chm .= 't' . $values['num'] . ',000000,0,' . $i . ',11,1|';
- $i++;
- }
- $chd = $this->arrayToExtendedEncoding($counts);
- $chm = substr($chm, 0, -1);
- if ($max <= 5) {
- $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|3:||' . I18N::translate('Number of children') . '|';
- } elseif ($max <= 10) {
- $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|6|7|8|9|10|3:||' . I18N::translate('Number of children') . '|';
- } else {
- $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|3:||' . I18N::translate('Number of children') . '|';
- }
+ /**
+ * General query on familes/children.
+ *
+ * @param bool $simple
+ * @param string $sex
+ * @param int $year1
+ * @param int $year2
+ * @param string[] $params
+ *
+ * @return string|string[][]
+ */
+ public function statsChildrenQuery($simple = true, $sex = 'BOTH', $year1 = -1, $year2 = -1, $params = [])
+ {
+ if ($simple) {
+ if (isset($params[0]) && $params[0] != '') {
+ $size = strtolower($params[0]);
+ } else {
+ $size = '220x200';
+ }
+ $sizes = explode('x', $size);
+ $max = 0;
+ $rows = $this->runSql(
+ " SELECT ROUND(AVG(f_numchil),2) AS num, FLOOR(d_year/100+1) AS century" .
+ " FROM `##families`" .
+ " JOIN `##dates` ON (d_file = f_file AND d_gid=f_id)" .
+ " WHERE f_file = {$this->tree->getTreeId()}" .
+ " AND d_julianday1<>0" .
+ " AND d_fact = 'MARR'" .
+ " AND d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')" .
+ " GROUP BY century" .
+ " ORDER BY century");
+ if (empty($rows)) {
+ return '';
+ }
+ foreach ($rows as $values) {
+ if ($max < $values['num']) {
+ $max = $values['num'];
+ }
+ }
+ $chm = '';
+ $chxl = '0:|';
+ $i = 0;
+ $counts = [];
+ foreach ($rows as $values) {
+ if ($sizes[0] < 980) {
+ $sizes[0] += 38;
+ }
+ $chxl .= $this->centuryName($values['century']) . '|';
+ if ($max <= 5) {
+ $counts[] = round($values['num'] * 819.2 - 1, 1);
+ } elseif ($max <= 10) {
+ $counts[] = round($values['num'] * 409.6, 1);
+ } else {
+ $counts[] = round($values['num'] * 204.8, 1);
+ }
+ $chm .= 't' . $values['num'] . ',000000,0,' . $i . ',11,1|';
+ $i++;
+ }
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chm = substr($chm, 0, -1);
+ if ($max <= 5) {
+ $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|3:||' . I18N::translate('Number of children') . '|';
+ } elseif ($max <= 10) {
+ $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|6|7|8|9|10|3:||' . I18N::translate('Number of children') . '|';
+ } else {
+ $chxl .= '1:||' . I18N::translate('century') . '|2:|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|3:||' . I18N::translate('Number of children') . '|';
+ }
- return "<img src=\"https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chm=D,FF0000,0,0,3,1|{$chm}&amp;chd=e:{$chd}&amp;chco=0000FF&amp;chbh=30,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average number of children per family') . '" title="' . I18N::translate('Average number of children per family') . '" />';
- } else {
- if ($sex == 'M') {
- $sql =
- "SELECT num, COUNT(*) AS total FROM " .
- "(SELECT count(i_sex) AS num FROM `##link` " .
- "LEFT OUTER JOIN `##individuals` " .
- "ON l_from=i_id AND l_file=i_file AND i_sex='M' AND l_type='FAMC' " .
- "JOIN `##families` ON f_file=l_file AND f_id=l_to WHERE f_file={$this->tree->getTreeId()} GROUP BY l_to" .
- ") boys" .
- " GROUP BY num" .
- " ORDER BY num";
- } elseif ($sex == 'F') {
- $sql =
- "SELECT num, COUNT(*) AS total FROM " .
- "(SELECT count(i_sex) AS num FROM `##link` " .
- "LEFT OUTER JOIN `##individuals` " .
- "ON l_from=i_id AND l_file=i_file AND i_sex='F' AND l_type='FAMC' " .
- "JOIN `##families` ON f_file=l_file AND f_id=l_to WHERE f_file={$this->tree->getTreeId()} GROUP BY l_to" .
- ") girls" .
- " GROUP BY num" .
- " ORDER BY num";
- } else {
- $sql = "SELECT f_numchil, COUNT(*) AS total FROM `##families` ";
- if ($year1 >= 0 && $year2 >= 0) {
- $sql .=
- "AS fam LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}"
- . " WHERE"
- . " married.d_gid = fam.f_id AND"
- . " fam.f_file = {$this->tree->getTreeId()} AND"
- . " married.d_fact = 'MARR' AND"
- . " married.d_year BETWEEN '{$year1}' AND '{$year2}'";
- } else {
- $sql .= "WHERE f_file={$this->tree->getTreeId()}";
- }
- $sql .= ' GROUP BY f_numchil';
- }
- $rows = $this->runSql($sql);
+ return "<img src=\"https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chm=D,FF0000,0,0,3,1|{$chm}&amp;chd=e:{$chd}&amp;chco=0000FF&amp;chbh=30,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Average number of children per family') . '" title="' . I18N::translate('Average number of children per family') . '" />';
+ } else {
+ if ($sex == 'M') {
+ $sql =
+ "SELECT num, COUNT(*) AS total FROM " .
+ "(SELECT count(i_sex) AS num FROM `##link` " .
+ "LEFT OUTER JOIN `##individuals` " .
+ "ON l_from=i_id AND l_file=i_file AND i_sex='M' AND l_type='FAMC' " .
+ "JOIN `##families` ON f_file=l_file AND f_id=l_to WHERE f_file={$this->tree->getTreeId()} GROUP BY l_to" .
+ ") boys" .
+ " GROUP BY num" .
+ " ORDER BY num";
+ } elseif ($sex == 'F') {
+ $sql =
+ "SELECT num, COUNT(*) AS total FROM " .
+ "(SELECT count(i_sex) AS num FROM `##link` " .
+ "LEFT OUTER JOIN `##individuals` " .
+ "ON l_from=i_id AND l_file=i_file AND i_sex='F' AND l_type='FAMC' " .
+ "JOIN `##families` ON f_file=l_file AND f_id=l_to WHERE f_file={$this->tree->getTreeId()} GROUP BY l_to" .
+ ") girls" .
+ " GROUP BY num" .
+ " ORDER BY num";
+ } else {
+ $sql = "SELECT f_numchil, COUNT(*) AS total FROM `##families` ";
+ if ($year1 >= 0 && $year2 >= 0) {
+ $sql .=
+ "AS fam LEFT JOIN `##dates` AS married ON married.d_file = {$this->tree->getTreeId()}"
+ . " WHERE"
+ . " married.d_gid = fam.f_id AND"
+ . " fam.f_file = {$this->tree->getTreeId()} AND"
+ . " married.d_fact = 'MARR' AND"
+ . " married.d_year BETWEEN '{$year1}' AND '{$year2}'";
+ } else {
+ $sql .= "WHERE f_file={$this->tree->getTreeId()}";
+ }
+ $sql .= ' GROUP BY f_numchil';
+ }
+ $rows = $this->runSql($sql);
- return $rows;
- }
- }
+ return $rows;
+ }
+ }
- /**
- * Genearl query on families/children.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function statsChildren($params = []) {
- return $this->statsChildrenQuery(true, 'BOTH', -1, -1, $params);
- }
+ /**
+ * Genearl query on families/children.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function statsChildren($params = [])
+ {
+ return $this->statsChildrenQuery(true, 'BOTH', -1, -1, $params);
+ }
- /**
- * Find the names of siblings with the widest age gap.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeBetweenSiblingsName($params = []) {
- return $this->ageBetweenSiblingsQuery('name', $params);
- }
+ /**
+ * Find the names of siblings with the widest age gap.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeBetweenSiblingsName($params = [])
+ {
+ return $this->ageBetweenSiblingsQuery('name', $params);
+ }
- /**
- * Find the widest age gap between siblings.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeBetweenSiblings($params = []) {
- return $this->ageBetweenSiblingsQuery('age', $params);
- }
+ /**
+ * Find the widest age gap between siblings.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeBetweenSiblings($params = [])
+ {
+ return $this->ageBetweenSiblingsQuery('age', $params);
+ }
- /**
- * Find the name of siblings with the widest age gap.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeBetweenSiblingsFullName($params = []) {
- return $this->ageBetweenSiblingsQuery('nolist', $params);
- }
+ /**
+ * Find the name of siblings with the widest age gap.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeBetweenSiblingsFullName($params = [])
+ {
+ return $this->ageBetweenSiblingsQuery('nolist', $params);
+ }
- /**
- * Find the siblings with the widest age gaps.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topAgeBetweenSiblingsList($params = []) {
- return $this->ageBetweenSiblingsQuery('list', $params);
- }
+ /**
+ * Find the siblings with the widest age gaps.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topAgeBetweenSiblingsList($params = [])
+ {
+ return $this->ageBetweenSiblingsQuery('list', $params);
+ }
- /**
- * Find the families with no children.
- *
- * @return string
- */
- private function noChildrenFamiliesQuery() {
- $rows = $this->runSql(
- " SELECT COUNT(*) AS tot" .
- " FROM `##families`" .
- " WHERE f_numchil = 0 AND f_file = {$this->tree->getTreeId()}");
+ /**
+ * Find the families with no children.
+ *
+ * @return string
+ */
+ private function noChildrenFamiliesQuery()
+ {
+ $rows = $this->runSql(
+ " SELECT COUNT(*) AS tot" .
+ " FROM `##families`" .
+ " WHERE f_numchil = 0 AND f_file = {$this->tree->getTreeId()}");
- return $rows[0]['tot'];
- }
+ return $rows[0]['tot'];
+ }
- /**
- * Find the families with no children.
- *
- * @return string
- */
- public function noChildrenFamilies() {
- return I18N::number($this->noChildrenFamiliesQuery());
- }
+ /**
+ * Find the families with no children.
+ *
+ * @return string
+ */
+ public function noChildrenFamilies()
+ {
+ return I18N::number($this->noChildrenFamiliesQuery());
+ }
- /**
- * Find the families with no children.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function noChildrenFamiliesList($params = []) {
- if (isset($params[0]) && $params[0] != '') {
- $type = strtolower($params[0]);
- } else {
- $type = 'list';
- }
- $rows = $this->runSql(
- " SELECT f_id AS family" .
- " FROM `##families` AS fam" .
- " WHERE f_numchil = 0 AND fam.f_file = {$this->tree->getTreeId()}");
- if (!isset($rows[0])) {
- return '';
- }
- $top10 = [];
- foreach ($rows as $row) {
- $family = Family::getInstance($row['family'], $this->tree);
- if ($family->canShow()) {
- if ($type == 'list') {
- $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a></li>';
- } else {
- $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a>';
- }
- }
- }
- if ($type == 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode('; ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * Find the families with no children.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function noChildrenFamiliesList($params = [])
+ {
+ if (isset($params[0]) && $params[0] != '') {
+ $type = strtolower($params[0]);
+ } else {
+ $type = 'list';
+ }
+ $rows = $this->runSql(
+ " SELECT f_id AS family" .
+ " FROM `##families` AS fam" .
+ " WHERE f_numchil = 0 AND fam.f_file = {$this->tree->getTreeId()}");
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $top10 = [];
+ foreach ($rows as $row) {
+ $family = Family::getInstance($row['family'], $this->tree);
+ if ($family->canShow()) {
+ if ($type == 'list') {
+ $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a></li>';
+ } else {
+ $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a>';
+ }
+ }
+ }
+ if ($type == 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode('; ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Create a chart of children with no families.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartNoChildrenFamilies($params = []) {
- if (isset($params[0]) && $params[0] != '') {
- $size = strtolower($params[0]);
- } else {
- $size = '220x200';
- }
- if (isset($params[1]) && $params[1] != '') {
- $year1 = $params[1];
- } else {
- $year1 = -1;
- }
- if (isset($params[2]) && $params[2] != '') {
- $year2 = $params[2];
- } else {
- $year2 = -1;
- }
- $sizes = explode('x', $size);
- if ($year1 >= 0 && $year2 >= 0) {
- $years = " married.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
- } else {
- $years = '';
- }
- $max = 0;
- $tot = 0;
- $rows = $this->runSql(
- "SELECT" .
- " COUNT(*) AS count," .
- " FLOOR(married.d_year/100+1) AS century" .
- " FROM" .
- " `##families` AS fam" .
- " JOIN" .
- " `##dates` AS married ON (married.d_file = fam.f_file AND married.d_gid = fam.f_id)" .
- " WHERE" .
- " f_numchil = 0 AND" .
- " fam.f_file = {$this->tree->getTreeId()} AND" .
- $years .
- " married.d_fact = 'MARR' AND" .
- " married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')" .
- " GROUP BY century ORDER BY century"
- );
- if (empty($rows)) {
- return '';
- }
- foreach ($rows as $values) {
- if ($max < $values['count']) {
- $max = $values['count'];
- }
- $tot += (int) $values['count'];
- }
- $unknown = $this->noChildrenFamiliesQuery() - $tot;
- if ($unknown > $max) {
- $max = $unknown;
- }
- $chm = '';
- $chxl = '0:|';
- $i = 0;
- $counts = [];
- foreach ($rows as $values) {
- if ($sizes[0] < 980) {
- $sizes[0] += 38;
- }
- $chxl .= $this->centuryName($values['century']) . '|';
- $counts[] = round(4095 * $values['count'] / ($max + 1));
- $chm .= 't' . $values['count'] . ',000000,0,' . $i . ',11,1|';
- $i++;
- }
- $counts[] = round(4095 * $unknown / ($max + 1));
- $chd = $this->arrayToExtendedEncoding($counts);
- $chm .= 't' . $unknown . ',000000,0,' . $i . ',11,1';
- $chxl .= I18N::translateContext('unknown century', 'Unknown') . '|1:||' . I18N::translate('century') . '|2:|0|';
- $step = $max + 1;
- for ($d = (int) ($max + 1); $d > 0; $d--) {
- if (($max + 1) < ($d * 10 + 1) && fmod(($max + 1), $d) == 0) {
- $step = $d;
- }
- }
- if ($step == (int) ($max + 1)) {
- for ($d = (int) ($max); $d > 0; $d--) {
- if ($max < ($d * 10 + 1) && fmod($max, $d) == 0) {
- $step = $d;
- }
- }
- }
- for ($n = $step; $n <= ($max + 1); $n += $step) {
- $chxl .= $n . '|';
- }
- $chxl .= '3:||' . I18N::translate('Total families') . '|';
+ /**
+ * Create a chart of children with no families.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartNoChildrenFamilies($params = [])
+ {
+ if (isset($params[0]) && $params[0] != '') {
+ $size = strtolower($params[0]);
+ } else {
+ $size = '220x200';
+ }
+ if (isset($params[1]) && $params[1] != '') {
+ $year1 = $params[1];
+ } else {
+ $year1 = -1;
+ }
+ if (isset($params[2]) && $params[2] != '') {
+ $year2 = $params[2];
+ } else {
+ $year2 = -1;
+ }
+ $sizes = explode('x', $size);
+ if ($year1 >= 0 && $year2 >= 0) {
+ $years = " married.d_year BETWEEN '{$year1}' AND '{$year2}' AND";
+ } else {
+ $years = '';
+ }
+ $max = 0;
+ $tot = 0;
+ $rows = $this->runSql(
+ "SELECT" .
+ " COUNT(*) AS count," .
+ " FLOOR(married.d_year/100+1) AS century" .
+ " FROM" .
+ " `##families` AS fam" .
+ " JOIN" .
+ " `##dates` AS married ON (married.d_file = fam.f_file AND married.d_gid = fam.f_id)" .
+ " WHERE" .
+ " f_numchil = 0 AND" .
+ " fam.f_file = {$this->tree->getTreeId()} AND" .
+ $years .
+ " married.d_fact = 'MARR' AND" .
+ " married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')" .
+ " GROUP BY century ORDER BY century"
+ );
+ if (empty($rows)) {
+ return '';
+ }
+ foreach ($rows as $values) {
+ if ($max < $values['count']) {
+ $max = $values['count'];
+ }
+ $tot += (int)$values['count'];
+ }
+ $unknown = $this->noChildrenFamiliesQuery() - $tot;
+ if ($unknown > $max) {
+ $max = $unknown;
+ }
+ $chm = '';
+ $chxl = '0:|';
+ $i = 0;
+ $counts = [];
+ foreach ($rows as $values) {
+ if ($sizes[0] < 980) {
+ $sizes[0] += 38;
+ }
+ $chxl .= $this->centuryName($values['century']) . '|';
+ $counts[] = round(4095 * $values['count'] / ($max + 1));
+ $chm .= 't' . $values['count'] . ',000000,0,' . $i . ',11,1|';
+ $i++;
+ }
+ $counts[] = round(4095 * $unknown / ($max + 1));
+ $chd = $this->arrayToExtendedEncoding($counts);
+ $chm .= 't' . $unknown . ',000000,0,' . $i . ',11,1';
+ $chxl .= I18N::translateContext('unknown century', 'Unknown') . '|1:||' . I18N::translate('century') . '|2:|0|';
+ $step = $max + 1;
+ for ($d = (int)($max + 1); $d > 0; $d--) {
+ if (($max + 1) < ($d * 10 + 1) && fmod(($max + 1), $d) == 0) {
+ $step = $d;
+ }
+ }
+ if ($step == (int)($max + 1)) {
+ for ($d = (int)($max); $d > 0; $d--) {
+ if ($max < ($d * 10 + 1) && fmod($max, $d) == 0) {
+ $step = $d;
+ }
+ }
+ }
+ for ($n = $step; $n <= ($max + 1); $n += $step) {
+ $chxl .= $n . '|';
+ }
+ $chxl .= '3:||' . I18N::translate('Total families') . '|';
- return "<img src=\"https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chm=D,FF0000,0,0:" . ($i - 1) . ",3,1|{$chm}&amp;chd=e:{$chd}&amp;chco=0000FF,ffffff00&amp;chbh=30,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Number of families without children') . '" title="' . I18N::translate('Number of families without children') . '" />';
- }
+ return "<img src=\"https://chart.googleapis.com/chart?cht=bvg&amp;chs={$sizes[0]}x{$sizes[1]}&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chm=D,FF0000,0,0:" . ($i - 1) . ",3,1|{$chm}&amp;chd=e:{$chd}&amp;chco=0000FF,ffffff00&amp;chbh=30,3&amp;chxt=x,x,y,y&amp;chxl=" . rawurlencode($chxl) . "\" width=\"{$sizes[0]}\" height=\"{$sizes[1]}\" alt=\"" . I18N::translate('Number of families without children') . '" title="' . I18N::translate('Number of families without children') . '" />';
+ }
- /**
- * Find the couple with the most grandchildren.
- *
- * @param string $type
- * @param string[] $params
- *
- * @return string
- */
- private function topTenGrandFamilyQuery($type = 'list', $params = []) {
- if (isset($params[0])) {
- $total = (int) $params[0];
- } else {
- $total = 10;
- }
- $rows = $this->runSql(
- "SELECT COUNT(*) AS tot, f_id AS id" .
- " FROM `##families`" .
- " JOIN `##link` AS children ON children.l_file = {$this->tree->getTreeId()}" .
- " JOIN `##link` AS mchildren ON mchildren.l_file = {$this->tree->getTreeId()}" .
- " JOIN `##link` AS gchildren ON gchildren.l_file = {$this->tree->getTreeId()}" .
- " WHERE" .
- " f_file={$this->tree->getTreeId()} AND" .
- " children.l_from=f_id AND" .
- " children.l_type='CHIL' AND" .
- " children.l_to=mchildren.l_from AND" .
- " mchildren.l_type='FAMS' AND" .
- " mchildren.l_to=gchildren.l_from AND" .
- " gchildren.l_type='CHIL'" .
- " GROUP BY id" .
- " ORDER BY tot DESC" .
- " LIMIT " . $total
- );
- if (!isset($rows[0])) {
- return '';
- }
- $top10 = [];
- foreach ($rows as $row) {
- $family = Family::getInstance($row['id'], $this->tree);
- if ($family->canShow()) {
- if ($type === 'list') {
- $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s grandchild', '%s grandchildren', $row['tot'], I18N::number($row['tot']));
- } else {
- $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s grandchild', '%s grandchildren', $row['tot'], I18N::number($row['tot']));
- }
- }
- }
- if ($type === 'list') {
- $top10 = implode('', $top10);
- } else {
- $top10 = implode('; ', $top10);
- }
- if (I18N::direction() === 'rtl') {
- $top10 = str_replace(['[', ']', '(', ')', '+'], ['&rlm;[', '&rlm;]', '&rlm;(', '&rlm;)', '&rlm;+'], $top10);
- }
- if ($type === 'list') {
- return '<ul>' . $top10 . '</ul>';
- }
+ /**
+ * Find the couple with the most grandchildren.
+ *
+ * @param string $type
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function topTenGrandFamilyQuery($type = 'list', $params = [])
+ {
+ if (isset($params[0])) {
+ $total = (int)$params[0];
+ } else {
+ $total = 10;
+ }
+ $rows = $this->runSql(
+ "SELECT COUNT(*) AS tot, f_id AS id" .
+ " FROM `##families`" .
+ " JOIN `##link` AS children ON children.l_file = {$this->tree->getTreeId()}" .
+ " JOIN `##link` AS mchildren ON mchildren.l_file = {$this->tree->getTreeId()}" .
+ " JOIN `##link` AS gchildren ON gchildren.l_file = {$this->tree->getTreeId()}" .
+ " WHERE" .
+ " f_file={$this->tree->getTreeId()} AND" .
+ " children.l_from=f_id AND" .
+ " children.l_type='CHIL' AND" .
+ " children.l_to=mchildren.l_from AND" .
+ " mchildren.l_type='FAMS' AND" .
+ " mchildren.l_to=gchildren.l_from AND" .
+ " gchildren.l_type='CHIL'" .
+ " GROUP BY id" .
+ " ORDER BY tot DESC" .
+ " LIMIT " . $total
+ );
+ if (!isset($rows[0])) {
+ return '';
+ }
+ $top10 = [];
+ foreach ($rows as $row) {
+ $family = Family::getInstance($row['id'], $this->tree);
+ if ($family->canShow()) {
+ if ($type === 'list') {
+ $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s grandchild', '%s grandchildren', $row['tot'], I18N::number($row['tot']));
+ } else {
+ $top10[] = '<a href="' . e($family->url()) . '">' . $family->getFullName() . '</a> - ' . I18N::plural('%s grandchild', '%s grandchildren', $row['tot'], I18N::number($row['tot']));
+ }
+ }
+ }
+ if ($type === 'list') {
+ $top10 = implode('', $top10);
+ } else {
+ $top10 = implode('; ', $top10);
+ }
+ if (I18N::direction() === 'rtl') {
+ $top10 = str_replace([
+ '[',
+ ']',
+ '(',
+ ')',
+ '+',
+ ], [
+ '&rlm;[',
+ '&rlm;]',
+ '&rlm;(',
+ '&rlm;)',
+ '&rlm;+',
+ ], $top10);
+ }
+ if ($type === 'list') {
+ return '<ul>' . $top10 . '</ul>';
+ }
- return $top10;
- }
+ return $top10;
+ }
- /**
- * Find the couple with the most grandchildren.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenLargestGrandFamily($params = []) {
- return $this->topTenGrandFamilyQuery('nolist', $params);
- }
+ /**
+ * Find the couple with the most grandchildren.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenLargestGrandFamily($params = [])
+ {
+ return $this->topTenGrandFamilyQuery('nolist', $params);
+ }
- /**
- * Find the couple with the most grandchildren.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function topTenLargestGrandFamilyList($params = []) {
- return $this->topTenGrandFamilyQuery('list', $params);
- }
+ /**
+ * Find the couple with the most grandchildren.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function topTenLargestGrandFamilyList($params = [])
+ {
+ return $this->topTenGrandFamilyQuery('list', $params);
+ }
- /**
- * Find common surnames.
- *
- * @param string $type
- * @param bool $show_tot
- * @param string[] $params
- *
- * @return string
- */
- private function commonSurnamesQuery($type = 'list', $show_tot = false, $params = []) {
- $threshold = empty($params[0]) ? 10 : (int) $params[0];
- $number_of_surnames = empty($params[1]) ? 10 : (int) $params[1];
- $sorting = empty($params[2]) ? 'alpha' : $params[2];
+ /**
+ * Find common surnames.
+ *
+ * @param string $type
+ * @param bool $show_tot
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function commonSurnamesQuery($type = 'list', $show_tot = false, $params = [])
+ {
+ $threshold = empty($params[0]) ? 10 : (int)$params[0];
+ $number_of_surnames = empty($params[1]) ? 10 : (int)$params[1];
+ $sorting = empty($params[2]) ? 'alpha' : $params[2];
- $surname_list = FunctionsDb::getTopSurnames($this->tree->getTreeId(), $threshold, $number_of_surnames);
- if (empty($surname_list)) {
- return '';
- }
+ $surname_list = FunctionsDb::getTopSurnames($this->tree->getTreeId(), $threshold, $number_of_surnames);
+ if (empty($surname_list)) {
+ return '';
+ }
- switch ($sorting) {
- default:
- case 'alpha':
- uksort($surname_list, '\Fisharebest\Webtrees\I18N::strcasecmp');
- break;
- case 'count':
- asort($surname_list);
- break;
- case 'rcount':
- arsort($surname_list);
- break;
- }
+ switch ($sorting) {
+ default:
+ case 'alpha':
+ uksort($surname_list, '\Fisharebest\Webtrees\I18N::strcasecmp');
+ break;
+ case 'count':
+ asort($surname_list);
+ break;
+ case 'rcount':
+ arsort($surname_list);
+ break;
+ }
- // Note that we count/display SPFX SURN, but sort/group under just SURN
- $surnames = [];
- foreach (array_keys($surname_list) as $surname) {
- $surnames = array_merge($surnames, QueryName::surnames($this->tree, $surname, '', false, false));
- }
+ // Note that we count/display SPFX SURN, but sort/group under just SURN
+ $surnames = [];
+ foreach (array_keys($surname_list) as $surname) {
+ $surnames = array_merge($surnames, QueryName::surnames($this->tree, $surname, '', false, false));
+ }
- return FunctionsPrintLists::surnameList($surnames, ($type == 'list' ? 1 : 2), $show_tot, 'individual-list', $this->tree);
- }
+ return FunctionsPrintLists::surnameList($surnames, ($type == 'list' ? 1 : 2), $show_tot, 'individual-list', $this->tree);
+ }
- /**
- * Find common surnames.
- *
- * @return string
- */
- public function getCommonSurname() {
- $surnames = array_keys(FunctionsDb::getTopSurnames($this->tree->getTreeId(), 1, 1));
+ /**
+ * Find common surnames.
+ *
+ * @return string
+ */
+ public function getCommonSurname()
+ {
+ $surnames = array_keys(FunctionsDb::getTopSurnames($this->tree->getTreeId(), 1, 1));
- return array_shift($surnames);
- }
+ return array_shift($surnames);
+ }
- /**
- * Find common surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonSurnames($params = ['', '', 'alpha']) {
- return $this->commonSurnamesQuery('nolist', false, $params);
- }
+ /**
+ * Find common surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonSurnames($params = [
+ '',
+ '',
+ 'alpha',
+ ])
+ {
+ return $this->commonSurnamesQuery('nolist', false, $params);
+ }
- /**
- * Find common surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonSurnamesTotals($params = ['', '', 'rcount']) {
- return $this->commonSurnamesQuery('nolist', true, $params);
- }
+ /**
+ * Find common surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonSurnamesTotals($params = [
+ '',
+ '',
+ 'rcount',
+ ])
+ {
+ return $this->commonSurnamesQuery('nolist', true, $params);
+ }
- /**
- * Find common surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonSurnamesList($params = ['', '', 'alpha']) {
- return $this->commonSurnamesQuery('list', false, $params);
- }
+ /**
+ * Find common surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonSurnamesList($params = [
+ '',
+ '',
+ 'alpha',
+ ])
+ {
+ return $this->commonSurnamesQuery('list', false, $params);
+ }
- /**
- * Find common surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonSurnamesListTotals($params = ['', '', 'rcount']) {
- return $this->commonSurnamesQuery('list', true, $params);
- }
+ /**
+ * Find common surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonSurnamesListTotals($params = [
+ '',
+ '',
+ 'rcount',
+ ])
+ {
+ return $this->commonSurnamesQuery('list', true, $params);
+ }
- /**
- * Create a chart of common surnames.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartCommonSurnames($params = []) {
- $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');
+ /**
+ * Create a chart of common surnames.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartCommonSurnames($params = [])
+ {
+ $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];
+ $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 = [];
- $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 = [];
- 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(['/ska$/', '/cka$/', '/dzka$/', '/żka$/'], ['ski', 'cki', 'dzki', 'żki'], $top_name);
- }
- $per = round(100 * $count_per / $tot_indi, 0);
- $chd .= $this->arrayToExtendedEncoding([$per]);
- $chl[] = $top_name . ' - ' . I18N::number($count_per);
- }
- $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0);
- $chd .= $this->arrayToExtendedEncoding([$per]);
- $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot);
+ $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 = [];
+ $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 = [];
+ 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([
+ '/ska$/',
+ '/cka$/',
+ '/dzka$/',
+ '/żka$/',
+ ], [
+ 'ski',
+ 'cki',
+ 'dzki',
+ 'żki',
+ ], $top_name);
+ }
+ $per = round(100 * $count_per / $tot_indi, 0);
+ $chd .= $this->arrayToExtendedEncoding([$per]);
+ $chl[] = $top_name . ' - ' . I18N::number($count_per);
+ }
+ $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0);
+ $chd .= $this->arrayToExtendedEncoding([$per]);
+ $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot);
- $chart_title = implode(I18N::$list_separator, $chl);
- $chl = implode('|', $chl);
+ $chart_title = implode(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 . '" />';
- }
+ 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 . '" />';
+ }
- /**
- * Find common given names.
- *
- * @param string $sex
- * @param string $type
- * @param bool $show_tot
- * @param string[] $params
- *
- * @return string
- */
- private function commonGivenQuery($sex = 'B', $type = 'list', $show_tot = false, $params = []) {
- if (isset($params[0]) && $params[0] != '' && $params[0] >= 0) {
- $threshold = (int) $params[0];
- } else {
- $threshold = 1;
- }
- if (isset($params[1]) && $params[1] != '' && $params[1] >= 0) {
- $maxtoshow = (int) $params[1];
- } else {
- $maxtoshow = 10;
- }
+ /**
+ * Find common given names.
+ *
+ * @param string $sex
+ * @param string $type
+ * @param bool $show_tot
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function commonGivenQuery($sex = 'B', $type = 'list', $show_tot = false, $params = [])
+ {
+ if (isset($params[0]) && $params[0] != '' && $params[0] >= 0) {
+ $threshold = (int)$params[0];
+ } else {
+ $threshold = 1;
+ }
+ if (isset($params[1]) && $params[1] != '' && $params[1] >= 0) {
+ $maxtoshow = (int)$params[1];
+ } else {
+ $maxtoshow = 10;
+ }
- switch ($sex) {
- case 'M':
- $sex_sql = "i_sex='M'";
- break;
- case 'F':
- $sex_sql = "i_sex='F'";
- break;
- case 'U':
- $sex_sql = "i_sex='U'";
- break;
- case 'B':
- default:
- $sex_sql = "i_sex<>'U'";
- break;
- }
- $ged_id = $this->tree->getTreeId();
+ switch ($sex) {
+ case 'M':
+ $sex_sql = "i_sex='M'";
+ break;
+ case 'F':
+ $sex_sql = "i_sex='F'";
+ break;
+ case 'U':
+ $sex_sql = "i_sex='U'";
+ break;
+ case 'B':
+ default:
+ $sex_sql = "i_sex<>'U'";
+ break;
+ }
+ $ged_id = $this->tree->getTreeId();
- $rows = Database::prepare("SELECT n_givn, COUNT(*) AS num FROM `##name` JOIN `##individuals` ON (n_id=i_id AND n_file=i_file) WHERE n_file={$ged_id} AND n_type<>'_MARNM' AND n_givn NOT IN ('@P.N.', '') AND LENGTH(n_givn)>1 AND {$sex_sql} GROUP BY n_id, n_givn")
- ->fetchAll();
- $nameList = [];
- foreach ($rows as $row) {
- // Split “John Thomas” into “John” and “Thomas” and count against both totals
- foreach (explode(' ', $row->n_givn) as $given) {
- // Exclude initials and particles.
- if (!preg_match('/^([A-Z]|[a-z]{1,3})$/', $given)) {
- if (array_key_exists($given, $nameList)) {
- $nameList[$given] += $row->num;
- } else {
- $nameList[$given] = $row->num;
- }
- }
- }
- }
- arsort($nameList, SORT_NUMERIC);
- $nameList = array_slice($nameList, 0, $maxtoshow);
+ $rows = Database::prepare("SELECT n_givn, COUNT(*) AS num FROM `##name` JOIN `##individuals` ON (n_id=i_id AND n_file=i_file) WHERE n_file={$ged_id} AND n_type<>'_MARNM' AND n_givn NOT IN ('@P.N.', '') AND LENGTH(n_givn)>1 AND {$sex_sql} GROUP BY n_id, n_givn")
+ ->fetchAll();
+ $nameList = [];
+ foreach ($rows as $row) {
+ // Split “John Thomas” into “John” and “Thomas” and count against both totals
+ foreach (explode(' ', $row->n_givn) as $given) {
+ // Exclude initials and particles.
+ if (!preg_match('/^([A-Z]|[a-z]{1,3})$/', $given)) {
+ if (array_key_exists($given, $nameList)) {
+ $nameList[$given] += $row->num;
+ } else {
+ $nameList[$given] = $row->num;
+ }
+ }
+ }
+ }
+ arsort($nameList, SORT_NUMERIC);
+ $nameList = array_slice($nameList, 0, $maxtoshow);
- if (count($nameList) == 0) {
- return '';
- }
- if ($type == 'chart') {
- return $nameList;
- }
- $common = [];
- foreach ($nameList as $given => $total) {
- if ($maxtoshow !== -1) {
- if ($maxtoshow-- <= 0) {
- break;
- }
- }
- if ($total < $threshold) {
- break;
- }
- if ($show_tot) {
- $tot = ' (' . I18N::number($total) . ')';
- } else {
- $tot = '';
- }
- switch ($type) {
- case 'table':
- $common[] = '<tr><td>' . $given . '</td><td class="text-center" data-sort="' . $total . '">' . I18N::number($total) . '</td></tr>';
- break;
- case 'list':
- $common[] = '<li><span dir="auto">' . $given . '</span>' . $tot . '</li>';
- break;
- case 'nolist':
- $common[] = '<span dir="auto">' . $given . '</span>' . $tot;
- break;
- }
- }
- if ($common) {
- switch ($type) {
- case 'table':
- $lookup = ['M' => I18N::translate('Male'), 'F' => I18N::translate('Female'), 'U' => I18N::translateContext('unknown gender', 'Unknown'), 'B' => I18N::translate('All')];
+ if (count($nameList) == 0) {
+ return '';
+ }
+ if ($type == 'chart') {
+ return $nameList;
+ }
+ $common = [];
+ foreach ($nameList as $given => $total) {
+ if ($maxtoshow !== -1) {
+ if ($maxtoshow-- <= 0) {
+ break;
+ }
+ }
+ if ($total < $threshold) {
+ break;
+ }
+ if ($show_tot) {
+ $tot = ' (' . I18N::number($total) . ')';
+ } else {
+ $tot = '';
+ }
+ switch ($type) {
+ case 'table':
+ $common[] = '<tr><td>' . $given . '</td><td class="text-center" data-sort="' . $total . '">' . I18N::number($total) . '</td></tr>';
+ break;
+ case 'list':
+ $common[] = '<li><span dir="auto">' . $given . '</span>' . $tot . '</li>';
+ break;
+ case 'nolist':
+ $common[] = '<span dir="auto">' . $given . '</span>' . $tot;
+ break;
+ }
+ }
+ if ($common) {
+ switch ($type) {
+ case 'table':
+ $lookup = [
+ 'M' => I18N::translate('Male'),
+ 'F' => I18N::translate('Female'),
+ 'U' => I18N::translateContext('unknown gender', 'Unknown'),
+ 'B' => I18N::translate('All'),
+ ];
- return '<table ' . Datatables::givenNameTableAttributes() . '><thead><tr><th colspan="3">' . $lookup[$sex] . '</th></tr><tr><th>' . I18N::translate('Name') . '</th><th>' . I18N::translate('Individuals') . '</th></tr></thead><tbody>' . implode('', $common) . '</tbody></table>';
- case 'list':
- return '<ul>' . implode('', $common) . '</ul>';
- case 'nolist':
- return implode(I18N::$list_separator, $common);
- default:
- return '';
- }
- } else {
- return '';
- }
- }
+ return '<table ' . Datatables::givenNameTableAttributes() . '><thead><tr><th colspan="3">' . $lookup[$sex] . '</th></tr><tr><th>' . I18N::translate('Name') . '</th><th>' . I18N::translate('Individuals') . '</th></tr></thead><tbody>' . implode('', $common) . '</tbody></table>';
+ case 'list':
+ return '<ul>' . implode('', $common) . '</ul>';
+ case 'nolist':
+ return implode(I18N::$list_separator, $common);
+ default:
+ return '';
+ }
+ } else {
+ return '';
+ }
+ }
- /**
- * Find common give names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGiven($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('B', 'nolist', false, $params);
- }
+ /**
+ * Find common give names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGiven($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('B', 'nolist', false, $params);
+ }
- /**
- * Find common give names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('B', 'nolist', true, $params);
- }
+ /**
+ * Find common give names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('B', 'nolist', true, $params);
+ }
- /**
- * Find common give names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenList($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('B', 'list', false, $params);
- }
+ /**
+ * Find common give names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenList($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('B', 'list', false, $params);
+ }
- /**
- * Find common give names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenListTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('B', 'list', true, $params);
- }
+ /**
+ * Find common give names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenListTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('B', 'list', true, $params);
+ }
- /**
- * Find common give names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenTable($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('B', 'table', false, $params);
- }
+ /**
+ * Find common give names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenTable($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('B', 'table', false, $params);
+ }
- /**
- * Find common give names of females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenFemale($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('F', 'nolist', false, $params);
- }
+ /**
+ * Find common give names of females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenFemale($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('F', 'nolist', false, $params);
+ }
- /**
- * Find common give names of females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenFemaleTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('F', 'nolist', true, $params);
- }
+ /**
+ * Find common give names of females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenFemaleTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('F', 'nolist', true, $params);
+ }
- /**
- * Find common give names of females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenFemaleList($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('F', 'list', false, $params);
- }
+ /**
+ * Find common give names of females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenFemaleList($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('F', 'list', false, $params);
+ }
- /**
- * Find common give names of females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenFemaleListTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('F', 'list', true, $params);
- }
+ /**
+ * Find common give names of females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenFemaleListTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('F', 'list', true, $params);
+ }
- /**
- * Find common give names of females.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenFemaleTable($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('F', 'table', false, $params);
- }
+ /**
+ * Find common give names of females.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenFemaleTable($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('F', 'table', false, $params);
+ }
- /**
- * Find common give names of males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenMale($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('M', 'nolist', false, $params);
- }
+ /**
+ * Find common give names of males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenMale($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('M', 'nolist', false, $params);
+ }
- /**
- * Find common give names of males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenMaleTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('M', 'nolist', true, $params);
- }
+ /**
+ * Find common give names of males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenMaleTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('M', 'nolist', true, $params);
+ }
- /**
- * Find common give names of males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenMaleList($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('M', 'list', false, $params);
- }
+ /**
+ * Find common give names of males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenMaleList($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('M', 'list', false, $params);
+ }
- /**
- * Find common give names of males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenMaleListTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('M', 'list', true, $params);
- }
+ /**
+ * Find common give names of males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenMaleListTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('M', 'list', true, $params);
+ }
- /**
- * Find common give names of males.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenMaleTable($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('M', 'table', false, $params);
- }
+ /**
+ * Find common give names of males.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenMaleTable($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('M', 'table', false, $params);
+ }
- /**
- * Find common give names of unknown sexes.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenUnknown($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('U', 'nolist', false, $params);
- }
+ /**
+ * Find common give names of unknown sexes.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenUnknown($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('U', 'nolist', false, $params);
+ }
- /**
- * Find common give names of unknown sexes.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenUnknownTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('U', 'nolist', true, $params);
- }
+ /**
+ * Find common give names of unknown sexes.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenUnknownTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('U', 'nolist', true, $params);
+ }
- /**
- * Find common give names of unknown sexes.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenUnknownList($params = [1, 10, 'alpha']) {
- return $this->commonGivenQuery('U', 'list', false, $params);
- }
+ /**
+ * Find common give names of unknown sexes.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenUnknownList($params = [
+ 1,
+ 10,
+ 'alpha',
+ ])
+ {
+ return $this->commonGivenQuery('U', 'list', false, $params);
+ }
- /**
- * Find common give names of unknown sexes.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenUnknownListTotals($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('U', 'list', true, $params);
- }
+ /**
+ * Find common give names of unknown sexes.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenUnknownListTotals($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('U', 'list', true, $params);
+ }
- /**
- * Find common give names of unknown sexes.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function commonGivenUnknownTable($params = [1, 10, 'rcount']) {
- return $this->commonGivenQuery('U', 'table', false, $params);
- }
+ /**
+ * Find common give names of unknown sexes.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function commonGivenUnknownTable($params = [
+ 1,
+ 10,
+ 'rcount',
+ ])
+ {
+ return $this->commonGivenQuery('U', 'table', false, $params);
+ }
- /**
- * Create a chart of common given names.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function chartCommonGiven($params = []) {
- $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');
+ /**
+ * Create a chart of common given names.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function chartCommonGiven($params = [])
+ {
+ $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[4]) && $params[4] != '') {
- $maxtoshow = strtolower($params[4]);
- } else {
- $maxtoshow = 7;
- }
- $sizes = explode('x', $size);
- $tot_indi = $this->totalIndividualsQuery();
- $given = $this->commonGivenQuery('B', 'chart');
- if (!is_array($given)) {
- return '';
- }
- $given = array_slice($given, 0, $maxtoshow);
- if (count($given) <= 0) {
- return '';
- }
- $tot = 0;
- foreach ($given as $count) {
- $tot += $count;
- }
- $chd = '';
- $chl = [];
- foreach ($given as $givn => $count) {
- if ($tot == 0) {
- $per = 0;
- } else {
- $per = round(100 * $count / $tot_indi, 0);
- }
- $chd .= $this->arrayToExtendedEncoding([$per]);
- $chl[] = $givn . ' - ' . I18N::number($count);
- }
- $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0);
- $chd .= $this->arrayToExtendedEncoding([$per]);
- $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot);
+ 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[4]) && $params[4] != '') {
+ $maxtoshow = strtolower($params[4]);
+ } else {
+ $maxtoshow = 7;
+ }
+ $sizes = explode('x', $size);
+ $tot_indi = $this->totalIndividualsQuery();
+ $given = $this->commonGivenQuery('B', 'chart');
+ if (!is_array($given)) {
+ return '';
+ }
+ $given = array_slice($given, 0, $maxtoshow);
+ if (count($given) <= 0) {
+ return '';
+ }
+ $tot = 0;
+ foreach ($given as $count) {
+ $tot += $count;
+ }
+ $chd = '';
+ $chl = [];
+ foreach ($given as $givn => $count) {
+ if ($tot == 0) {
+ $per = 0;
+ } else {
+ $per = round(100 * $count / $tot_indi, 0);
+ }
+ $chd .= $this->arrayToExtendedEncoding([$per]);
+ $chl[] = $givn . ' - ' . I18N::number($count);
+ }
+ $per = round(100 * ($tot_indi - $tot) / $tot_indi, 0);
+ $chd .= $this->arrayToExtendedEncoding([$per]);
+ $chl[] = I18N::translate('Other') . ' - ' . I18N::number($tot_indi - $tot);
- $chart_title = implode(I18N::$list_separator, $chl);
- $chl = implode('|', $chl);
+ $chart_title = implode(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 . '" />';
- }
+ 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 . '" />';
+ }
- /**
- * Who is currently logged in?
- *
- * @param string $type
- *
- * @return string
- */
- private function usersLoggedInQuery($type = 'nolist') {
- $content = '';
- // List active users
- $NumAnonymous = 0;
- $loggedusers = [];
- foreach (User::allLoggedIn() as $user) {
- if (Auth::isAdmin() || $user->getPreference('visibleonline')) {
- $loggedusers[] = $user;
- } else {
- $NumAnonymous++;
- }
- }
- $LoginUsers = count($loggedusers);
- if ($LoginUsers == 0 && $NumAnonymous == 0) {
- return I18N::translate('No signed-in and no anonymous users');
- }
- if ($NumAnonymous > 0) {
- $content .= '<b>' . I18N::plural('%s anonymous signed-in user', '%s anonymous signed-in users', $NumAnonymous, I18N::number($NumAnonymous)) . '</b>';
- }
- if ($LoginUsers > 0) {
- if ($NumAnonymous) {
- if ($type == 'list') {
- $content .= '<br><br>';
- } else {
- $content .= ' ' . I18N::translate('and') . ' ';
- }
- }
- $content .= '<b>' . I18N::plural('%s signed-in user', '%s signed-in users', $LoginUsers, I18N::number($LoginUsers)) . '</b>';
- if ($type == 'list') {
- $content .= '<ul>';
- } else {
- $content .= ': ';
- }
- }
- if (Auth::check()) {
- foreach ($loggedusers as $user) {
- if ($type == 'list') {
- $content .= '<li>' . e($user->getRealName()) . ' - ' . e($user->getUserName());
- } else {
- $content .= e($user->getRealName()) . ' - ' . e($user->getUserName());
- }
- if (Auth::id() != $user->getUserId() && $user->getPreference('contactmethod') != 'none') {
- if ($type == 'list') {
- $content .= '<br>';
- }
- $content .= FontAwesome::linkIcon('email', I18N::translate('Send a message'), ['class' => 'btn btn-link', 'href' => route('message', ['to' => $user->getUserName(), 'ged' => $this->tree->getName()])]);
- }
- if ($type == 'list') {
- $content .= '</li>';
- }
- }
- }
- if ($type == 'list') {
- $content .= '</ul>';
- }
+ /**
+ * Who is currently logged in?
+ *
+ * @param string $type
+ *
+ * @return string
+ */
+ private function usersLoggedInQuery($type = 'nolist')
+ {
+ $content = '';
+ // List active users
+ $NumAnonymous = 0;
+ $loggedusers = [];
+ foreach (User::allLoggedIn() as $user) {
+ if (Auth::isAdmin() || $user->getPreference('visibleonline')) {
+ $loggedusers[] = $user;
+ } else {
+ $NumAnonymous++;
+ }
+ }
+ $LoginUsers = count($loggedusers);
+ if ($LoginUsers == 0 && $NumAnonymous == 0) {
+ return I18N::translate('No signed-in and no anonymous users');
+ }
+ if ($NumAnonymous > 0) {
+ $content .= '<b>' . I18N::plural('%s anonymous signed-in user', '%s anonymous signed-in users', $NumAnonymous, I18N::number($NumAnonymous)) . '</b>';
+ }
+ if ($LoginUsers > 0) {
+ if ($NumAnonymous) {
+ if ($type == 'list') {
+ $content .= '<br><br>';
+ } else {
+ $content .= ' ' . I18N::translate('and') . ' ';
+ }
+ }
+ $content .= '<b>' . I18N::plural('%s signed-in user', '%s signed-in users', $LoginUsers, I18N::number($LoginUsers)) . '</b>';
+ if ($type == 'list') {
+ $content .= '<ul>';
+ } else {
+ $content .= ': ';
+ }
+ }
+ if (Auth::check()) {
+ foreach ($loggedusers as $user) {
+ if ($type == 'list') {
+ $content .= '<li>' . e($user->getRealName()) . ' - ' . e($user->getUserName());
+ } else {
+ $content .= e($user->getRealName()) . ' - ' . e($user->getUserName());
+ }
+ if (Auth::id() != $user->getUserId() && $user->getPreference('contactmethod') != 'none') {
+ if ($type == 'list') {
+ $content .= '<br>';
+ }
+ $content .= FontAwesome::linkIcon('email', I18N::translate('Send a message'), [
+ 'class' => 'btn btn-link',
+ 'href' => route('message', [
+ 'to' => $user->getUserName(),
+ 'ged' => $this->tree->getName(),
+ ]),
+ ]);
+ }
+ if ($type == 'list') {
+ $content .= '</li>';
+ }
+ }
+ }
+ if ($type == 'list') {
+ $content .= '</ul>';
+ }
- return $content;
- }
+ return $content;
+ }
- /**
- * NUmber of users who are currently logged in?
- *
- * @param string $type
- *
- * @return int
- */
- private function usersLoggedInTotalQuery($type = 'all') {
- $anon = 0;
- $visible = 0;
- foreach (User::allLoggedIn() as $user) {
- if (Auth::isAdmin() || $user->getPreference('visibleonline')) {
- $visible++;
- } else {
- $anon++;
- }
- }
- if ($type == 'anon') {
- return $anon;
- } elseif ($type == 'visible') {
- return $visible;
- } else {
- return $visible + $anon;
- }
- }
+ /**
+ * NUmber of users who are currently logged in?
+ *
+ * @param string $type
+ *
+ * @return int
+ */
+ private function usersLoggedInTotalQuery($type = 'all')
+ {
+ $anon = 0;
+ $visible = 0;
+ foreach (User::allLoggedIn() as $user) {
+ if (Auth::isAdmin() || $user->getPreference('visibleonline')) {
+ $visible++;
+ } else {
+ $anon++;
+ }
+ }
+ if ($type == 'anon') {
+ return $anon;
+ } elseif ($type == 'visible') {
+ return $visible;
+ } else {
+ return $visible + $anon;
+ }
+ }
- /**
- * Who is currently logged in?
- *
- * @return string
- */
- public function usersLoggedIn() {
- return $this->usersLoggedInQuery('nolist');
- }
+ /**
+ * Who is currently logged in?
+ *
+ * @return string
+ */
+ public function usersLoggedIn()
+ {
+ return $this->usersLoggedInQuery('nolist');
+ }
- /**
- * Who is currently logged in?
- *
- * @return string
- */
- public function usersLoggedInList() {
- return $this->usersLoggedInQuery('list');
- }
+ /**
+ * Who is currently logged in?
+ *
+ * @return string
+ */
+ public function usersLoggedInList()
+ {
+ return $this->usersLoggedInQuery('list');
+ }
- /**
- * Who is currently logged in?
- *
- * @return int
- */
- public function usersLoggedInTotal() {
- return $this->usersLoggedInTotalQuery('all');
- }
+ /**
+ * Who is currently logged in?
+ *
+ * @return int
+ */
+ public function usersLoggedInTotal()
+ {
+ return $this->usersLoggedInTotalQuery('all');
+ }
- /**
- * Which visitors are currently logged in?
- *
- * @return int
- */
- public function usersLoggedInTotalAnon() {
- return $this->usersLoggedInTotalQuery('anon');
- }
+ /**
+ * Which visitors are currently logged in?
+ *
+ * @return int
+ */
+ public function usersLoggedInTotalAnon()
+ {
+ return $this->usersLoggedInTotalQuery('anon');
+ }
- /**
- * Which visitors are currently logged in?
- *
- * @return int
- */
- public function usersLoggedInTotalVisible() {
- return $this->usersLoggedInTotalQuery('visible');
- }
+ /**
+ * Which visitors are currently logged in?
+ *
+ * @return int
+ */
+ public function usersLoggedInTotalVisible()
+ {
+ return $this->usersLoggedInTotalQuery('visible');
+ }
- /**
- * Get the current user's ID.
- *
- * @return null|string
- */
- public function userId() {
- return Auth::id();
- }
+ /**
+ * Get the current user's ID.
+ *
+ * @return null|string
+ */
+ public function userId()
+ {
+ return Auth::id();
+ }
- /**
- * Get the current user's username.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function userName($params = []) {
- if (Auth::check()) {
- return e(Auth::user()->getUserName());
- } elseif (isset($params[0]) && $params[0] != '') {
- // if #username:visitor# was specified, then "visitor" will be returned when the user is not logged in
- return e($params[0]);
- } else {
- return '';
- }
- }
+ /**
+ * Get the current user's username.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function userName($params = [])
+ {
+ if (Auth::check()) {
+ return e(Auth::user()->getUserName());
+ } elseif (isset($params[0]) && $params[0] != '') {
+ // if #username:visitor# was specified, then "visitor" will be returned when the user is not logged in
+ return e($params[0]);
+ } else {
+ return '';
+ }
+ }
- /**
- * Get the current user's full name.
- *
- * @return string
- */
- public function userFullName() {
- return Auth::check() ? '<span dir="auto">' . e(Auth::user()->getRealName()) . '</span>' : '';
- }
+ /**
+ * Get the current user's full name.
+ *
+ * @return string
+ */
+ public function userFullName()
+ {
+ return Auth::check() ? '<span dir="auto">' . e(Auth::user()->getRealName()) . '</span>' : '';
+ }
- /**
- * Get the newest registered user.
- *
- * @param string $type
- * @param string[] $params
- *
- * @return string
- */
- private function getLatestUserData($type = 'userid', $params = []) {
- static $user_id = null;
+ /**
+ * Get the newest registered user.
+ *
+ * @param string $type
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function getLatestUserData($type = 'userid', $params = [])
+ {
+ static $user_id = null;
- if ($user_id === null) {
- $user = User::findLatestToRegister();
- } else {
- $user = User::find($user_id);
- }
+ if ($user_id === null) {
+ $user = User::findLatestToRegister();
+ } else {
+ $user = User::find($user_id);
+ }
- switch ($type) {
- default:
- case 'userid':
- return $user->getUserId();
- case 'username':
- return e($user->getUserName());
- case 'fullname':
- return e($user->getRealName());
- case 'regdate':
- if (is_array($params) && isset($params[0]) && $params[0] != '') {
- $datestamp = $params[0];
- } else {
- $datestamp = I18N::dateFormat();
- }
+ switch ($type) {
+ default:
+ case 'userid':
+ return $user->getUserId();
+ case 'username':
+ return e($user->getUserName());
+ case 'fullname':
+ return e($user->getRealName());
+ case 'regdate':
+ if (is_array($params) && isset($params[0]) && $params[0] != '') {
+ $datestamp = $params[0];
+ } else {
+ $datestamp = I18N::dateFormat();
+ }
- return FunctionsDate::timestampToGedcomDate((int) $user->getPreference('reg_timestamp'))->display(false, $datestamp);
- case 'regtime':
- if (is_array($params) && isset($params[0]) && $params[0] != '') {
- $datestamp = $params[0];
- } else {
- $datestamp = str_replace('%', '', I18N::timeFormat());
- }
+ return FunctionsDate::timestampToGedcomDate((int)$user->getPreference('reg_timestamp'))->display(false, $datestamp);
+ case 'regtime':
+ if (is_array($params) && isset($params[0]) && $params[0] != '') {
+ $datestamp = $params[0];
+ } else {
+ $datestamp = str_replace('%', '', I18N::timeFormat());
+ }
- return date($datestamp, (int) $user->getPreference('reg_timestamp'));
- case 'loggedin':
- if (is_array($params) && isset($params[0]) && $params[0] != '') {
- $yes = $params[0];
- } else {
- $yes = I18N::translate('yes');
- }
- if (is_array($params) && isset($params[1]) && $params[1] != '') {
- $no = $params[1];
- } else {
- $no = I18N::translate('no');
- }
+ return date($datestamp, (int)$user->getPreference('reg_timestamp'));
+ case 'loggedin':
+ if (is_array($params) && isset($params[0]) && $params[0] != '') {
+ $yes = $params[0];
+ } else {
+ $yes = I18N::translate('yes');
+ }
+ if (is_array($params) && isset($params[1]) && $params[1] != '') {
+ $no = $params[1];
+ } else {
+ $no = I18N::translate('no');
+ }
- return Database::prepare("SELECT 1 FROM `##session` WHERE user_id=? LIMIT 1")->execute([$user->getUserId()])->fetchOne() ? $yes : $no;
- }
- }
+ return Database::prepare("SELECT 1 FROM `##session` WHERE user_id=? LIMIT 1")->execute([$user->getUserId()])->fetchOne() ? $yes : $no;
+ }
+ }
- /**
- * Get the newest registered user's ID.
- *
- * @return string
- */
- public function latestUserId() {
- return $this->getLatestUserData('userid');
- }
+ /**
+ * Get the newest registered user's ID.
+ *
+ * @return string
+ */
+ public function latestUserId()
+ {
+ return $this->getLatestUserData('userid');
+ }
- /**
- * Get the newest registered user's username.
- *
- * @return string
- */
- public function latestUserName() {
- return $this->getLatestUserData('username');
- }
+ /**
+ * Get the newest registered user's username.
+ *
+ * @return string
+ */
+ public function latestUserName()
+ {
+ return $this->getLatestUserData('username');
+ }
- /**
- * Get the newest registered user's real name.
- *
- * @return string
- */
- public function latestUserFullName() {
- return $this->getLatestUserData('fullname');
- }
+ /**
+ * Get the newest registered user's real name.
+ *
+ * @return string
+ */
+ public function latestUserFullName()
+ {
+ return $this->getLatestUserData('fullname');
+ }
- /**
- * Get the date of the newest user registration.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function latestUserRegDate($params = []) {
- return $this->getLatestUserData('regdate', $params);
- }
+ /**
+ * Get the date of the newest user registration.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function latestUserRegDate($params = [])
+ {
+ return $this->getLatestUserData('regdate', $params);
+ }
- /**
- * Find the timestamp of the latest user to register.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function latestUserRegTime($params = []) {
- return $this->getLatestUserData('regtime', $params);
- }
+ /**
+ * Find the timestamp of the latest user to register.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function latestUserRegTime($params = [])
+ {
+ return $this->getLatestUserData('regtime', $params);
+ }
- /**
- * Find the most recent user to log in.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function latestUserLoggedin($params = []) {
- return $this->getLatestUserData('loggedin', $params);
- }
+ /**
+ * Find the most recent user to log in.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function latestUserLoggedin($params = [])
+ {
+ return $this->getLatestUserData('loggedin', $params);
+ }
- /**
- * Create a link to contact the webmaster.
- *
- * @return string
- */
- public function contactWebmaster() {
- $user_id = $this->tree->getPreference('WEBMASTER_USER_ID');
- $user = User::find($user_id);
- if ($user) {
- return Theme::theme()->contactLink($user);
- } else {
- return $user_id;
- }
- }
+ /**
+ * Create a link to contact the webmaster.
+ *
+ * @return string
+ */
+ public function contactWebmaster()
+ {
+ $user_id = $this->tree->getPreference('WEBMASTER_USER_ID');
+ $user = User::find($user_id);
+ if ($user) {
+ return Theme::theme()->contactLink($user);
+ } else {
+ return $user_id;
+ }
+ }
- /**
- * Create a link to contact the genealogy contact.
- *
- * @return string
- */
- public function contactGedcom() {
- $user_id = $this->tree->getPreference('CONTACT_USER_ID');
- $user = User::find($user_id);
- if ($user) {
- return Theme::theme()->contactLink($user);
- } else {
- return $user_id;
- }
- }
+ /**
+ * Create a link to contact the genealogy contact.
+ *
+ * @return string
+ */
+ public function contactGedcom()
+ {
+ $user_id = $this->tree->getPreference('CONTACT_USER_ID');
+ $user = User::find($user_id);
+ if ($user) {
+ return Theme::theme()->contactLink($user);
+ } else {
+ return $user_id;
+ }
+ }
- /**
- * What is the current date on the server?
- *
- * @return string
- */
- public function serverDate() {
- return FunctionsDate::timestampToGedcomDate(WT_TIMESTAMP)->display();
- }
+ /**
+ * What is the current date on the server?
+ *
+ * @return string
+ */
+ public function serverDate()
+ {
+ return FunctionsDate::timestampToGedcomDate(WT_TIMESTAMP)->display();
+ }
- /**
- * What is the current time on the server (in 12 hour clock)?
- *
- * @return string
- */
- public function serverTime() {
- return date('g:i a');
- }
+ /**
+ * What is the current time on the server (in 12 hour clock)?
+ *
+ * @return string
+ */
+ public function serverTime()
+ {
+ return date('g:i a');
+ }
- /**
- * What is the current time on the server (in 24 hour clock)?
- *
- * @return string
- */
- public function serverTime24() {
- return date('G:i');
- }
+ /**
+ * What is the current time on the server (in 24 hour clock)?
+ *
+ * @return string
+ */
+ public function serverTime24()
+ {
+ return date('G:i');
+ }
- /**
- * What is the timezone of the server.
- *
- * @return string
- */
- public function serverTimezone() {
- return date('T');
- }
+ /**
+ * What is the timezone of the server.
+ *
+ * @return string
+ */
+ public function serverTimezone()
+ {
+ return date('T');
+ }
- /**
- * What is the client's date.
- *
- * @return string
- */
- public function browserDate() {
- return FunctionsDate::timestampToGedcomDate(WT_TIMESTAMP + WT_TIMESTAMP_OFFSET)->display();
- }
+ /**
+ * What is the client's date.
+ *
+ * @return string
+ */
+ public function browserDate()
+ {
+ return FunctionsDate::timestampToGedcomDate(WT_TIMESTAMP + WT_TIMESTAMP_OFFSET)->display();
+ }
- /**
- * What is the client's timestamp.
- *
- * @return string
- */
- public function browserTime() {
- return date(str_replace('%', '', I18N::timeFormat()), WT_TIMESTAMP + WT_TIMESTAMP_OFFSET);
- }
+ /**
+ * What is the client's timestamp.
+ *
+ * @return string
+ */
+ public function browserTime()
+ {
+ return date(str_replace('%', '', I18N::timeFormat()), WT_TIMESTAMP + WT_TIMESTAMP_OFFSET);
+ }
- /**
- * What is the browser's tiemzone.
- *
- * @return string
- */
- public function browserTimezone() {
- return date('T', WT_TIMESTAMP + WT_TIMESTAMP_OFFSET);
- }
+ /**
+ * What is the browser's tiemzone.
+ *
+ * @return string
+ */
+ public function browserTimezone()
+ {
+ return date('T', WT_TIMESTAMP + WT_TIMESTAMP_OFFSET);
+ }
- /**
- * What is the current version of webtrees.
- *
- * @return string
- */
- public function webtreesVersion() {
- return WT_VERSION;
- }
+ /**
+ * What is the current version of webtrees.
+ *
+ * @return string
+ */
+ public function webtreesVersion()
+ {
+ return WT_VERSION;
+ }
- /**
- * These functions provide access to hitcounter for use in the HTML block.
- *
- * @param string $page_name
- * @param string[] $params
- *
- * @return string
- */
- private function hitCountQuery($page_name, $params) {
- if (is_array($params) && isset($params[0]) && $params[0] != '') {
- $page_parameter = $params[0];
- } else {
- $page_parameter = '';
- }
+ /**
+ * These functions provide access to hitcounter for use in the HTML block.
+ *
+ * @param string $page_name
+ * @param string[] $params
+ *
+ * @return string
+ */
+ private function hitCountQuery($page_name, $params)
+ {
+ if (is_array($params) && isset($params[0]) && $params[0] != '') {
+ $page_parameter = $params[0];
+ } else {
+ $page_parameter = '';
+ }
- if ($page_name === null) {
- // index.php?ctype=gedcom
- $page_name = 'index.php';
- $page_parameter = 'gedcom:' . ($page_parameter ? Tree::findByName($page_parameter)->getTreeId() : $this->tree->getTreeId());
- } elseif ($page_name == 'index.php') {
- // index.php?ctype=user
- $user = User::findByIdentifier($page_parameter);
- $page_parameter = 'user:' . ($user ? $user->getUserId() : Auth::id());
- } else {
- // indi/fam/sour/etc.
- }
+ if ($page_name === null) {
+ // index.php?ctype=gedcom
+ $page_name = 'index.php';
+ $page_parameter = 'gedcom:' . ($page_parameter ? Tree::findByName($page_parameter)->getTreeId() : $this->tree->getTreeId());
+ } elseif ($page_name == 'index.php') {
+ // index.php?ctype=user
+ $user = User::findByIdentifier($page_parameter);
+ $page_parameter = 'user:' . ($user ? $user->getUserId() : Auth::id());
+ } else {
+ // indi/fam/sour/etc.
+ }
- return '<span class="odometer">' . I18N::digits(PageHitCounter::getCount($this->tree, $page_name, $page_parameter)) . '</span>';
- }
+ return '<span class="odometer">' . I18N::digits(PageHitCounter::getCount($this->tree, $page_name, $page_parameter)) . '</span>';
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCount($params = []) {
- return $this->hitCountQuery(null, $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCount($params = [])
+ {
+ return $this->hitCountQuery(null, $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountUser($params = []) {
- return $this->hitCountQuery('index.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountUser($params = [])
+ {
+ return $this->hitCountQuery('index.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountIndi($params = []) {
- return $this->hitCountQuery('individual.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountIndi($params = [])
+ {
+ return $this->hitCountQuery('individual.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountFam($params = []) {
- return $this->hitCountQuery('family.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountFam($params = [])
+ {
+ return $this->hitCountQuery('family.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountSour($params = []) {
- return $this->hitCountQuery('source.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountSour($params = [])
+ {
+ return $this->hitCountQuery('source.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountRepo($params = []) {
- return $this->hitCountQuery('repo.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountRepo($params = [])
+ {
+ return $this->hitCountQuery('repo.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountNote($params = []) {
- return $this->hitCountQuery('note.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountNote($params = [])
+ {
+ return $this->hitCountQuery('note.php', $params);
+ }
- /**
- * How many times has a page been viewed.
- *
- * @param string[] $params
- *
- * @return string
- */
- public function hitCountObje($params = []) {
- return $this->hitCountQuery('mediaviewer.php', $params);
- }
+ /**
+ * How many times has a page been viewed.
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function hitCountObje($params = [])
+ {
+ return $this->hitCountQuery('mediaviewer.php', $params);
+ }
- /**
- * Convert numbers to Google's custom encoding.
- *
- * @link http://bendodson.com/news/google-extended-encoding-made-easy
- *
- * @param int[] $a
- *
- * @return string
- */
- private function arrayToExtendedEncoding($a) {
- $xencoding = self::GOOGLE_CHART_ENCODING;
+ /**
+ * Convert numbers to Google's custom encoding.
+ *
+ * @link http://bendodson.com/news/google-extended-encoding-made-easy
+ *
+ * @param int[] $a
+ *
+ * @return string
+ */
+ private function arrayToExtendedEncoding($a)
+ {
+ $xencoding = self::GOOGLE_CHART_ENCODING;
- $encoding = '';
- foreach ($a as $value) {
- if ($value < 0) {
- $value = 0;
- }
- $first = (int) ($value / 64);
- $second = $value % 64;
- $encoding .= $xencoding[(int) $first] . $xencoding[(int) $second];
- }
+ $encoding = '';
+ foreach ($a as $value) {
+ if ($value < 0) {
+ $value = 0;
+ }
+ $first = (int)($value / 64);
+ $second = $value % 64;
+ $encoding .= $xencoding[(int)$first] . $xencoding[(int)$second];
+ }
- return $encoding;
- }
+ return $encoding;
+ }
- /**
- * Run an SQL query and cache the result.
- *
- * @param string $sql
- *
- * @return string[][]
- */
- private function runSql($sql) {
- static $cache = [];
+ /**
+ * Run an SQL query and cache the result.
+ *
+ * @param string $sql
+ *
+ * @return string[][]
+ */
+ private function runSql($sql)
+ {
+ static $cache = [];
- $id = md5($sql);
- if (isset($cache[$id])) {
- return $cache[$id];
- }
- $rows = Database::prepare($sql)->fetchAll(PDO::FETCH_ASSOC);
- $cache[$id] = $rows;
+ $id = md5($sql);
+ if (isset($cache[$id])) {
+ return $cache[$id];
+ }
+ $rows = Database::prepare($sql)->fetchAll(PDO::FETCH_ASSOC);
+ $cache[$id] = $rows;
- return $rows;
- }
+ return $rows;
+ }
- /**
- * Find the favorites for the tree.
- *
- * @param Tree $tree
- *
- * @return string
- */
- public function gedcomFavorites(Tree $tree) {
- if (Module::getModuleByName('gedcom_favorites')) {
- $block = new FamilyTreeFavoritesModule(WT_MODULES_DIR . 'gedcom_favorites');
+ /**
+ * Find the favorites for the tree.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function gedcomFavorites(Tree $tree)
+ {
+ if (Module::getModuleByName('gedcom_favorites')) {
+ $block = new FamilyTreeFavoritesModule(WT_MODULES_DIR . 'gedcom_favorites');
- return $block->getBlock($tree, 0, false);
- } else {
- return '';
- }
- }
+ return $block->getBlock($tree, 0, false);
+ } else {
+ return '';
+ }
+ }
- /**
- * Find the favorites for the user.
- *
- * @param Tree $tree
- * @return string
- */
- public function userFavorites(Tree $tree) {
- if (Auth::check() && Module::getModuleByName('user_favorites')) {
- $block = new UserFavoritesModule(WT_MODULES_DIR . 'gedcom_favorites');
+ /**
+ * Find the favorites for the user.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function userFavorites(Tree $tree)
+ {
+ if (Auth::check() && Module::getModuleByName('user_favorites')) {
+ $block = new UserFavoritesModule(WT_MODULES_DIR . 'gedcom_favorites');
- return $block->getBlock($tree, 0, false);
- } else {
- return '';
- }
- }
+ return $block->getBlock($tree, 0, false);
+ } else {
+ return '';
+ }
+ }
- /**
- * Find the number of favorites for the tree.
- *
- * @return int
- */
- public function totalGedcomFavorites() {
- if (Module::getModuleByName('gedcom_favorites')) {
- return count(FamilyTreeFavoritesModule::getFavorites($this->tree, Auth::user()));
- } else {
- return 0;
- }
- }
+ /**
+ * Find the number of favorites for the tree.
+ *
+ * @return int
+ */
+ public function totalGedcomFavorites()
+ {
+ if (Module::getModuleByName('gedcom_favorites')) {
+ return count(FamilyTreeFavoritesModule::getFavorites($this->tree, Auth::user()));
+ } else {
+ return 0;
+ }
+ }
- /**
- * Find the number of favorites for the user.
- *
- * @return int
- */
- public function totalUserFavorites() {
- if (Module::getModuleByName('user_favorites')) {
- return count(UserFavoritesModule::getFavorites($this->tree, Auth::user()));
- } else {
- return 0;
- }
- }
+ /**
+ * Find the number of favorites for the user.
+ *
+ * @return int
+ */
+ public function totalUserFavorites()
+ {
+ if (Module::getModuleByName('user_favorites')) {
+ return count(UserFavoritesModule::getFavorites($this->tree, Auth::user()));
+ } else {
+ return 0;
+ }
+ }
- /**
- * Create any of the other blocks.
- *
- * Use as #callBlock:block_name#
- *
- * @param string[] $params
- *
- * @return string
- */
- public function callBlock($params = []) {
- global $ctype;
+ /**
+ * Create any of the other blocks.
+ *
+ * Use as #callBlock:block_name#
+ *
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function callBlock($params = [])
+ {
+ global $ctype;
- if (isset($params[0]) && $params[0] != '') {
- $block = $params[0];
- } else {
- return '';
- }
- $all_blocks = [];
- foreach (Module::getActiveBlocks($this->tree) as $name => $active_block) {
- if ($ctype == 'user' && $active_block->isUserBlock() || $ctype == 'gedcom' && $active_block->isGedcomBlock()) {
- $all_blocks[$name] = $active_block;
- }
- }
- if (!array_key_exists($block, $all_blocks) || $block == 'html') {
- return '';
- }
- // Build the config array
- array_shift($params);
- $cfg = [];
- foreach ($params as $config) {
- $bits = explode('=', $config);
- if (count($bits) < 2) {
- continue;
- }
- $v = array_shift($bits);
- $cfg[$v] = implode('=', $bits);
- }
- $block = $all_blocks[$block];
- $block_id = Filter::getInteger('block_id');
- $content = $block->getBlock($block_id, false, $cfg);
+ if (isset($params[0]) && $params[0] != '') {
+ $block = $params[0];
+ } else {
+ return '';
+ }
+ $all_blocks = [];
+ foreach (Module::getActiveBlocks($this->tree) as $name => $active_block) {
+ if ($ctype == 'user' && $active_block->isUserBlock() || $ctype == 'gedcom' && $active_block->isGedcomBlock()) {
+ $all_blocks[$name] = $active_block;
+ }
+ }
+ if (!array_key_exists($block, $all_blocks) || $block == 'html') {
+ return '';
+ }
+ // Build the config array
+ array_shift($params);
+ $cfg = [];
+ foreach ($params as $config) {
+ $bits = explode('=', $config);
+ if (count($bits) < 2) {
+ continue;
+ }
+ $v = array_shift($bits);
+ $cfg[$v] = implode('=', $bits);
+ }
+ $block = $all_blocks[$block];
+ $block_id = Filter::getInteger('block_id');
+ $content = $block->getBlock($block_id, false, $cfg);
- return $content;
- }
+ return $content;
+ }
- /**
- * How many messages in the user's inbox.
- *
- * @return string
- */
- public function totalUserMessages() {
- $total = (int) Database::prepare("SELECT COUNT(*) FROM `##message` WHERE user_id = ?")
- ->execute([Auth::id()])
- ->fetchOne();
+ /**
+ * How many messages in the user's inbox.
+ *
+ * @return string
+ */
+ public function totalUserMessages()
+ {
+ $total = (int)Database::prepare("SELECT COUNT(*) FROM `##message` WHERE user_id = ?")
+ ->execute([Auth::id()])
+ ->fetchOne();
- return I18N::number($total);
- }
+ return I18N::number($total);
+ }
- /**
- * How many blog entries exist for this user.
- *
- * @return string
- */
- public function totalUserJournal() {
- try {
- $number = (int) Database::prepare("SELECT COUNT(*) FROM `##news` WHERE user_id = ?")
- ->execute([Auth::id()])
- ->fetchOne();
- } catch (PDOException $ex) {
- DebugBar::addThrowable($ex);
+ /**
+ * How many blog entries exist for this user.
+ *
+ * @return string
+ */
+ public function totalUserJournal()
+ {
+ try {
+ $number = (int)Database::prepare("SELECT COUNT(*) FROM `##news` WHERE user_id = ?")
+ ->execute([Auth::id()])
+ ->fetchOne();
+ } catch (PDOException $ex) {
+ DebugBar::addThrowable($ex);
- // The module may not be installed, so the table may not exist.
- $number = 0;
- }
+ // The module may not be installed, so the table may not exist.
+ $number = 0;
+ }
- return I18N::number($number);
- }
+ return I18N::number($number);
+ }
- /**
- * How many news items exist for this tree.
- *
- * @return string
- */
- public function totalGedcomNews() {
- try {
- $number = (int) Database::prepare("SELECT COUNT(*) FROM `##news` WHERE gedcom_id = ?")
- ->execute([$this->tree->getTreeId()])
- ->fetchOne();
- } catch (PDOException $ex) {
- DebugBar::addThrowable($ex);
+ /**
+ * How many news items exist for this tree.
+ *
+ * @return string
+ */
+ public function totalGedcomNews()
+ {
+ try {
+ $number = (int)Database::prepare("SELECT COUNT(*) FROM `##news` WHERE gedcom_id = ?")
+ ->execute([$this->tree->getTreeId()])
+ ->fetchOne();
+ } catch (PDOException $ex) {
+ DebugBar::addThrowable($ex);
- // The module may not be installed, so the table may not exist.
- $number = 0;
- }
+ // The module may not be installed, so the table may not exist.
+ $number = 0;
+ }
- return I18N::number($number);
- }
+ return I18N::number($number);
+ }
- /**
- * ISO3166 3 letter codes, with their 2 letter equivalent.
- * NOTE: this is not 1:1. ENG/SCO/WAL/NIR => GB
- * NOTE: this also includes champman codes and others. Should it?
- *
- * @return string[]
- */
- public function iso3166() {
- return [
- 'ABW' => 'AW', 'AFG' => 'AF', 'AGO' => 'AO', 'AIA' => 'AI', 'ALA' => 'AX', 'ALB' => 'AL',
- 'AND' => 'AD', 'ARE' => 'AE', 'ARG' => 'AR', 'ARM' => 'AM', 'ASM' => 'AS',
- 'ATA' => 'AQ', 'ATF' => 'TF', 'ATG' => 'AG', 'AUS' => 'AU', 'AUT' => 'AT', 'AZE' => 'AZ',
- 'BDI' => 'BI', 'BEL' => 'BE', 'BEN' => 'BJ', 'BFA' => 'BF', 'BGD' => 'BD', 'BGR' => 'BG',
- 'BHR' => 'BH', 'BHS' => 'BS', 'BIH' => 'BA', 'BLR' => 'BY', 'BLZ' => 'BZ', 'BMU' => 'BM',
- 'BOL' => 'BO', 'BRA' => 'BR', 'BRB' => 'BB', 'BRN' => 'BN', 'BTN' => 'BT', 'BVT' => 'BV',
- 'BWA' => 'BW', 'CAF' => 'CF', 'CAN' => 'CA', 'CCK' => 'CC', 'CHE' => 'CH', 'CHL' => 'CL',
- 'CHN' => 'CN', 'CIV' => 'CI', 'CMR' => 'CM', 'COD' => 'CD', 'COG' => 'CG',
- 'COK' => 'CK', 'COL' => 'CO', 'COM' => 'KM', 'CPV' => 'CV', 'CRI' => 'CR', 'CUB' => 'CU',
- 'CXR' => 'CX', 'CYM' => 'KY', 'CYP' => 'CY', 'CZE' => 'CZ', 'DEU' => 'DE', 'DJI' => 'DJ',
- 'DMA' => 'DM', 'DNK' => 'DK', 'DOM' => 'DO', 'DZA' => 'DZ', 'ECU' => 'EC', 'EGY' => 'EG',
- 'ENG' => 'GB', 'ERI' => 'ER', 'ESH' => 'EH', 'ESP' => 'ES', 'EST' => 'EE', 'ETH' => 'ET',
- 'FIN' => 'FI', 'FJI' => 'FJ', 'FLK' => 'FK', 'FRA' => 'FR', 'FRO' => 'FO', 'FSM' => 'FM',
- 'GAB' => 'GA', 'GBR' => 'GB', 'GEO' => 'GE', 'GHA' => 'GH', 'GIB' => 'GI', 'GIN' => 'GN',
- 'GLP' => 'GP', 'GMB' => 'GM', 'GNB' => 'GW', 'GNQ' => 'GQ', 'GRC' => 'GR', 'GRD' => 'GD',
- 'GRL' => 'GL', 'GTM' => 'GT', 'GUF' => 'GF', 'GUM' => 'GU', 'GUY' => 'GY', 'HKG' => 'HK',
- 'HMD' => 'HM', 'HND' => 'HN', 'HRV' => 'HR', 'HTI' => 'HT', 'HUN' => 'HU', 'IDN' => 'ID',
- 'IND' => 'IN', 'IOT' => 'IO', 'IRL' => 'IE', 'IRN' => 'IR', 'IRQ' => 'IQ', 'ISL' => 'IS',
- 'ISR' => 'IL', 'ITA' => 'IT', 'JAM' => 'JM', 'JOR' => 'JO', 'JPN' => 'JA', 'KAZ' => 'KZ',
- 'KEN' => 'KE', 'KGZ' => 'KG', 'KHM' => 'KH', 'KIR' => 'KI', 'KNA' => 'KN', 'KOR' => 'KO',
- 'KWT' => 'KW', 'LAO' => 'LA', 'LBN' => 'LB', 'LBR' => 'LR', 'LBY' => 'LY', 'LCA' => 'LC',
- 'LIE' => 'LI', 'LKA' => 'LK', 'LSO' => 'LS', 'LTU' => 'LT', 'LUX' => 'LU', 'LVA' => 'LV',
- 'MAC' => 'MO', 'MAR' => 'MA', 'MCO' => 'MC', 'MDA' => 'MD', 'MDG' => 'MG', 'MDV' => 'MV',
- 'MEX' => 'MX', 'MHL' => 'MH', 'MKD' => 'MK', 'MLI' => 'ML', 'MLT' => 'MT', 'MMR' => 'MM',
- 'MNG' => 'MN', 'MNP' => 'MP', 'MNT' => 'ME', 'MOZ' => 'MZ', 'MRT' => 'MR', 'MSR' => 'MS',
- 'MTQ' => 'MQ', 'MUS' => 'MU', 'MWI' => 'MW', 'MYS' => 'MY', 'MYT' => 'YT', 'NAM' => 'NA',
- 'NCL' => 'NC', 'NER' => 'NE', 'NFK' => 'NF', 'NGA' => 'NG', 'NIC' => 'NI', 'NIR' => 'GB',
- 'NIU' => 'NU', 'NLD' => 'NL', 'NOR' => 'NO', 'NPL' => 'NP', 'NRU' => 'NR', 'NZL' => 'NZ',
- 'OMN' => 'OM', 'PAK' => 'PK', 'PAN' => 'PA', 'PCN' => 'PN', 'PER' => 'PE', 'PHL' => 'PH',
- 'PLW' => 'PW', 'PNG' => 'PG', 'POL' => 'PL', 'PRI' => 'PR', 'PRK' => 'KP', 'PRT' => 'PO',
- 'PRY' => 'PY', 'PSE' => 'PS', 'PYF' => 'PF', 'QAT' => 'QA', 'REU' => 'RE', 'ROM' => 'RO',
- 'RUS' => 'RU', 'RWA' => 'RW', 'SAU' => 'SA', 'SCT' => 'GB', 'SDN' => 'SD', 'SEN' => 'SN',
- 'SER' => 'RS', 'SGP' => 'SG', 'SGS' => 'GS', 'SHN' => 'SH', 'SJM' => 'SJ',
- 'SLB' => 'SB', 'SLE' => 'SL', 'SLV' => 'SV', 'SMR' => 'SM', 'SOM' => 'SO', 'SPM' => 'PM',
- 'STP' => 'ST', 'SUR' => 'SR', 'SVK' => 'SK', 'SVN' => 'SI', 'SWE' => 'SE',
- 'SWZ' => 'SZ', 'SYC' => 'SC', 'SYR' => 'SY', 'TCA' => 'TC', 'TCD' => 'TD', 'TGO' => 'TG',
- 'THA' => 'TH', 'TJK' => 'TJ', 'TKL' => 'TK', 'TKM' => 'TM', 'TLS' => 'TL', 'TON' => 'TO',
- 'TTO' => 'TT', 'TUN' => 'TN', 'TUR' => 'TR', 'TUV' => 'TV', 'TWN' => 'TW', 'TZA' => 'TZ',
- 'UGA' => 'UG', 'UKR' => 'UA', 'UMI' => 'UM', 'URY' => 'UY', 'USA' => 'US', 'UZB' => 'UZ',
- 'VAT' => 'VA', 'VCT' => 'VC', 'VEN' => 'VE', 'VGB' => 'VG', 'VIR' => 'VI', 'VNM' => 'VN',
- 'VUT' => 'VU', 'WLF' => 'WF', 'WLS' => 'GB', 'WSM' => 'WS', 'YEM' => 'YE', 'ZAF' => 'ZA',
- 'ZMB' => 'ZM', 'ZWE' => 'ZW',
- ];
- }
+ /**
+ * ISO3166 3 letter codes, with their 2 letter equivalent.
+ * NOTE: this is not 1:1. ENG/SCO/WAL/NIR => GB
+ * NOTE: this also includes champman codes and others. Should it?
+ *
+ * @return string[]
+ */
+ public function iso3166()
+ {
+ return [
+ 'ABW' => 'AW',
+ 'AFG' => 'AF',
+ 'AGO' => 'AO',
+ 'AIA' => 'AI',
+ 'ALA' => 'AX',
+ 'ALB' => 'AL',
+ 'AND' => 'AD',
+ 'ARE' => 'AE',
+ 'ARG' => 'AR',
+ 'ARM' => 'AM',
+ 'ASM' => 'AS',
+ 'ATA' => 'AQ',
+ 'ATF' => 'TF',
+ 'ATG' => 'AG',
+ 'AUS' => 'AU',
+ 'AUT' => 'AT',
+ 'AZE' => 'AZ',
+ 'BDI' => 'BI',
+ 'BEL' => 'BE',
+ 'BEN' => 'BJ',
+ 'BFA' => 'BF',
+ 'BGD' => 'BD',
+ 'BGR' => 'BG',
+ 'BHR' => 'BH',
+ 'BHS' => 'BS',
+ 'BIH' => 'BA',
+ 'BLR' => 'BY',
+ 'BLZ' => 'BZ',
+ 'BMU' => 'BM',
+ 'BOL' => 'BO',
+ 'BRA' => 'BR',
+ 'BRB' => 'BB',
+ 'BRN' => 'BN',
+ 'BTN' => 'BT',
+ 'BVT' => 'BV',
+ 'BWA' => 'BW',
+ 'CAF' => 'CF',
+ 'CAN' => 'CA',
+ 'CCK' => 'CC',
+ 'CHE' => 'CH',
+ 'CHL' => 'CL',
+ 'CHN' => 'CN',
+ 'CIV' => 'CI',
+ 'CMR' => 'CM',
+ 'COD' => 'CD',
+ 'COG' => 'CG',
+ 'COK' => 'CK',
+ 'COL' => 'CO',
+ 'COM' => 'KM',
+ 'CPV' => 'CV',
+ 'CRI' => 'CR',
+ 'CUB' => 'CU',
+ 'CXR' => 'CX',
+ 'CYM' => 'KY',
+ 'CYP' => 'CY',
+ 'CZE' => 'CZ',
+ 'DEU' => 'DE',
+ 'DJI' => 'DJ',
+ 'DMA' => 'DM',
+ 'DNK' => 'DK',
+ 'DOM' => 'DO',
+ 'DZA' => 'DZ',
+ 'ECU' => 'EC',
+ 'EGY' => 'EG',
+ 'ENG' => 'GB',
+ 'ERI' => 'ER',
+ 'ESH' => 'EH',
+ 'ESP' => 'ES',
+ 'EST' => 'EE',
+ 'ETH' => 'ET',
+ 'FIN' => 'FI',
+ 'FJI' => 'FJ',
+ 'FLK' => 'FK',
+ 'FRA' => 'FR',
+ 'FRO' => 'FO',
+ 'FSM' => 'FM',
+ 'GAB' => 'GA',
+ 'GBR' => 'GB',
+ 'GEO' => 'GE',
+ 'GHA' => 'GH',
+ 'GIB' => 'GI',
+ 'GIN' => 'GN',
+ 'GLP' => 'GP',
+ 'GMB' => 'GM',
+ 'GNB' => 'GW',
+ 'GNQ' => 'GQ',
+ 'GRC' => 'GR',
+ 'GRD' => 'GD',
+ 'GRL' => 'GL',
+ 'GTM' => 'GT',
+ 'GUF' => 'GF',
+ 'GUM' => 'GU',
+ 'GUY' => 'GY',
+ 'HKG' => 'HK',
+ 'HMD' => 'HM',
+ 'HND' => 'HN',
+ 'HRV' => 'HR',
+ 'HTI' => 'HT',
+ 'HUN' => 'HU',
+ 'IDN' => 'ID',
+ 'IND' => 'IN',
+ 'IOT' => 'IO',
+ 'IRL' => 'IE',
+ 'IRN' => 'IR',
+ 'IRQ' => 'IQ',
+ 'ISL' => 'IS',
+ 'ISR' => 'IL',
+ 'ITA' => 'IT',
+ 'JAM' => 'JM',
+ 'JOR' => 'JO',
+ 'JPN' => 'JA',
+ 'KAZ' => 'KZ',
+ 'KEN' => 'KE',
+ 'KGZ' => 'KG',
+ 'KHM' => 'KH',
+ 'KIR' => 'KI',
+ 'KNA' => 'KN',
+ 'KOR' => 'KO',
+ 'KWT' => 'KW',
+ 'LAO' => 'LA',
+ 'LBN' => 'LB',
+ 'LBR' => 'LR',
+ 'LBY' => 'LY',
+ 'LCA' => 'LC',
+ 'LIE' => 'LI',
+ 'LKA' => 'LK',
+ 'LSO' => 'LS',
+ 'LTU' => 'LT',
+ 'LUX' => 'LU',
+ 'LVA' => 'LV',
+ 'MAC' => 'MO',
+ 'MAR' => 'MA',
+ 'MCO' => 'MC',
+ 'MDA' => 'MD',
+ 'MDG' => 'MG',
+ 'MDV' => 'MV',
+ 'MEX' => 'MX',
+ 'MHL' => 'MH',
+ 'MKD' => 'MK',
+ 'MLI' => 'ML',
+ 'MLT' => 'MT',
+ 'MMR' => 'MM',
+ 'MNG' => 'MN',
+ 'MNP' => 'MP',
+ 'MNT' => 'ME',
+ 'MOZ' => 'MZ',
+ 'MRT' => 'MR',
+ 'MSR' => 'MS',
+ 'MTQ' => 'MQ',
+ 'MUS' => 'MU',
+ 'MWI' => 'MW',
+ 'MYS' => 'MY',
+ 'MYT' => 'YT',
+ 'NAM' => 'NA',
+ 'NCL' => 'NC',
+ 'NER' => 'NE',
+ 'NFK' => 'NF',
+ 'NGA' => 'NG',
+ 'NIC' => 'NI',
+ 'NIR' => 'GB',
+ 'NIU' => 'NU',
+ 'NLD' => 'NL',
+ 'NOR' => 'NO',
+ 'NPL' => 'NP',
+ 'NRU' => 'NR',
+ 'NZL' => 'NZ',
+ 'OMN' => 'OM',
+ 'PAK' => 'PK',
+ 'PAN' => 'PA',
+ 'PCN' => 'PN',
+ 'PER' => 'PE',
+ 'PHL' => 'PH',
+ 'PLW' => 'PW',
+ 'PNG' => 'PG',
+ 'POL' => 'PL',
+ 'PRI' => 'PR',
+ 'PRK' => 'KP',
+ 'PRT' => 'PO',
+ 'PRY' => 'PY',
+ 'PSE' => 'PS',
+ 'PYF' => 'PF',
+ 'QAT' => 'QA',
+ 'REU' => 'RE',
+ 'ROM' => 'RO',
+ 'RUS' => 'RU',
+ 'RWA' => 'RW',
+ 'SAU' => 'SA',
+ 'SCT' => 'GB',
+ 'SDN' => 'SD',
+ 'SEN' => 'SN',
+ 'SER' => 'RS',
+ 'SGP' => 'SG',
+ 'SGS' => 'GS',
+ 'SHN' => 'SH',
+ 'SJM' => 'SJ',
+ 'SLB' => 'SB',
+ 'SLE' => 'SL',
+ 'SLV' => 'SV',
+ 'SMR' => 'SM',
+ 'SOM' => 'SO',
+ 'SPM' => 'PM',
+ 'STP' => 'ST',
+ 'SUR' => 'SR',
+ 'SVK' => 'SK',
+ 'SVN' => 'SI',
+ 'SWE' => 'SE',
+ 'SWZ' => 'SZ',
+ 'SYC' => 'SC',
+ 'SYR' => 'SY',
+ 'TCA' => 'TC',
+ 'TCD' => 'TD',
+ 'TGO' => 'TG',
+ 'THA' => 'TH',
+ 'TJK' => 'TJ',
+ 'TKL' => 'TK',
+ 'TKM' => 'TM',
+ 'TLS' => 'TL',
+ 'TON' => 'TO',
+ 'TTO' => 'TT',
+ 'TUN' => 'TN',
+ 'TUR' => 'TR',
+ 'TUV' => 'TV',
+ 'TWN' => 'TW',
+ 'TZA' => 'TZ',
+ 'UGA' => 'UG',
+ 'UKR' => 'UA',
+ 'UMI' => 'UM',
+ 'URY' => 'UY',
+ 'USA' => 'US',
+ 'UZB' => 'UZ',
+ 'VAT' => 'VA',
+ 'VCT' => 'VC',
+ 'VEN' => 'VE',
+ 'VGB' => 'VG',
+ 'VIR' => 'VI',
+ 'VNM' => 'VN',
+ 'VUT' => 'VU',
+ 'WLF' => 'WF',
+ 'WLS' => 'GB',
+ 'WSM' => 'WS',
+ 'YEM' => 'YE',
+ 'ZAF' => 'ZA',
+ 'ZMB' => 'ZM',
+ 'ZWE' => 'ZW',
+ ];
+ }
- /**
- * Country codes and names
- *
- * @return string[]
- */
- public function getAllCountries() {
- return [
- '???' => /* I18N: Name of a country or state */ I18N::translate('Unknown'),
- 'ABW' => /* I18N: Name of a country or state */ I18N::translate('Aruba'),
- 'AFG' => /* I18N: Name of a country or state */ I18N::translate('Afghanistan'),
- 'AGO' => /* I18N: Name of a country or state */ I18N::translate('Angola'),
- 'AIA' => /* I18N: Name of a country or state */ I18N::translate('Anguilla'),
- 'ALA' => /* I18N: Name of a country or state */ I18N::translate('Aland Islands'),
- 'ALB' => /* I18N: Name of a country or state */ I18N::translate('Albania'),
- 'AND' => /* I18N: Name of a country or state */ I18N::translate('Andorra'),
- 'ARE' => /* I18N: Name of a country or state */ I18N::translate('United Arab Emirates'),
- 'ARG' => /* I18N: Name of a country or state */ I18N::translate('Argentina'),
- 'ARM' => /* I18N: Name of a country or state */ I18N::translate('Armenia'),
- 'ASM' => /* I18N: Name of a country or state */ I18N::translate('American Samoa'),
- 'ATA' => /* I18N: Name of a country or state */ I18N::translate('Antarctica'),
- 'ATF' => /* I18N: Name of a country or state */ I18N::translate('French Southern Territories'),
- 'ATG' => /* I18N: Name of a country or state */ I18N::translate('Antigua and Barbuda'),
- 'AUS' => /* I18N: Name of a country or state */ I18N::translate('Australia'),
- 'AUT' => /* I18N: Name of a country or state */ I18N::translate('Austria'),
- 'AZE' => /* I18N: Name of a country or state */ I18N::translate('Azerbaijan'),
- 'AZR' => /* I18N: Name of a country or state */ I18N::translate('Azores'),
- 'BDI' => /* I18N: Name of a country or state */ I18N::translate('Burundi'),
- 'BEL' => /* I18N: Name of a country or state */ I18N::translate('Belgium'),
- 'BEN' => /* I18N: Name of a country or state */ I18N::translate('Benin'),
- // BES => Bonaire, Sint Eustatius and Saba
- 'BFA' => /* I18N: Name of a country or state */ I18N::translate('Burkina Faso'),
- 'BGD' => /* I18N: Name of a country or state */ I18N::translate('Bangladesh'),
- 'BGR' => /* I18N: Name of a country or state */ I18N::translate('Bulgaria'),
- 'BHR' => /* I18N: Name of a country or state */ I18N::translate('Bahrain'),
- 'BHS' => /* I18N: Name of a country or state */ I18N::translate('Bahamas'),
- 'BIH' => /* I18N: Name of a country or state */ I18N::translate('Bosnia and Herzegovina'),
- // BLM => Saint Barthélemy
- 'BLR' => /* I18N: Name of a country or state */ I18N::translate('Belarus'),
- 'BLZ' => /* I18N: Name of a country or state */ I18N::translate('Belize'),
- 'BMU' => /* I18N: Name of a country or state */ I18N::translate('Bermuda'),
- 'BOL' => /* I18N: Name of a country or state */ I18N::translate('Bolivia'),
- 'BRA' => /* I18N: Name of a country or state */ I18N::translate('Brazil'),
- 'BRB' => /* I18N: Name of a country or state */ I18N::translate('Barbados'),
- 'BRN' => /* I18N: Name of a country or state */ I18N::translate('Brunei Darussalam'),
- 'BTN' => /* I18N: Name of a country or state */ I18N::translate('Bhutan'),
- 'BVT' => /* I18N: Name of a country or state */ I18N::translate('Bouvet Island'),
- 'BWA' => /* I18N: Name of a country or state */ I18N::translate('Botswana'),
- 'CAF' => /* I18N: Name of a country or state */ I18N::translate('Central African Republic'),
- 'CAN' => /* I18N: Name of a country or state */ I18N::translate('Canada'),
- 'CCK' => /* I18N: Name of a country or state */ I18N::translate('Cocos (Keeling) Islands'),
- 'CHE' => /* I18N: Name of a country or state */ I18N::translate('Switzerland'),
- 'CHL' => /* I18N: Name of a country or state */ I18N::translate('Chile'),
- 'CHN' => /* I18N: Name of a country or state */ I18N::translate('China'),
- 'CIV' => /* I18N: Name of a country or state */ I18N::translate('Cote d’Ivoire'),
- 'CMR' => /* I18N: Name of a country or state */ I18N::translate('Cameroon'),
- 'COD' => /* I18N: Name of a country or state */ I18N::translate('Democratic Republic of the Congo'),
- 'COG' => /* I18N: Name of a country or state */ I18N::translate('Republic of the Congo'),
- 'COK' => /* I18N: Name of a country or state */ I18N::translate('Cook Islands'),
- 'COL' => /* I18N: Name of a country or state */ I18N::translate('Colombia'),
- 'COM' => /* I18N: Name of a country or state */ I18N::translate('Comoros'),
- 'CPV' => /* I18N: Name of a country or state */ I18N::translate('Cape Verde'),
- 'CRI' => /* I18N: Name of a country or state */ I18N::translate('Costa Rica'),
- 'CUB' => /* I18N: Name of a country or state */ I18N::translate('Cuba'),
- // CUW => Curaçao
- 'CXR' => /* I18N: Name of a country or state */ I18N::translate('Christmas Island'),
- 'CYM' => /* I18N: Name of a country or state */ I18N::translate('Cayman Islands'),
- 'CYP' => /* I18N: Name of a country or state */ I18N::translate('Cyprus'),
- 'CZE' => /* I18N: Name of a country or state */ I18N::translate('Czech Republic'),
- 'DEU' => /* I18N: Name of a country or state */ I18N::translate('Germany'),
- 'DJI' => /* I18N: Name of a country or state */ I18N::translate('Djibouti'),
- 'DMA' => /* I18N: Name of a country or state */ I18N::translate('Dominica'),
- 'DNK' => /* I18N: Name of a country or state */ I18N::translate('Denmark'),
- 'DOM' => /* I18N: Name of a country or state */ I18N::translate('Dominican Republic'),
- 'DZA' => /* I18N: Name of a country or state */ I18N::translate('Algeria'),
- 'ECU' => /* I18N: Name of a country or state */ I18N::translate('Ecuador'),
- 'EGY' => /* I18N: Name of a country or state */ I18N::translate('Egypt'),
- 'ENG' => /* I18N: Name of a country or state */ I18N::translate('England'),
- 'ERI' => /* I18N: Name of a country or state */ I18N::translate('Eritrea'),
- 'ESH' => /* I18N: Name of a country or state */ I18N::translate('Western Sahara'),
- 'ESP' => /* I18N: Name of a country or state */ I18N::translate('Spain'),
- 'EST' => /* I18N: Name of a country or state */ I18N::translate('Estonia'),
- 'ETH' => /* I18N: Name of a country or state */ I18N::translate('Ethiopia'),
- 'FIN' => /* I18N: Name of a country or state */ I18N::translate('Finland'),
- 'FJI' => /* I18N: Name of a country or state */ I18N::translate('Fiji'),
- 'FLD' => /* I18N: Name of a country or state */ I18N::translate('Flanders'),
- 'FLK' => /* I18N: Name of a country or state */ I18N::translate('Falkland Islands'),
- 'FRA' => /* I18N: Name of a country or state */ I18N::translate('France'),
- 'FRO' => /* I18N: Name of a country or state */ I18N::translate('Faroe Islands'),
- 'FSM' => /* I18N: Name of a country or state */ I18N::translate('Micronesia'),
- 'GAB' => /* I18N: Name of a country or state */ I18N::translate('Gabon'),
- 'GBR' => /* I18N: Name of a country or state */ I18N::translate('United Kingdom'),
- 'GEO' => /* I18N: Name of a country or state */ I18N::translate('Georgia'),
- 'GGY' => /* I18N: Name of a country or state */ I18N::translate('Guernsey'),
- 'GHA' => /* I18N: Name of a country or state */ I18N::translate('Ghana'),
- 'GIB' => /* I18N: Name of a country or state */ I18N::translate('Gibraltar'),
- 'GIN' => /* I18N: Name of a country or state */ I18N::translate('Guinea'),
- 'GLP' => /* I18N: Name of a country or state */ I18N::translate('Guadeloupe'),
- 'GMB' => /* I18N: Name of a country or state */ I18N::translate('Gambia'),
- 'GNB' => /* I18N: Name of a country or state */ I18N::translate('Guinea-Bissau'),
- 'GNQ' => /* I18N: Name of a country or state */ I18N::translate('Equatorial Guinea'),
- 'GRC' => /* I18N: Name of a country or state */ I18N::translate('Greece'),
- 'GRD' => /* I18N: Name of a country or state */ I18N::translate('Grenada'),
- 'GRL' => /* I18N: Name of a country or state */ I18N::translate('Greenland'),
- 'GTM' => /* I18N: Name of a country or state */ I18N::translate('Guatemala'),
- 'GUF' => /* I18N: Name of a country or state */ I18N::translate('French Guiana'),
- 'GUM' => /* I18N: Name of a country or state */ I18N::translate('Guam'),
- 'GUY' => /* I18N: Name of a country or state */ I18N::translate('Guyana'),
- 'HKG' => /* I18N: Name of a country or state */ I18N::translate('Hong Kong'),
- 'HMD' => /* I18N: Name of a country or state */ I18N::translate('Heard Island and McDonald Islands'),
- 'HND' => /* I18N: Name of a country or state */ I18N::translate('Honduras'),
- 'HRV' => /* I18N: Name of a country or state */ I18N::translate('Croatia'),
- 'HTI' => /* I18N: Name of a country or state */ I18N::translate('Haiti'),
- 'HUN' => /* I18N: Name of a country or state */ I18N::translate('Hungary'),
- 'IDN' => /* I18N: Name of a country or state */ I18N::translate('Indonesia'),
- 'IND' => /* I18N: Name of a country or state */ I18N::translate('India'),
- 'IOM' => /* I18N: Name of a country or state */ I18N::translate('Isle of Man'),
- 'IOT' => /* I18N: Name of a country or state */ I18N::translate('British Indian Ocean Territory'),
- 'IRL' => /* I18N: Name of a country or state */ I18N::translate('Ireland'),
- 'IRN' => /* I18N: Name of a country or state */ I18N::translate('Iran'),
- 'IRQ' => /* I18N: Name of a country or state */ I18N::translate('Iraq'),
- 'ISL' => /* I18N: Name of a country or state */ I18N::translate('Iceland'),
- 'ISR' => /* I18N: Name of a country or state */ I18N::translate('Israel'),
- 'ITA' => /* I18N: Name of a country or state */ I18N::translate('Italy'),
- 'JAM' => /* I18N: Name of a country or state */ I18N::translate('Jamaica'),
- //'JEY' => Jersey
- 'JOR' => /* I18N: Name of a country or state */ I18N::translate('Jordan'),
- 'JPN' => /* I18N: Name of a country or state */ I18N::translate('Japan'),
- 'KAZ' => /* I18N: Name of a country or state */ I18N::translate('Kazakhstan'),
- 'KEN' => /* I18N: Name of a country or state */ I18N::translate('Kenya'),
- 'KGZ' => /* I18N: Name of a country or state */ I18N::translate('Kyrgyzstan'),
- 'KHM' => /* I18N: Name of a country or state */ I18N::translate('Cambodia'),
- 'KIR' => /* I18N: Name of a country or state */ I18N::translate('Kiribati'),
- 'KNA' => /* I18N: Name of a country or state */ I18N::translate('Saint Kitts and Nevis'),
- 'KOR' => /* I18N: Name of a country or state */ I18N::translate('Korea'),
- 'KWT' => /* I18N: Name of a country or state */ I18N::translate('Kuwait'),
- 'LAO' => /* I18N: Name of a country or state */ I18N::translate('Laos'),
- 'LBN' => /* I18N: Name of a country or state */ I18N::translate('Lebanon'),
- 'LBR' => /* I18N: Name of a country or state */ I18N::translate('Liberia'),
- 'LBY' => /* I18N: Name of a country or state */ I18N::translate('Libya'),
- 'LCA' => /* I18N: Name of a country or state */ I18N::translate('Saint Lucia'),
- 'LIE' => /* I18N: Name of a country or state */ I18N::translate('Liechtenstein'),
- 'LKA' => /* I18N: Name of a country or state */ I18N::translate('Sri Lanka'),
- 'LSO' => /* I18N: Name of a country or state */ I18N::translate('Lesotho'),
- 'LTU' => /* I18N: Name of a country or state */ I18N::translate('Lithuania'),
- 'LUX' => /* I18N: Name of a country or state */ I18N::translate('Luxembourg'),
- 'LVA' => /* I18N: Name of a country or state */ I18N::translate('Latvia'),
- 'MAC' => /* I18N: Name of a country or state */ I18N::translate('Macau'),
- // MAF => Saint Martin
- 'MAR' => /* I18N: Name of a country or state */ I18N::translate('Morocco'),
- 'MCO' => /* I18N: Name of a country or state */ I18N::translate('Monaco'),
- 'MDA' => /* I18N: Name of a country or state */ I18N::translate('Moldova'),
- 'MDG' => /* I18N: Name of a country or state */ I18N::translate('Madagascar'),
- 'MDV' => /* I18N: Name of a country or state */ I18N::translate('Maldives'),
- 'MEX' => /* I18N: Name of a country or state */ I18N::translate('Mexico'),
- 'MHL' => /* I18N: Name of a country or state */ I18N::translate('Marshall Islands'),
- 'MKD' => /* I18N: Name of a country or state */ I18N::translate('Macedonia'),
- 'MLI' => /* I18N: Name of a country or state */ I18N::translate('Mali'),
- 'MLT' => /* I18N: Name of a country or state */ I18N::translate('Malta'),
- 'MMR' => /* I18N: Name of a country or state */ I18N::translate('Myanmar'),
- 'MNG' => /* I18N: Name of a country or state */ I18N::translate('Mongolia'),
- 'MNP' => /* I18N: Name of a country or state */ I18N::translate('Northern Mariana Islands'),
- 'MNT' => /* I18N: Name of a country or state */ I18N::translate('Montenegro'),
- 'MOZ' => /* I18N: Name of a country or state */ I18N::translate('Mozambique'),
- 'MRT' => /* I18N: Name of a country or state */ I18N::translate('Mauritania'),
- 'MSR' => /* I18N: Name of a country or state */ I18N::translate('Montserrat'),
- 'MTQ' => /* I18N: Name of a country or state */ I18N::translate('Martinique'),
- 'MUS' => /* I18N: Name of a country or state */ I18N::translate('Mauritius'),
- 'MWI' => /* I18N: Name of a country or state */ I18N::translate('Malawi'),
- 'MYS' => /* I18N: Name of a country or state */ I18N::translate('Malaysia'),
- 'MYT' => /* I18N: Name of a country or state */ I18N::translate('Mayotte'),
- 'NAM' => /* I18N: Name of a country or state */ I18N::translate('Namibia'),
- 'NCL' => /* I18N: Name of a country or state */ I18N::translate('New Caledonia'),
- 'NER' => /* I18N: Name of a country or state */ I18N::translate('Niger'),
- 'NFK' => /* I18N: Name of a country or state */ I18N::translate('Norfolk Island'),
- 'NGA' => /* I18N: Name of a country or state */ I18N::translate('Nigeria'),
- 'NIC' => /* I18N: Name of a country or state */ I18N::translate('Nicaragua'),
- 'NIR' => /* I18N: Name of a country or state */ I18N::translate('Northern Ireland'),
- 'NIU' => /* I18N: Name of a country or state */ I18N::translate('Niue'),
- 'NLD' => /* I18N: Name of a country or state */ I18N::translate('Netherlands'),
- 'NOR' => /* I18N: Name of a country or state */ I18N::translate('Norway'),
- 'NPL' => /* I18N: Name of a country or state */ I18N::translate('Nepal'),
- 'NRU' => /* I18N: Name of a country or state */ I18N::translate('Nauru'),
- 'NZL' => /* I18N: Name of a country or state */ I18N::translate('New Zealand'),
- 'OMN' => /* I18N: Name of a country or state */ I18N::translate('Oman'),
- 'PAK' => /* I18N: Name of a country or state */ I18N::translate('Pakistan'),
- 'PAN' => /* I18N: Name of a country or state */ I18N::translate('Panama'),
- 'PCN' => /* I18N: Name of a country or state */ I18N::translate('Pitcairn'),
- 'PER' => /* I18N: Name of a country or state */ I18N::translate('Peru'),
- 'PHL' => /* I18N: Name of a country or state */ I18N::translate('Philippines'),
- 'PLW' => /* I18N: Name of a country or state */ I18N::translate('Palau'),
- 'PNG' => /* I18N: Name of a country or state */ I18N::translate('Papua New Guinea'),
- 'POL' => /* I18N: Name of a country or state */ I18N::translate('Poland'),
- 'PRI' => /* I18N: Name of a country or state */ I18N::translate('Puerto Rico'),
- 'PRK' => /* I18N: Name of a country or state */ I18N::translate('North Korea'),
- 'PRT' => /* I18N: Name of a country or state */ I18N::translate('Portugal'),
- 'PRY' => /* I18N: Name of a country or state */ I18N::translate('Paraguay'),
- 'PSE' => /* I18N: Name of a country or state */ I18N::translate('Occupied Palestinian Territory'),
- 'PYF' => /* I18N: Name of a country or state */ I18N::translate('French Polynesia'),
- 'QAT' => /* I18N: Name of a country or state */ I18N::translate('Qatar'),
- 'REU' => /* I18N: Name of a country or state */ I18N::translate('Reunion'),
- 'ROM' => /* I18N: Name of a country or state */ I18N::translate('Romania'),
- 'RUS' => /* I18N: Name of a country or state */ I18N::translate('Russia'),
- 'RWA' => /* I18N: Name of a country or state */ I18N::translate('Rwanda'),
- 'SAU' => /* I18N: Name of a country or state */ I18N::translate('Saudi Arabia'),
- 'SCT' => /* I18N: Name of a country or state */ I18N::translate('Scotland'),
- 'SDN' => /* I18N: Name of a country or state */ I18N::translate('Sudan'),
- 'SEA' => /* I18N: Name of a country or state */ I18N::translate('At sea'),
- 'SEN' => /* I18N: Name of a country or state */ I18N::translate('Senegal'),
- 'SER' => /* I18N: Name of a country or state */ I18N::translate('Serbia'),
- 'SGP' => /* I18N: Name of a country or state */ I18N::translate('Singapore'),
- 'SGS' => /* I18N: Name of a country or state */ I18N::translate('South Georgia and the South Sandwich Islands'),
- 'SHN' => /* I18N: Name of a country or state */ I18N::translate('Saint Helena'),
- 'SJM' => /* I18N: Name of a country or state */ I18N::translate('Svalbard and Jan Mayen'),
- 'SLB' => /* I18N: Name of a country or state */ I18N::translate('Solomon Islands'),
- 'SLE' => /* I18N: Name of a country or state */ I18N::translate('Sierra Leone'),
- 'SLV' => /* I18N: Name of a country or state */ I18N::translate('El Salvador'),
- 'SMR' => /* I18N: Name of a country or state */ I18N::translate('San Marino'),
- 'SOM' => /* I18N: Name of a country or state */ I18N::translate('Somalia'),
- 'SPM' => /* I18N: Name of a country or state */ I18N::translate('Saint Pierre and Miquelon'),
- 'SSD' => /* I18N: Name of a country or state */ I18N::translate('South Sudan'),
- 'STP' => /* I18N: Name of a country or state */ I18N::translate('Sao Tome and Principe'),
- 'SUR' => /* I18N: Name of a country or state */ I18N::translate('Suriname'),
- 'SVK' => /* I18N: Name of a country or state */ I18N::translate('Slovakia'),
- 'SVN' => /* I18N: Name of a country or state */ I18N::translate('Slovenia'),
- 'SWE' => /* I18N: Name of a country or state */ I18N::translate('Sweden'),
- 'SWZ' => /* I18N: Name of a country or state */ I18N::translate('Swaziland'),
- // SXM => Sint Maarten
- 'SYC' => /* I18N: Name of a country or state */ I18N::translate('Seychelles'),
- 'SYR' => /* I18N: Name of a country or state */ I18N::translate('Syria'),
- 'TCA' => /* I18N: Name of a country or state */ I18N::translate('Turks and Caicos Islands'),
- 'TCD' => /* I18N: Name of a country or state */ I18N::translate('Chad'),
- 'TGO' => /* I18N: Name of a country or state */ I18N::translate('Togo'),
- 'THA' => /* I18N: Name of a country or state */ I18N::translate('Thailand'),
- 'TJK' => /* I18N: Name of a country or state */ I18N::translate('Tajikistan'),
- 'TKL' => /* I18N: Name of a country or state */ I18N::translate('Tokelau'),
- 'TKM' => /* I18N: Name of a country or state */ I18N::translate('Turkmenistan'),
- 'TLS' => /* I18N: Name of a country or state */ I18N::translate('Timor-Leste'),
- 'TON' => /* I18N: Name of a country or state */ I18N::translate('Tonga'),
- 'TTO' => /* I18N: Name of a country or state */ I18N::translate('Trinidad and Tobago'),
- 'TUN' => /* I18N: Name of a country or state */ I18N::translate('Tunisia'),
- 'TUR' => /* I18N: Name of a country or state */ I18N::translate('Turkey'),
- 'TUV' => /* I18N: Name of a country or state */ I18N::translate('Tuvalu'),
- 'TWN' => /* I18N: Name of a country or state */ I18N::translate('Taiwan'),
- 'TZA' => /* I18N: Name of a country or state */ I18N::translate('Tanzania'),
- 'UGA' => /* I18N: Name of a country or state */ I18N::translate('Uganda'),
- 'UKR' => /* I18N: Name of a country or state */ I18N::translate('Ukraine'),
- 'UMI' => /* I18N: Name of a country or state */ I18N::translate('US Minor Outlying Islands'),
- 'URY' => /* I18N: Name of a country or state */ I18N::translate('Uruguay'),
- 'USA' => /* I18N: Name of a country or state */ I18N::translate('United States'),
- 'UZB' => /* I18N: Name of a country or state */ I18N::translate('Uzbekistan'),
- 'VAT' => /* I18N: Name of a country or state */ I18N::translate('Vatican City'),
- 'VCT' => /* I18N: Name of a country or state */ I18N::translate('Saint Vincent and the Grenadines'),
- 'VEN' => /* I18N: Name of a country or state */ I18N::translate('Venezuela'),
- 'VGB' => /* I18N: Name of a country or state */ I18N::translate('British Virgin Islands'),
- 'VIR' => /* I18N: Name of a country or state */ I18N::translate('US Virgin Islands'),
- 'VNM' => /* I18N: Name of a country or state */ I18N::translate('Vietnam'),
- 'VUT' => /* I18N: Name of a country or state */ I18N::translate('Vanuatu'),
- 'WLF' => /* I18N: Name of a country or state */ I18N::translate('Wallis and Futuna'),
- 'WLS' => /* I18N: Name of a country or state */ I18N::translate('Wales'),
- 'WSM' => /* I18N: Name of a country or state */ I18N::translate('Samoa'),
- 'YEM' => /* I18N: Name of a country or state */ I18N::translate('Yemen'),
- 'ZAF' => /* I18N: Name of a country or state */ I18N::translate('South Africa'),
- 'ZMB' => /* I18N: Name of a country or state */ I18N::translate('Zambia'),
- 'ZWE' => /* I18N: Name of a country or state */ I18N::translate('Zimbabwe'),
- ];
- }
+ /**
+ * Country codes and names
+ *
+ * @return string[]
+ */
+ public function getAllCountries()
+ {
+ return [
+ '???' => /* I18N: Name of a country or state */
+ I18N::translate('Unknown'),
+ 'ABW' => /* I18N: Name of a country or state */
+ I18N::translate('Aruba'),
+ 'AFG' => /* I18N: Name of a country or state */
+ I18N::translate('Afghanistan'),
+ 'AGO' => /* I18N: Name of a country or state */
+ I18N::translate('Angola'),
+ 'AIA' => /* I18N: Name of a country or state */
+ I18N::translate('Anguilla'),
+ 'ALA' => /* I18N: Name of a country or state */
+ I18N::translate('Aland Islands'),
+ 'ALB' => /* I18N: Name of a country or state */
+ I18N::translate('Albania'),
+ 'AND' => /* I18N: Name of a country or state */
+ I18N::translate('Andorra'),
+ 'ARE' => /* I18N: Name of a country or state */
+ I18N::translate('United Arab Emirates'),
+ 'ARG' => /* I18N: Name of a country or state */
+ I18N::translate('Argentina'),
+ 'ARM' => /* I18N: Name of a country or state */
+ I18N::translate('Armenia'),
+ 'ASM' => /* I18N: Name of a country or state */
+ I18N::translate('American Samoa'),
+ 'ATA' => /* I18N: Name of a country or state */
+ I18N::translate('Antarctica'),
+ 'ATF' => /* I18N: Name of a country or state */
+ I18N::translate('French Southern Territories'),
+ 'ATG' => /* I18N: Name of a country or state */
+ I18N::translate('Antigua and Barbuda'),
+ 'AUS' => /* I18N: Name of a country or state */
+ I18N::translate('Australia'),
+ 'AUT' => /* I18N: Name of a country or state */
+ I18N::translate('Austria'),
+ 'AZE' => /* I18N: Name of a country or state */
+ I18N::translate('Azerbaijan'),
+ 'AZR' => /* I18N: Name of a country or state */
+ I18N::translate('Azores'),
+ 'BDI' => /* I18N: Name of a country or state */
+ I18N::translate('Burundi'),
+ 'BEL' => /* I18N: Name of a country or state */
+ I18N::translate('Belgium'),
+ 'BEN' => /* I18N: Name of a country or state */
+ I18N::translate('Benin'),
+ // BES => Bonaire, Sint Eustatius and Saba
+ 'BFA' => /* I18N: Name of a country or state */
+ I18N::translate('Burkina Faso'),
+ 'BGD' => /* I18N: Name of a country or state */
+ I18N::translate('Bangladesh'),
+ 'BGR' => /* I18N: Name of a country or state */
+ I18N::translate('Bulgaria'),
+ 'BHR' => /* I18N: Name of a country or state */
+ I18N::translate('Bahrain'),
+ 'BHS' => /* I18N: Name of a country or state */
+ I18N::translate('Bahamas'),
+ 'BIH' => /* I18N: Name of a country or state */
+ I18N::translate('Bosnia and Herzegovina'),
+ // BLM => Saint Barthélemy
+ 'BLR' => /* I18N: Name of a country or state */
+ I18N::translate('Belarus'),
+ 'BLZ' => /* I18N: Name of a country or state */
+ I18N::translate('Belize'),
+ 'BMU' => /* I18N: Name of a country or state */
+ I18N::translate('Bermuda'),
+ 'BOL' => /* I18N: Name of a country or state */
+ I18N::translate('Bolivia'),
+ 'BRA' => /* I18N: Name of a country or state */
+ I18N::translate('Brazil'),
+ 'BRB' => /* I18N: Name of a country or state */
+ I18N::translate('Barbados'),
+ 'BRN' => /* I18N: Name of a country or state */
+ I18N::translate('Brunei Darussalam'),
+ 'BTN' => /* I18N: Name of a country or state */
+ I18N::translate('Bhutan'),
+ 'BVT' => /* I18N: Name of a country or state */
+ I18N::translate('Bouvet Island'),
+ 'BWA' => /* I18N: Name of a country or state */
+ I18N::translate('Botswana'),
+ 'CAF' => /* I18N: Name of a country or state */
+ I18N::translate('Central African Republic'),
+ 'CAN' => /* I18N: Name of a country or state */
+ I18N::translate('Canada'),
+ 'CCK' => /* I18N: Name of a country or state */
+ I18N::translate('Cocos (Keeling) Islands'),
+ 'CHE' => /* I18N: Name of a country or state */
+ I18N::translate('Switzerland'),
+ 'CHL' => /* I18N: Name of a country or state */
+ I18N::translate('Chile'),
+ 'CHN' => /* I18N: Name of a country or state */
+ I18N::translate('China'),
+ 'CIV' => /* I18N: Name of a country or state */
+ I18N::translate('Cote d’Ivoire'),
+ 'CMR' => /* I18N: Name of a country or state */
+ I18N::translate('Cameroon'),
+ 'COD' => /* I18N: Name of a country or state */
+ I18N::translate('Democratic Republic of the Congo'),
+ 'COG' => /* I18N: Name of a country or state */
+ I18N::translate('Republic of the Congo'),
+ 'COK' => /* I18N: Name of a country or state */
+ I18N::translate('Cook Islands'),
+ 'COL' => /* I18N: Name of a country or state */
+ I18N::translate('Colombia'),
+ 'COM' => /* I18N: Name of a country or state */
+ I18N::translate('Comoros'),
+ 'CPV' => /* I18N: Name of a country or state */
+ I18N::translate('Cape Verde'),
+ 'CRI' => /* I18N: Name of a country or state */
+ I18N::translate('Costa Rica'),
+ 'CUB' => /* I18N: Name of a country or state */
+ I18N::translate('Cuba'),
+ // CUW => Curaçao
+ 'CXR' => /* I18N: Name of a country or state */
+ I18N::translate('Christmas Island'),
+ 'CYM' => /* I18N: Name of a country or state */
+ I18N::translate('Cayman Islands'),
+ 'CYP' => /* I18N: Name of a country or state */
+ I18N::translate('Cyprus'),
+ 'CZE' => /* I18N: Name of a country or state */
+ I18N::translate('Czech Republic'),
+ 'DEU' => /* I18N: Name of a country or state */
+ I18N::translate('Germany'),
+ 'DJI' => /* I18N: Name of a country or state */
+ I18N::translate('Djibouti'),
+ 'DMA' => /* I18N: Name of a country or state */
+ I18N::translate('Dominica'),
+ 'DNK' => /* I18N: Name of a country or state */
+ I18N::translate('Denmark'),
+ 'DOM' => /* I18N: Name of a country or state */
+ I18N::translate('Dominican Republic'),
+ 'DZA' => /* I18N: Name of a country or state */
+ I18N::translate('Algeria'),
+ 'ECU' => /* I18N: Name of a country or state */
+ I18N::translate('Ecuador'),
+ 'EGY' => /* I18N: Name of a country or state */
+ I18N::translate('Egypt'),
+ 'ENG' => /* I18N: Name of a country or state */
+ I18N::translate('England'),
+ 'ERI' => /* I18N: Name of a country or state */
+ I18N::translate('Eritrea'),
+ 'ESH' => /* I18N: Name of a country or state */
+ I18N::translate('Western Sahara'),
+ 'ESP' => /* I18N: Name of a country or state */
+ I18N::translate('Spain'),
+ 'EST' => /* I18N: Name of a country or state */
+ I18N::translate('Estonia'),
+ 'ETH' => /* I18N: Name of a country or state */
+ I18N::translate('Ethiopia'),
+ 'FIN' => /* I18N: Name of a country or state */
+ I18N::translate('Finland'),
+ 'FJI' => /* I18N: Name of a country or state */
+ I18N::translate('Fiji'),
+ 'FLD' => /* I18N: Name of a country or state */
+ I18N::translate('Flanders'),
+ 'FLK' => /* I18N: Name of a country or state */
+ I18N::translate('Falkland Islands'),
+ 'FRA' => /* I18N: Name of a country or state */
+ I18N::translate('France'),
+ 'FRO' => /* I18N: Name of a country or state */
+ I18N::translate('Faroe Islands'),
+ 'FSM' => /* I18N: Name of a country or state */
+ I18N::translate('Micronesia'),
+ 'GAB' => /* I18N: Name of a country or state */
+ I18N::translate('Gabon'),
+ 'GBR' => /* I18N: Name of a country or state */
+ I18N::translate('United Kingdom'),
+ 'GEO' => /* I18N: Name of a country or state */
+ I18N::translate('Georgia'),
+ 'GGY' => /* I18N: Name of a country or state */
+ I18N::translate('Guernsey'),
+ 'GHA' => /* I18N: Name of a country or state */
+ I18N::translate('Ghana'),
+ 'GIB' => /* I18N: Name of a country or state */
+ I18N::translate('Gibraltar'),
+ 'GIN' => /* I18N: Name of a country or state */
+ I18N::translate('Guinea'),
+ 'GLP' => /* I18N: Name of a country or state */
+ I18N::translate('Guadeloupe'),
+ 'GMB' => /* I18N: Name of a country or state */
+ I18N::translate('Gambia'),
+ 'GNB' => /* I18N: Name of a country or state */
+ I18N::translate('Guinea-Bissau'),
+ 'GNQ' => /* I18N: Name of a country or state */
+ I18N::translate('Equatorial Guinea'),
+ 'GRC' => /* I18N: Name of a country or state */
+ I18N::translate('Greece'),
+ 'GRD' => /* I18N: Name of a country or state */
+ I18N::translate('Grenada'),
+ 'GRL' => /* I18N: Name of a country or state */
+ I18N::translate('Greenland'),
+ 'GTM' => /* I18N: Name of a country or state */
+ I18N::translate('Guatemala'),
+ 'GUF' => /* I18N: Name of a country or state */
+ I18N::translate('French Guiana'),
+ 'GUM' => /* I18N: Name of a country or state */
+ I18N::translate('Guam'),
+ 'GUY' => /* I18N: Name of a country or state */
+ I18N::translate('Guyana'),
+ 'HKG' => /* I18N: Name of a country or state */
+ I18N::translate('Hong Kong'),
+ 'HMD' => /* I18N: Name of a country or state */
+ I18N::translate('Heard Island and McDonald Islands'),
+ 'HND' => /* I18N: Name of a country or state */
+ I18N::translate('Honduras'),
+ 'HRV' => /* I18N: Name of a country or state */
+ I18N::translate('Croatia'),
+ 'HTI' => /* I18N: Name of a country or state */
+ I18N::translate('Haiti'),
+ 'HUN' => /* I18N: Name of a country or state */
+ I18N::translate('Hungary'),
+ 'IDN' => /* I18N: Name of a country or state */
+ I18N::translate('Indonesia'),
+ 'IND' => /* I18N: Name of a country or state */
+ I18N::translate('India'),
+ 'IOM' => /* I18N: Name of a country or state */
+ I18N::translate('Isle of Man'),
+ 'IOT' => /* I18N: Name of a country or state */
+ I18N::translate('British Indian Ocean Territory'),
+ 'IRL' => /* I18N: Name of a country or state */
+ I18N::translate('Ireland'),
+ 'IRN' => /* I18N: Name of a country or state */
+ I18N::translate('Iran'),
+ 'IRQ' => /* I18N: Name of a country or state */
+ I18N::translate('Iraq'),
+ 'ISL' => /* I18N: Name of a country or state */
+ I18N::translate('Iceland'),
+ 'ISR' => /* I18N: Name of a country or state */
+ I18N::translate('Israel'),
+ 'ITA' => /* I18N: Name of a country or state */
+ I18N::translate('Italy'),
+ 'JAM' => /* I18N: Name of a country or state */
+ I18N::translate('Jamaica'),
+ //'JEY' => Jersey
+ 'JOR' => /* I18N: Name of a country or state */
+ I18N::translate('Jordan'),
+ 'JPN' => /* I18N: Name of a country or state */
+ I18N::translate('Japan'),
+ 'KAZ' => /* I18N: Name of a country or state */
+ I18N::translate('Kazakhstan'),
+ 'KEN' => /* I18N: Name of a country or state */
+ I18N::translate('Kenya'),
+ 'KGZ' => /* I18N: Name of a country or state */
+ I18N::translate('Kyrgyzstan'),
+ 'KHM' => /* I18N: Name of a country or state */
+ I18N::translate('Cambodia'),
+ 'KIR' => /* I18N: Name of a country or state */
+ I18N::translate('Kiribati'),
+ 'KNA' => /* I18N: Name of a country or state */
+ I18N::translate('Saint Kitts and Nevis'),
+ 'KOR' => /* I18N: Name of a country or state */
+ I18N::translate('Korea'),
+ 'KWT' => /* I18N: Name of a country or state */
+ I18N::translate('Kuwait'),
+ 'LAO' => /* I18N: Name of a country or state */
+ I18N::translate('Laos'),
+ 'LBN' => /* I18N: Name of a country or state */
+ I18N::translate('Lebanon'),
+ 'LBR' => /* I18N: Name of a country or state */
+ I18N::translate('Liberia'),
+ 'LBY' => /* I18N: Name of a country or state */
+ I18N::translate('Libya'),
+ 'LCA' => /* I18N: Name of a country or state */
+ I18N::translate('Saint Lucia'),
+ 'LIE' => /* I18N: Name of a country or state */
+ I18N::translate('Liechtenstein'),
+ 'LKA' => /* I18N: Name of a country or state */
+ I18N::translate('Sri Lanka'),
+ 'LSO' => /* I18N: Name of a country or state */
+ I18N::translate('Lesotho'),
+ 'LTU' => /* I18N: Name of a country or state */
+ I18N::translate('Lithuania'),
+ 'LUX' => /* I18N: Name of a country or state */
+ I18N::translate('Luxembourg'),
+ 'LVA' => /* I18N: Name of a country or state */
+ I18N::translate('Latvia'),
+ 'MAC' => /* I18N: Name of a country or state */
+ I18N::translate('Macau'),
+ // MAF => Saint Martin
+ 'MAR' => /* I18N: Name of a country or state */
+ I18N::translate('Morocco'),
+ 'MCO' => /* I18N: Name of a country or state */
+ I18N::translate('Monaco'),
+ 'MDA' => /* I18N: Name of a country or state */
+ I18N::translate('Moldova'),
+ 'MDG' => /* I18N: Name of a country or state */
+ I18N::translate('Madagascar'),
+ 'MDV' => /* I18N: Name of a country or state */
+ I18N::translate('Maldives'),
+ 'MEX' => /* I18N: Name of a country or state */
+ I18N::translate('Mexico'),
+ 'MHL' => /* I18N: Name of a country or state */
+ I18N::translate('Marshall Islands'),
+ 'MKD' => /* I18N: Name of a country or state */
+ I18N::translate('Macedonia'),
+ 'MLI' => /* I18N: Name of a country or state */
+ I18N::translate('Mali'),
+ 'MLT' => /* I18N: Name of a country or state */
+ I18N::translate('Malta'),
+ 'MMR' => /* I18N: Name of a country or state */
+ I18N::translate('Myanmar'),
+ 'MNG' => /* I18N: Name of a country or state */
+ I18N::translate('Mongolia'),
+ 'MNP' => /* I18N: Name of a country or state */
+ I18N::translate('Northern Mariana Islands'),
+ 'MNT' => /* I18N: Name of a country or state */
+ I18N::translate('Montenegro'),
+ 'MOZ' => /* I18N: Name of a country or state */
+ I18N::translate('Mozambique'),
+ 'MRT' => /* I18N: Name of a country or state */
+ I18N::translate('Mauritania'),
+ 'MSR' => /* I18N: Name of a country or state */
+ I18N::translate('Montserrat'),
+ 'MTQ' => /* I18N: Name of a country or state */
+ I18N::translate('Martinique'),
+ 'MUS' => /* I18N: Name of a country or state */
+ I18N::translate('Mauritius'),
+ 'MWI' => /* I18N: Name of a country or state */
+ I18N::translate('Malawi'),
+ 'MYS' => /* I18N: Name of a country or state */
+ I18N::translate('Malaysia'),
+ 'MYT' => /* I18N: Name of a country or state */
+ I18N::translate('Mayotte'),
+ 'NAM' => /* I18N: Name of a country or state */
+ I18N::translate('Namibia'),
+ 'NCL' => /* I18N: Name of a country or state */
+ I18N::translate('New Caledonia'),
+ 'NER' => /* I18N: Name of a country or state */
+ I18N::translate('Niger'),
+ 'NFK' => /* I18N: Name of a country or state */
+ I18N::translate('Norfolk Island'),
+ 'NGA' => /* I18N: Name of a country or state */
+ I18N::translate('Nigeria'),
+ 'NIC' => /* I18N: Name of a country or state */
+ I18N::translate('Nicaragua'),
+ 'NIR' => /* I18N: Name of a country or state */
+ I18N::translate('Northern Ireland'),
+ 'NIU' => /* I18N: Name of a country or state */
+ I18N::translate('Niue'),
+ 'NLD' => /* I18N: Name of a country or state */
+ I18N::translate('Netherlands'),
+ 'NOR' => /* I18N: Name of a country or state */
+ I18N::translate('Norway'),
+ 'NPL' => /* I18N: Name of a country or state */
+ I18N::translate('Nepal'),
+ 'NRU' => /* I18N: Name of a country or state */
+ I18N::translate('Nauru'),
+ 'NZL' => /* I18N: Name of a country or state */
+ I18N::translate('New Zealand'),
+ 'OMN' => /* I18N: Name of a country or state */
+ I18N::translate('Oman'),
+ 'PAK' => /* I18N: Name of a country or state */
+ I18N::translate('Pakistan'),
+ 'PAN' => /* I18N: Name of a country or state */
+ I18N::translate('Panama'),
+ 'PCN' => /* I18N: Name of a country or state */
+ I18N::translate('Pitcairn'),
+ 'PER' => /* I18N: Name of a country or state */
+ I18N::translate('Peru'),
+ 'PHL' => /* I18N: Name of a country or state */
+ I18N::translate('Philippines'),
+ 'PLW' => /* I18N: Name of a country or state */
+ I18N::translate('Palau'),
+ 'PNG' => /* I18N: Name of a country or state */
+ I18N::translate('Papua New Guinea'),
+ 'POL' => /* I18N: Name of a country or state */
+ I18N::translate('Poland'),
+ 'PRI' => /* I18N: Name of a country or state */
+ I18N::translate('Puerto Rico'),
+ 'PRK' => /* I18N: Name of a country or state */
+ I18N::translate('North Korea'),
+ 'PRT' => /* I18N: Name of a country or state */
+ I18N::translate('Portugal'),
+ 'PRY' => /* I18N: Name of a country or state */
+ I18N::translate('Paraguay'),
+ 'PSE' => /* I18N: Name of a country or state */
+ I18N::translate('Occupied Palestinian Territory'),
+ 'PYF' => /* I18N: Name of a country or state */
+ I18N::translate('French Polynesia'),
+ 'QAT' => /* I18N: Name of a country or state */
+ I18N::translate('Qatar'),
+ 'REU' => /* I18N: Name of a country or state */
+ I18N::translate('Reunion'),
+ 'ROM' => /* I18N: Name of a country or state */
+ I18N::translate('Romania'),
+ 'RUS' => /* I18N: Name of a country or state */
+ I18N::translate('Russia'),
+ 'RWA' => /* I18N: Name of a country or state */
+ I18N::translate('Rwanda'),
+ 'SAU' => /* I18N: Name of a country or state */
+ I18N::translate('Saudi Arabia'),
+ 'SCT' => /* I18N: Name of a country or state */
+ I18N::translate('Scotland'),
+ 'SDN' => /* I18N: Name of a country or state */
+ I18N::translate('Sudan'),
+ 'SEA' => /* I18N: Name of a country or state */
+ I18N::translate('At sea'),
+ 'SEN' => /* I18N: Name of a country or state */
+ I18N::translate('Senegal'),
+ 'SER' => /* I18N: Name of a country or state */
+ I18N::translate('Serbia'),
+ 'SGP' => /* I18N: Name of a country or state */
+ I18N::translate('Singapore'),
+ 'SGS' => /* I18N: Name of a country or state */
+ I18N::translate('South Georgia and the South Sandwich Islands'),
+ 'SHN' => /* I18N: Name of a country or state */
+ I18N::translate('Saint Helena'),
+ 'SJM' => /* I18N: Name of a country or state */
+ I18N::translate('Svalbard and Jan Mayen'),
+ 'SLB' => /* I18N: Name of a country or state */
+ I18N::translate('Solomon Islands'),
+ 'SLE' => /* I18N: Name of a country or state */
+ I18N::translate('Sierra Leone'),
+ 'SLV' => /* I18N: Name of a country or state */
+ I18N::translate('El Salvador'),
+ 'SMR' => /* I18N: Name of a country or state */
+ I18N::translate('San Marino'),
+ 'SOM' => /* I18N: Name of a country or state */
+ I18N::translate('Somalia'),
+ 'SPM' => /* I18N: Name of a country or state */
+ I18N::translate('Saint Pierre and Miquelon'),
+ 'SSD' => /* I18N: Name of a country or state */
+ I18N::translate('South Sudan'),
+ 'STP' => /* I18N: Name of a country or state */
+ I18N::translate('Sao Tome and Principe'),
+ 'SUR' => /* I18N: Name of a country or state */
+ I18N::translate('Suriname'),
+ 'SVK' => /* I18N: Name of a country or state */
+ I18N::translate('Slovakia'),
+ 'SVN' => /* I18N: Name of a country or state */
+ I18N::translate('Slovenia'),
+ 'SWE' => /* I18N: Name of a country or state */
+ I18N::translate('Sweden'),
+ 'SWZ' => /* I18N: Name of a country or state */
+ I18N::translate('Swaziland'),
+ // SXM => Sint Maarten
+ 'SYC' => /* I18N: Name of a country or state */
+ I18N::translate('Seychelles'),
+ 'SYR' => /* I18N: Name of a country or state */
+ I18N::translate('Syria'),
+ 'TCA' => /* I18N: Name of a country or state */
+ I18N::translate('Turks and Caicos Islands'),
+ 'TCD' => /* I18N: Name of a country or state */
+ I18N::translate('Chad'),
+ 'TGO' => /* I18N: Name of a country or state */
+ I18N::translate('Togo'),
+ 'THA' => /* I18N: Name of a country or state */
+ I18N::translate('Thailand'),
+ 'TJK' => /* I18N: Name of a country or state */
+ I18N::translate('Tajikistan'),
+ 'TKL' => /* I18N: Name of a country or state */
+ I18N::translate('Tokelau'),
+ 'TKM' => /* I18N: Name of a country or state */
+ I18N::translate('Turkmenistan'),
+ 'TLS' => /* I18N: Name of a country or state */
+ I18N::translate('Timor-Leste'),
+ 'TON' => /* I18N: Name of a country or state */
+ I18N::translate('Tonga'),
+ 'TTO' => /* I18N: Name of a country or state */
+ I18N::translate('Trinidad and Tobago'),
+ 'TUN' => /* I18N: Name of a country or state */
+ I18N::translate('Tunisia'),
+ 'TUR' => /* I18N: Name of a country or state */
+ I18N::translate('Turkey'),
+ 'TUV' => /* I18N: Name of a country or state */
+ I18N::translate('Tuvalu'),
+ 'TWN' => /* I18N: Name of a country or state */
+ I18N::translate('Taiwan'),
+ 'TZA' => /* I18N: Name of a country or state */
+ I18N::translate('Tanzania'),
+ 'UGA' => /* I18N: Name of a country or state */
+ I18N::translate('Uganda'),
+ 'UKR' => /* I18N: Name of a country or state */
+ I18N::translate('Ukraine'),
+ 'UMI' => /* I18N: Name of a country or state */
+ I18N::translate('US Minor Outlying Islands'),
+ 'URY' => /* I18N: Name of a country or state */
+ I18N::translate('Uruguay'),
+ 'USA' => /* I18N: Name of a country or state */
+ I18N::translate('United States'),
+ 'UZB' => /* I18N: Name of a country or state */
+ I18N::translate('Uzbekistan'),
+ 'VAT' => /* I18N: Name of a country or state */
+ I18N::translate('Vatican City'),
+ 'VCT' => /* I18N: Name of a country or state */
+ I18N::translate('Saint Vincent and the Grenadines'),
+ 'VEN' => /* I18N: Name of a country or state */
+ I18N::translate('Venezuela'),
+ 'VGB' => /* I18N: Name of a country or state */
+ I18N::translate('British Virgin Islands'),
+ 'VIR' => /* I18N: Name of a country or state */
+ I18N::translate('US Virgin Islands'),
+ 'VNM' => /* I18N: Name of a country or state */
+ I18N::translate('Vietnam'),
+ 'VUT' => /* I18N: Name of a country or state */
+ I18N::translate('Vanuatu'),
+ 'WLF' => /* I18N: Name of a country or state */
+ I18N::translate('Wallis and Futuna'),
+ 'WLS' => /* I18N: Name of a country or state */
+ I18N::translate('Wales'),
+ 'WSM' => /* I18N: Name of a country or state */
+ I18N::translate('Samoa'),
+ 'YEM' => /* I18N: Name of a country or state */
+ I18N::translate('Yemen'),
+ 'ZAF' => /* I18N: Name of a country or state */
+ I18N::translate('South Africa'),
+ 'ZMB' => /* I18N: Name of a country or state */
+ I18N::translate('Zambia'),
+ 'ZWE' => /* I18N: Name of a country or state */
+ I18N::translate('Zimbabwe'),
+ ];
+ }
- /**
- * Century name, English => 21st, Polish => XXI, etc.
- *
- * @param int $century
- *
- * @return string
- */
- private function centuryName($century) {
- if ($century < 0) {
- return str_replace(-$century, self::centuryName(-$century), /* I18N: BCE=Before the Common Era, for Julian years < 0. See http://en.wikipedia.org/wiki/Common_Era */
- I18N::translate('%s BCE', I18N::number(-$century)));
- }
- // The current chart engine (Google charts) can't handle <sup></sup> markup
- switch ($century) {
- case 21:
- return strip_tags(I18N::translateContext('CENTURY', '21st'));
- case 20:
- return strip_tags(I18N::translateContext('CENTURY', '20th'));
- case 19:
- return strip_tags(I18N::translateContext('CENTURY', '19th'));
- case 18:
- return strip_tags(I18N::translateContext('CENTURY', '18th'));
- case 17:
- return strip_tags(I18N::translateContext('CENTURY', '17th'));
- case 16:
- return strip_tags(I18N::translateContext('CENTURY', '16th'));
- case 15:
- return strip_tags(I18N::translateContext('CENTURY', '15th'));
- case 14:
- return strip_tags(I18N::translateContext('CENTURY', '14th'));
- case 13:
- return strip_tags(I18N::translateContext('CENTURY', '13th'));
- case 12:
- return strip_tags(I18N::translateContext('CENTURY', '12th'));
- case 11:
- return strip_tags(I18N::translateContext('CENTURY', '11th'));
- case 10:
- return strip_tags(I18N::translateContext('CENTURY', '10th'));
- case 9:
- return strip_tags(I18N::translateContext('CENTURY', '9th'));
- case 8:
- return strip_tags(I18N::translateContext('CENTURY', '8th'));
- case 7:
- return strip_tags(I18N::translateContext('CENTURY', '7th'));
- case 6:
- return strip_tags(I18N::translateContext('CENTURY', '6th'));
- case 5:
- return strip_tags(I18N::translateContext('CENTURY', '5th'));
- case 4:
- return strip_tags(I18N::translateContext('CENTURY', '4th'));
- case 3:
- return strip_tags(I18N::translateContext('CENTURY', '3rd'));
- case 2:
- return strip_tags(I18N::translateContext('CENTURY', '2nd'));
- case 1:
- return strip_tags(I18N::translateContext('CENTURY', '1st'));
- default:
- return ($century - 1) . '01-' . $century . '00';
- }
- }
+ /**
+ * Century name, English => 21st, Polish => XXI, etc.
+ *
+ * @param int $century
+ *
+ * @return string
+ */
+ private function centuryName($century)
+ {
+ if ($century < 0) {
+ return str_replace(-$century, self::centuryName(-$century), /* I18N: BCE=Before the Common Era, for Julian years < 0. See http://en.wikipedia.org/wiki/Common_Era */
+ I18N::translate('%s BCE', I18N::number(-$century)));
+ }
+ // The current chart engine (Google charts) can't handle <sup></sup> markup
+ switch ($century) {
+ case 21:
+ return strip_tags(I18N::translateContext('CENTURY', '21st'));
+ case 20:
+ return strip_tags(I18N::translateContext('CENTURY', '20th'));
+ case 19:
+ return strip_tags(I18N::translateContext('CENTURY', '19th'));
+ case 18:
+ return strip_tags(I18N::translateContext('CENTURY', '18th'));
+ case 17:
+ return strip_tags(I18N::translateContext('CENTURY', '17th'));
+ case 16:
+ return strip_tags(I18N::translateContext('CENTURY', '16th'));
+ case 15:
+ return strip_tags(I18N::translateContext('CENTURY', '15th'));
+ case 14:
+ return strip_tags(I18N::translateContext('CENTURY', '14th'));
+ case 13:
+ return strip_tags(I18N::translateContext('CENTURY', '13th'));
+ case 12:
+ return strip_tags(I18N::translateContext('CENTURY', '12th'));
+ case 11:
+ return strip_tags(I18N::translateContext('CENTURY', '11th'));
+ case 10:
+ return strip_tags(I18N::translateContext('CENTURY', '10th'));
+ case 9:
+ return strip_tags(I18N::translateContext('CENTURY', '9th'));
+ case 8:
+ return strip_tags(I18N::translateContext('CENTURY', '8th'));
+ case 7:
+ return strip_tags(I18N::translateContext('CENTURY', '7th'));
+ case 6:
+ return strip_tags(I18N::translateContext('CENTURY', '6th'));
+ case 5:
+ return strip_tags(I18N::translateContext('CENTURY', '5th'));
+ case 4:
+ return strip_tags(I18N::translateContext('CENTURY', '4th'));
+ case 3:
+ return strip_tags(I18N::translateContext('CENTURY', '3rd'));
+ case 2:
+ return strip_tags(I18N::translateContext('CENTURY', '2nd'));
+ case 1:
+ return strip_tags(I18N::translateContext('CENTURY', '1st'));
+ default:
+ return ($century - 1) . '01-' . $century . '00';
+ }
+ }
}