xref: /webtrees/app/Statistics/Google/ChartMarriageAge.php (revision b6017f990d38d8c56e04c0096ce9a7e8745ad4ba)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2021 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\Statistics\Google;
21
22use Fisharebest\Webtrees\I18N;
23use Fisharebest\Webtrees\Statistics\Service\CenturyService;
24use Fisharebest\Webtrees\Tree;
25use Illuminate\Database\Capsule\Manager as DB;
26use Illuminate\Database\Query\Expression;
27use Illuminate\Database\Query\JoinClause;
28use Illuminate\Support\Collection;
29use stdClass;
30
31/**
32 * A chart showing the marriage ages by century.
33 */
34class ChartMarriageAge
35{
36    /**
37     * @var Tree
38     */
39    private $tree;
40
41    /**
42     * @var CenturyService
43     */
44    private $century_service;
45
46    /**
47     * Constructor.
48     *
49     * @param Tree $tree
50     */
51    public function __construct(Tree $tree)
52    {
53        $this->tree            = $tree;
54        $this->century_service = new CenturyService();
55    }
56
57    /**
58     * Returns the related database records.
59     *
60     * @return Collection<stdClass>
61     */
62    private function queryRecords(): Collection
63    {
64        $prefix = DB::connection()->getTablePrefix();
65
66        $male = DB::table('dates as married')
67            ->select([
68                new Expression('AVG(' . $prefix . 'married.d_julianday2 - ' . $prefix . 'birth.d_julianday1 - 182.5) / 365.25 AS age'),
69                new Expression('ROUND((' . $prefix . 'married.d_year + 49) / 100) AS century'),
70                new Expression("'M' as sex")
71            ])
72            ->join('families as fam', static function (JoinClause $join): void {
73                $join->on('fam.f_id', '=', 'married.d_gid')
74                    ->on('fam.f_file', '=', 'married.d_file');
75            })
76            ->join('dates as birth', static function (JoinClause $join): void {
77                $join->on('birth.d_gid', '=', 'fam.f_husb')
78                    ->on('birth.d_file', '=', 'fam.f_file');
79            })
80            ->whereIn('married.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
81            ->where('married.d_file', '=', $this->tree->id())
82            ->where('married.d_fact', '=', 'MARR')
83            ->where('married.d_julianday1', '>', 'birth.d_julianday1')
84            ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
85            ->where('birth.d_fact', '=', 'BIRT')
86            ->where('birth.d_julianday1', '<>', 0)
87            ->groupBy(['century', 'sex']);
88
89        $female = DB::table('dates as married')
90            ->select([
91                new Expression('ROUND(AVG(' . $prefix . 'married.d_julianday2 - ' . $prefix . 'birth.d_julianday1 - 182.5) / 365.25, 1) AS age'),
92                new Expression('ROUND((' . $prefix . 'married.d_year + 49) / 100) AS century'),
93                new Expression("'F' as sex")
94            ])
95            ->join('families as fam', static function (JoinClause $join): void {
96                $join->on('fam.f_id', '=', 'married.d_gid')
97                    ->on('fam.f_file', '=', 'married.d_file');
98            })
99            ->join('dates as birth', static function (JoinClause $join): void {
100                $join->on('birth.d_gid', '=', 'fam.f_wife')
101                    ->on('birth.d_file', '=', 'fam.f_file');
102            })
103            ->whereIn('married.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
104            ->where('married.d_file', '=', $this->tree->id())
105            ->where('married.d_fact', '=', 'MARR')
106            ->where('married.d_julianday1', '>', 'birth.d_julianday1')
107            ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@'])
108            ->where('birth.d_fact', '=', 'BIRT')
109            ->where('birth.d_julianday1', '<>', 0)
110            ->groupBy(['century', 'sex']);
111
112        return $male->unionAll($female)
113            ->orderBy('century')
114            ->get()
115            ->map(static function (stdClass $row): stdClass {
116                return (object) [
117                    'age'     => (float) $row->age,
118                    'century' => (int) $row->century,
119                    'sex'     => $row->sex,
120                ];
121            });
122    }
123
124    /**
125     * General query on ages at marriage.
126     *
127     * @return string
128     */
129    public function chartMarriageAge(): string
130    {
131        $out = [];
132
133        foreach ($this->queryRecords() as $record) {
134            $out[$record->century][$record->sex] = $record->age;
135        }
136
137        $data = [
138            [
139                I18N::translate('Century'),
140                I18N::translate('Males'),
141                I18N::translate('Females'),
142                I18N::translate('Average age'),
143            ]
144        ];
145
146        foreach ($out as $century => $values) {
147            $female_age  = $values['F'] ?? 0;
148            $male_age    = $values['M'] ?? 0;
149            $average_age = ($female_age + $male_age) / 2.0;
150
151            $data[] = [
152                $this->century_service->centuryName($century),
153                round($male_age, 1),
154                round($female_age, 1),
155                round($average_age, 1),
156            ];
157        }
158
159        $chart_title   = I18N::translate('Average age in century of marriage');
160        $chart_options = [
161            'title' => $chart_title,
162            'subtitle' => I18N::translate('Average age at marriage'),
163            'vAxis' => [
164                'title' => I18N::translate('Age'),
165            ],
166            'hAxis' => [
167                'title' => I18N::translate('Century'),
168            ],
169            'colors' => [
170                '#84beff',
171                '#ffd1dc',
172                '#ff0000',
173            ],
174        ];
175
176        return view('statistics/other/charts/combo', [
177            'data'          => $data,
178            'chart_options' => $chart_options,
179            'chart_title'   => $chart_title,
180            'language'      => I18N::languageTag(),
181        ]);
182    }
183}
184