xref: /webtrees/app/Statistics/Google/ChartAge.php (revision bf57b58092d898900e7b5483b92b51c65a15460e)
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\I18N;
21use Fisharebest\Webtrees\Statistics\AbstractGoogle;
22use Fisharebest\Webtrees\Statistics\Helper\Century;
23use Fisharebest\Webtrees\Tree;
24use Illuminate\Database\Capsule\Manager as DB;
25use Illuminate\Database\Query\JoinClause;
26
27/**
28 *
29 */
30class ChartAge extends AbstractGoogle
31{
32    /**
33     * @var Tree
34     */
35    private $tree;
36
37    /**
38     * @var Century
39     */
40    private $centuryHelper;
41
42    /**
43     * Constructor.
44     *
45     * @param Tree $tree
46     */
47    public function __construct(Tree $tree)
48    {
49        $this->tree          = $tree;
50        $this->centuryHelper = new Century();
51    }
52
53    /**
54     * Returns the related database records.
55     *
56     * @return \stdClass[]
57     */
58    private function queryRecords(): array
59    {
60        $prefix = DB::connection()->getTablePrefix();
61
62        return DB::table('individuals')
63            ->join('dates AS birth', function (JoinClause $join): void {
64                $join
65                    ->on('birth.d_file', '=', 'i_file')
66                    ->on('birth.d_gid', '=', 'i_id');
67            })
68           ->join('dates AS death', function (JoinClause $join): void {
69               $join
70                    ->on('death.d_file', '=', 'i_file')
71                    ->on('death.d_gid', '=', 'i_id');
72           })
73            ->where('i_file', '=', $this->tree->id())
74            ->where('birth.d_fact', '=', 'BIRT')
75            ->where('death.d_fact', '=', 'DEAT')
76            ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
77            ->whereIn('death.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
78            ->whereColumn('death.d_julianday1', '>=', 'birth.d_julianday2')
79            ->where('birth.d_julianday2', '<>', 0)
80            ->select([
81                DB::raw('ROUND(AVG(' . $prefix . 'death.d_julianday2 - ' . $prefix . 'birth.d_julianday1) / 365.25,1) AS age'),
82                DB::raw('ROUND((' . $prefix . 'death.d_year - 50) / 100) AS century'),
83                'i_sex AS sex'
84            ])
85            ->groupBy(['century', 'sex'])
86            ->orderBy('century')
87            ->orderBy('sex')
88            ->get()
89            ->all();
90    }
91
92    /**
93     * General query on ages.
94     *
95     * @param string $size
96     *
97     * @return string
98     */
99    public function chartAge(string $size = '230x250'): string
100    {
101        $sizes = explode('x', $size);
102        $rows  = $this->queryRecords();
103
104        if (empty($rows)) {
105            return '';
106        }
107
108        $chxl    = '0:|';
109        $countsm = '';
110        $countsf = '';
111        $countsa = '';
112        $out     = [];
113
114        foreach ($rows as $values) {
115            $out[(int) $values->century][$values->sex] = $values->age;
116        }
117
118        foreach ($out as $century => $values) {
119            if ($sizes[0] < 980) {
120                $sizes[0] += 50;
121            }
122            $chxl .= $this->centuryHelper->centuryName($century) . '|';
123
124            $female_age  = $values['F'] ?? 0;
125            $male_age    = $values['M'] ?? 0;
126            $average_age = $female_age + $male_age;
127
128            if ($female_age > 0 && $male_age > 0) {
129                $average_age /= 2.0;
130            }
131
132            $countsf .= $female_age . ',';
133            $countsm .= $male_age . ',';
134            $countsa .= $average_age . ',';
135        }
136
137        $countsm = substr($countsm, 0, -1);
138        $countsf = substr($countsf, 0, -1);
139        $countsa = substr($countsa, 0, -1);
140        $chd     = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
141        $decades = '';
142
143        for ($i = 0; $i <= 100; $i += 10) {
144            $decades .= '|' . I18N::number($i);
145        }
146
147        $chxl  .= '1:||' . I18N::translate('century') . '|2:' . $decades . '|3:||' . I18N::translate('Age') . '|';
148        $title = I18N::translate('Average age related to death century');
149
150        if (\count($rows) > 6 || mb_strlen($title) < 30) {
151            $chtt = $title;
152        } else {
153            $offset  = 0;
154            $counter = [];
155
156            while ($offset = strpos($title, ' ', $offset + 1)) {
157                $counter[] = $offset;
158            }
159
160            $half = intdiv(\count($counter), 2);
161            $chtt = substr_replace($title, '|', $counter[$half], 1);
162        }
163
164        $chart_url = 'https://chart.googleapis.com/chart?cht=bvg&amp;chs=' . $sizes[0] . 'x' . $sizes[1]
165             . '&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='
166             . rawurlencode($chtt) . '&amp;chd=' . $chd . '&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl='
167             . rawurlencode($chxl) . '&amp;chdl='
168             . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age at death'));
169
170        return view(
171            'statistics/other/chart-google',
172            [
173                'chart_title' => I18N::translate('Average age related to death century'),
174                'chart_url'   => $chart_url,
175                'sizes'       => $sizes,
176            ]
177        );
178    }
179}
180