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