xref: /webtrees/app/Statistics/Google/ChartDistribution.php (revision 8add1155cb77caede54752196ff44696d1346431)
1*8add1155SRico Sonntag<?php
2*8add1155SRico Sonntag/**
3*8add1155SRico Sonntag * webtrees: online genealogy
4*8add1155SRico Sonntag * Copyright (C) 2018 webtrees development team
5*8add1155SRico Sonntag * This program is free software: you can redistribute it and/or modify
6*8add1155SRico Sonntag * it under the terms of the GNU General Public License as published by
7*8add1155SRico Sonntag * the Free Software Foundation, either version 3 of the License, or
8*8add1155SRico Sonntag * (at your option) any later version.
9*8add1155SRico Sonntag * This program is distributed in the hope that it will be useful,
10*8add1155SRico Sonntag * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*8add1155SRico Sonntag * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*8add1155SRico Sonntag * GNU General Public License for more details.
13*8add1155SRico Sonntag * You should have received a copy of the GNU General Public License
14*8add1155SRico Sonntag * along with this program. If not, see <http://www.gnu.org/licenses/>.
15*8add1155SRico Sonntag */
16*8add1155SRico Sonntagdeclare(strict_types=1);
17*8add1155SRico Sonntag
18*8add1155SRico Sonntagnamespace Fisharebest\Webtrees\Statistics\Google;
19*8add1155SRico Sonntag
20*8add1155SRico Sonntaguse Fisharebest\Webtrees\Database;
21*8add1155SRico Sonntaguse Fisharebest\Webtrees\I18N;
22*8add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Helper\Country;
23*8add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\AbstractGoogle;
24*8add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\PlaceRepository;
25*8add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\IndividualRepository;
26*8add1155SRico Sonntaguse Fisharebest\Webtrees\Theme;
27*8add1155SRico Sonntaguse Fisharebest\Webtrees\Tree;
28*8add1155SRico Sonntag
29*8add1155SRico Sonntag/**
30*8add1155SRico Sonntag * Create a chart showing where events occurred.
31*8add1155SRico Sonntag */
32*8add1155SRico Sonntagclass ChartDistribution extends AbstractGoogle
33*8add1155SRico Sonntag{
34*8add1155SRico Sonntag    /**
35*8add1155SRico Sonntag     * @var Tree
36*8add1155SRico Sonntag     */
37*8add1155SRico Sonntag    private $tree;
38*8add1155SRico Sonntag
39*8add1155SRico Sonntag    /**
40*8add1155SRico Sonntag     * @var Country
41*8add1155SRico Sonntag     */
42*8add1155SRico Sonntag    private $countryHelper;
43*8add1155SRico Sonntag
44*8add1155SRico Sonntag    /**
45*8add1155SRico Sonntag     * @var IndividualRepository
46*8add1155SRico Sonntag     */
47*8add1155SRico Sonntag    private $individualRepository;
48*8add1155SRico Sonntag
49*8add1155SRico Sonntag    /**
50*8add1155SRico Sonntag     * @var PlaceRepository
51*8add1155SRico Sonntag     */
52*8add1155SRico Sonntag    private $placeRepository;
53*8add1155SRico Sonntag
54*8add1155SRico Sonntag    /**
55*8add1155SRico Sonntag     * Constructor.
56*8add1155SRico Sonntag     *
57*8add1155SRico Sonntag     * @param Tree $tree
58*8add1155SRico Sonntag     */
59*8add1155SRico Sonntag    public function __construct(Tree $tree)
60*8add1155SRico Sonntag    {
61*8add1155SRico Sonntag        $this->tree                 = $tree;
62*8add1155SRico Sonntag        $this->countryHelper        = new Country();
63*8add1155SRico Sonntag        $this->individualRepository = new IndividualRepository($tree);
64*8add1155SRico Sonntag        $this->placeRepository      = new PlaceRepository($tree);
65*8add1155SRico Sonntag    }
66*8add1155SRico Sonntag
67*8add1155SRico Sonntag    /**
68*8add1155SRico Sonntag     * Create a chart showing where events occurred.
69*8add1155SRico Sonntag     *
70*8add1155SRico Sonntag     * @param int    $tot_pl      The total number of places
71*8add1155SRico Sonntag     * @param string $chart_shows
72*8add1155SRico Sonntag     * @param string $chart_type
73*8add1155SRico Sonntag     * @param string $surname
74*8add1155SRico Sonntag     *
75*8add1155SRico Sonntag     * @return string
76*8add1155SRico Sonntag     */
77*8add1155SRico Sonntag    public function chartDistribution(
78*8add1155SRico Sonntag        int $tot_pl,
79*8add1155SRico Sonntag        string $chart_shows = 'world',
80*8add1155SRico Sonntag        string $chart_type  = '',
81*8add1155SRico Sonntag        string $surname     = ''
82*8add1155SRico Sonntag    ): string {
83*8add1155SRico Sonntag        $chart_color1 = Theme::theme()->parameter('distribution-chart-no-values');
84*8add1155SRico Sonntag        $chart_color2 = Theme::theme()->parameter('distribution-chart-high-values');
85*8add1155SRico Sonntag        $chart_color3 = Theme::theme()->parameter('distribution-chart-low-values');
86*8add1155SRico Sonntag        $map_x        = Theme::theme()->parameter('distribution-chart-x');
87*8add1155SRico Sonntag        $map_y        = Theme::theme()->parameter('distribution-chart-y');
88*8add1155SRico Sonntag
89*8add1155SRico Sonntag        if ($tot_pl === 0) {
90*8add1155SRico Sonntag            return '';
91*8add1155SRico Sonntag        }
92*8add1155SRico Sonntag
93*8add1155SRico Sonntag        $countries = $this->countryHelper->getAllCountries();
94*8add1155SRico Sonntag
95*8add1155SRico Sonntag        // Get the country names for each language
96*8add1155SRico Sonntag        $country_to_iso3166 = [];
97*8add1155SRico Sonntag        foreach (I18N::activeLocales() as $locale) {
98*8add1155SRico Sonntag            I18N::init($locale->languageTag());
99*8add1155SRico Sonntag
100*8add1155SRico Sonntag            foreach ($this->countryHelper->iso3166() as $three => $two) {
101*8add1155SRico Sonntag                $country_to_iso3166[$three]             = $two;
102*8add1155SRico Sonntag                $country_to_iso3166[$countries[$three]] = $two;
103*8add1155SRico Sonntag            }
104*8add1155SRico Sonntag        }
105*8add1155SRico Sonntag
106*8add1155SRico Sonntag        I18N::init(WT_LOCALE);
107*8add1155SRico Sonntag
108*8add1155SRico Sonntag        switch ($chart_type) {
109*8add1155SRico Sonntag            case 'surname_distribution_chart':
110*8add1155SRico Sonntag                if ($surname === '') {
111*8add1155SRico Sonntag                    $surname = $this->individualRepository->getCommonSurname();
112*8add1155SRico Sonntag                }
113*8add1155SRico Sonntag                $chart_title = I18N::translate('Surname distribution chart') . ': ' . $surname;
114*8add1155SRico Sonntag                // Count how many people are events in each country
115*8add1155SRico Sonntag                $surn_countries = [];
116*8add1155SRico Sonntag
117*8add1155SRico Sonntag                $rows = Database::prepare(
118*8add1155SRico Sonntag                    'SELECT i_gedcom' . ' FROM `##individuals`' . ' JOIN `##name` ON n_id = i_id AND n_file = i_file' . ' WHERE n_file = :tree_id' . ' AND n_surn COLLATE :collate = :surname'
119*8add1155SRico Sonntag                )->execute([
120*8add1155SRico Sonntag                    'tree_id' => $this->tree->id(),
121*8add1155SRico Sonntag                    'collate' => I18N::collation(),
122*8add1155SRico Sonntag                    'surname' => $surname,
123*8add1155SRico Sonntag                ])->fetchAll();
124*8add1155SRico Sonntag
125*8add1155SRico Sonntag                foreach ($rows as $row) {
126*8add1155SRico Sonntag                    if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $row->i_gedcom, $matches)) {
127*8add1155SRico Sonntag                        // webtrees uses 3 letter country codes and localised country names,
128*8add1155SRico Sonntag                        // but google uses 2 letter codes.
129*8add1155SRico Sonntag                        foreach ($matches[1] as $country) {
130*8add1155SRico Sonntag                            if (\array_key_exists($country, $country_to_iso3166)) {
131*8add1155SRico Sonntag                                if (\array_key_exists($country_to_iso3166[$country], $surn_countries)) {
132*8add1155SRico Sonntag                                    $surn_countries[$country_to_iso3166[$country]]++;
133*8add1155SRico Sonntag                                } else {
134*8add1155SRico Sonntag                                    $surn_countries[$country_to_iso3166[$country]] = 1;
135*8add1155SRico Sonntag                                }
136*8add1155SRico Sonntag                            }
137*8add1155SRico Sonntag                        }
138*8add1155SRico Sonntag                    }
139*8add1155SRico Sonntag                }
140*8add1155SRico Sonntag
141*8add1155SRico Sonntag                break;
142*8add1155SRico Sonntag
143*8add1155SRico Sonntag            case 'birth_distribution_chart':
144*8add1155SRico Sonntag                $chart_title = I18N::translate('Birth by country');
145*8add1155SRico Sonntag                // Count how many people were born in each country
146*8add1155SRico Sonntag                $surn_countries = [];
147*8add1155SRico Sonntag                $b_countries    = $this->placeRepository->statsPlaces('INDI', 'BIRT', 0, true);
148*8add1155SRico Sonntag                foreach ($b_countries as $place => $count) {
149*8add1155SRico Sonntag                    $country = $place;
150*8add1155SRico Sonntag                    if (\array_key_exists($country, $country_to_iso3166)) {
151*8add1155SRico Sonntag                        if (!isset($surn_countries[$country_to_iso3166[$country]])) {
152*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] = $count;
153*8add1155SRico Sonntag                        } else {
154*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] += $count;
155*8add1155SRico Sonntag                        }
156*8add1155SRico Sonntag                    }
157*8add1155SRico Sonntag                }
158*8add1155SRico Sonntag                break;
159*8add1155SRico Sonntag
160*8add1155SRico Sonntag            case 'death_distribution_chart':
161*8add1155SRico Sonntag                $chart_title = I18N::translate('Death by country');
162*8add1155SRico Sonntag                // Count how many people were death in each country
163*8add1155SRico Sonntag                $surn_countries = [];
164*8add1155SRico Sonntag                $d_countries    = $this->placeRepository->statsPlaces('INDI', 'DEAT', 0, true);
165*8add1155SRico Sonntag                foreach ($d_countries as $place => $count) {
166*8add1155SRico Sonntag                    $country = $place;
167*8add1155SRico Sonntag                    if (\array_key_exists($country, $country_to_iso3166)) {
168*8add1155SRico Sonntag                        if (!isset($surn_countries[$country_to_iso3166[$country]])) {
169*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] = $count;
170*8add1155SRico Sonntag                        } else {
171*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] += $count;
172*8add1155SRico Sonntag                        }
173*8add1155SRico Sonntag                    }
174*8add1155SRico Sonntag                }
175*8add1155SRico Sonntag                break;
176*8add1155SRico Sonntag
177*8add1155SRico Sonntag            case 'marriage_distribution_chart':
178*8add1155SRico Sonntag                $chart_title = I18N::translate('Marriage by country');
179*8add1155SRico Sonntag                // Count how many families got marriage in each country
180*8add1155SRico Sonntag                $surn_countries = [];
181*8add1155SRico Sonntag                $m_countries    = $this->placeRepository->statsPlaces('FAM');
182*8add1155SRico Sonntag                // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
183*8add1155SRico Sonntag                foreach ($m_countries as $place) {
184*8add1155SRico Sonntag                    $country = $place->country;
185*8add1155SRico Sonntag                    if (\array_key_exists($country, $country_to_iso3166)) {
186*8add1155SRico Sonntag                        if (!isset($surn_countries[$country_to_iso3166[$country]])) {
187*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] = $place->tot;
188*8add1155SRico Sonntag                        } else {
189*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] += $place->tot;
190*8add1155SRico Sonntag                        }
191*8add1155SRico Sonntag                    }
192*8add1155SRico Sonntag                }
193*8add1155SRico Sonntag                break;
194*8add1155SRico Sonntag
195*8add1155SRico Sonntag            case 'indi_distribution_chart':
196*8add1155SRico Sonntag            default:
197*8add1155SRico Sonntag                $chart_title = I18N::translate('Individual distribution chart');
198*8add1155SRico Sonntag                // Count how many people have events in each country
199*8add1155SRico Sonntag                $surn_countries = [];
200*8add1155SRico Sonntag                $a_countries    = $this->placeRepository->statsPlaces('INDI');
201*8add1155SRico Sonntag                // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
202*8add1155SRico Sonntag                foreach ($a_countries as $place) {
203*8add1155SRico Sonntag                    $country = $place->country;
204*8add1155SRico Sonntag                    if (\array_key_exists($country, $country_to_iso3166)) {
205*8add1155SRico Sonntag                        if (!isset($surn_countries[$country_to_iso3166[$country]])) {
206*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] = $place->tot;
207*8add1155SRico Sonntag                        } else {
208*8add1155SRico Sonntag                            $surn_countries[$country_to_iso3166[$country]] += $place->tot;
209*8add1155SRico Sonntag                        }
210*8add1155SRico Sonntag                    }
211*8add1155SRico Sonntag                }
212*8add1155SRico Sonntag                break;
213*8add1155SRico Sonntag        }
214*8add1155SRico Sonntag
215*8add1155SRico Sonntag        $chart_url = 'https://chart.googleapis.com/chart?cht=t&amp;chtm=' . $chart_shows;
216*8add1155SRico Sonntag        $chart_url .= '&amp;chco=' . $chart_color1 . ',' . $chart_color3 . ',' . $chart_color2; // country colours
217*8add1155SRico Sonntag        $chart_url .= '&amp;chf=bg,s,ECF5FF'; // sea colour
218*8add1155SRico Sonntag        $chart_url .= '&amp;chs=' . $map_x . 'x' . $map_y;
219*8add1155SRico Sonntag        $chart_url .= '&amp;chld=' . implode('', array_keys($surn_countries)) . '&amp;chd=s:';
220*8add1155SRico Sonntag
221*8add1155SRico Sonntag        foreach ($surn_countries as $count) {
222*8add1155SRico Sonntag            $chart_url .= substr(self::GOOGLE_CHART_ENCODING, (int) ($count / max($surn_countries) * 61), 1);
223*8add1155SRico Sonntag        }
224*8add1155SRico Sonntag
225*8add1155SRico Sonntag        return view(
226*8add1155SRico Sonntag            'statistics/other/chart-distribution',
227*8add1155SRico Sonntag            [
228*8add1155SRico Sonntag                'chart_title'  => $chart_title,
229*8add1155SRico Sonntag                'chart_url'    => $chart_url,
230*8add1155SRico Sonntag                'chart_color1' => $chart_color1,
231*8add1155SRico Sonntag                'chart_color2' => $chart_color2,
232*8add1155SRico Sonntag                'chart_color3' => $chart_color3,
233*8add1155SRico Sonntag            ]
234*8add1155SRico Sonntag        );
235*8add1155SRico Sonntag    }
236*8add1155SRico Sonntag}
237