xref: /webtrees/app/Module/DescendancyChartModule.php (revision 0b93976a9c83f1ad374620df2dc12a210d5be076)
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
2054452b04SGreg Roachuse Fisharebest\Webtrees\Auth;
21e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
22168ff6f3Sric2016use Fisharebest\Webtrees\I18N;
23168ff6f3Sric2016use Fisharebest\Webtrees\Individual;
24e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu;
2554452b04SGreg Roachuse Fisharebest\Webtrees\Services\ChartService;
2654452b04SGreg Roachuse Fisharebest\Webtrees\Tree;
2754452b04SGreg Roachuse Illuminate\Support\Collection;
286ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface;
296ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
30168ff6f3Sric2016
31168ff6f3Sric2016/**
32168ff6f3Sric2016 * Class DescendancyChartModule
33168ff6f3Sric2016 */
3437eb8894SGreg Roachclass DescendancyChartModule extends AbstractModule implements ModuleChartInterface
35c1010edaSGreg Roach{
3649a243cbSGreg Roach    use ModuleChartTrait;
3749a243cbSGreg Roach
3854452b04SGreg Roach    // Chart styles
3931e26437SGreg Roach    public const CHART_STYLE_TREE        = 'tree';
4031e26437SGreg Roach    public const CHART_STYLE_INDIVIDUALS = 'individuals';
4131e26437SGreg Roach    public const CHART_STYLE_FAMILIES    = 'families';
4254452b04SGreg Roach
4354452b04SGreg Roach    // Defaults
440f1e0f10SGreg Roach    public const DEFAULT_STYLE               = self::CHART_STYLE_TREE;
45677aaceaSGreg Roach    public const DEFAULT_GENERATIONS         = '3';
46e759aebbSGreg Roach
47e759aebbSGreg Roach    // Limits
48e759aebbSGreg Roach    public const MINIMUM_GENERATIONS = 2;
49e759aebbSGreg Roach    public const MAXIMUM_GENERATIONS = 10;
5054452b04SGreg Roach
5154452b04SGreg Roach    /** @var int[] */
5254452b04SGreg Roach    protected $dabo_num = [];
5354452b04SGreg Roach
5454452b04SGreg Roach    /** @var string[] */
5554452b04SGreg Roach    protected $dabo_sex = [];
5654452b04SGreg Roach
57168ff6f3Sric2016    /**
580cfd6963SGreg Roach     * How should this module be identified in the control panel, etc.?
59168ff6f3Sric2016     *
60168ff6f3Sric2016     * @return string
61168ff6f3Sric2016     */
6249a243cbSGreg Roach    public function title(): string
63c1010edaSGreg Roach    {
64bbb76c12SGreg Roach        /* I18N: Name of a module/chart */
65bbb76c12SGreg Roach        return I18N::translate('Descendants');
66168ff6f3Sric2016    }
67168ff6f3Sric2016
68168ff6f3Sric2016    /**
69168ff6f3Sric2016     * A sentence describing what this module does.
70168ff6f3Sric2016     *
71168ff6f3Sric2016     * @return string
72168ff6f3Sric2016     */
7349a243cbSGreg Roach    public function description(): string
74c1010edaSGreg Roach    {
75bbb76c12SGreg Roach        /* I18N: Description of the “DescendancyChart” module */
76bbb76c12SGreg Roach        return I18N::translate('A chart of an individual’s descendants.');
77168ff6f3Sric2016    }
78168ff6f3Sric2016
79168ff6f3Sric2016    /**
80377a2979SGreg Roach     * CSS class for the URL.
81377a2979SGreg Roach     *
82377a2979SGreg Roach     * @return string
83377a2979SGreg Roach     */
84377a2979SGreg Roach    public function chartMenuClass(): string
85377a2979SGreg Roach    {
86377a2979SGreg Roach        return 'menu-chart-descendants';
87377a2979SGreg Roach    }
88377a2979SGreg Roach
89377a2979SGreg Roach    /**
904eb71cfaSGreg Roach     * Return a menu item for this chart - for use in individual boxes.
914eb71cfaSGreg Roach     *
9260bc3e3fSGreg Roach     * @param Individual $individual
9360bc3e3fSGreg Roach     *
944eb71cfaSGreg Roach     * @return Menu|null
954eb71cfaSGreg Roach     */
96377a2979SGreg Roach    public function chartBoxMenu(Individual $individual): ?Menu
97c1010edaSGreg Roach    {
98e6562982SGreg Roach        return $this->chartMenu($individual);
99e6562982SGreg Roach    }
100e6562982SGreg Roach
101e6562982SGreg Roach    /**
102e6562982SGreg Roach     * The title for a specific instance of this chart.
103e6562982SGreg Roach     *
104e6562982SGreg Roach     * @param Individual $individual
105e6562982SGreg Roach     *
106e6562982SGreg Roach     * @return string
107e6562982SGreg Roach     */
108e6562982SGreg Roach    public function chartTitle(Individual $individual): string
109e6562982SGreg Roach    {
110e6562982SGreg Roach        /* I18N: %s is an individual’s name */
11139ca88baSGreg Roach        return I18N::translate('Descendants of %s', $individual->fullName());
112e6562982SGreg Roach    }
113e6562982SGreg Roach
114e6562982SGreg Roach    /**
11554452b04SGreg Roach     * A form to request the chart parameters.
11654452b04SGreg Roach     *
1176ccdf4f0SGreg Roach     * @param ServerRequestInterface $request
11854452b04SGreg Roach     * @param Tree                   $tree
119e5a6b4d4SGreg Roach     * @param UserInterface          $user
12054452b04SGreg Roach     * @param ChartService           $chart_service
12154452b04SGreg Roach     *
1226ccdf4f0SGreg Roach     * @return ResponseInterface
12354452b04SGreg Roach     */
1246ccdf4f0SGreg Roach    public function getChartAction(ServerRequestInterface $request, Tree $tree, UserInterface $user, ChartService $chart_service): ResponseInterface
12554452b04SGreg Roach    {
126*0b93976aSGreg Roach        $ajax       = $request->getQueryParams()['ajax'] ?? '';
12716e8b6e8SGreg Roach        $xref       = $request->getQueryParams()['xref'] ?? '';
12854452b04SGreg Roach        $individual = Individual::getInstance($xref, $tree);
12954452b04SGreg Roach
13054452b04SGreg Roach        Auth::checkIndividualAccess($individual);
1319867b2f0SGreg Roach        Auth::checkComponentAccess($this, 'chart', $tree, $user);
13254452b04SGreg Roach
13331e26437SGreg Roach        $chart_style = $request->getQueryParams()['chart_style'] ?? self::DEFAULT_STYLE;
13416e8b6e8SGreg Roach        $generations = (int) ($request->getQueryParams()['generations'] ?? self::DEFAULT_GENERATIONS);
13554452b04SGreg Roach
136e759aebbSGreg Roach        $generations = min($generations, self::MAXIMUM_GENERATIONS);
137e759aebbSGreg Roach        $generations = max($generations, self::MINIMUM_GENERATIONS);
13854452b04SGreg Roach
139*0b93976aSGreg Roach        if ($ajax === '1') {
14054452b04SGreg Roach            return $this->chart($request, $tree, $chart_service);
14154452b04SGreg Roach        }
14254452b04SGreg Roach
14354452b04SGreg Roach        $ajax_url = $this->chartUrl($individual, [
14454452b04SGreg Roach            'chart_style' => $chart_style,
14554452b04SGreg Roach            'generations' => $generations,
1469b5537c3SGreg Roach            'ajax'        => true,
14754452b04SGreg Roach        ]);
14854452b04SGreg Roach
1499b5537c3SGreg Roach        return $this->viewResponse('modules/descendancy_chart/page', [
15054452b04SGreg Roach            'ajax_url'            => $ajax_url,
15154452b04SGreg Roach            'chart_style'         => $chart_style,
15254452b04SGreg Roach            'chart_styles'        => $this->chartStyles(),
153e759aebbSGreg Roach            'default_generations' => self::DEFAULT_GENERATIONS,
15454452b04SGreg Roach            'generations'         => $generations,
15554452b04SGreg Roach            'individual'          => $individual,
156e759aebbSGreg Roach            'maximum_generations' => self::MAXIMUM_GENERATIONS,
157e759aebbSGreg Roach            'minimum_generations' => self::MINIMUM_GENERATIONS,
15826684e68SGreg Roach            'module_name'         => $this->name(),
15954452b04SGreg Roach            'title'               => $this->chartTitle($individual),
16054452b04SGreg Roach        ]);
16154452b04SGreg Roach    }
16254452b04SGreg Roach
16354452b04SGreg Roach    /**
1646ccdf4f0SGreg Roach     * @param ServerRequestInterface $request
16554452b04SGreg Roach     * @param Tree                   $tree
16654452b04SGreg Roach     * @param ChartService           $chart_service
16754452b04SGreg Roach     *
1686ccdf4f0SGreg Roach     * @return ResponseInterface
16954452b04SGreg Roach     */
1706ccdf4f0SGreg Roach    public function chart(ServerRequestInterface $request, Tree $tree, ChartService $chart_service): ResponseInterface
17154452b04SGreg Roach    {
17254452b04SGreg Roach        $this->layout = 'layouts/ajax';
17354452b04SGreg Roach
17416e8b6e8SGreg Roach        $xref       = $request->getQueryParams()['xref'];
17554452b04SGreg Roach        $individual = Individual::getInstance($xref, $tree);
17654452b04SGreg Roach
17754452b04SGreg Roach        Auth::checkIndividualAccess($individual);
17854452b04SGreg Roach
17931e26437SGreg Roach        $chart_style = $request->getQueryParams()['chart_style'];
18016e8b6e8SGreg Roach        $generations = (int) $request->getQueryParams()['generations'];
18154452b04SGreg Roach
182e759aebbSGreg Roach        $generations = min($generations, self::MAXIMUM_GENERATIONS);
183e759aebbSGreg Roach        $generations = max($generations, self::MINIMUM_GENERATIONS);
18454452b04SGreg Roach
18554452b04SGreg Roach        switch ($chart_style) {
1860f1e0f10SGreg Roach            case self::CHART_STYLE_TREE:
18754452b04SGreg Roach            default:
1880f1e0f10SGreg Roach                return response(view('modules/descendancy_chart/tree', ['individual' => $individual, 'generations' => $generations, 'daboville' => '1']));
18954452b04SGreg Roach
19054452b04SGreg Roach            case self::CHART_STYLE_INDIVIDUALS:
19154452b04SGreg Roach                $individuals = $chart_service->descendants($individual, $generations - 1);
19254452b04SGreg Roach
19354452b04SGreg Roach                return $this->descendantsIndividuals($tree, $individuals);
19454452b04SGreg Roach
19554452b04SGreg Roach            case self::CHART_STYLE_FAMILIES:
19654452b04SGreg Roach                $families = $chart_service->descendantFamilies($individual, $generations - 1);
19754452b04SGreg Roach
19854452b04SGreg Roach                return $this->descendantsFamilies($tree, $families);
19954452b04SGreg Roach        }
20054452b04SGreg Roach    }
20154452b04SGreg Roach
20254452b04SGreg Roach    /**
20354452b04SGreg Roach     * Show a tabular list of individual descendants.
20454452b04SGreg Roach     *
20554452b04SGreg Roach     * @param Tree       $tree
20654452b04SGreg Roach     * @param Collection $individuals
20754452b04SGreg Roach     *
2086ccdf4f0SGreg Roach     * @return ResponseInterface
20954452b04SGreg Roach     */
2106ccdf4f0SGreg Roach    private function descendantsIndividuals(Tree $tree, Collection $individuals): ResponseInterface
21154452b04SGreg Roach    {
21254452b04SGreg Roach        $this->layout = 'layouts/ajax';
21354452b04SGreg Roach
21454452b04SGreg Roach        return $this->viewResponse('lists/individuals-table', [
21554452b04SGreg Roach            'individuals' => $individuals,
21654452b04SGreg Roach            'sosa'        => false,
21754452b04SGreg Roach            'tree'        => $tree,
21854452b04SGreg Roach        ]);
21954452b04SGreg Roach    }
22054452b04SGreg Roach
22154452b04SGreg Roach    /**
22254452b04SGreg Roach     * Show a tabular list of individual descendants.
22354452b04SGreg Roach     *
22454452b04SGreg Roach     * @param Tree       $tree
22554452b04SGreg Roach     * @param Collection $families
22654452b04SGreg Roach     *
2276ccdf4f0SGreg Roach     * @return ResponseInterface
22854452b04SGreg Roach     */
2296ccdf4f0SGreg Roach    private function descendantsFamilies(Tree $tree, Collection $families): ResponseInterface
23054452b04SGreg Roach    {
23154452b04SGreg Roach        $this->layout = 'layouts/ajax';
23254452b04SGreg Roach
23354452b04SGreg Roach        return $this->viewResponse('lists/families-table', [
23454452b04SGreg Roach            'families' => $families,
23554452b04SGreg Roach            'tree'     => $tree,
23654452b04SGreg Roach        ]);
23754452b04SGreg Roach    }
23854452b04SGreg Roach
23954452b04SGreg Roach    /**
24054452b04SGreg Roach     * This chart can display its output in a number of styles
24154452b04SGreg Roach     *
2424db4b4a9SGreg Roach     * @return string[]
24354452b04SGreg Roach     */
24454452b04SGreg Roach    private function chartStyles(): array
24554452b04SGreg Roach    {
24654452b04SGreg Roach        return [
2470f1e0f10SGreg Roach            self::CHART_STYLE_TREE        => I18N::translate('Tree'),
24854452b04SGreg Roach            self::CHART_STYLE_INDIVIDUALS => I18N::translate('Individuals'),
24954452b04SGreg Roach            self::CHART_STYLE_FAMILIES    => I18N::translate('Families'),
25054452b04SGreg Roach        ];
251e6562982SGreg Roach    }
252168ff6f3Sric2016}
253