1168ff6f3Sric2016<?php 2168ff6f3Sric2016/** 3168ff6f3Sric2016 * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 5168ff6f3Sric2016 * This program is free software: you can redistribute it and/or modify 6168ff6f3Sric2016 * it under the terms of the GNU General Public License as published by 7168ff6f3Sric2016 * the Free Software Foundation, either version 3 of the License, or 8168ff6f3Sric2016 * (at your option) any later version. 9168ff6f3Sric2016 * This program is distributed in the hope that it will be useful, 10168ff6f3Sric2016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11168ff6f3Sric2016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12168ff6f3Sric2016 * GNU General Public License for more details. 13168ff6f3Sric2016 * You should have received a copy of the GNU General Public License 14168ff6f3Sric2016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15168ff6f3Sric2016 */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 18168ff6f3Sric2016namespace Fisharebest\Webtrees\Module; 19168ff6f3Sric2016 20*54452b04SGreg Roachuse Fisharebest\Webtrees\Auth; 21*54452b04SGreg Roachuse Fisharebest\Webtrees\Family; 22*54452b04SGreg Roachuse Fisharebest\Webtrees\FontAwesome; 23*54452b04SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsCharts; 24*54452b04SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint; 25*54452b04SGreg Roachuse Fisharebest\Webtrees\Gedcom; 26*54452b04SGreg Roachuse Fisharebest\Webtrees\GedcomTag; 27168ff6f3Sric2016use Fisharebest\Webtrees\I18N; 28168ff6f3Sric2016use Fisharebest\Webtrees\Individual; 29e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu; 30*54452b04SGreg Roachuse Fisharebest\Webtrees\Services\ChartService; 31*54452b04SGreg Roachuse Fisharebest\Webtrees\Theme; 32*54452b04SGreg Roachuse Fisharebest\Webtrees\Tree; 33*54452b04SGreg Roachuse Illuminate\Support\Collection; 34*54452b04SGreg Roachuse Ramsey\Uuid\Uuid; 35*54452b04SGreg Roachuse Symfony\Component\HttpFoundation\Request; 36*54452b04SGreg Roachuse Symfony\Component\HttpFoundation\Response; 37168ff6f3Sric2016 38168ff6f3Sric2016/** 39168ff6f3Sric2016 * Class DescendancyChartModule 40168ff6f3Sric2016 */ 4149a243cbSGreg Roachclass DescendancyChartModule extends AbstractModule implements ModuleInterface, ModuleChartInterface 42c1010edaSGreg Roach{ 4349a243cbSGreg Roach use ModuleChartTrait; 4449a243cbSGreg Roach 45*54452b04SGreg Roach // Chart styles 46*54452b04SGreg Roach private const CHART_STYLE_LIST = 0; 47*54452b04SGreg Roach private const CHART_STYLE_BOOKLET = 1; 48*54452b04SGreg Roach private const CHART_STYLE_INDIVIDUALS = 2; 49*54452b04SGreg Roach private const CHART_STYLE_FAMILIES = 3; 50*54452b04SGreg Roach 51*54452b04SGreg Roach // Defaults 52*54452b04SGreg Roach private const DEFAULT_STYLE = self::CHART_STYLE_LIST; 53*54452b04SGreg Roach private const DEFAULT_GENERATIONS = '3'; 54*54452b04SGreg Roach private const DEFAULT_MAXIMUM_GENERATIONS = '9'; 55*54452b04SGreg Roach 56*54452b04SGreg Roach /** @var int[] */ 57*54452b04SGreg Roach protected $dabo_num = []; 58*54452b04SGreg Roach 59*54452b04SGreg Roach /** @var string[] */ 60*54452b04SGreg Roach protected $dabo_sex = []; 61*54452b04SGreg Roach 62168ff6f3Sric2016 /** 63168ff6f3Sric2016 * How should this module be labelled on tabs, menus, etc.? 64168ff6f3Sric2016 * 65168ff6f3Sric2016 * @return string 66168ff6f3Sric2016 */ 6749a243cbSGreg Roach public function title(): string 68c1010edaSGreg Roach { 69bbb76c12SGreg Roach /* I18N: Name of a module/chart */ 70bbb76c12SGreg Roach return I18N::translate('Descendants'); 71168ff6f3Sric2016 } 72168ff6f3Sric2016 73168ff6f3Sric2016 /** 74168ff6f3Sric2016 * A sentence describing what this module does. 75168ff6f3Sric2016 * 76168ff6f3Sric2016 * @return string 77168ff6f3Sric2016 */ 7849a243cbSGreg Roach public function description(): string 79c1010edaSGreg Roach { 80bbb76c12SGreg Roach /* I18N: Description of the “DescendancyChart” module */ 81bbb76c12SGreg Roach return I18N::translate('A chart of an individual’s descendants.'); 82168ff6f3Sric2016 } 83168ff6f3Sric2016 84168ff6f3Sric2016 /** 85377a2979SGreg Roach * CSS class for the URL. 86377a2979SGreg Roach * 87377a2979SGreg Roach * @return string 88377a2979SGreg Roach */ 89377a2979SGreg Roach public function chartMenuClass(): string 90377a2979SGreg Roach { 91377a2979SGreg Roach return 'menu-chart-descendants'; 92377a2979SGreg Roach } 93377a2979SGreg Roach 94377a2979SGreg Roach /** 954eb71cfaSGreg Roach * Return a menu item for this chart - for use in individual boxes. 964eb71cfaSGreg Roach * 9760bc3e3fSGreg Roach * @param Individual $individual 9860bc3e3fSGreg Roach * 994eb71cfaSGreg Roach * @return Menu|null 1004eb71cfaSGreg Roach */ 101377a2979SGreg Roach public function chartBoxMenu(Individual $individual): ?Menu 102c1010edaSGreg Roach { 103e6562982SGreg Roach return $this->chartMenu($individual); 104e6562982SGreg Roach } 105e6562982SGreg Roach 106e6562982SGreg Roach /** 107e6562982SGreg Roach * The title for a specific instance of this chart. 108e6562982SGreg Roach * 109e6562982SGreg Roach * @param Individual $individual 110e6562982SGreg Roach * 111e6562982SGreg Roach * @return string 112e6562982SGreg Roach */ 113e6562982SGreg Roach public function chartTitle(Individual $individual): string 114e6562982SGreg Roach { 115e6562982SGreg Roach /* I18N: %s is an individual’s name */ 116e6562982SGreg Roach return I18N::translate('Descendants of %s', $individual->getFullName()); 117e6562982SGreg Roach } 118e6562982SGreg Roach 119e6562982SGreg Roach /** 120*54452b04SGreg Roach * A form to request the chart parameters. 121*54452b04SGreg Roach * 122*54452b04SGreg Roach * @param Request $request 123*54452b04SGreg Roach * @param Tree $tree 124*54452b04SGreg Roach * @param ChartService $chart_service 125*54452b04SGreg Roach * 126*54452b04SGreg Roach * @return Response 127*54452b04SGreg Roach */ 128*54452b04SGreg Roach public function getChartAction(Request $request, Tree $tree, ChartService $chart_service): Response 129*54452b04SGreg Roach { 130*54452b04SGreg Roach $ajax = $request->get('ajax', ''); 131*54452b04SGreg Roach $xref = $request->get('xref', ''); 132*54452b04SGreg Roach $individual = Individual::getInstance($xref, $tree); 133*54452b04SGreg Roach 134*54452b04SGreg Roach Auth::checkIndividualAccess($individual); 135*54452b04SGreg Roach 136*54452b04SGreg Roach $minimum_generations = 2; 137*54452b04SGreg Roach $maximum_generations = (int) $tree->getPreference('MAX_DESCENDANCY_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS); 138*54452b04SGreg Roach $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS); 139*54452b04SGreg Roach 140*54452b04SGreg Roach $chart_style = (int) $request->get('chart_style', self::DEFAULT_STYLE); 141*54452b04SGreg Roach $generations = (int) $request->get('generations', $default_generations); 142*54452b04SGreg Roach 143*54452b04SGreg Roach $generations = min($generations, $maximum_generations); 144*54452b04SGreg Roach $generations = max($generations, $minimum_generations); 145*54452b04SGreg Roach 146*54452b04SGreg Roach if ($ajax === '1') { 147*54452b04SGreg Roach return $this->chart($request, $tree, $chart_service); 148*54452b04SGreg Roach } 149*54452b04SGreg Roach 150*54452b04SGreg Roach $ajax_url = $this->chartUrl($individual, [ 151*54452b04SGreg Roach 'chart_style' => $chart_style, 152*54452b04SGreg Roach 'generations' => $generations, 153*54452b04SGreg Roach 'ajax' => '1', 154*54452b04SGreg Roach ]); 155*54452b04SGreg Roach 156*54452b04SGreg Roach return $this->viewResponse('modules/descendancy_chart/chart-page', [ 157*54452b04SGreg Roach 'ajax_url' => $ajax_url, 158*54452b04SGreg Roach 'chart_style' => $chart_style, 159*54452b04SGreg Roach 'chart_styles' => $this->chartStyles(), 160*54452b04SGreg Roach 'default_generations' => $default_generations, 161*54452b04SGreg Roach 'generations' => $generations, 162*54452b04SGreg Roach 'individual' => $individual, 163*54452b04SGreg Roach 'maximum_generations' => $maximum_generations, 164*54452b04SGreg Roach 'minimum_generations' => $minimum_generations, 165*54452b04SGreg Roach 'module' => $this, 166*54452b04SGreg Roach 'title' => $this->chartTitle($individual), 167*54452b04SGreg Roach ]); 168*54452b04SGreg Roach } 169*54452b04SGreg Roach 170*54452b04SGreg Roach /** 171*54452b04SGreg Roach * @param Request $request 172*54452b04SGreg Roach * @param Tree $tree 173*54452b04SGreg Roach * @param ChartService $chart_service 174*54452b04SGreg Roach * 175*54452b04SGreg Roach * @return Response 176*54452b04SGreg Roach */ 177*54452b04SGreg Roach public function chart(Request $request, Tree $tree, ChartService $chart_service): Response 178*54452b04SGreg Roach { 179*54452b04SGreg Roach $this->layout = 'layouts/ajax'; 180*54452b04SGreg Roach 181*54452b04SGreg Roach $xref = $request->get('xref', ''); 182*54452b04SGreg Roach $individual = Individual::getInstance($xref, $tree); 183*54452b04SGreg Roach 184*54452b04SGreg Roach Auth::checkIndividualAccess($individual); 185*54452b04SGreg Roach 186*54452b04SGreg Roach $minimum_generations = 2; 187*54452b04SGreg Roach $maximum_generations = (int) $tree->getPreference('MAX_PEDIGREE_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS); 188*54452b04SGreg Roach $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS); 189*54452b04SGreg Roach 190*54452b04SGreg Roach $chart_style = (int) $request->get('chart_style', self::DEFAULT_STYLE); 191*54452b04SGreg Roach $generations = (int) $request->get('generations', $default_generations); 192*54452b04SGreg Roach 193*54452b04SGreg Roach $generations = min($generations, $maximum_generations); 194*54452b04SGreg Roach $generations = max($generations, $minimum_generations); 195*54452b04SGreg Roach 196*54452b04SGreg Roach switch ($chart_style) { 197*54452b04SGreg Roach case self::CHART_STYLE_LIST: 198*54452b04SGreg Roach default: 199*54452b04SGreg Roach return $this->descendantsList($individual, $generations); 200*54452b04SGreg Roach 201*54452b04SGreg Roach case self::CHART_STYLE_BOOKLET: 202*54452b04SGreg Roach return $this->descendantsBooklet($individual, $generations); 203*54452b04SGreg Roach 204*54452b04SGreg Roach case self::CHART_STYLE_INDIVIDUALS: 205*54452b04SGreg Roach $individuals = $chart_service->descendants($individual, $generations - 1); 206*54452b04SGreg Roach 207*54452b04SGreg Roach return $this->descendantsIndividuals($tree, $individuals); 208*54452b04SGreg Roach 209*54452b04SGreg Roach case self::CHART_STYLE_FAMILIES: 210*54452b04SGreg Roach $families = $chart_service->descendantFamilies($individual, $generations - 1); 211*54452b04SGreg Roach 212*54452b04SGreg Roach return $this->descendantsFamilies($tree, $families); 213*54452b04SGreg Roach } 214*54452b04SGreg Roach } 215*54452b04SGreg Roach 216*54452b04SGreg Roach /** 217*54452b04SGreg Roach * Show a hierarchical list of descendants 218*54452b04SGreg Roach * 219*54452b04SGreg Roach * @TODO replace ob_start() with views. 220e6562982SGreg Roach * 221e6562982SGreg Roach * @param Individual $individual 222*54452b04SGreg Roach * @param int $generations 223e6562982SGreg Roach * 224*54452b04SGreg Roach * @return Response 225e6562982SGreg Roach */ 226*54452b04SGreg Roach private function descendantsList(Individual $individual, int $generations): Response 227e6562982SGreg Roach { 228*54452b04SGreg Roach ob_start(); 229*54452b04SGreg Roach 230*54452b04SGreg Roach echo '<ul class="chart_common">'; 231*54452b04SGreg Roach $this->printChildDescendancy($individual, $generations, $generations); 232*54452b04SGreg Roach echo '</ul>'; 233*54452b04SGreg Roach 234*54452b04SGreg Roach $html = ob_get_clean(); 235*54452b04SGreg Roach 236*54452b04SGreg Roach return new Response($html); 237*54452b04SGreg Roach } 238*54452b04SGreg Roach 239*54452b04SGreg Roach /** 240*54452b04SGreg Roach * print a child descendancy 241*54452b04SGreg Roach * 242*54452b04SGreg Roach * @param Individual $person 243*54452b04SGreg Roach * @param int $depth the descendancy depth to show 244*54452b04SGreg Roach * @param int $generations 245*54452b04SGreg Roach * 246*54452b04SGreg Roach * @return void 247*54452b04SGreg Roach */ 248*54452b04SGreg Roach private function printChildDescendancy(Individual $person, $depth, int $generations) 249*54452b04SGreg Roach { 250*54452b04SGreg Roach echo '<li>'; 251*54452b04SGreg Roach echo '<table><tr><td>'; 252*54452b04SGreg Roach if ($depth == $generations) { 253*54452b04SGreg Roach echo '<img alt="" role="presentation" src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="15"></td><td>'; 254*54452b04SGreg Roach } else { 255*54452b04SGreg Roach echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="3">'; 256*54452b04SGreg Roach echo '<img src="' . Theme::theme()->parameter('image-hline') . '" height="3" width="', 12, '"></td><td>'; 257*54452b04SGreg Roach } 258*54452b04SGreg Roach echo FunctionsPrint::printPedigreePerson($person); 259*54452b04SGreg Roach echo '</td>'; 260*54452b04SGreg Roach 261*54452b04SGreg Roach // check if child has parents and add an arrow 262*54452b04SGreg Roach echo '<td></td>'; 263*54452b04SGreg Roach echo '<td>'; 264*54452b04SGreg Roach foreach ($person->getChildFamilies() as $cfamily) { 265*54452b04SGreg Roach foreach ($cfamily->getSpouses() as $parent) { 266*54452b04SGreg Roach echo FontAwesome::linkIcon('arrow-up', I18N::translate('Start at parents'), ['href' => route('descendants', ['ged' => $parent->tree()->name(), 267*54452b04SGreg Roach 'xref' => $parent->xref(), 268*54452b04SGreg Roach 'generations' => $generations, 269*54452b04SGreg Roach ]), 270*54452b04SGreg Roach ]); 271*54452b04SGreg Roach // only show the arrow for one of the parents 272*54452b04SGreg Roach break; 273*54452b04SGreg Roach } 274*54452b04SGreg Roach } 275*54452b04SGreg Roach 276*54452b04SGreg Roach // d'Aboville child number 277*54452b04SGreg Roach $level = $generations - $depth; 278*54452b04SGreg Roach echo '<br><br> '; 279*54452b04SGreg Roach echo '<span dir="ltr">'; //needed so that RTL languages will display this properly 280*54452b04SGreg Roach if (!isset($this->dabo_num[$level])) { 281*54452b04SGreg Roach $this->dabo_num[$level] = 0; 282*54452b04SGreg Roach } 283*54452b04SGreg Roach $this->dabo_num[$level]++; 284*54452b04SGreg Roach $this->dabo_num[$level + 1] = 0; 285*54452b04SGreg Roach $this->dabo_sex[$level] = $person->getSex(); 286*54452b04SGreg Roach for ($i = 0; $i <= $level; $i++) { 287*54452b04SGreg Roach $isf = $this->dabo_sex[$i]; 288*54452b04SGreg Roach if ($isf === 'M') { 289*54452b04SGreg Roach $isf = ''; 290*54452b04SGreg Roach } 291*54452b04SGreg Roach if ($isf === 'U') { 292*54452b04SGreg Roach $isf = 'NN'; 293*54452b04SGreg Roach } 294*54452b04SGreg Roach echo '<span class="person_box' . $isf . '"> ' . $this->dabo_num[$i] . ' </span>'; 295*54452b04SGreg Roach if ($i < $level) { 296*54452b04SGreg Roach echo '.'; 297*54452b04SGreg Roach } 298*54452b04SGreg Roach } 299*54452b04SGreg Roach echo '</span>'; 300*54452b04SGreg Roach echo '</td></tr>'; 301*54452b04SGreg Roach echo '</table>'; 302*54452b04SGreg Roach echo '</li>'; 303*54452b04SGreg Roach 304*54452b04SGreg Roach // loop for each spouse 305*54452b04SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 306*54452b04SGreg Roach $this->printFamilyDescendancy($person, $family, $depth, $generations); 307*54452b04SGreg Roach } 308*54452b04SGreg Roach } 309*54452b04SGreg Roach 310*54452b04SGreg Roach /** 311*54452b04SGreg Roach * print a family descendancy 312*54452b04SGreg Roach * 313*54452b04SGreg Roach * @param Individual $person 314*54452b04SGreg Roach * @param Family $family 315*54452b04SGreg Roach * @param int $depth the descendancy depth to show 316*54452b04SGreg Roach * @param int $generations 317*54452b04SGreg Roach * 318*54452b04SGreg Roach * @return void 319*54452b04SGreg Roach */ 320*54452b04SGreg Roach private function printFamilyDescendancy(Individual $person, Family $family, int $depth, int $generations) 321*54452b04SGreg Roach { 322*54452b04SGreg Roach $uid = Uuid::uuid4()->toString(); // create a unique ID 323*54452b04SGreg Roach // print marriage info 324*54452b04SGreg Roach echo '<li>'; 325*54452b04SGreg Roach echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="', 19, '">'; 326*54452b04SGreg Roach echo '<span class="details1">'; 327*54452b04SGreg Roach echo '<a href="#" onclick="expand_layer(\'' . $uid . '\'); return false;" class="top"><i id="' . $uid . '_img" class="icon-minus" title="' . I18N::translate('View this family') . '"></i></a>'; 328*54452b04SGreg Roach if ($family->canShow()) { 329*54452b04SGreg Roach foreach ($family->facts(Gedcom::MARRIAGE_EVENTS) as $fact) { 330*54452b04SGreg Roach echo ' <a href="', e($family->url()), '" class="details1">', $fact->summary(), '</a>'; 331*54452b04SGreg Roach } 332*54452b04SGreg Roach } 333*54452b04SGreg Roach echo '</span>'; 334*54452b04SGreg Roach 335*54452b04SGreg Roach // print spouse 336*54452b04SGreg Roach $spouse = $family->getSpouse($person); 337*54452b04SGreg Roach echo '<ul class="generations" id="' . $uid . '">'; 338*54452b04SGreg Roach echo '<li>'; 339*54452b04SGreg Roach echo '<table><tr><td>'; 340*54452b04SGreg Roach echo FunctionsPrint::printPedigreePerson($spouse); 341*54452b04SGreg Roach echo '</td>'; 342*54452b04SGreg Roach 343*54452b04SGreg Roach // check if spouse has parents and add an arrow 344*54452b04SGreg Roach echo '<td></td>'; 345*54452b04SGreg Roach echo '<td>'; 346*54452b04SGreg Roach if ($spouse) { 347*54452b04SGreg Roach foreach ($spouse->getChildFamilies() as $cfamily) { 348*54452b04SGreg Roach foreach ($cfamily->getSpouses() as $parent) { 349*54452b04SGreg Roach echo FontAwesome::linkIcon('arrow-up', I18N::translate('Start at parents'), ['href' => route('descendants', ['ged' => $parent->tree()->name(), 350*54452b04SGreg Roach 'xref' => $parent->xref(), 351*54452b04SGreg Roach 'generations' => $generations, 352*54452b04SGreg Roach ]), 353*54452b04SGreg Roach ]); 354*54452b04SGreg Roach // only show the arrow for one of the parents 355*54452b04SGreg Roach break; 356*54452b04SGreg Roach } 357*54452b04SGreg Roach } 358*54452b04SGreg Roach } 359*54452b04SGreg Roach echo '<br><br> '; 360*54452b04SGreg Roach echo '</td></tr>'; 361*54452b04SGreg Roach 362*54452b04SGreg Roach // children 363*54452b04SGreg Roach $children = $family->getChildren(); 364*54452b04SGreg Roach echo '<tr><td colspan="3" class="details1" > '; 365*54452b04SGreg Roach if (!empty($children)) { 366*54452b04SGreg Roach echo GedcomTag::getLabel('NCHI') . ': ' . count($children); 367*54452b04SGreg Roach } else { 368*54452b04SGreg Roach // Distinguish between no children (NCHI 0) and no recorded 369*54452b04SGreg Roach // children (no CHIL records) 370*54452b04SGreg Roach if (strpos($family->gedcom(), '\n1 NCHI 0') !== false) { 371*54452b04SGreg Roach echo GedcomTag::getLabel('NCHI') . ': ' . count($children); 372*54452b04SGreg Roach } else { 373*54452b04SGreg Roach echo I18N::translate('No children'); 374*54452b04SGreg Roach } 375*54452b04SGreg Roach } 376*54452b04SGreg Roach echo '</td></tr></table>'; 377*54452b04SGreg Roach echo '</li>'; 378*54452b04SGreg Roach if ($depth > 1) { 379*54452b04SGreg Roach foreach ($children as $child) { 380*54452b04SGreg Roach $this->printChildDescendancy($child, $depth - 1, $generations); 381*54452b04SGreg Roach } 382*54452b04SGreg Roach } 383*54452b04SGreg Roach echo '</ul>'; 384*54452b04SGreg Roach echo '</li>'; 385*54452b04SGreg Roach } 386*54452b04SGreg Roach 387*54452b04SGreg Roach /** 388*54452b04SGreg Roach * Show a tabular list of individual descendants. 389*54452b04SGreg Roach * 390*54452b04SGreg Roach * @param Tree $tree 391*54452b04SGreg Roach * @param Collection $individuals 392*54452b04SGreg Roach * 393*54452b04SGreg Roach * @return Response 394*54452b04SGreg Roach */ 395*54452b04SGreg Roach private function descendantsIndividuals(Tree $tree, Collection $individuals): Response 396*54452b04SGreg Roach { 397*54452b04SGreg Roach $this->layout = 'layouts/ajax'; 398*54452b04SGreg Roach 399*54452b04SGreg Roach return $this->viewResponse('lists/individuals-table', [ 400*54452b04SGreg Roach 'individuals' => $individuals, 401*54452b04SGreg Roach 'sosa' => false, 402*54452b04SGreg Roach 'tree' => $tree, 403*54452b04SGreg Roach ]); 404*54452b04SGreg Roach } 405*54452b04SGreg Roach 406*54452b04SGreg Roach /** 407*54452b04SGreg Roach * Show a tabular list of individual descendants. 408*54452b04SGreg Roach * 409*54452b04SGreg Roach * @param Tree $tree 410*54452b04SGreg Roach * @param Collection $families 411*54452b04SGreg Roach * 412*54452b04SGreg Roach * @return Response 413*54452b04SGreg Roach */ 414*54452b04SGreg Roach private function descendantsFamilies(Tree $tree, Collection $families): Response 415*54452b04SGreg Roach { 416*54452b04SGreg Roach $this->layout = 'layouts/ajax'; 417*54452b04SGreg Roach 418*54452b04SGreg Roach return $this->viewResponse('lists/families-table', [ 419*54452b04SGreg Roach 'families' => $families, 420*54452b04SGreg Roach 'tree' => $tree, 421*54452b04SGreg Roach ]); 422*54452b04SGreg Roach } 423*54452b04SGreg Roach 424*54452b04SGreg Roach /** 425*54452b04SGreg Roach * Show a booklet view of descendants 426*54452b04SGreg Roach * 427*54452b04SGreg Roach * @TODO replace ob_start() with views. 428*54452b04SGreg Roach * 429*54452b04SGreg Roach * @param Individual $individual 430*54452b04SGreg Roach * @param int $generations 431*54452b04SGreg Roach * 432*54452b04SGreg Roach * @return Response 433*54452b04SGreg Roach */ 434*54452b04SGreg Roach private function descendantsBooklet(Individual $individual, int $generations): Response 435*54452b04SGreg Roach { 436*54452b04SGreg Roach ob_start(); 437*54452b04SGreg Roach 438*54452b04SGreg Roach $this->printChildFamily($individual, $generations); 439*54452b04SGreg Roach 440*54452b04SGreg Roach $html = ob_get_clean(); 441*54452b04SGreg Roach 442*54452b04SGreg Roach return new Response($html); 443*54452b04SGreg Roach } 444*54452b04SGreg Roach 445*54452b04SGreg Roach 446*54452b04SGreg Roach /** 447*54452b04SGreg Roach * Print a child family 448*54452b04SGreg Roach * 449*54452b04SGreg Roach * @param Individual $individual 450*54452b04SGreg Roach * @param int $depth - the descendancy depth to show 451*54452b04SGreg Roach * @param string $daboville - d'Aboville number 452*54452b04SGreg Roach * @param string $gpid 453*54452b04SGreg Roach * 454*54452b04SGreg Roach * @return void 455*54452b04SGreg Roach */ 456*54452b04SGreg Roach private function printChildFamily(Individual $individual, $depth, $daboville = '1.', $gpid = '') 457*54452b04SGreg Roach { 458*54452b04SGreg Roach if ($depth < 2) { 459*54452b04SGreg Roach return; 460*54452b04SGreg Roach } 461*54452b04SGreg Roach 462*54452b04SGreg Roach $i = 1; 463*54452b04SGreg Roach 464*54452b04SGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 465*54452b04SGreg Roach FunctionsCharts::printSosaFamily($family, '', -1, $daboville, $individual->xref(), $gpid, false); 466*54452b04SGreg Roach foreach ($family->getChildren() as $child) { 467*54452b04SGreg Roach $this->printChildFamily($child, $depth - 1, $daboville . ($i++) . '.', $individual->xref()); 468*54452b04SGreg Roach } 469*54452b04SGreg Roach } 470*54452b04SGreg Roach } 471*54452b04SGreg Roach 472*54452b04SGreg Roach /** 473*54452b04SGreg Roach * This chart can display its output in a number of styles 474*54452b04SGreg Roach * 475*54452b04SGreg Roach * @return array 476*54452b04SGreg Roach */ 477*54452b04SGreg Roach private function chartStyles(): array 478*54452b04SGreg Roach { 479*54452b04SGreg Roach return [ 480*54452b04SGreg Roach self::CHART_STYLE_LIST => I18N::translate('List'), 481*54452b04SGreg Roach self::CHART_STYLE_BOOKLET => I18N::translate('Booklet'), 482*54452b04SGreg Roach self::CHART_STYLE_INDIVIDUALS => I18N::translate('Individuals'), 483*54452b04SGreg Roach self::CHART_STYLE_FAMILIES => I18N::translate('Families'), 484*54452b04SGreg Roach ]; 485e6562982SGreg Roach } 486168ff6f3Sric2016} 487