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; 24 25/** 26 * 27 */ 28class ChartMarriageAge extends AbstractGoogle 29{ 30 /** 31 * @var Tree 32 */ 33 private $tree; 34 35 /** 36 * @var Century 37 */ 38 private $centuryHelper; 39 40 /** 41 * Constructor. 42 * 43 * @param Tree $tree 44 */ 45 public function __construct(Tree $tree) 46 { 47 $this->tree = $tree; 48 $this->centuryHelper = new Century(); 49 } 50 51 /** 52 * Returns the related database records. 53 * 54 * @param string $sex 55 * 56 * @return \stdClass[] 57 */ 58 private function queryRecords(string $sex): array 59 { 60 // TODO 61 return $this->runSql( 62 'SELECT ' 63 . ' ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, ' 64 . ' ROUND((married.d_year - 50) / 100) AS century,' 65 . " 'M' AS sex " 66 . 'FROM `##dates` AS married ' 67 . 'JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) ' 68 . 'JOIN `##dates` AS birth ON (birth.d_gid=fam.f_husb AND birth.d_file=fam.f_file) ' 69 . 'WHERE ' 70 . " '{$sex}' IN ('M', 'BOTH') AND " 71 . " married.d_file={$this->tree->id()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " 72 . " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " 73 . ' married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 ' 74 . 'GROUP BY century, sex ' 75 . 'UNION ALL ' 76 . 'SELECT ' 77 . ' ROUND(AVG(married.d_julianday2-birth.d_julianday1-182.5)/365.25,1) AS age, ' 78 . ' ROUND((married.d_year - 50) / 100) AS century,' 79 . " 'F' AS sex " 80 . 'FROM `##dates` AS married ' 81 . 'JOIN `##families` AS fam ON (married.d_gid=fam.f_id AND married.d_file=fam.f_file) ' 82 . 'JOIN `##dates` AS birth ON (birth.d_gid=fam.f_wife AND birth.d_file=fam.f_file) ' 83 . 'WHERE ' 84 . " '{$sex}' IN ('F', 'BOTH') AND " 85 . " married.d_file={$this->tree->id()} AND married.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND married.d_fact='MARR' AND " 86 . " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND birth.d_fact='BIRT' AND " 87 . ' married.d_julianday1>birth.d_julianday1 AND birth.d_julianday1<>0 ' 88 . ' GROUP BY century, sex ORDER BY century' 89 ); 90 } 91 92 /** 93 * General query on ages at marriage. 94 * 95 * @param string $size 96 * 97 * @return string 98 */ 99 public function chartMarriageAge(string $size = '200x250'): string 100 { 101 $sex = 'BOTH'; 102 $sizes = explode('x', $size); 103 $rows = $this->queryRecords($sex); 104 105 if (empty($rows)) { 106 return ''; 107 } 108 109 $max = 0; 110 111 foreach ($rows as $values) { 112 $values->age = (int) $values->age; 113 if ($max < $values->age) { 114 $max = $values->age; 115 } 116 } 117 118 $chxl = '0:|'; 119 $chmm = ''; 120 $chmf = ''; 121 $i = 0; 122 $countsm = ''; 123 $countsf = ''; 124 $countsa = ''; 125 $out = []; 126 127 foreach ($rows as $values) { 128 $out[(int) $values->century][$values->sex] = $values->age; 129 } 130 131 foreach ($out as $century => $values) { 132 if ($sizes[0] < 1000) { 133 $sizes[0] += 50; 134 } 135 $chxl .= $this->centuryHelper->centuryName($century) . '|'; 136 $average = 0; 137 if (isset($values['F'])) { 138 if ($max <= 50) { 139 $value = $values['F'] * 2; 140 } else { 141 $value = $values['F']; 142 } 143 $countsf .= $value . ','; 144 $average = $value; 145 $chmf .= 't' . $values['F'] . ',000000,1,' . $i . ',11,1|'; 146 } else { 147 $countsf .= '0,'; 148 $chmf .= 't0,000000,1,' . $i . ',11,1|'; 149 } 150 if (isset($values['M'])) { 151 if ($max <= 50) { 152 $value = $values['M'] * 2; 153 } else { 154 $value = $values['M']; 155 } 156 $countsm .= $value . ','; 157 if ($average === 0) { 158 $countsa .= $value . ','; 159 } else { 160 $countsa .= (($value + $average) / 2) . ','; 161 } 162 $chmm .= 't' . $values['M'] . ',000000,0,' . $i . ',11,1|'; 163 } else { 164 $countsm .= '0,'; 165 if ($average === 0) { 166 $countsa .= '0,'; 167 } else { 168 $countsa .= $value . ','; 169 } 170 $chmm .= 't0,000000,0,' . $i . ',11,1|'; 171 } 172 $i++; 173 } 174 175 $countsm = substr($countsm, 0, -1); 176 $countsf = substr($countsf, 0, -1); 177 $countsa = substr($countsa, 0, -1); 178 $chmf = substr($chmf, 0, -1); 179 $chd = 't2:' . $countsm . '|' . $countsf . '|' . $countsa; 180 181 if ($max <= 50) { 182 $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|3:||' . I18N::translate('Age') . '|'; 183 } else { 184 $chxl .= '1:||' . I18N::translate('century') . '|2:|0|10|20|30|40|50|60|70|80|90|100|3:||' . I18N::translate('Age') . '|'; 185 } 186 187 if (\count($rows) > 4 || mb_strlen(I18N::translate('Average age in century of marriage')) < 30) { 188 $chtt = I18N::translate('Average age in century of marriage'); 189 } else { 190 $offset = 0; 191 $counter = []; 192 193 while ($offset = strpos(I18N::translate('Average age in century of marriage'), ' ', $offset + 1)) { 194 $counter[] = $offset; 195 } 196 197 $half = intdiv(\count($counter), 2); 198 $chtt = substr_replace(I18N::translate('Average age in century of marriage'), '|', $counter[$half], 1); 199 } 200 201 $chart_url = 'https://chart.googleapis.com/chart?cht=bvg&chs=' . $sizes[0] . 'x' . $sizes[1] 202 . '&chm=D,FF0000,2,0,3,1|' . $chmm . $chmf 203 . '&chf=bg,s,ffffff00|c,s,ffffff00&chtt=' . rawurlencode($chtt) 204 . '&chd=' . $chd . '&chco=0000FF,FFA0CB,FF0000&chbh=20,3&chxt=x,x,y,y&chxl=' 205 . rawurlencode($chxl) . '&chdl=' 206 . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age')); 207 208 return view( 209 'statistics/other/chart-google', 210 [ 211 'chart_title' => I18N::translate('Average age in century of marriage'), 212 'chart_url' => $chart_url, 213 'sizes' => $sizes, 214 ] 215 ); 216 } 217} 218