18c2e8227SGreg Roach<?php 28c2e8227SGreg Roach/** 38c2e8227SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 88c2e8227SGreg Roach * (at your option) any later version. 98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 128c2e8227SGreg Roach * GNU General Public License for more details. 138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 158c2e8227SGreg Roach */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 1876692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1976692c8bSGreg Roach 200e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 2332cd2800SGreg Roachuse Fisharebest\Webtrees\Services\SearchService; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 251c0676b2SGreg Roachuse Symfony\Component\HttpFoundation\Request; 261c0676b2SGreg Roachuse Symfony\Component\HttpFoundation\Response; 278c2e8227SGreg Roach 288c2e8227SGreg Roach/** 298c2e8227SGreg Roach * Class DescendancyModule 308c2e8227SGreg Roach */ 3137eb8894SGreg Roachclass DescendancyModule extends AbstractModule implements ModuleSidebarInterface 32c1010edaSGreg Roach{ 3349a243cbSGreg Roach use ModuleSidebarTrait; 3449a243cbSGreg Roach 35961ec755SGreg Roach /** 36961ec755SGreg Roach * How should this module be labelled on tabs, menus, etc.? 37961ec755SGreg Roach * 38961ec755SGreg Roach * @return string 39961ec755SGreg Roach */ 4049a243cbSGreg Roach public function title(): string 41c1010edaSGreg Roach { 42bbb76c12SGreg Roach /* I18N: Name of a module/sidebar */ 43bbb76c12SGreg Roach return I18N::translate('Descendants'); 448c2e8227SGreg Roach } 458c2e8227SGreg Roach 46961ec755SGreg Roach /** 47961ec755SGreg Roach * A sentence describing what this module does. 48961ec755SGreg Roach * 49961ec755SGreg Roach * @return string 50961ec755SGreg Roach */ 5149a243cbSGreg Roach public function description(): string 52c1010edaSGreg Roach { 53bbb76c12SGreg Roach /* I18N: Description of the “Descendants” module */ 54bbb76c12SGreg Roach return I18N::translate('A sidebar showing the descendants of an individual.'); 558c2e8227SGreg Roach } 568c2e8227SGreg Roach 5776692c8bSGreg Roach /** 5849a243cbSGreg Roach * The default position for this sidebar. It can be changed in the control panel. 5949a243cbSGreg Roach * 6049a243cbSGreg Roach * @return int 6149a243cbSGreg Roach */ 6249a243cbSGreg Roach public function defaultSidebarOrder(): int 6349a243cbSGreg Roach { 64353b36abSGreg Roach return 3; 6549a243cbSGreg Roach } 6649a243cbSGreg Roach 6749a243cbSGreg Roach /** 681c0676b2SGreg Roach * @param Request $request 69b6db7c1fSGreg Roach * @param Tree $tree 7032cd2800SGreg Roach * @param SearchService $search_service 7176692c8bSGreg Roach * 721c0676b2SGreg Roach * @return Response 7376692c8bSGreg Roach */ 7432cd2800SGreg Roach public function getSearchAction(Request $request, Tree $tree, SearchService $search_service): Response 75c1010edaSGreg Roach { 761c0676b2SGreg Roach $search = $request->get('search', ''); 778c2e8227SGreg Roach 781c0676b2SGreg Roach $html = ''; 791c0676b2SGreg Roach 801c0676b2SGreg Roach if (strlen($search) >= 2) { 8132cd2800SGreg Roach $html = $search_service 82a7a24840SGreg Roach ->searchIndividualNames([$tree], [$search]) 8332cd2800SGreg Roach ->map(function (Individual $individual): string { 8432cd2800SGreg Roach return $this->getPersonLi($individual); 8532cd2800SGreg Roach }) 8632cd2800SGreg Roach ->implode(''); 878c2e8227SGreg Roach } 888c2e8227SGreg Roach 891c0676b2SGreg Roach if ($html !== '') { 901c0676b2SGreg Roach $html = '<ul>' . $html . '</ul>'; 911c0676b2SGreg Roach } 921c0676b2SGreg Roach 931c0676b2SGreg Roach return new Response($html); 941c0676b2SGreg Roach } 951c0676b2SGreg Roach 961c0676b2SGreg Roach /** 971c0676b2SGreg Roach * @param Request $request 98b6db7c1fSGreg Roach * @param Tree $tree 991c0676b2SGreg Roach * 1001c0676b2SGreg Roach * @return Response 1011c0676b2SGreg Roach */ 102b6db7c1fSGreg Roach public function getDescendantsAction(Request $request, Tree $tree): Response 103c1010edaSGreg Roach { 1049e648e55SGreg Roach $xref = $request->get('xref', ''); 1051c0676b2SGreg Roach 1061c0676b2SGreg Roach $individual = Individual::getInstance($xref, $tree); 1071c0676b2SGreg Roach 1081c0676b2SGreg Roach if ($individual !== null && $individual->canShow()) { 1091c0676b2SGreg Roach $html = $this->loadSpouses($individual, 1); 1101c0676b2SGreg Roach } else { 1111c0676b2SGreg Roach $html = ''; 1121c0676b2SGreg Roach } 1131c0676b2SGreg Roach 1141c0676b2SGreg Roach return new Response($html); 1151c0676b2SGreg Roach } 1161c0676b2SGreg Roach 1178c2e8227SGreg Roach /** {@inheritdoc} */ 1188f53f488SRico Sonntag public function hasSidebarContent(Individual $individual): bool 119c1010edaSGreg Roach { 12038a9583bSGreg Roach return true; 1218c2e8227SGreg Roach } 1228c2e8227SGreg Roach 12376692c8bSGreg Roach /** 12476692c8bSGreg Roach * Load this sidebar synchronously. 12576692c8bSGreg Roach * 126225e381fSGreg Roach * @param Individual $individual 127225e381fSGreg Roach * 12876692c8bSGreg Roach * @return string 12976692c8bSGreg Roach */ 1308f53f488SRico Sonntag public function getSidebarContent(Individual $individual): string 131c1010edaSGreg Roach { 1321ef93f16SGreg Roach return view('modules/descendancy/sidebar', [ 133a817de92SGreg Roach 'individual_list' => $this->getPersonLi($individual, 1), 134a817de92SGreg Roach ]); 1358c2e8227SGreg Roach } 1368c2e8227SGreg Roach 1378c2e8227SGreg Roach /** 13876692c8bSGreg Roach * Format an individual in a list. 13976692c8bSGreg Roach * 1408c2e8227SGreg Roach * @param Individual $person 141cbc1590aSGreg Roach * @param int $generations 1428c2e8227SGreg Roach * 1438c2e8227SGreg Roach * @return string 1448c2e8227SGreg Roach */ 1458f53f488SRico Sonntag public function getPersonLi(Individual $person, $generations = 0): string 146c1010edaSGreg Roach { 1478c2e8227SGreg Roach $icon = $generations > 0 ? 'icon-minus' : 'icon-plus'; 1488c2e8227SGreg Roach $lifespan = $person->canShow() ? '(' . $person->getLifeSpan() . ')' : ''; 1498c2e8227SGreg Roach $spouses = $generations > 0 ? $this->loadSpouses($person, 0) : ''; 1502622ba92SGreg Roach 1512622ba92SGreg Roach return 1522622ba92SGreg Roach '<li class="sb_desc_indi_li">' . 153c1010edaSGreg Roach '<a class="sb_desc_indi" href="' . e(route('module', [ 15426684e68SGreg Roach 'module' => $this->name(), 155c1010edaSGreg Roach 'action' => 'Descendants', 156f4afa648SGreg Roach 'ged' => $person->tree()->name(), 157c0935879SGreg Roach 'xref' => $person->xref(), 158c1010edaSGreg Roach ])) . '">' . 1592622ba92SGreg Roach '<i class="plusminus ' . $icon . '"></i>' . 160*3b51eb75SGreg Roach $person->getSexImage() . $person->fullName() . $lifespan . 1612622ba92SGreg Roach '</a>' . 16239ca88baSGreg Roach '<a href="' . e($person->url()) . '" title="' . strip_tags($person->fullName()) . '">' . view('icons/individual') . '</a>' . 1632622ba92SGreg Roach '<div>' . $spouses . '</div>' . 1642622ba92SGreg Roach '</li>'; 1658c2e8227SGreg Roach } 1668c2e8227SGreg Roach 1678c2e8227SGreg Roach /** 16876692c8bSGreg Roach * Format a family in a list. 16976692c8bSGreg Roach * 1708c2e8227SGreg Roach * @param Family $family 1718c2e8227SGreg Roach * @param Individual $person 172cbc1590aSGreg Roach * @param int $generations 1738c2e8227SGreg Roach * 1748c2e8227SGreg Roach * @return string 1758c2e8227SGreg Roach */ 1768f53f488SRico Sonntag public function getFamilyLi(Family $family, Individual $person, $generations = 0): string 177c1010edaSGreg Roach { 17839ca88baSGreg Roach $spouse = $family->spouse($person); 1792622ba92SGreg Roach if ($spouse) { 180*3b51eb75SGreg Roach $spouse_name = $spouse->getSexImage() . $spouse->fullName(); 18139ca88baSGreg Roach $spouse_link = '<a href="' . e($person->url()) . '" title="' . strip_tags($person->fullName()) . '">' . view('icons/individual') . '</a>'; 1822622ba92SGreg Roach } else { 1832622ba92SGreg Roach $spouse_name = ''; 1842622ba92SGreg Roach $spouse_link = ''; 1852622ba92SGreg Roach } 1862622ba92SGreg Roach 18739ca88baSGreg Roach $family_link = '<a href="' . e($family->url()) . '" title="' . strip_tags($family->fullName()) . '">' . view('icons/family') . '</a>'; 18839b853a7SGreg Roach 1898c2e8227SGreg Roach $marryear = $family->getMarriageYear(); 1908c2e8227SGreg Roach $marr = $marryear ? '<i class="icon-rings"></i>' . $marryear : ''; 1912622ba92SGreg Roach 1922622ba92SGreg Roach return 1932622ba92SGreg Roach '<li class="sb_desc_indi_li">' . 19439b853a7SGreg Roach '<a class="sb_desc_indi" href="#"><i class="plusminus icon-minus"></i>' . 19539b853a7SGreg Roach $spouse_name . 19639b853a7SGreg Roach $marr . 19739b853a7SGreg Roach '</a>' . 1982622ba92SGreg Roach $spouse_link . 19939b853a7SGreg Roach $family_link . 2002622ba92SGreg Roach '<div>' . $this->loadChildren($family, $generations) . '</div>' . 2012622ba92SGreg Roach '</li>'; 2028c2e8227SGreg Roach } 2038c2e8227SGreg Roach 2048c2e8227SGreg Roach /** 20576692c8bSGreg Roach * Display spouses. 20676692c8bSGreg Roach * 20749a243cbSGreg Roach * @param Individual $individual 208cbc1590aSGreg Roach * @param int $generations 2098c2e8227SGreg Roach * 2108c2e8227SGreg Roach * @return string 2118c2e8227SGreg Roach */ 21249a243cbSGreg Roach public function loadSpouses(Individual $individual, $generations) 213c1010edaSGreg Roach { 2148c2e8227SGreg Roach $out = ''; 21549a243cbSGreg Roach if ($individual->canShow()) { 21639ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 21749a243cbSGreg Roach $out .= $this->getFamilyLi($family, $individual, $generations - 1); 2188c2e8227SGreg Roach } 2198c2e8227SGreg Roach } 2208c2e8227SGreg Roach if ($out) { 2218c2e8227SGreg Roach return '<ul>' . $out . '</ul>'; 2228c2e8227SGreg Roach } 223b2ce94c6SRico Sonntag 224b2ce94c6SRico Sonntag return ''; 2258c2e8227SGreg Roach } 2268c2e8227SGreg Roach 2278c2e8227SGreg Roach /** 22876692c8bSGreg Roach * Display descendants. 22976692c8bSGreg Roach * 2308c2e8227SGreg Roach * @param Family $family 231cbc1590aSGreg Roach * @param int $generations 2328c2e8227SGreg Roach * 2338c2e8227SGreg Roach * @return string 2348c2e8227SGreg Roach */ 235c1010edaSGreg Roach public function loadChildren(Family $family, $generations) 236c1010edaSGreg Roach { 2378c2e8227SGreg Roach $out = ''; 2388c2e8227SGreg Roach if ($family->canShow()) { 23939ca88baSGreg Roach $children = $family->children(); 240820b62dfSGreg Roach 241820b62dfSGreg Roach if ($children->isNotEmpty()) { 2428c2e8227SGreg Roach foreach ($children as $child) { 2438c2e8227SGreg Roach $out .= $this->getPersonLi($child, $generations - 1); 2448c2e8227SGreg Roach } 2458c2e8227SGreg Roach } else { 2468c2e8227SGreg Roach $out .= '<li class="sb_desc_none">' . I18N::translate('No children') . '</li>'; 2478c2e8227SGreg Roach } 2488c2e8227SGreg Roach } 2498c2e8227SGreg Roach if ($out) { 2508c2e8227SGreg Roach return '<ul>' . $out . '</ul>'; 2518c2e8227SGreg Roach } 252b2ce94c6SRico Sonntag 253b2ce94c6SRico Sonntag return ''; 2548c2e8227SGreg Roach } 2558c2e8227SGreg Roach} 256